Repository: tact-lang/tact

Issue:
Static field for message opcodes
So, instead of 

```tact
const TakeWalletAddressOpcode: Int = 0xd1735400;

message(TakeWalletAddressOpcode) TakeWalletAddress {
    queryId: Int as uint64;
    walletAddress: Address;
    ownerAddress: Cell?; //It is Maybe ^Address, just encoded it like this
}
```

the user should be able to use

```tact
TakeWalletAddress.opcode
```

Discussion:

Solution patch:
diff --git a/dev-docs/CHANGELOG.md b/dev-docs/CHANGELOG.md
index 39dfd02a..744b0777 100644
--- a/dev-docs/CHANGELOG.md
+++ b/dev-docs/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Compiler now generates more efficient code for `Address?` fields deserialization: PR [#2834](https://github.com/tact-lang/tact/pull/2834)
 - Optimized `self.notify`, `self.reply`, and `self.forward` in `BaseTrait` by using message directly where possible and avoiding unnecessary use of alias: PR [#2515](https://github.com/tact-lang/tact/pull/2515)
 - Compiler now generates more efficient code for `if` statements: PR [#2844](https://github.com/tact-lang/tact/pull/2844)
+- Any message now has an `opcode()` method to obtain its opcode: PR [#2886](https://github.com/tact-lang/tact/pull/2886)
 - Contract `init` function now can have parameters with `as` annotations: PR [#2890](https://github.com/tact-lang/tact/pull/2890)
 - [fix] Compiler now correctly handles get functions with an empty message parameter: PR [#2892](https://github.com/tact-lang/tact/pull/2892)
 
diff --git a/docs/src/content/docs/book/structs-and-messages.mdx b/docs/src/content/docs/book/structs-and-messages.mdx
index 662d2b75..fb68ea58 100644
--- a/docs/src/content/docs/book/structs-and-messages.mdx
+++ b/docs/src/content/docs/book/structs-and-messages.mdx
@@ -166,6 +166,20 @@ message((crc32("Tact") + 42) & 0xFFFF_FFFF) MsgWithExprOpcode {
 
 :::
 
+<Badge text="Available since Tact 1.7" variant="tip" size="small"/> A message opcode can be obtained by calling the `opcode()` method on any message type:
+
+```tact
+message(0x777) TripleAxe {
+    prize: Int as uint32;
+}
+
+contract Example {
+    receive(msg: TripleAxe) {
+        dump(TripleAxe.opcode()); // 0x777
+   }
+}
+```
+
 ## Operations
 
 ### Instantiate
diff --git a/docs/src/content/docs/ref/core-cells.mdx b/docs/src/content/docs/ref/core-cells.mdx
index 9974dca2..18493a71 100644
--- a/docs/src/content/docs/ref/core-cells.mdx
+++ b/docs/src/content/docs/ref/core-cells.mdx
@@ -1832,7 +1832,7 @@ fun coinSlice(): Slice {
 ## Struct.fromCell
 
 ```tact
-extends fun fromCell(self: Struct, cell: Cell): Struct;
+fun Struct.fromCell(cell: Cell): Struct;
 ```
 
 Extension function for any [Struct][struct] type.
@@ -1867,7 +1867,7 @@ fun cautiousParse(payload: Cell): GuessCoin? {
 ## Struct.fromSlice
 
 ```tact
-extends fun fromSlice(self: Struct, slice: Slice): Struct;
+fun Struct.fromSlice(slice: Slice): Struct;
 ```
 
 Extension function for any [Struct][struct] type.
@@ -1956,7 +1956,7 @@ fun coinSlice(): Slice {
 ## Message.fromCell
 
 ```tact
-extends fun fromCell(self: Message, cell: Cell): Message;
+fun Message.fromCell(cell: Cell): Message;
 ```
 
 Extension function for any [Message][message] type.
@@ -1992,7 +1992,7 @@ fun cautiousParse(payload: Cell): TripleAxe? {
 ## Message.fromSlice
 
 ```tact
-extends fun fromSlice(self: Message, slice: Slice): Message;
+fun Message.fromSlice(slice: Slice): Message;
 ```
 
 Extension function for any [Message][message] type.
@@ -2025,6 +2025,32 @@ fun cautiousParse(payload: Slice): TripleAxe? {
 }
 ```
 
+## Message.opcode
+
+<Badge text="Available since Tact 1.7" variant="tip" size="medium"/><p/>
+
+```tact
+fun Message.opcode(): Int;
+```
+
+Extension function for any [Message][message] type.
+
+Returns the [opcode][opcode] of the [Message][message].
+
+Usage example:
+
+```tact
+message(0x777) TripleAxe {
+    prize: Int as uint32;
+}
+
+contract Example {
+    receive(msg: TripleAxe) {
+        dump(TripleAxe.opcode()); // 0x777
+   }
+}
+```
+
 [p]: /book/types#primitive-types
 [bool]: /book/types#booleans
 [int]: /book/integers
diff --git a/src/abi/struct.ts b/src/abi/struct.ts
index 7dcd6723..84594773 100644
--- a/src/abi/struct.ts
+++ b/src/abi/struct.ts
@@ -1,8 +1,12 @@
 import { ops } from "@/generator/writers/ops";
 import { writeExpression } from "@/generator/writers/writeExpression";
-import { throwCompilationError } from "@/error/errors";
+import {
+    throwCompilationError,
+    throwInternalCompilerError,
+} from "@/error/errors";
 import { getType } from "@/types/resolveDescriptors";
 import type { AbiFunction } from "@/abi/AbiFunction";
+import { messageOpcode } from "@/generator/writers/writeRouter";
 
 export const StructFunctions: Map<string, AbiFunction> = new Map([
     [
@@ -103,6 +107,60 @@ export const StructFunctions: Map<string, AbiFunction> = new Map([
             },
         },
     ],
+    [
+        "opcode",
+        {
+            name: "opcode",
+            resolve: (ctx, args, ref) => {
+                const [arg] = args;
+                if (typeof arg === "undefined" || args.length !== 1) {
+                    throwCompilationError("opcode() expects no arguments", ref);
+                }
+                if (arg.kind !== "ref") {
+                    throwCompilationError(
+                        `opcode() method can be used only for messages`,
+                        ref,
+                    );
+                }
+                const type = getType(ctx, arg.name);
+                if (type.kind !== "struct" || type.ast.kind === "struct_decl") {
+                    throwCompilationError(
+                        `opcode() method can be used only for messages`,
+                        ref,
+                    );
+                }
+                return { kind: "ref", name: "Int", optional: false };
+            },
+            generate: (ctx, args, _resolved, ref) => {
+                const [arg] = args;
+                if (typeof arg === "undefined" || args.length !== 1) {
+                    throwCompilationError("opcode() expects no arguments", ref);
+                }
+                if (arg.kind !== "ref") {
+                    throwCompilationError(
+                        `opcode() method can be used only for messages`,
+                        ref,
+                    );
+                }
+                const type = getType(ctx.ctx, arg.name);
+                if (type.kind !== "struct" || type.ast.kind === "struct_decl") {
+                    throwCompilationError(
+                        `opcode() method can be used only for messages`,
+                        ref,
+                    );
+                }
+
+                if (!type.header) {
+                    throwInternalCompilerError(
+                        `Invalid allocation: ${type.name}`,
+                        type.ast.name.loc,
+                    );
+                }
+
+                return messageOpcode(type.header);
+            },
+        },
+    ],
     [
         "toSlice",
         {
diff --git a/src/benchmarks/contracts/jetton-minter-discoverable.tact b/src/benchmarks/contracts/jetton-minter-discoverable.tact
index b8fb3fc6..20532624 100644
--- a/src/benchmarks/contracts/jetton-minter-discoverable.tact
+++ b/src/benchmarks/contracts/jetton-minter-discoverable.tact
@@ -102,7 +102,7 @@ asm fun emptyAddress(): Address { b{00} PUSHSLICE }
 
 inline fun makeTakeWalletAddressMsg(targetJettonWallet: BasechainAddress, msg: ProvideWalletAddress): Cell {
     return beginCell()
-        .storeUint(TakeWalletAddressOpcode, 32)
+        .storeUint(TakeWalletAddress.opcode(), 32)
         .storeUint(msg.queryId, 64)
         .storeBasechainAddress(targetJettonWallet)
         .storeMaybeRef(msg.includeAddress ? beginCell().storeAddress(msg.ownerAddress).endCell() : null)
diff --git a/src/benchmarks/contracts/jetton-minter-notcoin.tact b/src/benchmarks/contracts/jetton-minter-notcoin.tact
index 79c449b3..ae0903d3 100644
--- a/src/benchmarks/contracts/jetton-minter-notcoin.tact
+++ b/src/benchmarks/contracts/jetton-minter-notcoin.tact
@@ -114,7 +114,7 @@ asm fun emptyAddress(): Address { b{00} PUSHSLICE }
 
 inline fun makeTakeWalletAddressMsg(targetJettonWallet: BasechainAddress, msg: ProvideWalletAddress): Cell {
     return beginCell()
-        .storeUint(TakeWalletAddressOpcode, 32)
+        .storeUint(TakeWalletAddress.opcode(), 32)
         .storeUint(msg.queryId, 64)
         .storeBasechainAddress(targetJettonWallet)
         .storeMaybeRef(msg.includeAddress ? beginCell().storeAddress(msg.ownerAddress).endCell() : null)
diff --git a/src/benchmarks/contracts/messages.tact b/src/benchmarks/contracts/messages.tact
index deb09d9a..edc9149b 100644
--- a/src/benchmarks/contracts/messages.tact
+++ b/src/benchmarks/contracts/messages.tact
@@ -72,8 +72,7 @@ message(0x2c76b973) ProvideWalletAddress {
     includeAddress: Bool;
 }
 
-const TakeWalletAddressOpcode: Int = 0xd1735400;
-message(TakeWalletAddressOpcode) TakeWalletAddress {
+message(0xd1735400) TakeWalletAddress {
     queryId: Int as uint64;
     walletAddress: Address;
     ownerAddress: Cell?; //It is Maybe ^Address, just encoded it like this
diff --git a/src/generator/writers/writeRouter.ts b/src/generator/writers/writeRouter.ts
index 49e1d97b..6d677f85 100644
--- a/src/generator/writers/writeRouter.ts
+++ b/src/generator/writers/writeRouter.ts
@@ -710,7 +710,7 @@ function writeRcvStatement(
     writeStatement(stmt, null, returns, wCtx);
 }
 
-function messageOpcode(n: Ast.Number): string {
+export function messageOpcode(n: Ast.Number): string {
     // FunC does not support binary and octal numerals
     switch (n.base) {
         case 10:
diff --git a/src/stdlib/stdlib.ts b/src/stdlib/stdlib.ts
index 5e5c4f73..fb1870e2 100644
--- a/src/stdlib/stdlib.ts
+++ b/src/stdlib/stdlib.ts
@@ -2665,59 +2665,63 @@ files["std/stubs.tact"] =
     "W0NlbGwgdW5kZXJmbG93XSDigJQgVGhyb3duIHdoZW4gYXR0ZW1wdGluZyB0byBwYXNzIGEgYFNsaWNlYCB3aXRoIGEgbGF5b3V0IGRpZmZlcmVudAovLy8gZnJvbSB0" +
     "aGUgc3BlY2lmaWVkIGBNZXNzYWdlYCBvciB0byBsb2FkIG1vcmUgZGF0YSB0aGFuIGBTbGljZWAgY29udGFpbnMuCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFj" +
     "dC1sYW5nLm9yZy9yZWYvY29yZS1jZWxscy8jbWVzc2FnZWZyb21zbGljZQovLy8KLy8vIFtleGl0IGNvZGUgOV06IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jv" +
-    "b2svZXhpdC1jb2RlcyM5Ci8vLwpmdW4gQW55TWVzc2FnZV9mcm9tU2xpY2Uoc2xpY2U6IFNsaWNlKTogTTsKCi8vLyBFeHRlbnNpb24gZnVuY3Rpb24gZm9yIGFueSBT" +
-    "dHJ1Y3QuCi8vLwovLy8gQ29udmVydHMgdGhlIFN0cnVjdCB0byBhIGBDZWxsYCBhbmQgcmV0dXJucyBpdC4KLy8vCi8vLyBgYGB0YWN0Ci8vLyBzdHJ1Y3QgR3Vlc3ND" +
-    "b2luIHsKLy8vICAgICBwcm9iYWJseTogSW50IGFzIGNvaW5zOwovLy8gICAgIG5vdGhpbmc6IEludCBhcyBjb2luczsKLy8vIH0KLy8vCi8vLyBmdW4gY29pbkNlbGwo" +
-    "KTogQ2VsbCB7Ci8vLyAgICAgbGV0IHM6IEd1ZXNzQ29pbiA9IEd1ZXNzQ29pbnsgcHJvYmFibHk6IDQyLCBub3RoaW5nOiAyNyB9OwovLy8gICAgIGxldCBmaXp6OiBD" +
-    "ZWxsID0gcy50b0NlbGwoKTsKLy8vCi8vLyAgICAgcmV0dXJuIGZpeno7IC8vICJ4ezEyQTExQn0iCi8vLyB9Ci8vLyBgYGAKLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9j" +
-    "cy50YWN0LWxhbmcub3JnL3JlZi9jb3JlLWNlbGxzLyNzdHJ1Y3R0b2NlbGwKLy8vCmV4dGVuZHMgZnVuIHRvQ2VsbChzZWxmOiBBbnlTdHJ1Y3QpOiBDZWxsOwoKLy8v" +
-    "IEV4dGVuc2lvbiBmdW5jdGlvbiBmb3IgYW55IFN0cnVjdC4gQXZhaWxhYmxlIHNpbmNlIFRhY3QgMS41LjAuCi8vLwovLy8gQ29udmVydHMgdGhlIFN0cnVjdCB0byBh" +
-    "IGBTbGljZWAgYW5kIHJldHVybnMgaXQuIEFsaWFzIHRvIGBzZWxmLnRvQ2VsbCgpLmFzU2xpY2UoKWAuCi8vLwovLy8gYGBgdGFjdAovLy8gc3RydWN0IEd1ZXNzQ29p" +
-    "biB7Ci8vLyAgICAgcHJvYmFibHk6IEludCBhcyBjb2luczsKLy8vICAgICBub3RoaW5nOiBJbnQgYXMgY29pbnM7Ci8vLyB9Ci8vLwovLy8gZnVuIGNvaW5TbGljZSgp" +
-    "OiBTbGljZSB7Ci8vLyAgICAgbGV0IHM6IEd1ZXNzQ29pbiA9IEd1ZXNzQ29pbnsgcHJvYmFibHk6IDQyLCBub3RoaW5nOiAyNyB9OwovLy8gICAgIGxldCBmaXp6OiBT" +
-    "bGljZSA9IHMudG9TbGljZSgpOwovLy8KLy8vICAgICByZXR1cm4gZml6ejsgLy8gIkNTe0NlbGx7MDAwNjEyYTExYn0gYml0czogMC4uMjQ7IHJlZnM6IDAuLjB9Igov" +
-    "Ly8gfQovLy8gYGBgCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFjdC1sYW5nLm9yZy9yZWYvY29yZS1jZWxscy8jc3RydWN0dG9zbGljZQovLy8KZXh0ZW5kcyBm" +
-    "dW4gdG9TbGljZShzZWxmOiBBbnlTdHJ1Y3QpOiBTbGljZTsKCi8vLyBFeHRlbnNpb24gZnVuY3Rpb24gZm9yIGFueSBNZXNzYWdlLgovLy8KLy8vIENvbnZlcnRzIHRo" +
-    "ZSBNZXNzYWdlIHRvIGEgYENlbGxgIGFuZCByZXR1cm5zIGl0LgovLy8KLy8vIGBgYHRhY3QKLy8vIG1lc3NhZ2UgR3Vlc3NDb2luIHsKLy8vICAgICBwcm9iYWJseTog" +
-    "SW50IGFzIGNvaW5zOwovLy8gICAgIG5vdGhpbmc6IEludCBhcyBjb2luczsKLy8vIH0KLy8vCi8vLyBmdW4gY29pbkNlbGwoKTogQ2VsbCB7Ci8vLyAgICAgbGV0IHM6" +
-    "IEd1ZXNzQ29pbiA9IEd1ZXNzQ29pbnsgcHJvYmFibHk6IDQyLCBub3RoaW5nOiAyNyB9OwovLy8gICAgIGxldCBmaXp6OiBDZWxsID0gcy50b0NlbGwoKTsKLy8vCi8v" +
-    "LyAgICAgcmV0dXJuIGZpeno7IC8vICJ4e0FCMzcxMDc3MTJBMTFCfSIKLy8vIH0KLy8vIGBgYAovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcv" +
-    "cmVmL2NvcmUtY2VsbHMvI21lc3NhZ2V0b2NlbGwKLy8vCmV4dGVuZHMgZnVuIHRvQ2VsbChzZWxmOiBBbnlNZXNzYWdlKTogQ2VsbDsKCi8vLyBFeHRlbnNpb24gZnVu" +
-    "Y3Rpb24gZm9yIGFueSBNZXNzYWdlLiBBdmFpbGFibGUgc2luY2UgVGFjdCAxLjUuMC4KLy8vCi8vLyBDb252ZXJ0cyB0aGUgTWVzc2FnZSB0byBhIGBTbGljZWAgYW5k" +
-    "IHJldHVybnMgaXQuIEFsaWFzIHRvIGBzZWxmLnRvQ2VsbCgpLmFzU2xpY2UoKWAuCi8vLwovLy8gYGBgdGFjdAovLy8gbWVzc2FnZSBHdWVzc0NvaW4gewovLy8gICAg" +
-    "IHByb2JhYmx5OiBJbnQgYXMgY29pbnM7Ci8vLyAgICAgbm90aGluZzogSW50IGFzIGNvaW5zOwovLy8gfQovLy8KLy8vIGZ1biBjb2luU2xpY2UoKTogU2xpY2Ugewov" +
-    "Ly8gICAgIGxldCBzOiBHdWVzc0NvaW4gPSBHdWVzc0NvaW57IHByb2JhYmx5OiA0Miwgbm90aGluZzogMjcgfTsKLy8vICAgICBsZXQgZml6ejogU2xpY2UgPSBzLnRv" +
-    "U2xpY2UoKTsKLy8vCi8vLyAgICAgcmV0dXJuIGZpeno7IC8vICJDU3tDZWxsezAwMGVhYjM3MTA3NzEyYTExYn0gYml0czogMC4uNTY7IHJlZnM6IDAuLjB9IgovLy8g" +
-    "fQovLy8gYGBgCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFjdC1sYW5nLm9yZy9yZWYvY29yZS1jZWxscy8jbWVzc2FnZXRvc2xpY2UKLy8vCmV4dGVuZHMgZnVu" +
-    "IHRvU2xpY2Uoc2VsZjogQW55TWVzc2FnZSk6IFNsaWNlOwoKLy8vIENyZWF0ZXMgYW4gZW1wdHkgbWFwIG9mIHR5cGUgYG1hcDxLLCBWPmAsIGluaXRpYWxseSBzZXQg" +
-    "dG8gYG51bGxgLgovLy8KLy8vIGBgYHRhY3QKLy8vIGZ1biBleGFtcGxlKCkgewovLy8gICAgIGxldCBlbnRyaWVzOiBtYXA8SW50LCBTdHJpbmc+ID0gZW1wdHlNYXAo" +
-    "KTsKLy8vICAgICAvLyAgICAgICAgICAgXl5eXl5eXl5eXl5eXl5eXiBub3RlIHRoYXQgeW91IG5lZWQgdG8gc3BlY2lmeSB0aGUga2V5IGFuZAovLy8gICAgIC8vICAg" +
-    "ICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIHR5cGVzIGluIHRoZSB0eXBlIGFubm90YXRpb24gd2hlbgovLy8gICAgIC8vICAgICAgICAgICAgICAgICAgICAg" +
-    "ICAgICAgIGRlY2xhcmluZyB0aGUgbWFwIHZhcmlhYmxlCi8vLyB9Ci8vLyBgYGAKLy8vCi8vLyBPbiBUVk0sIG1hcHMgYXJlIHJlcHJlc2VudGVkIGFzIGEgYENlbGxg" +
-    "IHR5cGUsIHdoaWNoIGlzIHZlcnkgZ2FzLWludGVuc2l2ZS4KLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jvb2svbWFwcy8jZW1wdHltYXAK" +
-    "Ly8vCmZ1biBlbXB0eU1hcCgpOiBtYXA8SywgVj47CgovLy8gU2V0cyBvciByZXBsYWNlcyBhIHZhbHVlIGB2YWxgIHVuZGVyIGEgYGtleWAgaW4gdGhlIG1hcC4KLy8v" +
-    "Ci8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jvb2svbWFwcy8jc2V0Ci8vLwpleHRlbmRzIG11dGF0ZXMgZnVuIHNldChzZWxmOiBtYXA8SywgVj4s" +
-    "IGtleTogSywgdmFsOiBWPyk7CgovLy8gR2V0cyBhIHZhbHVlIGJ5IGl0cyBga2V5YCBmcm9tIHRoZSBtYXAuIFJldHVybnMgYG51bGxgIGlmIHRoZSBga2V5YCBpcyBt" +
-    "aXNzaW5nLAovLy8gb3IgdGhlIHZhbHVlIGlmIHRoZSBga2V5YCBpcyBmb3VuZC4KLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jvb2svbWFw" +
-    "cy8jZ2V0Ci8vLwpleHRlbmRzIGZ1biBnZXQoc2VsZjogbWFwPEssIFY+LCBrZXk6IEspOiBWPzsKCi8vLyBSZXBsYWNlcyBhIHZhbHVlIGB2YWxgIHVuZGVyIHRoZSBz" +
-    "cGVjaWZpZWQgYGtleWAKLy8vIGlmIHN1Y2gga2V5IGV4aXN0cy4gUmV0dXJucyBgdHJ1ZWAgb24gc3VjY2Vzc2Z1bCByZXBsYWNlbWVudCBhbmQgYGZhbHNlYCBvdGhl" +
-    "cndpc2UuCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFjdC1sYW5nLm9yZy9ib29rL21hcHMvI3JlcGxhY2UKLy8vCmV4dGVuZHMgbXV0YXRlcyBmdW4gcmVwbGFj" +
-    "ZShzZWxmOiBtYXA8SywgVj4sIGtleTogSywgdmFsOiBWKTogQm9vbDsKCi8vLyBMaWtlIGByZXBsYWNlKClgLCBidXQgcmV0dXJucyB0aGUgb2xkIChwcmUtcmVwbGFj" +
-    "ZW1lbnQpIHZhbHVlCi8vLyBvbiBzdWNjZXNzZnVsIHJlcGxhY2VtZW50IGFuZCBgbnVsbGAgb3RoZXJ3aXNlLgovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3Qt" +
-    "bGFuZy5vcmcvYm9vay9tYXBzLyNyZXBsYWNlZ2V0Ci8vLwpleHRlbmRzIG11dGF0ZXMgZnVuIHJlcGxhY2VHZXQoc2VsZjogbWFwPEssIFY+LCBrZXk6IEssIHZhbDog" +
-    "Vik6IFY/OwoKLy8vIERlbGV0ZXMgYSBzaW5nbGUga2V5LXZhbHVlIHBhaXIgKHNpbmdsZSBlbnRyeSkgYnkgaXRzIGBrZXlgCi8vLyBmcm9tIHRoZSBtYXAuIFJldHVy" +
-    "bnMgYHRydWVgIGluIGNhc2Ugb2Ygc3VjY2Vzc2Z1bCBkZWxldGlvbiBhbmQgYGZhbHNlYCBvdGhlcndpc2UuCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFjdC1s" +
-    "YW5nLm9yZy9ib29rL21hcHMvI2RlbAovLy8KZXh0ZW5kcyBtdXRhdGVzIGZ1biBkZWwoc2VsZjogbWFwPEssIFY+LCBrZXk6IEspOiBCb29sOwoKLy8vIFJldHVybnMg" +
-    "YHRydWVgIGlmIHRoZSB2YWx1ZSB1bmRlciB0aGUgZ2l2ZW4gYGtleWAgZXhpc3RzIGluIHRoZSBtYXAgYW5kIGBmYWxzZWAgb3RoZXJ3aXNlLgovLy8KLy8vIFRoaXMg" +
-    "ZnVuY3Rpb24gaXMgbW9yZSBnYXMtZWZmaWNpZW50IHRoYW4gY2hlY2tpbmcgYHNlbGYuZ2V0KGtleSkgIT0gbnVsbGAuCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3Mu" +
-    "dGFjdC1sYW5nLm9yZy9ib29rL21hcHMvI2V4aXN0cwovLy8KZXh0ZW5kcyBmdW4gZXhpc3RzKHNlbGY6IG1hcDxLLCBWPiwga2V5OiBLKTogQm9vbDsKCi8vLyBSZXR1" +
-    "cm5zIGB0cnVlYCBpZiB0aGUgbWFwIGlzIGVtcHR5IGFuZCBgZmFsc2VgIG90aGVyd2lzZS4KLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jv" +
-    "b2svbWFwcy8jaXNlbXB0eQovLy8KZXh0ZW5kcyBmdW4gaXNFbXB0eShzZWxmOiBtYXA8SywgVj4pOiBCb29sOwoKLy8vIFJldHVybnMgYHRydWVgIGlmIGFsbCBlbnRy" +
-    "aWVzIG9mIHRoZSBtYXAgbWF0Y2ggY29ycmVzcG9uZGluZyBlbnRyaWVzIG9mIGFub3RoZXIgbWFwLAovLy8gaWdub3JpbmcgcG9zc2libGUgZGlmZmVyZW5jZXMgaW4g" +
-    "dGhlIHVuZGVybHlpbmcgc2VyaWFsaXphdGlvbiBsb2dpYy4gUmV0dXJucyBgZmFsc2VgIG90aGVyd2lzZS4KLy8vCi8vLyBUaGlzIGZ1bmN0aW9uIGlzIHZlcnkgZ2Fz" +
-    "IGV4cGVuc2l2ZSwgcHJlZmVyIGA9PWAgb3BlcmF0b3IgZm9yIHNpbXBsZSBjb21wYXJpc29ucy4KLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3Jn" +
-    "L2Jvb2svbWFwcy8jZGVlcGVxdWFscwovLy8KZXh0ZW5kcyBmdW4gZGVlcEVxdWFscyhzZWxmOiBtYXA8SywgVj4sIG90aGVyOiBtYXA8SywgVj4pOiBCb29sOwoKLy8v" +
-    "IENvbnZlcnRzIHRoZSBtYXAgdG8gaXRzIHVuZGVybHlpbmcgYENlbGxgIHJlcHJlc2VudGF0aW9uLgovLy8KLy8vIFNpbmNlIG1hcHMgYXJlIGluaXRpYWxpemVkIHRv" +
-    "IGBudWxsYCwgY2FsbGluZyBgYXNDZWxsKClgIG9uIGEgbWFwCi8vLyB3aXRoIG5vIHZhbHVlcyBhc3NpZ25lZCB3aWxsIHJldHVybiBgbnVsbGAgYW5kICoqbm90Kiog" +
-    "YW4gZW1wdHkgYENlbGxgLgovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcvYm9vay9tYXBzLyNhc2NlbGwKLy8vCmV4dGVuZHMgZnVuIGFzQ2Vs" +
-    "bChzZWxmOiBtYXA8SywgVj4pOiBDZWxsPzsK";
+    "b2svZXhpdC1jb2RlcyM5Ci8vLwpmdW4gQW55TWVzc2FnZV9mcm9tU2xpY2Uoc2xpY2U6IFNsaWNlKTogTTsKCi8vLyBFeHRlbnNpb24gZnVuY3Rpb24gZm9yIGFueSBN" +
+    "ZXNzYWdlIHR5cGUuIEF2YWlsYWJsZSBzaW5jZSBUYWN0IDEuNy4wLgovLy8KLy8vIFJldHVybnMgdGhlIG1lc3NhZ2Ugb3Bjb2RlLgovLy8KLy8vIGBgYHRhY3QKLy8v" +
+    "IG1lc3NhZ2UoMHg3NzcpIFRyaXBsZUF4ZSB7Ci8vLyAgICAgcHJpemU6IEludCBhcyB1aW50MzI7Ci8vLyB9Ci8vLwovLy8gY29udHJhY3QgRXhhbXBsZSB7Ci8vLyAg" +
+    "ICAgcmVjZWl2ZShtc2c6IFRyaXBsZUF4ZSkgewovLy8gICAgICAgICBkdW1wKFRyaXBsZUF4ZS5vcGNvZGUoKSk7IC8vIDB4Nzc3Ci8vLyAgICB9Ci8vLyB9Ci8vLyBg" +
+    "YGAKLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL3JlZi9jb3JlLWNlbGxzLyNtZXNzYWdlb3Bjb2RlCi8vLwpmdW4gQW55TWVzc2FnZV9vcGNv" +
+    "ZGUoKTogSW50OwoKLy8vIEV4dGVuc2lvbiBmdW5jdGlvbiBmb3IgYW55IFN0cnVjdC4KLy8vCi8vLyBDb252ZXJ0cyB0aGUgU3RydWN0IHRvIGEgYENlbGxgIGFuZCBy" +
+    "ZXR1cm5zIGl0LgovLy8KLy8vIGBgYHRhY3QKLy8vIHN0cnVjdCBHdWVzc0NvaW4gewovLy8gICAgIHByb2JhYmx5OiBJbnQgYXMgY29pbnM7Ci8vLyAgICAgbm90aGlu" +
+    "ZzogSW50IGFzIGNvaW5zOwovLy8gfQovLy8KLy8vIGZ1biBjb2luQ2VsbCgpOiBDZWxsIHsKLy8vICAgICBsZXQgczogR3Vlc3NDb2luID0gR3Vlc3NDb2lueyBwcm9i" +
+    "YWJseTogNDIsIG5vdGhpbmc6IDI3IH07Ci8vLyAgICAgbGV0IGZpeno6IENlbGwgPSBzLnRvQ2VsbCgpOwovLy8KLy8vICAgICByZXR1cm4gZml6ejsgLy8gInh7MTJB" +
+    "MTFCfSIKLy8vIH0KLy8vIGBgYAovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcvcmVmL2NvcmUtY2VsbHMvI3N0cnVjdHRvY2VsbAovLy8KZXh0" +
+    "ZW5kcyBmdW4gdG9DZWxsKHNlbGY6IEFueVN0cnVjdCk6IENlbGw7CgovLy8gRXh0ZW5zaW9uIGZ1bmN0aW9uIGZvciBhbnkgU3RydWN0LiBBdmFpbGFibGUgc2luY2Ug" +
+    "VGFjdCAxLjUuMC4KLy8vCi8vLyBDb252ZXJ0cyB0aGUgU3RydWN0IHRvIGEgYFNsaWNlYCBhbmQgcmV0dXJucyBpdC4gQWxpYXMgdG8gYHNlbGYudG9DZWxsKCkuYXNT" +
+    "bGljZSgpYC4KLy8vCi8vLyBgYGB0YWN0Ci8vLyBzdHJ1Y3QgR3Vlc3NDb2luIHsKLy8vICAgICBwcm9iYWJseTogSW50IGFzIGNvaW5zOwovLy8gICAgIG5vdGhpbmc6" +
+    "IEludCBhcyBjb2luczsKLy8vIH0KLy8vCi8vLyBmdW4gY29pblNsaWNlKCk6IFNsaWNlIHsKLy8vICAgICBsZXQgczogR3Vlc3NDb2luID0gR3Vlc3NDb2lueyBwcm9i" +
+    "YWJseTogNDIsIG5vdGhpbmc6IDI3IH07Ci8vLyAgICAgbGV0IGZpeno6IFNsaWNlID0gcy50b1NsaWNlKCk7Ci8vLwovLy8gICAgIHJldHVybiBmaXp6OyAvLyAiQ1N7" +
+    "Q2VsbHswMDA2MTJhMTFifSBiaXRzOiAwLi4yNDsgcmVmczogMC4uMH0iCi8vLyB9Ci8vLyBgYGAKLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3Jn" +
+    "L3JlZi9jb3JlLWNlbGxzLyNzdHJ1Y3R0b3NsaWNlCi8vLwpleHRlbmRzIGZ1biB0b1NsaWNlKHNlbGY6IEFueVN0cnVjdCk6IFNsaWNlOwoKLy8vIEV4dGVuc2lvbiBm" +
+    "dW5jdGlvbiBmb3IgYW55IE1lc3NhZ2UuCi8vLwovLy8gQ29udmVydHMgdGhlIE1lc3NhZ2UgdG8gYSBgQ2VsbGAgYW5kIHJldHVybnMgaXQuCi8vLwovLy8gYGBgdGFj" +
+    "dAovLy8gbWVzc2FnZSBHdWVzc0NvaW4gewovLy8gICAgIHByb2JhYmx5OiBJbnQgYXMgY29pbnM7Ci8vLyAgICAgbm90aGluZzogSW50IGFzIGNvaW5zOwovLy8gfQov" +
+    "Ly8KLy8vIGZ1biBjb2luQ2VsbCgpOiBDZWxsIHsKLy8vICAgICBsZXQgczogR3Vlc3NDb2luID0gR3Vlc3NDb2lueyBwcm9iYWJseTogNDIsIG5vdGhpbmc6IDI3IH07" +
+    "Ci8vLyAgICAgbGV0IGZpeno6IENlbGwgPSBzLnRvQ2VsbCgpOwovLy8KLy8vICAgICByZXR1cm4gZml6ejsgLy8gInh7QUIzNzEwNzcxMkExMUJ9IgovLy8gfQovLy8g" +
+    "YGBgCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFjdC1sYW5nLm9yZy9yZWYvY29yZS1jZWxscy8jbWVzc2FnZXRvY2VsbAovLy8KZXh0ZW5kcyBmdW4gdG9DZWxs" +
+    "KHNlbGY6IEFueU1lc3NhZ2UpOiBDZWxsOwoKLy8vIEV4dGVuc2lvbiBmdW5jdGlvbiBmb3IgYW55IE1lc3NhZ2UuIEF2YWlsYWJsZSBzaW5jZSBUYWN0IDEuNS4wLgov" +
+    "Ly8KLy8vIENvbnZlcnRzIHRoZSBNZXNzYWdlIHRvIGEgYFNsaWNlYCBhbmQgcmV0dXJucyBpdC4gQWxpYXMgdG8gYHNlbGYudG9DZWxsKCkuYXNTbGljZSgpYC4KLy8v" +
+    "Ci8vLyBgYGB0YWN0Ci8vLyBtZXNzYWdlIEd1ZXNzQ29pbiB7Ci8vLyAgICAgcHJvYmFibHk6IEludCBhcyBjb2luczsKLy8vICAgICBub3RoaW5nOiBJbnQgYXMgY29p" +
+    "bnM7Ci8vLyB9Ci8vLwovLy8gZnVuIGNvaW5TbGljZSgpOiBTbGljZSB7Ci8vLyAgICAgbGV0IHM6IEd1ZXNzQ29pbiA9IEd1ZXNzQ29pbnsgcHJvYmFibHk6IDQyLCBu" +
+    "b3RoaW5nOiAyNyB9OwovLy8gICAgIGxldCBmaXp6OiBTbGljZSA9IHMudG9TbGljZSgpOwovLy8KLy8vICAgICByZXR1cm4gZml6ejsgLy8gIkNTe0NlbGx7MDAwZWFi" +
+    "MzcxMDc3MTJhMTFifSBiaXRzOiAwLi41NjsgcmVmczogMC4uMH0iCi8vLyB9Ci8vLyBgYGAKLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL3Jl" +
+    "Zi9jb3JlLWNlbGxzLyNtZXNzYWdldG9zbGljZQovLy8KZXh0ZW5kcyBmdW4gdG9TbGljZShzZWxmOiBBbnlNZXNzYWdlKTogU2xpY2U7CgovLy8gQ3JlYXRlcyBhbiBl" +
+    "bXB0eSBtYXAgb2YgdHlwZSBgbWFwPEssIFY+YCwgaW5pdGlhbGx5IHNldCB0byBgbnVsbGAuCi8vLwovLy8gYGBgdGFjdAovLy8gZnVuIGV4YW1wbGUoKSB7Ci8vLyAg" +
+    "ICAgbGV0IGVudHJpZXM6IG1hcDxJbnQsIFN0cmluZz4gPSBlbXB0eU1hcCgpOwovLy8gICAgIC8vICAgICAgICAgICBeXl5eXl5eXl5eXl5eXl5eIG5vdGUgdGhhdCB5" +
+    "b3UgbmVlZCB0byBzcGVjaWZ5IHRoZSBrZXkgYW5kCi8vLyAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgdHlwZXMgaW4gdGhlIHR5cGUgYW5u" +
+    "b3RhdGlvbiB3aGVuCi8vLyAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjbGFyaW5nIHRoZSBtYXAgdmFyaWFibGUKLy8vIH0KLy8vIGBgYAovLy8K" +
+    "Ly8vIE9uIFRWTSwgbWFwcyBhcmUgcmVwcmVzZW50ZWQgYXMgYSBgQ2VsbGAgdHlwZSwgd2hpY2ggaXMgdmVyeSBnYXMtaW50ZW5zaXZlLgovLy8KLy8vIFNlZTogaHR0" +
+    "cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcvYm9vay9tYXBzLyNlbXB0eW1hcAovLy8KZnVuIGVtcHR5TWFwKCk6IG1hcDxLLCBWPjsKCi8vLyBTZXRzIG9yIHJlcGxhY2Vz" +
+    "IGEgdmFsdWUgYHZhbGAgdW5kZXIgYSBga2V5YCBpbiB0aGUgbWFwLgovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcvYm9vay9tYXBzLyNzZXQK" +
+    "Ly8vCmV4dGVuZHMgbXV0YXRlcyBmdW4gc2V0KHNlbGY6IG1hcDxLLCBWPiwga2V5OiBLLCB2YWw6IFY/KTsKCi8vLyBHZXRzIGEgdmFsdWUgYnkgaXRzIGBrZXlgIGZy" +
+    "b20gdGhlIG1hcC4gUmV0dXJucyBgbnVsbGAgaWYgdGhlIGBrZXlgIGlzIG1pc3NpbmcsCi8vLyBvciB0aGUgdmFsdWUgaWYgdGhlIGBrZXlgIGlzIGZvdW5kLgovLy8K" +
+    "Ly8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcvYm9vay9tYXBzLyNnZXQKLy8vCmV4dGVuZHMgZnVuIGdldChzZWxmOiBtYXA8SywgVj4sIGtleTogSyk6" +
+    "IFY/OwoKLy8vIFJlcGxhY2VzIGEgdmFsdWUgYHZhbGAgdW5kZXIgdGhlIHNwZWNpZmllZCBga2V5YAovLy8gaWYgc3VjaCBrZXkgZXhpc3RzLiBSZXR1cm5zIGB0cnVl" +
+    "YCBvbiBzdWNjZXNzZnVsIHJlcGxhY2VtZW50IGFuZCBgZmFsc2VgIG90aGVyd2lzZS4KLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jvb2sv" +
+    "bWFwcy8jcmVwbGFjZQovLy8KZXh0ZW5kcyBtdXRhdGVzIGZ1biByZXBsYWNlKHNlbGY6IG1hcDxLLCBWPiwga2V5OiBLLCB2YWw6IFYpOiBCb29sOwoKLy8vIExpa2Ug" +
+    "YHJlcGxhY2UoKWAsIGJ1dCByZXR1cm5zIHRoZSBvbGQgKHByZS1yZXBsYWNlbWVudCkgdmFsdWUKLy8vIG9uIHN1Y2Nlc3NmdWwgcmVwbGFjZW1lbnQgYW5kIGBudWxs" +
+    "YCBvdGhlcndpc2UuCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFjdC1sYW5nLm9yZy9ib29rL21hcHMvI3JlcGxhY2VnZXQKLy8vCmV4dGVuZHMgbXV0YXRlcyBm" +
+    "dW4gcmVwbGFjZUdldChzZWxmOiBtYXA8SywgVj4sIGtleTogSywgdmFsOiBWKTogVj87CgovLy8gRGVsZXRlcyBhIHNpbmdsZSBrZXktdmFsdWUgcGFpciAoc2luZ2xl" +
+    "IGVudHJ5KSBieSBpdHMgYGtleWAKLy8vIGZyb20gdGhlIG1hcC4gUmV0dXJucyBgdHJ1ZWAgaW4gY2FzZSBvZiBzdWNjZXNzZnVsIGRlbGV0aW9uIGFuZCBgZmFsc2Vg" +
+    "IG90aGVyd2lzZS4KLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jvb2svbWFwcy8jZGVsCi8vLwpleHRlbmRzIG11dGF0ZXMgZnVuIGRlbChz" +
+    "ZWxmOiBtYXA8SywgVj4sIGtleTogSyk6IEJvb2w7CgovLy8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHZhbHVlIHVuZGVyIHRoZSBnaXZlbiBga2V5YCBleGlzdHMgaW4g" +
+    "dGhlIG1hcCBhbmQgYGZhbHNlYCBvdGhlcndpc2UuCi8vLwovLy8gVGhpcyBmdW5jdGlvbiBpcyBtb3JlIGdhcy1lZmZpY2llbnQgdGhhbiBjaGVja2luZyBgc2VsZi5n" +
+    "ZXQoa2V5KSAhPSBudWxsYC4KLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL2Jvb2svbWFwcy8jZXhpc3RzCi8vLwpleHRlbmRzIGZ1biBleGlz" +
+    "dHMoc2VsZjogbWFwPEssIFY+LCBrZXk6IEspOiBCb29sOwoKLy8vIFJldHVybnMgYHRydWVgIGlmIHRoZSBtYXAgaXMgZW1wdHkgYW5kIGBmYWxzZWAgb3RoZXJ3aXNl" +
+    "LgovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcvYm9vay9tYXBzLyNpc2VtcHR5Ci8vLwpleHRlbmRzIGZ1biBpc0VtcHR5KHNlbGY6IG1hcDxL" +
+    "LCBWPik6IEJvb2w7CgovLy8gUmV0dXJucyBgdHJ1ZWAgaWYgYWxsIGVudHJpZXMgb2YgdGhlIG1hcCBtYXRjaCBjb3JyZXNwb25kaW5nIGVudHJpZXMgb2YgYW5vdGhl" +
+    "ciBtYXAsCi8vLyBpZ25vcmluZyBwb3NzaWJsZSBkaWZmZXJlbmNlcyBpbiB0aGUgdW5kZXJseWluZyBzZXJpYWxpemF0aW9uIGxvZ2ljLiBSZXR1cm5zIGBmYWxzZWAg" +
+    "b3RoZXJ3aXNlLgovLy8KLy8vIFRoaXMgZnVuY3Rpb24gaXMgdmVyeSBnYXMgZXhwZW5zaXZlLCBwcmVmZXIgYD09YCBvcGVyYXRvciBmb3Igc2ltcGxlIGNvbXBhcmlz" +
+    "b25zLgovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcvYm9vay9tYXBzLyNkZWVwZXF1YWxzCi8vLwpleHRlbmRzIGZ1biBkZWVwRXF1YWxzKHNl" +
+    "bGY6IG1hcDxLLCBWPiwgb3RoZXI6IG1hcDxLLCBWPik6IEJvb2w7CgovLy8gQ29udmVydHMgdGhlIG1hcCB0byBpdHMgdW5kZXJseWluZyBgQ2VsbGAgcmVwcmVzZW50" +
+    "YXRpb24uCi8vLwovLy8gU2luY2UgbWFwcyBhcmUgaW5pdGlhbGl6ZWQgdG8gYG51bGxgLCBjYWxsaW5nIGBhc0NlbGwoKWAgb24gYSBtYXAKLy8vIHdpdGggbm8gdmFs" +
+    "dWVzIGFzc2lnbmVkIHdpbGwgcmV0dXJuIGBudWxsYCBhbmQgKipub3QqKiBhbiBlbXB0eSBgQ2VsbGAuCi8vLwovLy8gU2VlOiBodHRwczovL2RvY3MudGFjdC1sYW5n" +
+    "Lm9yZy9ib29rL21hcHMvI2FzY2VsbAovLy8KZXh0ZW5kcyBmdW4gYXNDZWxsKHNlbGY6IG1hcDxLLCBWPik6IENlbGw/Owo=";
diff --git a/src/stdlib/stdlib/std/stubs.tact b/src/stdlib/stdlib/std/stubs.tact
index d7c4ce29..2bfbca22 100644
--- a/src/stdlib/stdlib/std/stubs.tact
+++ b/src/stdlib/stdlib/std/stubs.tact
@@ -394,6 +394,26 @@ fun AnyMessage_fromCell(cell: Cell): M;
 ///
 fun AnyMessage_fromSlice(slice: Slice): M;
 
+/// Extension function for any Message type. Available since Tact 1.7.0.
+///
+/// Returns the message opcode.
+///
+/// ```tact
+/// message(0x777) TripleAxe {
+///     prize: Int as uint32;
+/// }
+///
+/// contract Example {
+///     receive(msg: TripleAxe) {
+///         dump(TripleAxe.opcode()); // 0x777
+///    }
+/// }
+/// ```
+///
+/// See: https://docs.tact-lang.org/ref/core-cells/#messageopcode
+///
+fun AnyMessage_opcode(): Int;
+
 /// Extension function for any Struct.
 ///
 /// Converts the Struct to a `Cell` and returns it.
diff --git a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap
index 27c8333c..ecae4b20 100644
--- a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap
+++ b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap
@@ -711,6 +711,33 @@ exports[`resolveDescriptors should fail descriptors for not-extend-function-self
 "
 `;
 
+exports[`resolveDescriptors should fail descriptors for opcode-method-on-instance-int 1`] = `
+"<unknown>:7:16: Type "Int" does not have a function named "opcode"
+  6 |     get fun foo(): Int {
+> 7 |         return 10.opcode();
+                     ^~~~~~~~~~~
+  8 |     }
+"
+`;
+
+exports[`resolveDescriptors should fail descriptors for opcode-method-on-struct 1`] = `
+"<unknown>:11:16: opcode() method can be used only for messages
+  10 |     get fun foo(): Int {
+> 11 |         return Bar.opcode();
+                      ^~~~~~~~~~~~
+  12 |     }
+"
+`;
+
+exports[`resolveDescriptors should fail descriptors for opcode-method-on-trait 1`] = `
+"<unknown>:8:16: Cannot find 'Ownable'
+  7 |     get fun foo(): Int {
+> 8 |         return Ownable.opcode();
+                     ^~~~~~~
+  9 |     }
+"
+`;
+
 exports[`resolveDescriptors should fail descriptors for override-for-non-existing-constant-in-contract-from-base-trait 1`] = `
 "<unknown>:8:5: Constant "BAR" overrides nothing, remove "override" modifier or inherit any traits with this constant
   7 | contract Test {
diff --git a/src/types/test-failed/opcode-method-on-instance-int.tact b/src/types/test-failed/opcode-method-on-instance-int.tact
new file mode 100644
index 00000000..b15fa4f7
--- /dev/null
+++ b/src/types/test-failed/opcode-method-on-instance-int.tact
@@ -0,0 +1,9 @@
+primitive Int;
+
+trait BaseTrait {}
+
+contract Test {
+    get fun foo(): Int {
+        return 10.opcode();
+    }
+}
diff --git a/src/types/test-failed/opcode-method-on-struct.tact b/src/types/test-failed/opcode-method-on-struct.tact
new file mode 100644
index 00000000..aa28ed14
--- /dev/null
+++ b/src/types/test-failed/opcode-method-on-struct.tact
@@ -0,0 +1,13 @@
+primitive Int;
+
+trait BaseTrait {}
+
+struct Bar {
+    val: Int;
+}
+
+contract Test {
+    get fun foo(): Int {
+        return Bar.opcode();
+    }
+}
diff --git a/src/types/test-failed/opcode-method-on-trait.tact b/src/types/test-failed/opcode-method-on-trait.tact
new file mode 100644
index 00000000..98dea109
--- /dev/null
+++ b/src/types/test-failed/opcode-method-on-trait.tact
@@ -0,0 +1,10 @@
+primitive Int;
+
+trait BaseTrait {}
+trait Ownable {}
+
+contract Test {
+    get fun foo(): Int {
+        return Ownable.opcode();
+    }
+}



Test patch:
diff --git a/src/test/e2e-emulated/structs-and-messages/message-opcode-method.spec.ts b/src/test/e2e-emulated/structs-and-messages/message-opcode-method.spec.ts
new file mode 100644
index 00000000..a8834a0b
--- /dev/null
+++ b/src/test/e2e-emulated/structs-and-messages/message-opcode-method.spec.ts
@@ -0,0 +1,54 @@
+import { toNano } from "@ton/core";
+import { Blockchain } from "@ton/sandbox";
+import "@ton/test-utils";
+import { cached } from "@/test/utils/cache-state";
+import { MessageOpcode } from "@/test/e2e-emulated/structs-and-messages/output/message-opcode-method_MessageOpcode";
+
+const deployValue = toNano("1"); // `dump` is expensive
+
+const setup = async () => {
+    const blockchain = await Blockchain.create();
+    blockchain.verbosity.print = false;
+
+    const treasury = await blockchain.treasury("treasury");
+
+    const contract = blockchain.openContract(await MessageOpcode.fromInit());
+
+    const deployResult = await contract.send(
+        treasury.getSender(),
+        { value: deployValue },
+        null,
+    );
+    expect(deployResult.transactions).toHaveTransaction({
+        from: treasury.address,
+        to: contract.address,
+        success: true,
+        deploy: true,
+    });
+
+    return {
+        blockchain,
+        treasury,
+        contract,
+    };
+};
+
+describe("message-opcode-method", () => {
+    const state = cached(setup);
+
+    it("should return correct opcodes", async () => {
+        const { contract } = await state.get();
+        expect(Number(await contract.getAddOpcode())).toEqual(
+            MessageOpcode.opcodes["Add"],
+        );
+        expect(Number(await contract.getSubOpcode())).toEqual(
+            MessageOpcode.opcodes["Sub"],
+        );
+        expect(Number(await contract.getMulOpcode())).toEqual(
+            MessageOpcode.opcodes["Mul"],
+        );
+        expect(Number(await contract.getDivOpcode())).toEqual(
+            MessageOpcode.opcodes["Div"],
+        );
+    });
+});
diff --git a/src/test/e2e-emulated/structs-and-messages/message-opcode-method.tact b/src/test/e2e-emulated/structs-and-messages/message-opcode-method.tact
new file mode 100644
index 00000000..802a21ba
--- /dev/null
+++ b/src/test/e2e-emulated/structs-and-messages/message-opcode-method.tact
@@ -0,0 +1,24 @@
+message(0x100) Add {}
+message(0x101) Sub {}
+message Mul {}
+message Div {}
+
+contract MessageOpcode {
+    receive() {}
+
+    get fun addOpcode(): Int {
+        return Add.opcode();
+    }
+
+    get fun subOpcode(): Int {
+        return Sub.opcode();
+    }
+
+    get fun mulOpcode(): Int {
+        return Mul.opcode();
+    }
+
+    get fun divOpcode(): Int {
+        return Div.opcode();
+    }
+}