{"id":22243423,"url":"https://github.com/ton-community/ton-contract-executor","last_synced_at":"2025-07-28T01:32:45.571Z","repository":{"id":37929238,"uuid":"450186527","full_name":"ton-community/ton-contract-executor","owner":"ton-community","description":"The TON Contract Executor allows you to write, debug, and fully test your contracts before launching them to the TON blockchain.","archived":false,"fork":false,"pushed_at":"2024-01-31T18:12:22.000Z","size":34439,"stargazers_count":67,"open_issues_count":10,"forks_count":11,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-08-10T10:11:06.598Z","etag":null,"topics":["func","theopennetwork","ton"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ton-community.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-20T17:07:11.000Z","updated_at":"2024-07-30T16:17:10.000Z","dependencies_parsed_at":"2024-06-18T17:01:37.247Z","dependency_job_id":"6770a994-8953-418d-acaa-1c557996df83","html_url":"https://github.com/ton-community/ton-contract-executor","commit_stats":{"total_commits":81,"total_committers":8,"mean_commits":10.125,"dds":0.2592592592592593,"last_synced_commit":"95728fdc453d2a37f87ede30fe401558d7151fa0"},"previous_names":["naltox/ton-contract-executor"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-community%2Fton-contract-executor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-community%2Fton-contract-executor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-community%2Fton-contract-executor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-community%2Fton-contract-executor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ton-community","download_url":"https://codeload.github.com/ton-community/ton-contract-executor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227854097,"owners_count":17829876,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["func","theopennetwork","ton"],"created_at":"2024-12-03T04:26:50.775Z","updated_at":"2024-12-03T04:26:51.540Z","avatar_url":"https://github.com/ton-community.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TON Contract Executor [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ton-community/ton-contract-executor#license) [![npm version](https://img.shields.io/npm/v/ton-contract-executor.svg?style=flat)](https://www.npmjs.com/package/ton-contract-executor)\n\nThis library allows you to run TON Virtual Machine locally and execute contract.\nThat allows you to write \u0026 debug \u0026 fully test your contracts before launching them to the network.\n\n## Features\n\nTON Contract executor allows you to: \n\n- execute smart contracts from existing code and data Cells\n- get TVM execution logs\n- debug your contracts via debug primitives\n- seamlessly handle internal state changes of contract data and code\n- call so-called get methods of smart contracts\n- send and debug internal and external messages\n- debug messages sent by smart contract\n- manipulate the C7 register of the smart contract (including time, random seed, network config, etc.)\n- make some gas optimizations\n\n**Basically you can develop, debug, and fully cover your contract with unit-tests fully locally without deploying it to the network**\n\n## Installation\n\n```bash\nyarn add ton-contract-executor\n```\n\n## How it works \nThis package internally uses original TVM which runs on actual validator nodes to execute smart contracts.\nTVM is built to WASM so this library could be used on any platform.\nWe also added some layer of abstraction on top of original TVM to allow it to run contracts via JSON configuration (those changes could be found [here](https://github.com/ton-community/ton-blockchain/tree/vm-exec/crypto/vm-exec))\n\n## Usage\n\nUsage is pretty straightforward: first of all, you should create an instance of SmartContract.\nYou could think of SmartContract as an existing deployed smart contract with which you can communicate.\n\n\nCreating SmartContract from FunC source code (here the `@ton-community/func-js` package is used for compilation):\n```typescript\nimport { compileFunc } from \"@ton-community/func-js\";\nimport { SmartContract } from \"ton-contract-executor\";\nimport { Cell } from \"@ton/core\";\n\nasync function main() {\n    const source = `\n    () main() {\n        ;; noop\n    }\n\n    int sum(int a, int b) method_id {\n        return a + b;\n    }\n`\n\n    const compileResult = await compileFunc({\n        sources: {\n            'contract.fc': source,\n        },\n        entryPoints: ['contract.fc'],\n    })\n\n    if (compileResult.status === 'error') throw new Error('compilation failed')\n\n    const contract = await SmartContract.fromCell(\n        Cell.fromBoc(Buffer.from(compileResult.codeBoc, 'base64'))[0],\n        new Cell(),\n    )\n}\n```\n\nIn some cases it's useful to create SmartContract from existing precompiled code Cell \u0026 data Cell.\nFor example if you need to debug some existing contract from network.\n\nHere is an example of creating a local copy of existing wallet smart contract from the network deployed at ``EQD4FPq-PRDieyQKkizFTRtSDyucUIqrj0v_zXJmqaDp6_0t`` address and getting its seq:\n\n```typescript\nimport {Address, Cell, TonClient} from \"@ton/core\";\nimport {SmartContract} from \"ton-contract-executor\";\n\nconst contractAddress = Address.parse('EQD4FPq-PRDieyQKkizFTRtSDyucUIqrj0v_zXJmqaDp6_0t')\n\nlet client = new TonClient({\n    endpoint: 'https://toncenter.com/api/v2/jsonRPC'\n})\n\nasync function main() {\n    let state = await client.getContractState(contractAddress)\n\n    let code = Cell.fromBoc(state.code!)[0]\n    let data = Cell.fromBoc(state.data!)[0]\n\n    let wallet = await SmartContract.fromCell(code, data)\n\n    let res = await wallet.invokeGetMethod('seqno', [])\n    console.log('Wallet seq is: ', res.result[0])\n}\n\n```\n\n## Interacting with contract\n\nOnce you have created instance of SmartContract you can start interacting with it.\n\n### Invoking get methods\n\nYou can invoke any get method on contract using ```invokeGetMethod``` function:\n\n```typescript\nimport { SmartContract, stackInt } from \"ton-contract-executor\";\nimport { Cell } from \"@ton/core\";\n\nasync function main() {\n    const source = `\n    () main() {\n        ;; noop\n    }\n\n    int sum(int a, int b) method_id {\n        return a + b;\n    }\n`\n\n    const compileResult = await compileFunc({\n        sources: {\n            'contract.fc': source,\n        },\n        entryPoints: ['contract.fc'],\n    })\n\n    if (compileResult.status === 'error') throw new Error('compilation failed')\n\n    const contract = await SmartContract.fromCell(\n        Cell.fromBoc(Buffer.from(compileResult.codeBoc, 'base64'))[0],\n        new Cell(),\n    )\n    \n    const res = await contract.invokeGetMethod('sum', [\n        // argument a\n        stackInt(1),\n        // argument b\n        stackInt(2),\n    ])\n    \n    console.log('1 + 2 = ', res.result[0])\n}\n```\n\nYou can create arguments of other types for get methods using exported functions `stackInt`, `stackCell`, `stackSlice`, `stackTuple` and `stackNull`.\n\n### Sending messages to contract\n\nYou can send both external and internal messages to your contract by calling `sendMessage`:\n```typescript\nimport { SmartContract, internal } from \"ton-contract-executor\";\nimport { Cell } from \"@ton/core\";\n\nasync function main() {\n    const contract = await SmartContract.fromCell(\n        Cell.fromBoc(Buffer.from(compileResult.codeBoc, 'base64'))[0],\n        new Cell(),\n    )\n    \n    const msgBody = new Cell()\n    \n    const res = await this.contract.sendInternalMessage(internal({\n        dest: contractAddress,\n        value: 1n, // 1 nanoton\n        bounce: false,\n        body: msgBody,\n    }))\n}\n```\n\n`ton-contract-executor` exports two helpers, `internal` and `externalIn` to help you create the necessary `Message` objects.\n\nThere are two aliases for `sendMessage` - `sendInternalMessage` and `sendExternalMessage`, but they only check that the type of the provided `Message` is `internal` or `external-in` respectively, otherwise their behavior is the same as `sendMessage`.\n\n### Setting gas limits\n\n`invokeGetMethod`, `sendMessage`, `sendInternalMessage`, `sendExternalMessage` all support last optional `opts?: { gasLimits?: GasLimits; }` argument for setting gas limits.\nAs an example, the following code\n\n```typescript\nimport { compileFunc } from \"@ton-community/func-js\";\nimport { SmartContract, stackInt } from \"ton-contract-executor\";\nimport { Cell } from \"@ton/core\";\n\nasync function main() {\n    const source = `\n    () main() {\n        ;; noop\n    }\n\n    int sum(int a, int b) method_id {\n        return a + b;\n    }\n`\n\n    const compileResult = await compileFunc({\n        sources: {\n            'contract.fc': source,\n        },\n        entryPoints: ['contract.fc'],\n    })\n\n    if (compileResult.status === 'error') throw new Error('compilation failed')\n\n    let contract = await SmartContract.fromCell(\n        Cell.fromBoc(Buffer.from(compileResult.codeBoc, 'base64'))[0],\n        new Cell(),\n    )\n\n    console.log(await contract.invokeGetMethod('sum', [\n        stackInt(1),\n        stackInt(2),\n    ], {\n        gasLimits: {\n            limit: 308,\n        },\n    }))\n}\n```\nwill output a `failed` execution result to console, because such a call requires 309 gas.\n\n### Execution result\n\nAs the result of calling ```sendMessage```, ```sendInternalMessage```, ```sendExternalMessage``` or ```invokeGetMethod```, an `ExecutionResult` object is returned.\n\n`ExecutionResult` could be either successful or failed:\n\n```typescript\ndeclare type FailedExecutionResult = {\n    type: 'failed';\n    exit_code: number;\n    gas_consumed: number;\n    result: NormalizedStackEntry[];\n    actionList: OutAction[];\n    action_list_cell?: Cell;\n    logs: string;\n};\ndeclare type SuccessfulExecutionResult = {\n    type: 'success';\n    exit_code: number;\n    gas_consumed: number;\n    result: NormalizedStackEntry[];\n    actionList: OutAction[];\n    action_list_cell?: Cell;\n    logs: string;\n};\ndeclare type ExecutionResult = FailedExecutionResult | SuccessfulExecutionResult;\n```\n\nWhat is what: \n\n- exit_code: exit code of TVM\n- result: resulting stack (basically the result of function in case of get methods) \n- gas_consumed: consumed gas amount\n- actionList (list of output actions of smart contract, such as messages )\n- action_list_cell: raw cell with serialized action list \n- logs: logs of TVM\n\n### Configuration of SmartContract\n\nYou also can configure some parameters of your smart contract:\n\n```fromCell``` accepts configuration object as third parameter:\n\n```typescript\ntype SmartContractConfig = {\n    getMethodsMutate: boolean;  // this allows you to use set_code in get methods (useful for debugging)\n    debug: boolean;             // enables or disables TVM logs (it's useful to disable logs if you rely on performance)\n    runner: TvmRunner;\n};\n```\n\nTvmRunner allows you to select TVM executor for specific contract, by default all contracts use ```TvmRunnerAsynchronous``` which runs thread pool of WASM TVM (it uses worker_threads on node and web workers when bundled for web).\n\n### Contract time\n\nBy default, for each call to TVM current unixtime is set to C7 register, but you can change it by calling ```setUnixTime``` on SmartContract instance.\n\n### C7 register\n\nC7 register is used to access some external information in contract: \n\n```typescript\nexport declare type C7Config = {\n    unixtime?: number;\n    balance?: bigint;\n    myself?: Address;\n    randSeed?: bigint;\n    actions?: number;\n    messagesSent?: number;\n    blockLt?: number;\n    transLt?: number;\n    globalConfig?: Cell;\n};\n```\n\nWe prefill it by default, but you can change it by calling ```setC7Config``` or ```setC7```.\n\n### Termination of worker threads\n\nIn order for your tests to terminate successfully, you need to terminate the spawned worker threads, which can be done as follows:\n\n```typescript\nimport {TvmRunnerAsynchronous} from \"ton-contract-executor\";\n\nawait TvmRunnerAsynchronous.getShared().cleanup()\n```\n\n### Shipping to web\n\n`ton-contract-executor` can be bundled using webpack, but a polyfill for `Buffer` is required.\n\nThis can be done by installing the `buffer` package and adding the following to your webpack configuration:\n\n```js\n  resolve: {\n    fallback: {\n      \"buffer\": require.resolve(\"buffer/\")\n    }\n  }\n```\n\nHowever, if you are using `@ton-community/func-js` for compilation, you also need polyfills for `crypto` and `stream` (`crypto-browserify` and `stream-browserify` respectively), and add the following to your webpack configuration:\n\n```js\n  resolve: {\n    fallback: {\n      \"fs\": false,\n      \"path\": false,\n      \"crypto\": require.resolve(\"crypto-browserify\"),\n      \"stream\": require.resolve(\"stream-browserify\"),\n      \"buffer\": require.resolve(\"buffer/\")\n    }\n  }\n```\n\n### Building the WASM part\n\nIf you need to build the WASM part of this package, you can use [this repo](https://github.com/ton-community/ton-vm-exec-builder)\n\n# License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fton-community%2Fton-contract-executor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fton-community%2Fton-contract-executor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fton-community%2Fton-contract-executor/lists"}