gen-typescript-from-tolk-dev 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/bin/generator.js +15 -0
- package/package.json +32 -0
- package/src/abi-types.ts +157 -0
- package/src/abi.ts +132 -0
- package/src/cli-generate-from-abi-json.ts +21 -0
- package/src/codegen-ctx.ts +115 -0
- package/src/dynamic-ctx.ts +55 -0
- package/src/dynamic-debug-print.ts +191 -0
- package/src/dynamic-get-methods.ts +454 -0
- package/src/dynamic-serialization.ts +430 -0
- package/src/dynamic-validation.ts +55 -0
- package/src/emit-field-defs.ts +60 -0
- package/src/emit-pack-unpack.ts +280 -0
- package/src/emit-stack-rw.ts +239 -0
- package/src/emit-ts-types.ts +66 -0
- package/src/formatting.ts +98 -0
- package/src/generate-from-abi-json.ts +22 -0
- package/src/generate-ts-wrappers.ts +477 -0
- package/src/out-template.ts +514 -0
- package/src/tolk-to-abi.ts +5 -0
- package/src/types-kernel.ts +215 -0
- package/src/unsupported-errors.ts +82 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
// AUTO-GENERATED, do not edit
|
|
2
|
+
// it's a TypeScript wrapper for a CONTRACT_CLASS_NAME contract in Tolk
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
|
|
5
|
+
import * as c from '@ton/core'
|
|
6
|
+
import { beginCell, ContractProvider, Sender, SendMode } from '@ton/core';
|
|
7
|
+
|
|
8
|
+
// ————————————————————————————————————————————
|
|
9
|
+
// predefined types and functions
|
|
10
|
+
//
|
|
11
|
+
|
|
12
|
+
// {{if:has_remaining}}
|
|
13
|
+
type RemainingBitsAndRefs = c.Slice
|
|
14
|
+
// {{/if:has_remaining}}
|
|
15
|
+
|
|
16
|
+
// {{if:has_addressAny}}
|
|
17
|
+
export type any_address = c.Address | c.ExternalAddress | 'none'
|
|
18
|
+
// {{/if:has_addressAny}}
|
|
19
|
+
|
|
20
|
+
// {{if:has_arrayOf}}
|
|
21
|
+
type array<T> = T[]
|
|
22
|
+
// {{/if:has_arrayOf}}
|
|
23
|
+
|
|
24
|
+
// {{if:has_lispListOf}}
|
|
25
|
+
// TypeScript wrappers flatten a TVM linked list `[1 [2 [3 null]]]` to `[1 2 3]`
|
|
26
|
+
type lisp_list<T> = T[]
|
|
27
|
+
// {{/if:has_lispListOf}}
|
|
28
|
+
|
|
29
|
+
type StoreCallback<T> = (obj: T, b: c.Builder) => void
|
|
30
|
+
type LoadCallback<T> = (s: c.Slice) => T
|
|
31
|
+
|
|
32
|
+
export type CellRef<T> = {
|
|
33
|
+
ref: T
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function makeCellFrom<T>(self: T, storeFn_T: StoreCallback<T>): c.Cell {
|
|
37
|
+
let b = beginCell();
|
|
38
|
+
storeFn_T(self, b);
|
|
39
|
+
return b.endCell();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function loadAndCheckPrefix32(s: c.Slice, expected: number, structName: string): void {
|
|
43
|
+
let prefix = s.loadUint(32);
|
|
44
|
+
if (prefix !== expected) {
|
|
45
|
+
throw new Error(`Incorrect prefix for '${structName}': expected 0x${expected.toString(16).padStart(8, '0')}, got 0x${prefix.toString(16).padStart(8, '0')}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// {{if:has_non32Prefixes}}
|
|
50
|
+
function formatPrefix(prefixNum: number, prefixLen: number): string {
|
|
51
|
+
return prefixLen % 4 ? `0b${prefixNum.toString(2).padStart(prefixLen, '0')}` : `0x${prefixNum.toString(16).padStart(prefixLen / 4, '0')}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function loadAndCheckPrefix(s: c.Slice, expected: number, prefixLen: number, structName: string): void {
|
|
55
|
+
let prefix = s.loadUint(prefixLen);
|
|
56
|
+
if (prefix !== expected) {
|
|
57
|
+
throw new Error(`Incorrect prefix for '${structName}': expected ${formatPrefix(expected, prefixLen)}, got ${formatPrefix(prefix, prefixLen)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// {{/if:has_non32Prefixes}}
|
|
61
|
+
|
|
62
|
+
function lookupPrefix(s: c.Slice, expected: number, prefixLen: number): boolean {
|
|
63
|
+
return s.remainingBits >= prefixLen && s.preloadUint(prefixLen) === expected;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// {{if:has_implicitUnionPrefix}}
|
|
67
|
+
function lookupPrefixAndEat(s: c.Slice, expected: number, prefixLen: number): boolean {
|
|
68
|
+
if (lookupPrefix(s, expected, prefixLen)) {
|
|
69
|
+
s.skip(prefixLen);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// {{/if:has_implicitUnionPrefix}}
|
|
75
|
+
|
|
76
|
+
function throwNonePrefixMatch(fieldPath: string): never {
|
|
77
|
+
throw new Error(`Incorrect prefix for '${fieldPath}': none of variants matched`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function storeCellRef<T>(cell: CellRef<T>, b: c.Builder, storeFn_T: StoreCallback<T>): void {
|
|
81
|
+
let b_ref = c.beginCell();
|
|
82
|
+
storeFn_T(cell.ref, b_ref);
|
|
83
|
+
b.storeRef(b_ref.endCell());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function loadCellRef<T>(s: c.Slice, loadFn_T: LoadCallback<T>): CellRef<T> {
|
|
87
|
+
let s_ref = s.loadRef().beginParse();
|
|
88
|
+
return { ref: loadFn_T(s_ref) };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// {{if:has_addressAny}}
|
|
92
|
+
function storeTolkAddressAny(a: any_address, b: c.Builder): void {
|
|
93
|
+
let maybe_addr = a === 'none' ? null : a;
|
|
94
|
+
b.storeAddress(maybe_addr);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function loadTolkAddressAny(s: c.Slice): any_address {
|
|
98
|
+
let maybe_addr = s.loadAddressAny();
|
|
99
|
+
return maybe_addr === null ? 'none' : maybe_addr;
|
|
100
|
+
}
|
|
101
|
+
// {{/if:has_addressAny}}
|
|
102
|
+
|
|
103
|
+
// {{if:has_bitsN}}
|
|
104
|
+
function storeTolkBitsN(v: c.Slice, nBits: number, b: c.Builder): void {
|
|
105
|
+
if (v.remainingBits !== nBits) { throw new Error(`expected ${nBits} bits, got ${v.remainingBits}`); }
|
|
106
|
+
if (v.remainingRefs !== 0) { throw new Error(`expected 0 refs, got ${v.remainingRefs}`); }
|
|
107
|
+
b.storeSlice(v);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function loadTolkBitsN(s: c.Slice, nBits: number): c.Slice {
|
|
111
|
+
return new c.Slice(new c.BitReader(s.loadBits(nBits)), []);
|
|
112
|
+
}
|
|
113
|
+
// {{/if:has_bitsN}}
|
|
114
|
+
|
|
115
|
+
// {{if:has_remaining}}
|
|
116
|
+
function storeTolkRemaining(v: RemainingBitsAndRefs, b: c.Builder): void {
|
|
117
|
+
b.storeSlice(v);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function loadTolkRemaining(s: c.Slice): RemainingBitsAndRefs {
|
|
121
|
+
let rest = s.clone();
|
|
122
|
+
s.loadBits(s.remainingBits);
|
|
123
|
+
while (s.remainingRefs) {
|
|
124
|
+
s.loadRef();
|
|
125
|
+
}
|
|
126
|
+
return rest;
|
|
127
|
+
}
|
|
128
|
+
// {{/if:has_remaining}}
|
|
129
|
+
|
|
130
|
+
function storeTolkNullable<T>(v: T | null, b: c.Builder, storeFn_T: StoreCallback<T>): void {
|
|
131
|
+
if (v === null) {
|
|
132
|
+
b.storeUint(0, 1);
|
|
133
|
+
} else {
|
|
134
|
+
b.storeUint(1, 1);
|
|
135
|
+
storeFn_T(v, b);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// {{if:has_arrayOf}}
|
|
140
|
+
function storeArrayOf<T>(v: array<T>, b: c.Builder, storeFn_T: StoreCallback<T>): void {
|
|
141
|
+
// the compiler stores array<T> in chunks; in TypeScript, for simplicity, store "1 elem = 1 ref"
|
|
142
|
+
let tail = null as c.Cell | null;
|
|
143
|
+
for (let i = 0; i < v.length; ++i) {
|
|
144
|
+
let chunkB = beginCell().storeMaybeRef(tail);
|
|
145
|
+
storeFn_T(v[v.length - 1 - i], chunkB);
|
|
146
|
+
tail = chunkB.endCell();
|
|
147
|
+
}
|
|
148
|
+
b.storeUint(v.length, 8);
|
|
149
|
+
b.storeMaybeRef(tail);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function loadArrayOf<T>(s: c.Slice, loadFn_T: LoadCallback<T>): array<T> {
|
|
153
|
+
let len = s.loadUint(8);
|
|
154
|
+
let head = s.loadMaybeRef();
|
|
155
|
+
let outArr = [] as array<T>;
|
|
156
|
+
while (head != null) {
|
|
157
|
+
let s = head.beginParse();
|
|
158
|
+
head = s.loadMaybeRef();
|
|
159
|
+
while (s.remainingBits || s.remainingRefs) {
|
|
160
|
+
outArr.push(loadFn_T(s));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (len !== outArr.length) {
|
|
164
|
+
throw new Error(`mismatch array binary data: expected ${len} elements, got ${outArr.length}`);
|
|
165
|
+
}
|
|
166
|
+
return outArr;
|
|
167
|
+
}
|
|
168
|
+
// {{/if:has_arrayOf}}
|
|
169
|
+
|
|
170
|
+
// {{if:has_lispListOf}}
|
|
171
|
+
function storeLispListOf<T>(v: lisp_list<T>, b: c.Builder, storeFn_T: StoreCallback<T>): void {
|
|
172
|
+
let tail = c.Cell.EMPTY;
|
|
173
|
+
for (let i = 0; i < v.length; ++i) {
|
|
174
|
+
let itemB = beginCell();
|
|
175
|
+
storeFn_T(v[i], itemB);
|
|
176
|
+
tail = itemB.storeRef(tail).endCell();
|
|
177
|
+
}
|
|
178
|
+
b.storeRef(tail);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function loadLispListOf<T>(s: c.Slice, loadFn_T: LoadCallback<T>): lisp_list<T> {
|
|
182
|
+
let outArr = [] as lisp_list<T>;
|
|
183
|
+
let head = s.loadRef().beginParse();
|
|
184
|
+
while (head.remainingRefs) {
|
|
185
|
+
let tailSnaked = head.loadRef();
|
|
186
|
+
let headValue = loadFn_T(head);
|
|
187
|
+
head.endParse(); // ensure no data is present besides T
|
|
188
|
+
outArr.unshift(headValue);
|
|
189
|
+
head = tailSnaked.beginParse();
|
|
190
|
+
}
|
|
191
|
+
return outArr;
|
|
192
|
+
}
|
|
193
|
+
// {{/if:has_lispListOf}}
|
|
194
|
+
|
|
195
|
+
// {{if:has_customDictV}}
|
|
196
|
+
function createDictionaryValue<V>(loadFn_V: LoadCallback<V>, storeFn_V: StoreCallback<V>): c.DictionaryValue<V> {
|
|
197
|
+
return {
|
|
198
|
+
serialize(self: V, b: c.Builder) {
|
|
199
|
+
storeFn_V(self, b);
|
|
200
|
+
},
|
|
201
|
+
parse(s: c.Slice): V {
|
|
202
|
+
const value = loadFn_V(s);
|
|
203
|
+
s.endParse();
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// {{/if:has_customDictV}}
|
|
209
|
+
|
|
210
|
+
// ————————————————————————————————————————————
|
|
211
|
+
// parse get methods result from a TVM stack
|
|
212
|
+
//
|
|
213
|
+
|
|
214
|
+
class StackReader {
|
|
215
|
+
constructor(private tuple: c.TupleItem[]) {
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
static fromGetMethod(expectedN: number, getMethodResult: { stack: c.TupleReader }): StackReader {
|
|
219
|
+
let tuple = [] as c.TupleItem[];
|
|
220
|
+
while (getMethodResult.stack.remaining) {
|
|
221
|
+
tuple.push(getMethodResult.stack.pop());
|
|
222
|
+
}
|
|
223
|
+
if (tuple.length !== expectedN) {
|
|
224
|
+
throw new Error(`expected ${expectedN} stack width, got ${tuple.length}`);
|
|
225
|
+
}
|
|
226
|
+
return new StackReader(tuple);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private popExpecting<ItemT>(itemType: string): ItemT {
|
|
230
|
+
const item = this.tuple.shift();
|
|
231
|
+
if (item?.type !== itemType) {
|
|
232
|
+
throw new Error(`not '${itemType}' on a stack`);
|
|
233
|
+
}
|
|
234
|
+
return item as ItemT;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
readBigInt(): bigint {
|
|
238
|
+
return this.popExpecting<c.TupleItemInt>('int').value;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
readBoolean(): boolean {
|
|
242
|
+
return this.popExpecting<c.TupleItemInt>('int').value !== 0n;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
readCell(): c.Cell {
|
|
246
|
+
return this.popExpecting<c.TupleItemCell>('cell').cell;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
readSlice(): c.Slice {
|
|
250
|
+
return this.popExpecting<c.TupleItemSlice>('slice').cell.beginParse();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// {{if:stackReadsBuilder}}
|
|
254
|
+
readBuilder(): c.Builder {
|
|
255
|
+
return beginCell().storeSlice(this.popExpecting<c.TupleItemBuilder>('builder').cell.beginParse());
|
|
256
|
+
}
|
|
257
|
+
// {{/if:stackReadsBuilder}}
|
|
258
|
+
|
|
259
|
+
// {{if:stackReadsUnknown}}
|
|
260
|
+
readUnknown(): c.TupleItem {
|
|
261
|
+
// `unknown` from Tolk is left as a raw tuple item
|
|
262
|
+
return this.tuple.shift()!;
|
|
263
|
+
}
|
|
264
|
+
// {{/if:stackReadsUnknown}}
|
|
265
|
+
|
|
266
|
+
// {{if:stackReadsArrayOf}}
|
|
267
|
+
readArrayOf<T>(readFn_T: (nestedReader: StackReader) => T): T[] {
|
|
268
|
+
const subItems = this.popExpecting<c.Tuple>('tuple').items;
|
|
269
|
+
const subReader = new StackReader(subItems);
|
|
270
|
+
// array len N => N subItems => N calls to readFn_T
|
|
271
|
+
return [...subItems].map(_ => readFn_T(subReader))
|
|
272
|
+
}
|
|
273
|
+
// {{/if:stackReadsArrayOf}}
|
|
274
|
+
|
|
275
|
+
// {{if:stackReadsLispListOf}}
|
|
276
|
+
readLispListOf<T>(readFn_T: (nestedReader: StackReader) => T): T[] {
|
|
277
|
+
// read `[1 [2 [3 null]]]` to `[1 2 3]`
|
|
278
|
+
let pairReader: StackReader = this;
|
|
279
|
+
let outArr = [] as T[];
|
|
280
|
+
while (true) {
|
|
281
|
+
if (pairReader.tuple[0].type === 'null') {
|
|
282
|
+
pairReader.tuple.shift();
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
let headAndTail = pairReader.popExpecting<c.Tuple>('tuple').items;
|
|
286
|
+
if (headAndTail.length !== 2) {
|
|
287
|
+
throw new Error(`malformed lisp_list, expected 2 stack width, got ${headAndTail.length}`);
|
|
288
|
+
}
|
|
289
|
+
pairReader = new StackReader(headAndTail);
|
|
290
|
+
outArr.push(readFn_T(pairReader));
|
|
291
|
+
}
|
|
292
|
+
return outArr;
|
|
293
|
+
}
|
|
294
|
+
// {{/if:stackReadsLispListOf}}
|
|
295
|
+
|
|
296
|
+
// {{if:stackReadsSnakeString}}
|
|
297
|
+
readSnakeString(): string {
|
|
298
|
+
return this.readCell().beginParse().loadStringTail();
|
|
299
|
+
}
|
|
300
|
+
// {{/if:stackReadsSnakeString}}
|
|
301
|
+
|
|
302
|
+
// {{if:stackReadsTuple}}
|
|
303
|
+
readTuple<T>(expectedN: number, readFn_T: (nestedReader: StackReader) => T): T {
|
|
304
|
+
const subItems = this.popExpecting<c.Tuple>('tuple').items;
|
|
305
|
+
if (subItems.length !== expectedN) {
|
|
306
|
+
throw new Error(`expected ${expectedN} items in a tuple, got ${subItems.length}`);
|
|
307
|
+
}
|
|
308
|
+
return readFn_T(new StackReader(subItems));
|
|
309
|
+
}
|
|
310
|
+
// {{/if:stackReadsTuple}}
|
|
311
|
+
|
|
312
|
+
// {{if:stackReadsNullLiteral}}
|
|
313
|
+
readNullLiteral(): null {
|
|
314
|
+
this.popExpecting<c.TupleItemNull>('null');
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
// {{/if:stackReadsNullLiteral}}
|
|
318
|
+
|
|
319
|
+
// {{if:stackReadsNullable}}
|
|
320
|
+
readNullable<T>(readFn_T: (r: StackReader) => T): T | null {
|
|
321
|
+
if (this.tuple[0].type === 'null') {
|
|
322
|
+
this.tuple.shift();
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
return readFn_T(this);
|
|
326
|
+
}
|
|
327
|
+
// {{/if:stackReadsNullable}}
|
|
328
|
+
|
|
329
|
+
// {{if:stackReadsWideNullable}}
|
|
330
|
+
readWideNullable<T>(stackW: number, readFn_T: (r: StackReader) => T): T | null {
|
|
331
|
+
const slotTypeId = this.tuple[stackW - 1];
|
|
332
|
+
if (slotTypeId?.type !== 'int') {
|
|
333
|
+
throw new Error(`not 'int' on a stack`);
|
|
334
|
+
}
|
|
335
|
+
if (slotTypeId.value === 0n) {
|
|
336
|
+
this.tuple = this.tuple.slice(stackW);
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
const valueT = readFn_T(this);
|
|
340
|
+
this.tuple.shift();
|
|
341
|
+
return valueT;
|
|
342
|
+
}
|
|
343
|
+
// {{/if:stackReadsWideNullable}}
|
|
344
|
+
|
|
345
|
+
// {{if:stackReadsUnionType}}
|
|
346
|
+
readUnionType<T>(stackW: number, infoForTypeId: Record<number, [number, string | null, (r: StackReader) => any]>): T {
|
|
347
|
+
const slotTypeId = this.tuple[stackW - 1];
|
|
348
|
+
if (slotTypeId?.type !== 'int') {
|
|
349
|
+
throw new Error(`not 'int' on a stack`);
|
|
350
|
+
}
|
|
351
|
+
const info = infoForTypeId[Number(slotTypeId.value)]; // [stackWidth, label, readFn_T{i}]
|
|
352
|
+
if (info == null) {
|
|
353
|
+
throw new Error(`unexpected UTag=${slotTypeId.value}`);
|
|
354
|
+
}
|
|
355
|
+
const label = info[1];
|
|
356
|
+
this.tuple = this.tuple.slice(stackW - 1 - info[0]);
|
|
357
|
+
const valueT = info[2](this);
|
|
358
|
+
this.tuple.shift();
|
|
359
|
+
return label == null ? valueT : { $: label, value: valueT } as T;
|
|
360
|
+
}
|
|
361
|
+
// {{/if:stackReadsUnionType}}
|
|
362
|
+
|
|
363
|
+
// {{if:stackReadsCellRef}}
|
|
364
|
+
readCellRef<T>(loadFn_T: LoadCallback<T>): CellRef<T> {
|
|
365
|
+
return { ref: loadFn_T(this.readCell().beginParse()) };
|
|
366
|
+
}
|
|
367
|
+
// {{/if:stackReadsCellRef}}
|
|
368
|
+
|
|
369
|
+
// {{if:stackReadsMapKV}}
|
|
370
|
+
readDictionary<K extends c.DictionaryKeyTypes, V>(keySerializer: c.DictionaryKey<K>, valueSerializer: c.DictionaryValue<V>): c.Dictionary<K, V> {
|
|
371
|
+
if (this.tuple[0].type === 'null') {
|
|
372
|
+
this.tuple.shift();
|
|
373
|
+
return c.Dictionary.empty<K, V>(keySerializer, valueSerializer);
|
|
374
|
+
}
|
|
375
|
+
return c.Dictionary.loadDirect<K, V>(keySerializer, valueSerializer, this.readCell());
|
|
376
|
+
}
|
|
377
|
+
// {{/if:stackReadsMapKV}}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// {{if:has_customPackUnpack}}
|
|
381
|
+
// ————————————————————————————————————————————
|
|
382
|
+
// custom packToBuilder and unpackFromSlice
|
|
383
|
+
//
|
|
384
|
+
|
|
385
|
+
type CustomPackToBuilderFn<T> = (self: T, b: c.Builder) => void
|
|
386
|
+
type CustomUnpackFromSliceFn<T> = (s: c.Slice) => T
|
|
387
|
+
|
|
388
|
+
let customSerializersRegistry: Map<string, [CustomPackToBuilderFn<any> | null, CustomUnpackFromSliceFn<any> | null]> = new Map;
|
|
389
|
+
|
|
390
|
+
function ensureCustomSerializerRegistered(typeName: string) {
|
|
391
|
+
if (!customSerializersRegistry.has(typeName)) {
|
|
392
|
+
throw new Error(`Custom packToBuilder/unpackFromSlice was not registered for type 'CONTRACT_CLASS_NAME.${typeName}'.\n(in Tolk code, they have custom logic \`fun ${typeName}__packToBuilder\`)\nSteps to fix:\n1) in your code, create and implement\n > function ${typeName}__packToBuilder(self: ${typeName}, b: Builder): void { ... }\n > function ${typeName}__unpackFromSlice(s: Slice): ${typeName} { ... }\n2) register them in advance by calling\n > CONTRACT_CLASS_NAME.registerCustomPackUnpack('${typeName}', ${typeName}__packToBuilder, ${typeName}__unpackFromSlice);`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function invokeCustomPackToBuilder<T>(typeName: string, self: T, b: c.Builder) {
|
|
397
|
+
ensureCustomSerializerRegistered(typeName);
|
|
398
|
+
customSerializersRegistry.get(typeName)![0]!(self, b);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function invokeCustomUnpackFromSlice<T>(typeName: string, s: c.Slice): T {
|
|
402
|
+
ensureCustomSerializerRegistered(typeName);
|
|
403
|
+
return customSerializersRegistry.get(typeName)![1]!(s);
|
|
404
|
+
}
|
|
405
|
+
// {{/if:has_customPackUnpack}}
|
|
406
|
+
|
|
407
|
+
// ————————————————————————————————————————————
|
|
408
|
+
// auto-generated serializers to/from cells
|
|
409
|
+
//
|
|
410
|
+
|
|
411
|
+
type coins = bigint
|
|
412
|
+
|
|
413
|
+
// {{intNAliases}}
|
|
414
|
+
|
|
415
|
+
// {{uintNAliases}}
|
|
416
|
+
|
|
417
|
+
// {{if:has_varIntN}}
|
|
418
|
+
// {{varIntNAliases}}
|
|
419
|
+
// {{/if:has_varIntN}}
|
|
420
|
+
|
|
421
|
+
// {{if:has_bitsN}}
|
|
422
|
+
// {{sliceAliases}}
|
|
423
|
+
// {{/if:has_bitsN}}
|
|
424
|
+
|
|
425
|
+
// {{packUnpackSerializers}}
|
|
426
|
+
|
|
427
|
+
// ————————————————————————————————————————————
|
|
428
|
+
// class CONTRACT_CLASS_NAME
|
|
429
|
+
//
|
|
430
|
+
|
|
431
|
+
interface ExtraSendOptions {
|
|
432
|
+
bounce?: boolean // default: false
|
|
433
|
+
sendMode?: SendMode // default: SendMode.PAY_GAS_SEPARATELY
|
|
434
|
+
extraCurrencies?: c.ExtraCurrency // default: empty dict
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
interface DeployedAddrOptions {
|
|
438
|
+
workchain?: number // default: 0 (basechain)
|
|
439
|
+
toShard?: { fixedPrefixLength: number; closeTo: c.Address }
|
|
440
|
+
overrideContractCode?: c.Cell
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedAddrOptions): c.Address {
|
|
444
|
+
const stateInitCell = beginCell().store(c.storeStateInit({
|
|
445
|
+
code,
|
|
446
|
+
data,
|
|
447
|
+
splitDepth: options.toShard?.fixedPrefixLength,
|
|
448
|
+
special: null, // todo will somebody need special?
|
|
449
|
+
libraries: null, // todo will somebody need libraries?
|
|
450
|
+
})).endCell();
|
|
451
|
+
|
|
452
|
+
let addrHash = stateInitCell.hash();
|
|
453
|
+
if (options.toShard) {
|
|
454
|
+
const shardDepth = options.toShard.fixedPrefixLength;
|
|
455
|
+
addrHash = beginCell() // todo any way to do it better? N bits from closeTo + 256-N from stateInitCell
|
|
456
|
+
.storeBits(new c.BitString(options.toShard.closeTo.hash, 0, shardDepth))
|
|
457
|
+
.storeBits(new c.BitString(stateInitCell.hash(), shardDepth, 256 - shardDepth))
|
|
458
|
+
.endCell()
|
|
459
|
+
.beginParse().loadBuffer(32);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return new c.Address(options.workchain ?? 0, addrHash);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export class CONTRACT_CLASS_NAME implements c.Contract {
|
|
466
|
+
static CodeCell = c.Cell.fromBase64('{{codeBoc64}}');
|
|
467
|
+
|
|
468
|
+
static Errors = {
|
|
469
|
+
// {{errorCodes}}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
readonly address: c.Address
|
|
473
|
+
readonly init?: { code: c.Cell, data: c.Cell }
|
|
474
|
+
|
|
475
|
+
private constructor(address: c.Address, init?: { code: c.Cell, data: c.Cell }) {
|
|
476
|
+
this.address = address;
|
|
477
|
+
this.init = init;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// {{if:has_customPackUnpack}}
|
|
481
|
+
static registerCustomPackUnpack<T>(
|
|
482
|
+
typeName: string,
|
|
483
|
+
packToBuilderFn: CustomPackToBuilderFn<T> | null,
|
|
484
|
+
unpackFromSliceFn: CustomUnpackFromSliceFn<T> | null,
|
|
485
|
+
) {
|
|
486
|
+
if (customSerializersRegistry.has(typeName)) {
|
|
487
|
+
throw new Error(`Custom pack/unpack for 'CONTRACT_CLASS_NAME.${typeName}' already registered`);
|
|
488
|
+
}
|
|
489
|
+
customSerializersRegistry.set(typeName, [packToBuilderFn, unpackFromSliceFn]);
|
|
490
|
+
}
|
|
491
|
+
// {{/if:has_customPackUnpack}}
|
|
492
|
+
|
|
493
|
+
static fromAddress(address: c.Address) {
|
|
494
|
+
return new CONTRACT_CLASS_NAME(address);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// {{fromStorageMethod}}
|
|
498
|
+
|
|
499
|
+
// {{createCellsMethods}}
|
|
500
|
+
|
|
501
|
+
// {{if:has_sendDeploy}}
|
|
502
|
+
async sendDeploy(provider: ContractProvider, via: Sender, msgValue: coins, extraOptions?: ExtraSendOptions) {
|
|
503
|
+
return provider.internal(via, {
|
|
504
|
+
value: msgValue,
|
|
505
|
+
body: c.Cell.EMPTY,
|
|
506
|
+
...extraOptions
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
// {{/if:has_sendDeploy}}
|
|
510
|
+
|
|
511
|
+
// {{sendMethods}}
|
|
512
|
+
|
|
513
|
+
// {{getMethods}}
|
|
514
|
+
}
|