From aaab72fc7728e98312a05c20ab768f203753585a Mon Sep 17 00:00:00 2001 From: Gusarich Date: Fri, 17 May 2024 13:49:58 +0300 Subject: [PATCH] work in progress --- src/generator/writers/resolveFuncFlatPack.ts | 10 + src/generator/writers/resolveFuncFlatTypes.ts | 6 + .../writers/resolveFuncTupledType.ts | 4 + src/generator/writers/resolveFuncType.ts | 13 + .../writers/resolveFuncTypeFromAbi.ts | 4 + .../writers/resolveFuncTypeFromAbiUnpack.ts | 6 + .../writers/resolveFuncTypeUnpack.ts | 4 + src/generator/writers/writeExpression.ts | 14 +- src/generator/writers/writeSerialization.ts | 21 +- src/generator/writers/writeStdlib.ts | 32 ++ src/grammar/ast.ts | 13 +- src/grammar/grammar.ohm | 1 + src/grammar/grammar.ts | 7 + src/imports/stdlib.ts | 3 +- src/packaging/fileFormat.ts | 5 + src/storage/allocator.ts | 10 + src/storage/operation.ts | 4 + src/test/features/merkle-trees.tact | 38 +++ src/types/resolveABITypeRef.ts | 18 ++ src/types/resolveDescriptors.ts | 16 + src/types/resolveExpression.ts | 24 +- src/types/resolveSignatures.ts | 7 + src/types/types.ts | 9 + stdlib/stdlib.fc | 3 + tact.config.json | 298 +----------------- 25 files changed, 277 insertions(+), 293 deletions(-) create mode 100644 src/test/features/merkle-trees.tact diff --git a/src/generator/writers/resolveFuncFlatPack.ts b/src/generator/writers/resolveFuncFlatPack.ts index b57a40eb9..c4cc27c51 100644 --- a/src/generator/writers/resolveFuncFlatPack.ts +++ b/src/generator/writers/resolveFuncFlatPack.ts @@ -32,6 +32,16 @@ export function resolveFuncFlatPack( throw Error("Void type is not allowed in function arguments: " + name); } + if (descriptor.kind === "merkle_proof") { + return [name + `'rootHash`].concat( + resolveFuncFlatPack( + getType(ctx.ctx, descriptor.name), + name + `'data`, + ctx, + ), + ); + } + // TypeDescription if (descriptor.kind === "primitive") { return [name]; diff --git a/src/generator/writers/resolveFuncFlatTypes.ts b/src/generator/writers/resolveFuncFlatTypes.ts index d70590c65..023f4d876 100644 --- a/src/generator/writers/resolveFuncFlatTypes.ts +++ b/src/generator/writers/resolveFuncFlatTypes.ts @@ -31,6 +31,12 @@ export function resolveFuncFlatTypes( throw Error("Void type is not allowed in function arguments"); } + if (descriptor.kind === "merkle_proof") { + return ["int"].concat( + resolveFuncFlatTypes(getType(ctx.ctx, descriptor.name), ctx), + ); + } + // TypeDescription if (descriptor.kind === "primitive") { return [resolveFuncType(descriptor, ctx)]; diff --git a/src/generator/writers/resolveFuncTupledType.ts b/src/generator/writers/resolveFuncTupledType.ts index 12181f685..435aeb4dd 100644 --- a/src/generator/writers/resolveFuncTupledType.ts +++ b/src/generator/writers/resolveFuncTupledType.ts @@ -25,6 +25,10 @@ export function resolveFuncTupledType( return "()"; } + if (descriptor.kind === "merkle_proof") { + return "tuple"; + } + // TypeDescription if (descriptor.kind === "primitive") { if (descriptor.name === "Int") { diff --git a/src/generator/writers/resolveFuncType.ts b/src/generator/writers/resolveFuncType.ts index 6e113d787..11d0a2dfd 100644 --- a/src/generator/writers/resolveFuncType.ts +++ b/src/generator/writers/resolveFuncType.ts @@ -42,6 +42,19 @@ export function resolveFuncType( return "()"; } + if (descriptor.kind === "merkle_proof") { + return ( + "(int, " + + resolveFuncType( + getType(ctx.ctx, descriptor.name), + ctx, + false, + usePartialFields, + ) + + ")" + ); + } + // TypeDescription if (descriptor.kind === "primitive") { if (descriptor.name === "Int") { diff --git a/src/generator/writers/resolveFuncTypeFromAbi.ts b/src/generator/writers/resolveFuncTypeFromAbi.ts index 9d4dd4277..887852dc0 100644 --- a/src/generator/writers/resolveFuncTypeFromAbi.ts +++ b/src/generator/writers/resolveFuncTypeFromAbi.ts @@ -13,6 +13,10 @@ export function resolveFuncTypeFromAbi( for (const f of fields) { if (f.kind === "dict") { res.push("cell"); + } else if (f.kind === "merkle") { + const t = getType(ctx.ctx, f.name); + const loaded = t.fields.map((v) => v.abi.type); + res.push("(int, " + resolveFuncTypeFromAbi(loaded, ctx) + ")"); } else if (f.kind === "simple") { if (f.type === "int" || f.type === "uint" || f.type === "bool") { res.push("int"); diff --git a/src/generator/writers/resolveFuncTypeFromAbiUnpack.ts b/src/generator/writers/resolveFuncTypeFromAbiUnpack.ts index e50498fa6..cbadc8e69 100644 --- a/src/generator/writers/resolveFuncTypeFromAbiUnpack.ts +++ b/src/generator/writers/resolveFuncTypeFromAbiUnpack.ts @@ -14,6 +14,12 @@ export function resolveFuncTypeFromAbiUnpack( for (const f of fields) { if (f.type.kind === "dict") { res.push(`${name}'${f.name}`); + } else if (f.type.kind === "merkle") { + const t = getType(ctx.ctx, f.type.name); + const loaded = t.fields.map((v) => v.abi); + res.push( + resolveFuncTypeFromAbiUnpack(`${name}'${f.name}`, loaded, ctx), + ); } else if (f.type.kind === "simple") { if ( f.type.type === "int" || diff --git a/src/generator/writers/resolveFuncTypeUnpack.ts b/src/generator/writers/resolveFuncTypeUnpack.ts index 1396a977a..52ce1c374 100644 --- a/src/generator/writers/resolveFuncTypeUnpack.ts +++ b/src/generator/writers/resolveFuncTypeUnpack.ts @@ -46,6 +46,10 @@ export function resolveFuncTypeUnpack( throw Error("Void type is not allowed in function arguments: " + name); } + if (descriptor.kind === "merkle_proof") { + return `(${name}'rootHash, ${name}'data)`; + } + // TypeDescription if (descriptor.kind === "primitive") { return name; diff --git a/src/generator/writers/writeExpression.ts b/src/generator/writers/writeExpression.ts index 55499590b..e2a0f7aa0 100644 --- a/src/generator/writers/writeExpression.ts +++ b/src/generator/writers/writeExpression.ts @@ -483,13 +483,25 @@ export function writeExpression(f: ASTExpression, ctx: WriterContext): string { const src = getExpType(ctx.ctx, f.src); if ( src === null || - ((src.kind !== "ref" || src.optional) && src.kind !== "ref_bounced") + ((src.kind !== "ref" || src.optional) && + src.kind !== "ref_bounced" && + src.kind !== "merkle_proof") ) { throwError( `Cannot access field of non-struct type: ${printTypeRef(src)}`, f.ref, ); } + + if (src.kind === "merkle_proof") { + if (f.name === "rootHash") { + return `${writeExpression(f.src, ctx)}'rootHash`; + } + if (f.name === "data") { + return `${writeExpression(f.src, ctx)}'data`; + } + } + const srcT = getType(ctx.ctx, src.name); // Resolve field diff --git a/src/generator/writers/writeSerialization.ts b/src/generator/writers/writeSerialization.ts index 2c7ef7460..2bb34f864 100644 --- a/src/generator/writers/writeSerialization.ts +++ b/src/generator/writers/writeSerialization.ts @@ -292,6 +292,13 @@ function writeSerializerField( } return; } + if (op.kind === "merkle_proof") { + ctx.used(`__tact_store_merkle_proof`); + ctx.append( + `build_${gen} = __tact_store_merkle_proof(build_${gen}, ${fieldName});`, + ); + return; + } throw Error("Unsupported field kind: " + op.kind); } @@ -432,7 +439,8 @@ function writeFieldParser( ctx: WriterContext, ) { const op = f.op; - const varName = `var v'${f.name}`; + const name = `v'${f.name}`; + const varName = `var ${name}`; // Handle int if (op.kind === "int") { @@ -590,6 +598,17 @@ function writeFieldParser( } return; } + if (op.kind === "merkle_proof") { + console.log(varName); + ctx.used(`__tact_load_merkle_proof`); + ctx.append( + `var (${name}'rootHash, ${name}'data) = __tact_load_merkle_proof(sc_${gen});`, + ); + ctx.append( + `${varName} = (${name}'rootHash, ${ops.reader(op.dataType, ctx)}(${name}'data.begin_parse()));`, + ); + return; + } throw Error("Unsupported field kind: " + op.kind); } diff --git a/src/generator/writers/writeStdlib.ts b/src/generator/writers/writeStdlib.ts index 15505e732..7af106b53 100644 --- a/src/generator/writers/writeStdlib.ts +++ b/src/generator/writers/writeStdlib.ts @@ -13,6 +13,38 @@ export function writeStdlib(ctx: WriterContext) { ctx.skip("__tact_slice_to_str"); ctx.skip("__tact_address_to_slice"); + // + // Extotic cell (libraries, merkle proofs, merkle updates) + // + + ctx.fun("__tact_load_merkle_proof", () => { + ctx.signature(`(int, cell) __tact_load_merkle_proof(slice cs)`); + ctx.flag("inline"); + ctx.context("stdlib"); + ctx.body(() => { + ctx.write(` + cell proof_cell = cs~load_ref(); + (slice cs, int exotic?) = proof_cell.begin_parse_exotic(); + throw_unless(42, exotic?); + throw_unless(43, cs~load_uint(8) == 3); + return (cs~load_uint(256), cs~load_ref()); + `); + }); + }); + + ctx.fun("__tact_store_merkle_proof", () => { + ctx.signature( + `builder __tact_store_merkle_proof(builder b, int rootHash, cell data)`, + ); + ctx.flag("inline"); + ctx.context("stdlib"); + ctx.body(() => { + ctx.write(` + return b.store_ref(begin_cell().store_uint(3, 8).store_uint(rootHash, 256).store_ref(data).end_cell_exotic()); + `); + }); + }); + // // Addresses // diff --git a/src/grammar/ast.ts b/src/grammar/ast.ts index af824dfcb..678debf93 100644 --- a/src/grammar/ast.ts +++ b/src/grammar/ast.ts @@ -118,7 +118,18 @@ export type ASTTypeRefBounced = { ref: ASTRef; }; -export type ASTTypeRef = ASTTypeRefSimple | ASTTypeRefMap | ASTTypeRefBounced; +export type ASTTypeRefMerkleProof = { + kind: "type_ref_merkle_proof"; + id: number; + name: string; + ref: ASTRef; +}; + +export type ASTTypeRef = + | ASTTypeRefSimple + | ASTTypeRefMap + | ASTTypeRefBounced + | ASTTypeRefMerkleProof; // // Expressions diff --git a/src/grammar/grammar.ohm b/src/grammar/grammar.ohm index 2bdb4dd95..ea89d0a1a 100644 --- a/src/grammar/grammar.ohm +++ b/src/grammar/grammar.ohm @@ -25,6 +25,7 @@ Tact { | typeLiteral --required | "map" "<" typeLiteral (as id)? "," typeLiteral (as id)? ">" --map | "bounced" "<" typeLiteral ">" --bounced + | "merkleProof" "<" typeLiteral (as id)? ">" --merkleProof Field = id ":" Type ";" --default | id ":" Type "=" Expression ";" --defaultWithInit | id ":" Type as id ";" --withSerialization diff --git a/src/grammar/grammar.ts b/src/grammar/grammar.ts index 3e89ab3b4..987008af3 100644 --- a/src/grammar/grammar.ts +++ b/src/grammar/grammar.ts @@ -978,6 +978,13 @@ semantics.addOperation("resolve_expression", { ref: createRef(this), }); }, + Type_merkleProof(_arg0, _arg1, arg2, _arg3, _arg4, _arg5) { + return createNode({ + kind: "type_ref_merkle_proof", + name: arg2.sourceString, + ref: createRef(this), + }); + }, // Binary ExpressionAdd_add(arg0, _arg1, arg2) { diff --git a/src/imports/stdlib.ts b/src/imports/stdlib.ts index c6673c2a2..d20c1fccc 100644 --- a/src/imports/stdlib.ts +++ b/src/imports/stdlib.ts @@ -633,7 +633,8 @@ files['stdlib.fc'] = 'Ozs7IEVxdWl2YWxlbnQgdG8gcmFuZG9taXplKGN1cl9sdCgpKTsuCigpIHJhbmRvbWl6ZV9sdCgpIGltcHVyZSBhc20gIkxUSU1FIiAiQUREUkFORCI7Cgo7OzsgQ2hl' + 'Y2tzIHdoZXRoZXIgdGhlIGRhdGEgcGFydHMgb2YgdHdvIHNsaWNlcyBjb2luc2lkZQppbnQgZXF1YWxfc2xpY2VfYml0cyAoc2xpY2UgYSwgc2xpY2UgYikgYXNtICJT' + 'REVRIjsKCjs7OyBDb25jYXRlbmF0ZXMgdHdvIGJ1aWxkZXJzCmJ1aWxkZXIgc3RvcmVfYnVpbGRlcihidWlsZGVyIHRvLCBidWlsZGVyIGZyb20pIGFzbSAiU1RCUiI7' + - 'Cg=='; + 'Cgooc2xpY2UsIGludCkgYmVnaW5fcGFyc2VfZXhvdGljKGNlbGwgYykgYXNtICJYQ1RPUyI7CmNlbGwgZW5kX2NlbGxfZXhvdGljKHNsaWNlIHMpIGFzbSAiRU5EWEMi' + + 'Ow=='; files['stdlib.tact'] = 'aW1wb3J0ICIuL3N0ZC9wcmltaXRpdmVzIjsKaW1wb3J0ICIuL3N0ZC9jZWxscyI7CmltcG9ydCAiLi9zdGQvY3J5cHRvIjsKaW1wb3J0ICIuL3N0ZC90ZXh0IjsKaW1w' + 'b3J0ICIuL3N0ZC9tYXRoIjsKaW1wb3J0ICIuL3N0ZC9jb250cmFjdCI7CmltcG9ydCAiLi9zdGQvZGVidWciOwppbXBvcnQgIi4vc3RkL2NvbnRleHQiOwppbXBvcnQg' + diff --git a/src/packaging/fileFormat.ts b/src/packaging/fileFormat.ts index a177d5df1..a63331cd0 100644 --- a/src/packaging/fileFormat.ts +++ b/src/packaging/fileFormat.ts @@ -27,6 +27,11 @@ export const typeFormat = z.union([ .optional() .nullable(), }), + z.object({ + kind: z.literal("merkle"), + type: z.string(), + name: z.string(), + }), ]); export const initFormat = z.object({ diff --git a/src/storage/allocator.ts b/src/storage/allocator.ts index fde6c2dcf..cc1c8e2f1 100644 --- a/src/storage/allocator.ts +++ b/src/storage/allocator.ts @@ -47,6 +47,8 @@ export function getOperationSize(src: AllocationOperationType): { } } else if (src.kind === "map") { return { bits: 1, refs: 1 }; + } else if (src.kind === "merkle_proof") { + return { bits: 0, refs: 1 }; } else if (src.kind === "struct") { if (src.ref) { if (src.optional) { @@ -295,6 +297,14 @@ export function getAllocationOperationFromField( return { kind: "map" }; } + // Merkle proof and update + if (src.kind === "merkle") { + if (src.type === "proof") { + return { kind: "merkle_proof", dataType: src.name }; + } + throw Error("Unsupported merkle type " + src.type); + } + throw new Error("Unsupported operation"); } diff --git a/src/storage/operation.ts b/src/storage/operation.ts index 7b18fb466..64ca09968 100644 --- a/src/storage/operation.ts +++ b/src/storage/operation.ts @@ -55,6 +55,10 @@ export type AllocationOperationType = | { kind: "map"; } + | { + kind: "merkle_proof"; + dataType: string; + } | { kind: "string"; optional: boolean; diff --git a/src/test/features/merkle-trees.tact b/src/test/features/merkle-trees.tact new file mode 100644 index 000000000..7fa49e8b3 --- /dev/null +++ b/src/test/features/merkle-trees.tact @@ -0,0 +1,38 @@ +import "@stdlib/deploy"; + +struct AirdropEntry { + address: Address; + amount: Int as coins; +} + +struct ProvableData { + justForTestPurposes: Int; + entries: map; + anoterOne: Int as uint32; +} + +message ProcessClaim { + queryId: Int as uint64; + proof: merkleProof; + index: Int as uint256; +} + +contract MerkleTreesTestContract with Deployable { + rootHash: Int; + + init(rootHash: Int) { + self.rootHash = rootHash; + } + + receive(msg: ProcessClaim) { + require(msg.proof.rootHash == self.rootHash, "wrong merkle root"); + let entry: AirdropEntry = msg.proof.data.entries.get(msg.index)!!; + + send(SendParameters{ + to: entry.address, + value: 0, + mode: SendIgnoreErrors, + body: entry.toCell() + }); + } +} \ No newline at end of file diff --git a/src/types/resolveABITypeRef.ts b/src/types/resolveABITypeRef.ts index 696cd74fd..386a7f90b 100644 --- a/src/types/resolveABITypeRef.ts +++ b/src/types/resolveABITypeRef.ts @@ -297,6 +297,16 @@ export function resolveABIType(src: ASTField): ABITypeRef { return { kind: "dict", key, keyFormat, value, valueFormat }; } + // Merkle Proof + + if (src.type.kind === "type_ref_merkle_proof") { + return { + kind: "merkle", + type: "proof", + name: src.type.name, + }; + } + throwError(`Unsupported type`, src.ref); } @@ -432,5 +442,13 @@ export function createABITypeRefFromTypeRef( throw Error("Unexpected bounced reference"); } + if (src.kind === "merkle_proof") { + return { + kind: "merkle", + type: "proof", + name: src.name, + }; + } + throw Error(`Unsupported type`); } diff --git a/src/types/resolveDescriptors.ts b/src/types/resolveDescriptors.ts index a0567b111..a0be9b981 100644 --- a/src/types/resolveDescriptors.ts +++ b/src/types/resolveDescriptors.ts @@ -136,6 +136,13 @@ export function resolveTypeRef(ctx: CompilerContext, src: ASTTypeRef): TypeRef { name: t.name, }; } + if (src.kind === "type_ref_merkle_proof") { + const t = getType(ctx, src.name); + return { + kind: "merkle_proof", + name: t.name, + }; + } throw Error("Invalid type ref"); } @@ -174,6 +181,15 @@ function buildTypeRef( name: src.name, }; } + if (src.kind === "type_ref_merkle_proof") { + if (!types.has(src.name)) { + throwError("Type " + src.name + " not found", src.ref); + } + return { + kind: "merkle_proof", + name: src.name, + }; + } throw Error("Unknown type ref"); } diff --git a/src/types/resolveExpression.ts b/src/types/resolveExpression.ts index 4bf502371..1bc0b4d5a 100644 --- a/src/types/resolveExpression.ts +++ b/src/types/resolveExpression.ts @@ -361,9 +361,13 @@ function resolveField( // Find target type and check for type const src = getExpType(ctx, exp.src); + console.log(src); + if ( src === null || - ((src.kind !== "ref" || src.optional) && src.kind !== "ref_bounced") + ((src.kind !== "ref" || src.optional) && + src.kind !== "ref_bounced" && + src.kind !== "merkle_proof") ) { throwError( `Invalid type "${printTypeRef(src)}" for field access`, @@ -383,6 +387,24 @@ function resolveField( } // Find field + + if (src.kind === "merkle_proof") { + if (exp.name === "rootHash") { + return registerExpType(ctx, exp, { + kind: "ref", + name: "Int", + optional: false, + }); + } + if (exp.name === "data") { + return registerExpType(ctx, exp, { + kind: "ref", + name: src.name, + optional: false, + }); + } + } + let fields: FieldDescription[]; const srcT = getType(ctx, src.name); diff --git a/src/types/resolveSignatures.ts b/src/types/resolveSignatures.ts index 68b9d07ea..036b78c39 100644 --- a/src/types/resolveSignatures.ts +++ b/src/types/resolveSignatures.ts @@ -124,6 +124,13 @@ export function resolveSignatures(ctx: CompilerContext) { return src.name + ":dict<" + key + ", " + value + ">"; } + if (src.type.kind === "merkle") { + if (src.type.type === "proof") { + return src.name + ":merkle_proof<" + src.type.name + ">"; + } + throw Error("Unsupported merkle type " + src.type.type); + } + throw Error("Unsupported ABI field"); } diff --git a/src/types/types.ts b/src/types/types.ts index f44bc278e..bc5c78a49 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -50,6 +50,10 @@ export type TypeRef = kind: "ref_bounced"; name: string; } + | { + kind: "merkle_proof"; + name: string; + } | { kind: "void"; } @@ -186,6 +190,8 @@ export function printTypeRef(src: TypeRef): string { return ""; } else if (src.kind === "ref_bounced") { return `bounced<${src.name}>`; + } else if (src.kind === "merkle_proof") { + return `MerkleProof<${src.name}>`; } else { throw Error("Invalid type ref"); } @@ -204,6 +210,9 @@ export function typeRefEquals(a: TypeRef, b: TypeRef) { if (a.kind === "ref_bounced" && b.kind === "ref_bounced") { return a.name === b.name; } + if (a.kind === "merkle_proof" && b.kind === "merkle_proof") { + return a.name === b.name; + } if (a.kind === "null" && b.kind === "null") { return true; } diff --git a/stdlib/stdlib.fc b/stdlib/stdlib.fc index 978b94738..d98b6554e 100644 --- a/stdlib/stdlib.fc +++ b/stdlib/stdlib.fc @@ -637,3 +637,6 @@ int equal_slice_bits (slice a, slice b) asm "SDEQ"; ;;; Concatenates two builders builder store_builder(builder to, builder from) asm "STBR"; + +(slice, int) begin_parse_exotic(cell c) asm "XCTOS"; +cell end_cell_exotic(slice s) asm "ENDXC"; \ No newline at end of file diff --git a/tact.config.json b/tact.config.json index d5b2e7b55..1eb4769e9 100644 --- a/tact.config.json +++ b/tact.config.json @@ -1,291 +1,13 @@ { - "$schema": "http://raw.githubusercontent.com/tact-lang/tact/main/grammar/configSchema.json", - "projects": [ - { - "name": "echo", - "path": "./examples/echo.tact", - "output": "./examples/output" - }, - { - "name": "inheritance", - "path": "./examples/inheritance.tact", - "output": "./examples/output" - }, - { - "name": "large", - "path": "./examples/large.tact", - "output": "./examples/output" - }, - { - "name": "native", - "path": "./examples/native.tact", - "output": "./examples/output" - }, - { - "name": "maps", - "path": "./examples/maps.tact", - "output": "./examples/output" - }, - { - "name": "payouts", - "path": "./examples/payouts.tact", - "output": "./examples/output" - }, - { - "name": "external", - "path": "./examples/external.tact", - "output": "./examples/output", - "options": { - "external": true - } - }, - { - "name": "wallet", - "path": "./examples/wallet.tact", - "output": "./examples/output" - }, - { - "name": "wallet-opt", - "path": "./examples/wallet-opt.tact", - "output": "./examples/output", - "options": { - "experimental": { - "inline": true + "$schema": "http://raw.githubusercontent.com/tact-lang/tact/main/grammar/configSchema.json", + "projects": [ + { + "name": "merkle-trees", + "path": "./src/test/features/merkle-trees.tact", + "output": "./src/test/features/output", + "options": { + "debug": true + } } - } - }, - { - "name": "treasure", - "path": "./examples/treasure.tact", - "output": "./examples/output" - }, - { - "name": "multisig", - "path": "./examples/multisig.tact", - "output": "./examples/output" - }, - { - "name": "multisig-3", - "path": "./examples/multisig-3.tact", - "output": "./examples/output" - }, - { - "name": "increment", - "path": "./examples/increment.tact", - "output": "./examples/output" - }, - { - "name": "rugpull", - "path": "./examples/rugpull.tact", - "output": "./examples/output" - }, - { - "name": "maps", - "path": "./src/test/features/maps.tact", - "output": "./src/test/features/output" - }, - { - "name": "map-traverse", - "path": "./src/test/features/map-traverse.tact", - "output": "./src/test/features/output" - }, - { - "name": "optionals", - "path": "./src/test/features/optionals.tact", - "output": "./src/test/features/output", - "options": { - "debug": true, - "masterchain": true - } - }, - { - "name": "serialization", - "path": "./src/test/features/serialization.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "serialization-2", - "path": "./src/test/features/serialization-2.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "serialization-3", - "path": "./src/test/features/serialization-3.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "strings", - "path": "./src/test/features/strings.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "constants", - "path": "./src/test/features/constants.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "math", - "path": "./src/test/features/math.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "dns", - "path": "./src/test/features/dns.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "integer-literals", - "path": "./src/test/features/integer-literals.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "random", - "path": "./src/test/features/random.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "ordering", - "path": "./src/test/features/ordering.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "deep", - "path": "./src/test/features/deep-sequence.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "bounced-routing", - "path": "./src/test/features/bounced-routing.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "debug", - "path": "./src/test/features/debug.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "send", - "path": "./src/test/features/send.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "intrinsics", - "path": "./src/test/features/intrinsics.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "masterchain", - "path": "./src/test/features/masterchain.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "try-catch", - "path": "./src/test/features/try-catch.tact", - "output": "./src/test/features/output" - }, - { - "name": "masterchain-allow", - "path": "./src/test/features/masterchain.tact", - "output": "./src/test/features/output", - "options": { - "debug": true, - "masterchain": true - } - }, - { - "name": "address", - "path": "./src/test/features/address.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "ternary", - "path": "./src/test/features/ternary.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "implicit-init", - "path": "./src/test/features/implicit-init.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, - { - "name": "benchmark_functions", - "path": "./src/benchmarks/contracts/functions.tact", - "output": "./src/benchmarks/contracts/output" - }, - { - "name": "benchmark_functions_inline", - "path": "./src/benchmarks/contracts/functions.tact", - "output": "./src/benchmarks/contracts/output", - "options": { - "experimental": { - "inline": true - } - } - }, - { - "name": "bugs", - "path": "./src/test/bugs/bugs.tact", - "output": "./src/test/bugs/output", - "options": { - "debug": true - } - } - ] + ] }