From 59677d8ef99a4db87a8d59d0f28112a29eb70863 Mon Sep 17 00:00:00 2001 From: Novus Nota <68142933+novusnota@users.noreply.github.com> Date: Sun, 25 Aug 2024 10:38:22 +0200 Subject: [PATCH] feat: uint1-256 and int1-257 serialization formats for Ints (#558) In accordance to built-in types of TL-B & TON: https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types --- CHANGELOG.md | 1 + src/storage/allocator.ts | 93 ++++------------ .../__snapshots__/map.spec.ts.snap | 10 +- .../__snapshots__/structs.spec.ts.snap | 6 +- src/test/e2e-emulated/contracts/maps.tact | 87 ++++++++++++++- src/test/e2e-emulated/contracts/structs.tact | 52 ++++++++- src/test/e2e-emulated/map.spec.ts | 101 ++++++++++++++++++ src/test/e2e-emulated/structs.spec.ts | 52 +++++++++ src/types/resolveABITypeRef.ts | 45 +++----- src/types/resolveDescriptors.ts | 19 +--- 10 files changed, 330 insertions(+), 136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e4b1d418..c3b997496 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `exists` method for the `Map` type: PR [#581](https://github.com/tact-lang/tact/pull/581) - The `storeBit` method for `Builder` type and the `loadBit` method for `Slice` type: PR [#699](https://github.com/tact-lang/tact/pull/699) - The `toSlice` method for structs and messages: PR [#630](https://github.com/tact-lang/tact/pull/630) +- Wider range of serialization options for integers — `uint1` through `uint256` and `int1` through `int257`: PR [#558](https://github.com/tact-lang/tact/pull/558) ### Changed diff --git a/src/storage/allocator.ts b/src/storage/allocator.ts index 5a73eb600..27ab63d54 100644 --- a/src/storage/allocator.ts +++ b/src/storage/allocator.ts @@ -76,49 +76,17 @@ export function getAllocationOperationFromField( switch (src.kind) { case "simple": { if (src.type === "int") { - if (src.format === 8) { - return { - kind: "int", - bits: 8, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 16) { - return { - kind: "int", - bits: 16, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 32) { - return { - kind: "int", - bits: 32, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 64) { - return { - kind: "int", - bits: 64, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 128) { - return { - kind: "int", - bits: 128, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 256) { - return { - kind: "int", - bits: 256, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 257) { + if (typeof src.format === "number") { + if (src.format < 1 || src.format > 257) { + throw Error("Unsupported int format " + src.format); + } return { kind: "int", - bits: 257, + bits: src.format, optional: src.optional ? src.optional : false, }; - } else if (src.format !== null && src.format !== undefined) { + } + if (src.format !== null && src.format !== undefined) { throwInternalCompilerError( `Unsupported int format: ${src.format}`, ); @@ -130,50 +98,27 @@ export function getAllocationOperationFromField( }; } if (src.type === "uint") { - if (src.format === 8) { - return { - kind: "uint", - bits: 8, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 16) { - return { - kind: "uint", - bits: 16, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 32) { - return { - kind: "uint", - bits: 32, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 64) { - return { - kind: "uint", - bits: 64, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 128) { - return { - kind: "uint", - bits: 128, - optional: src.optional ? src.optional : false, - }; - } else if (src.format === 256) { + if (typeof src.format === "number") { + if (src.format < 1 || src.format > 256) { + throwInternalCompilerError( + `Unsupported uint format: ${src.format}`, + ); + } return { kind: "uint", - bits: 256, + bits: src.format, optional: src.optional ? src.optional : false, }; - } else if (src.format === "coins") { + } + if (src.format === "coins") { return { kind: "coins", optional: src.optional ? src.optional : false, }; - } else if (src.format !== null && src.format !== undefined) { + } + if (src.format !== null && src.format !== undefined) { throwInternalCompilerError( - `Unsupported int format: ${src.format}`, + `Unsupported uint format: ${src.format}`, ); } return { diff --git a/src/test/e2e-emulated/__snapshots__/map.spec.ts.snap b/src/test/e2e-emulated/__snapshots__/map.spec.ts.snap index 18def729b..06567310e 100644 --- a/src/test/e2e-emulated/__snapshots__/map.spec.ts.snap +++ b/src/test/e2e-emulated/__snapshots__/map.spec.ts.snap @@ -3,11 +3,11 @@ exports[`map should implement maps correctly 1`] = ` [ { - "$seq": 163, + "$seq": 173, "events": [ { "$type": "storage-charged", - "amount": "0.000000108", + "amount": "0.000000123", }, { "$type": "received", @@ -18,7 +18,7 @@ exports[`map should implement maps correctly 1`] = ` }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQD2HX3w4uRmCoe34-siEhRl5sEC6x8BSBZexutmtSOfYWoh", + "to": "kQB3MEsMEVBqn5m5-U9gWK8kE3oZHyWyY65DHGZB_94zLiUy", "type": "internal", "value": "1", }, @@ -36,10 +36,10 @@ exports[`map should implement maps correctly 1`] = ` "type": "cell", }, "bounce": false, - "from": "kQD2HX3w4uRmCoe34-siEhRl5sEC6x8BSBZexutmtSOfYWoh", + "from": "kQB3MEsMEVBqn5m5-U9gWK8kE3oZHyWyY65DHGZB_94zLiUy", "to": "@treasure(treasure)", "type": "internal", - "value": "0.982029", + "value": "0.981251", }, }, ], diff --git a/src/test/e2e-emulated/__snapshots__/structs.spec.ts.snap b/src/test/e2e-emulated/__snapshots__/structs.spec.ts.snap index b781726f9..271c2710c 100644 --- a/src/test/e2e-emulated/__snapshots__/structs.spec.ts.snap +++ b/src/test/e2e-emulated/__snapshots__/structs.spec.ts.snap @@ -289,7 +289,7 @@ exports[`structs should implement structs correctly 13`] = ` "events": [ { "$type": "storage-charged", - "amount": "0.000000035", + "amount": "0.000000038", }, { "$type": "received", @@ -300,7 +300,7 @@ exports[`structs should implement structs correctly 13`] = ` }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQCHYvnW92OPDk0lG_YI0DX9anWqZygSM4vJtR-ctm9picG2", + "to": "kQAEcYCw2VVyGBNnzjxjFiYHNMAveBH1SXQ3gL7H00QQaLQS", "type": "internal", "value": "10", }, @@ -318,7 +318,7 @@ exports[`structs should implement structs correctly 13`] = ` "type": "cell", }, "bounce": false, - "from": "kQCHYvnW92OPDk0lG_YI0DX9anWqZygSM4vJtR-ctm9picG2", + "from": "kQAEcYCw2VVyGBNnzjxjFiYHNMAveBH1SXQ3gL7H00QQaLQS", "to": "@treasure(treasure)", "type": "internal", "value": "9.988015", diff --git a/src/test/e2e-emulated/contracts/maps.tact b/src/test/e2e-emulated/contracts/maps.tact index 5c7e03f67..15c537cc5 100644 --- a/src/test/e2e-emulated/contracts/maps.tact +++ b/src/test/e2e-emulated/contracts/maps.tact @@ -43,6 +43,11 @@ message SetUIntMap9 { value: Int?; } +message SetUIntMap10 { + key: Int; + value: Int?; +} + message SetAddrMap1 { key: Address; value: Int?; @@ -118,6 +123,10 @@ message DelUIntMap9 { key: Int; } +message DelUIntMap10 { + key: Int; +} + message DelAddrMap1 { key: Address; } @@ -197,6 +206,11 @@ contract MapTestContract { intMap9_5: map; intMap9_6: map; + intMap10_1: map; + intMap10_2: map; + intMap10_3: map; + intMap10_4: map; + receive(msg: SetIntMap1) { self.intMap1.set(msg.key, msg.value); } @@ -255,6 +269,13 @@ contract MapTestContract { self.intMap9_6.set(msg.key, msg.value); } + receive(msg: SetUIntMap10) { + self.intMap10_1.set(msg.key, msg.value); + self.intMap10_2.set(msg.key, msg.value); + self.intMap10_3.set(msg.key, msg.value); + self.intMap10_4.set(msg.key, msg.value); + } + receive(msg: DelIntMap1) { self.intMap1.del(msg.key); } @@ -314,6 +335,13 @@ contract MapTestContract { self.intMap9_6.del(msg.key); } + receive(msg: DelUIntMap10) { + self.intMap10_1.del(msg.key); + self.intMap10_2.del(msg.key); + self.intMap10_3.del(msg.key); + self.intMap10_4.del(msg.key); + } + get fun intMap1(): map { return self.intMap1; } @@ -562,6 +590,38 @@ contract MapTestContract { return self.intMap9_6.get(key); } + get fun intMap10_1(): map { + return self.intMap10_1; + } + + get fun intMap10_1Value(key: Int): Int? { + return self.intMap10_1.get(key); + } + + get fun intMap10_2(): map { + return self.intMap10_2; + } + + get fun intMap10_2Value(key: Int): Int? { + return self.intMap10_2.get(key); + } + + get fun intMap10_3(): map { + return self.intMap10_3; + } + + get fun intMap10_3Value(key: Int): Int? { + return self.intMap10_3.get(key); + } + + get fun intMap10_4(): map { + return self.intMap10_4; + } + + get fun intMap10_4Value(key: Int): Int? { + return self.intMap10_4.get(key); + } + // // Int as Key inside the code (not storage) // @@ -593,7 +653,7 @@ contract MapTestContract { return value1 + value2 + value3 + value4 + value5 + value6 + value7; } - + get fun intMap11Value(key: Int, value: Int): Int { let map1: map = emptyMap(); let map2: map = emptyMap(); @@ -671,10 +731,29 @@ contract MapTestContract { let value5: Int = map5.get(key)!!; let value6: Int = map6.get(key)!!; let value7: Int = map7.get(key)!!; - + return value1 + value2 + value3 + value4 + value5 + value6 + value7; } + get fun intMap14Value(key: Int, value: Int): Int { + let map1: map = emptyMap(); + let map2: map = emptyMap(); + let map3: map = emptyMap(); + let map4: map = emptyMap(); + + map1.set(key, value); + map2.set(key, value); + map3.set(key, value); + map4.set(key, value); + + let value1: Int = map1.get(key)!!; + let value2: Int = map2.get(key)!!; + let value3: Int = map3.get(key)!!; + let value4: Int = map4.get(key)!!; + + return value1 + value2 + value3 + value4; + } + // // Address Keys // @@ -795,7 +874,7 @@ contract MapTestContract { get fun addrMap1(): map { return self.addrMap1; } - + get fun addrMap1Value(key: Address): Int? { return self.addrMap1.get(key); } @@ -997,4 +1076,4 @@ contract MapTestContract { get fun addrMap5Exists(key: Address): Bool { return self.addrMap5.exists(key); } -} \ No newline at end of file +} diff --git a/src/test/e2e-emulated/contracts/structs.tact b/src/test/e2e-emulated/contracts/structs.tact index b54dd1d5d..7e20b1c33 100644 --- a/src/test/e2e-emulated/contracts/structs.tact +++ b/src/test/e2e-emulated/contracts/structs.tact @@ -35,6 +35,24 @@ struct Coin { second: Int as uint32; } +struct IntFields { + i1: Int as int1; + i2: Int as int2; + i3: Int as int3; + i255: Int as int255; + i256: Int as int256; + i257: Int as int257; +} + +message(0xea01f46a) UintFields { + u1: Int as uint1; + u2: Int as uint2; + u3: Int as uint3; + u254: Int as uint254; + u255: Int as uint255; + u256: Int as uint256; +} + fun directParse(payload: Cell): Coin { return Coin.fromCell(payload); } @@ -169,7 +187,7 @@ struct Point { x: Int as int64; y: Int as int64; } - + struct Line { start: Point; end: Point; @@ -854,4 +872,34 @@ contract StructsTester { } } } -} \ No newline at end of file + + get fun intFieldsStruct(): IntFields { + return IntFields{ + i1: -1, + i2: -2, + i3: -4, + i255: -pow(2, 254), + i256: -pow(2, 255), + i257: -pow(2, 255) - pow(2, 255), + }; + } + + get fun intFieldsFromCell(src: Cell): IntFields { + return IntFields.fromCell(src); + } + + get fun uintFieldsMessage(): UintFields { + return UintFields{ + u1: 1, + u2: 3, + u3: 7, + u254: pow(2, 254) - 1, + u255: pow(2, 255) - 1, + u256: pow(2, 255) - 1 + pow(2, 255), + }; + } + + get fun uintFieldsFromCell(src: Cell): UintFields { + return UintFields.fromCell(src); + } +} diff --git a/src/test/e2e-emulated/map.spec.ts b/src/test/e2e-emulated/map.spec.ts index 893cdc75c..b1e6ed4ad 100644 --- a/src/test/e2e-emulated/map.spec.ts +++ b/src/test/e2e-emulated/map.spec.ts @@ -72,6 +72,10 @@ describe("map", () => { expect((await contract.getIntMap9_4()).size).toBe(0); expect((await contract.getIntMap9_5()).size).toBe(0); expect((await contract.getIntMap9_6()).size).toBe(0); + expect((await contract.getIntMap10_1()).size).toBe(0); + expect((await contract.getIntMap10_2()).size).toBe(0); + expect((await contract.getIntMap10_3()).size).toBe(0); + expect((await contract.getIntMap10_4()).size).toBe(0); expect((await contract.getAddrMap1()).size).toBe(0); expect((await contract.getAddrMap2()).size).toBe(0); expect((await contract.getAddrMap3()).size).toBe(0); @@ -167,6 +171,15 @@ describe("map", () => { { value: toNano(1) }, { $$type: "SetUIntMap9", key: k, value: valueSmallAbs }, ); + await contract.send( + treasure, + { value: toNano(1) }, + { + $$type: "SetUIntMap10", + key: keySmallAbs, + value: valueSmallAbs, + }, + ); await contract.send( treasure, { value: toNano(1) }, @@ -268,6 +281,18 @@ describe("map", () => { expect(await contract.getIntMap9_4Value(k)).toBe(valueSmallAbs); expect(await contract.getIntMap9_5Value(k)).toBe(valueSmallAbs); expect(await contract.getIntMap9_6Value(k)).toBe(valueSmallAbs); + expect(await contract.getIntMap10_1Value(keySmallAbs)).toBe( + valueSmallAbs, + ); + expect(await contract.getIntMap10_2Value(keySmallAbs)).toBe( + valueSmallAbs, + ); + expect(await contract.getIntMap10_3Value(keySmallAbs)).toBe( + valueSmallAbs, + ); + expect(await contract.getIntMap10_4Value(keySmallAbs)).toBe( + valueSmallAbs, + ); expect( await contract.getIntMap10Value(keySmall, valueInt), ).toBe(valueInt * 7n); @@ -280,6 +305,9 @@ describe("map", () => { expect(await contract.getIntMap13Value(k, valueSmallAbs)).toBe( valueSmallAbs * 7n, ); + expect( + await contract.getIntMap14Value(keySmallAbs, valueSmallAbs), + ).toBe(valueSmallAbs * 4n); expect(await contract.getAddrMap1Value(addr)).toBe(valueInt); expect((await contract.getAddrMap2Value(addr))!).toBe( valueBool, @@ -368,6 +396,10 @@ describe("map", () => { expect((await contract.getIntMap9_4()).size).toBe(1); expect((await contract.getIntMap9_5()).size).toBe(1); expect((await contract.getIntMap9_6()).size).toBe(1); + expect((await contract.getIntMap10_1()).size).toBe(1); + expect((await contract.getIntMap10_2()).size).toBe(1); + expect((await contract.getIntMap10_3()).size).toBe(1); + expect((await contract.getIntMap10_4()).size).toBe(1); expect((await contract.getAddrMap1()).size).toBe(1); expect((await contract.getAddrMap2()).size).toBe(1); expect((await contract.getAddrMap3()).size).toBe(1); @@ -419,6 +451,11 @@ describe("map", () => { { value: toNano(1) }, { $$type: "SetUIntMap9", key: k, value: null }, ); + await contract.send( + treasure, + { value: toNano(1) }, + { $$type: "SetUIntMap10", key: keySmallAbs, value: null }, + ); await contract.send( treasure, { value: toNano(1) }, @@ -500,6 +537,18 @@ describe("map", () => { expect(await contract.getIntMap9_4Value(k)).toBe(null); expect(await contract.getIntMap9_5Value(k)).toBe(null); expect(await contract.getIntMap9_6Value(k)).toBe(null); + expect(await contract.getIntMap10_1Value(keySmallAbs)).toBe( + null, + ); + expect(await contract.getIntMap10_2Value(keySmallAbs)).toBe( + null, + ); + expect(await contract.getIntMap10_3Value(keySmallAbs)).toBe( + null, + ); + expect(await contract.getIntMap10_4Value(keySmallAbs)).toBe( + null, + ); expect(await contract.getAddrMap1Value(addr)).toBeNull(); expect(await contract.getAddrMap2Value(addr)).toBeNull(); expect(await contract.getAddrMap3Value(addr)).toBeNull(); @@ -608,6 +657,10 @@ describe("map", () => { expect((await contract.getIntMap9_4()).size).toBe(0); expect((await contract.getIntMap9_5()).size).toBe(0); expect((await contract.getIntMap9_6()).size).toBe(0); + expect((await contract.getIntMap10_1()).size).toBe(0); + expect((await contract.getIntMap10_2()).size).toBe(0); + expect((await contract.getIntMap10_3()).size).toBe(0); + expect((await contract.getIntMap10_4()).size).toBe(0); expect((await contract.getAddrMap1()).size).toBe(0); expect((await contract.getAddrMap2()).size).toBe(0); expect((await contract.getAddrMap3()).size).toBe(0); @@ -703,6 +756,15 @@ describe("map", () => { { value: toNano(1) }, { $$type: "SetUIntMap9", key: k, value: valueSmallAbs }, ); + await contract.send( + treasure, + { value: toNano(1) }, + { + $$type: "SetUIntMap10", + key: keySmallAbs, + value: valueSmallAbs, + }, + ); await contract.send( treasure, { value: toNano(1) }, @@ -804,6 +866,18 @@ describe("map", () => { expect(await contract.getIntMap9_4Value(k)).toBe(valueSmallAbs); expect(await contract.getIntMap9_5Value(k)).toBe(valueSmallAbs); expect(await contract.getIntMap9_6Value(k)).toBe(valueSmallAbs); + expect(await contract.getIntMap10_1Value(keySmallAbs)).toBe( + valueSmallAbs, + ); + expect(await contract.getIntMap10_2Value(keySmallAbs)).toBe( + valueSmallAbs, + ); + expect(await contract.getIntMap10_3Value(keySmallAbs)).toBe( + valueSmallAbs, + ); + expect(await contract.getIntMap10_4Value(keySmallAbs)).toBe( + valueSmallAbs, + ); expect( await contract.getIntMap10Value(keySmall, valueInt), ).toBe(valueInt * 7n); @@ -816,6 +890,12 @@ describe("map", () => { expect(await contract.getIntMap13Value(k, valueSmallAbs)).toBe( valueSmallAbs * 7n, ); + expect( + await contract.getIntMap14Value(keySmallAbs, valueSmallAbs), + ).toBe(valueSmallAbs * 4n); + expect( + await contract.getIntMap14Value(keySmallAbs, valueSmallAbs), + ).toBe(valueSmallAbs * 4n); expect(await contract.getAddrMap1Value(addr)).toBe(valueInt); expect((await contract.getAddrMap2Value(addr))!).toBe( valueBool, @@ -904,6 +984,10 @@ describe("map", () => { expect((await contract.getIntMap9_4()).size).toBe(1); expect((await contract.getIntMap9_5()).size).toBe(1); expect((await contract.getIntMap9_6()).size).toBe(1); + expect((await contract.getIntMap10_1()).size).toBe(1); + expect((await contract.getIntMap10_2()).size).toBe(1); + expect((await contract.getIntMap10_3()).size).toBe(1); + expect((await contract.getIntMap10_4()).size).toBe(1); expect((await contract.getAddrMap1()).size).toBe(1); expect((await contract.getAddrMap2()).size).toBe(1); expect((await contract.getAddrMap3()).size).toBe(1); @@ -959,6 +1043,11 @@ describe("map", () => { { value: toNano(1) }, { $$type: "DelUIntMap9", key: k }, ); + await contract.send( + treasure, + { value: toNano(1) }, + { $$type: "DelUIntMap10", key: keySmallAbs }, + ); await contract.send( treasure, { value: toNano(1) }, @@ -1040,6 +1129,18 @@ describe("map", () => { expect(await contract.getIntMap9_4Value(k)).toBe(null); expect(await contract.getIntMap9_5Value(k)).toBe(null); expect(await contract.getIntMap9_6Value(k)).toBe(null); + expect(await contract.getIntMap10_1Value(keySmallAbs)).toBe( + null, + ); + expect(await contract.getIntMap10_2Value(keySmallAbs)).toBe( + null, + ); + expect(await contract.getIntMap10_3Value(keySmallAbs)).toBe( + null, + ); + expect(await contract.getIntMap10_4Value(keySmallAbs)).toBe( + null, + ); expect(await contract.getAddrMap1Value(addr)).toBeNull(); expect(await contract.getAddrMap2Value(addr)).toBeNull(); expect(await contract.getAddrMap3Value(addr)).toBeNull(); diff --git a/src/test/e2e-emulated/structs.spec.ts b/src/test/e2e-emulated/structs.spec.ts index 7d7fb6429..a19d8ff68 100644 --- a/src/test/e2e-emulated/structs.spec.ts +++ b/src/test/e2e-emulated/structs.spec.ts @@ -2,11 +2,13 @@ import { Dictionary, beginCell, toNano } from "@ton/core"; import { ContractSystem } from "@tact-lang/emulator"; import { __DANGER_resetNodeId } from "../../grammar/ast"; import { + IntFields, MyMessage1, MyStruct1, MyStruct2, MyStruct3, StructsTester, + UintFields, loadMyMessage1, loadMyStruct1, loadMyStruct2, @@ -286,5 +288,55 @@ describe("structs", () => { expect(await contract.getLongAndDeepNestedStruct1()).toMatchSnapshot(); expect(await contract.getLongAndDeepNestedStruct2()).toMatchSnapshot(); expect(await contract.getLongAndDeepNestedStruct3()).toMatchSnapshot(); + + // https://github.com/tact-lang/tact/issues/374 + + // int serialization formats + const sIntFields: IntFields = { + $$type: "IntFields", + i1: -1n, + i2: -2n, + i3: -4n, + i255: -(2n ** 254n), + i256: -(2n ** 255n), + i257: -(2n ** 256n), + }; + const sIntFieldsCell = beginCell() + // Storing min values for each bit length + .storeInt(-1n, 1) + .storeInt(-2n, 2) + .storeInt(-4n, 3) + .storeInt(-(2n ** 254n), 255) + .storeInt(-(2n ** 255n), 256) + .storeInt(-(2n ** 256n), 257) + .endCell(); + expect(await contract.getIntFieldsStruct()).toEqual(sIntFields); + expect(await contract.getIntFieldsFromCell(sIntFieldsCell)).toEqual( + sIntFields, + ); + + // uint serialization formats + const mUintFields: UintFields = { + $$type: "UintFields", + u1: 1n, + u2: 3n, + u3: 7n, + u254: 2n ** 254n - 1n, + u255: 2n ** 255n - 1n, + u256: 2n ** 256n - 1n, + }; + const _mUintFieldsCell = beginCell() + // Header + .storeUint(0xea01f46a, 32) + // Storing max values for each bit length + .storeUint(1n, 1) + .storeUint(3n, 2) + .storeUint(7n, 3) + .storeUint(2n ** 254n - 1n, 254) + .storeUint(2n ** 255n - 1n, 255) + .storeUint(2n ** 256n - 1n, 256) + .endCell(); + + expect(await contract.getUintFieldsMessage()).toEqual(mUintFields); }); }); diff --git a/src/types/resolveABITypeRef.ts b/src/types/resolveABITypeRef.ts index 7b9edbf62..dc049e101 100644 --- a/src/types/resolveABITypeRef.ts +++ b/src/types/resolveABITypeRef.ts @@ -28,43 +28,26 @@ type FormatDef = Record< { type: string; format: string | number } | undefined >; -const intFormats: FormatDef = { - int8: { type: "int", format: 8 }, - int16: { type: "int", format: 16 }, - int32: { type: "int", format: 32 }, - int64: { type: "int", format: 64 }, - int128: { type: "int", format: 128 }, - int256: { type: "int", format: 256 }, +const uintOptions: FormatDef = Object.fromEntries( + [...Array(257).keys()] + .slice(1) + .map((key) => [`uint${key}`, { type: "uint", format: key }]), +); - uint8: { type: "uint", format: 8 }, - uint16: { type: "uint", format: 16 }, - uint32: { type: "uint", format: 32 }, - uint64: { type: "uint", format: 64 }, - uint128: { type: "uint", format: 128 }, - uint256: { type: "uint", format: 256 }, +const intOptions: FormatDef = Object.fromEntries( + [...Array(257).keys()] + .slice(1) + .map((key) => [`int${key}`, { type: "int", format: key }]), +); +const intFormats: FormatDef = { + ...uintOptions, + ...intOptions, int257: { type: "int", format: 257 }, coins: { type: "uint", format: "coins" }, }; -const intMapFormats: FormatDef = { - int8: { type: "int", format: 8 }, - int16: { type: "int", format: 16 }, - int32: { type: "int", format: 32 }, - int64: { type: "int", format: 64 }, - int128: { type: "int", format: 128 }, - int256: { type: "int", format: 256 }, - - uint8: { type: "uint", format: 8 }, - uint16: { type: "uint", format: 16 }, - uint32: { type: "uint", format: 32 }, - uint64: { type: "uint", format: 64 }, - uint128: { type: "uint", format: 128 }, - uint256: { type: "uint", format: 256 }, - - int257: { type: "int", format: 257 }, - coins: { type: "uint", format: "coins" }, -}; +export const intMapFormats: FormatDef = { ...intFormats }; const cellFormats: FormatDef = { remaining: { type: "cell", format: "remainder" }, diff --git a/src/types/resolveDescriptors.ts b/src/types/resolveDescriptors.ts index 60027646b..18bcd29d6 100644 --- a/src/types/resolveDescriptors.ts +++ b/src/types/resolveDescriptors.ts @@ -43,7 +43,7 @@ import { getRawAST } from "../grammar/store"; import { cloneNode } from "../grammar/clone"; import { crc16 } from "../utils/crc16"; import { evalConstantExpression } from "../constEval"; -import { resolveABIType } from "./resolveABITypeRef"; +import { resolveABIType, intMapFormats } from "./resolveABITypeRef"; import { enabledExternals } from "../config/features"; import { isRuntimeType } from "./isRuntimeType"; import { GlobalFunctions } from "../abi/global"; @@ -65,22 +65,7 @@ function verifyMapAsAnnotationsForPrimitiveTypes( case "Int": { if ( asAnnotation !== null && - ![ - "int8", - "int16", - "int32", - "int64", - "int128", - "int256", - "int257", - "uint8", - "uint16", - "uint32", - "uint64", - "uint128", - "uint256", - "coins", - ].includes(idText(asAnnotation)) + !Object.keys(intMapFormats).includes(idText(asAnnotation)) ) { throwCompilationError( 'Invalid `as`-annotation for type "Int" type',