{"id":13796362,"url":"https://github.com/broxus/locklift","last_synced_at":"2026-06-08T13:01:11.412Z","repository":{"id":38337880,"uuid":"351046917","full_name":"broxus/locklift","owner":"broxus","description":"Node JS framework for working with Everscale and Venom contracts. Inspired by Truffle and Hardhat. Helps you build, test, run and maintain your smart contracts.","archived":false,"fork":false,"pushed_at":"2026-02-26T10:42:06.000Z","size":3248,"stargazers_count":53,"open_issues_count":11,"forks_count":31,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-02-26T16:31:58.512Z","etag":null,"topics":["blockchain","dapps","debugging","everscale","javascript","smart-contracts","solidity","stack-traces","task-runner","tooling","typescript","venom-blockchain","venom-developer-program"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/broxus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-03-24T11:01:34.000Z","updated_at":"2025-12-10T09:05:50.000Z","dependencies_parsed_at":"2024-04-06T22:32:32.860Z","dependency_job_id":"825e3552-afc4-431c-9f51-9a1062536251","html_url":"https://github.com/broxus/locklift","commit_stats":{"total_commits":303,"total_committers":9,"mean_commits":"33.666666666666664","dds":0.5742574257425743,"last_synced_commit":"0d3de3a513d52c4055a98d6e7c1539e6ccab876f"},"previous_names":["broxus/ton-locklift"],"tags_count":55,"template":false,"template_full_name":null,"purl":"pkg:github/broxus/locklift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Flocklift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Flocklift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Flocklift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Flocklift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/broxus","download_url":"https://codeload.github.com/broxus/locklift/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/broxus%2Flocklift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34063159,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["blockchain","dapps","debugging","everscale","javascript","smart-contracts","solidity","stack-traces","task-runner","tooling","typescript","venom-blockchain","venom-developer-program"],"created_at":"2024-08-03T23:01:09.386Z","updated_at":"2026-06-08T13:01:11.404Z","avatar_url":"https://github.com/broxus.png","language":"TypeScript","funding_links":[],"categories":["Programming"],"sub_categories":[],"readme":"![locklift logo](https://user-images.githubusercontent.com/15921290/183642554-6372baf5-bac5-4477-888b-870a6993f666.png)\n\n\u003cp align=\"center\"\u003e\n    \u003cp align=\"center\"\u003eDevelopment environment for TVM blockchain.\u003c/p\u003e\n    \u003cp align=\"center\"\u003e\n        \u003ca href=\"/LICENSE\"\u003e\n            \u003cimg alt=\"GitHub\" src=\"https://img.shields.io/badge/license-Apache--2.0-orange\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://www.npmjs.com/package/locklift\"\u003e\n            \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/locklift\"\u003e\n        \u003c/a\u003e\n    \u003c/p\u003e\n\u003c/p\u003e\n\nLocklift is a development environment aiming to help you with TVM contracts development. With Locklift, you get:\n\n- Network management for working with any networks (main, test, local, ...)\n- Automated contract testing with Mocha\n- Handy wrapper around TVM smart contract\n- Custom givers support\n- Keys management\n- External script runner that executes scripts within a specified environment\n\n## Quick start\n\nTo install Locklift you need node 14 or later. Go to an empty folder, initialize an npm project (i.e. npm init), and run\n\n```bash\nnpm install --save-dev locklift\n```\n\nOnce it's installed you can initialize the project\n\n```bash\n// initialize in current directory\nnpx locklift init -f\n// or specify new one\nnpx locklift init --path amazing-locklift-project\n```\n\n## Get version\n\n```bash\nnpx locklift --version\n```\n\n## CLI docs\n\nThis section describes the set of commands, supported by the `locklift` package.\n\n### Initialize Locklift package\n\n```bash\nnpx locklift init --path amazing-locklift-project\n# New Locklift project initialized in amazing-locklift-project\n```\n\nThis command initializes new Locklift project, filled with samples:\n\n```\n├── contracts\n│   └── Sample.sol\n├── locklift.config.ts\n├── scripts\n│   └── 1-deploy-sample.ts\n└── test\n    └── sample-test.ts\n```\n\n### Other flags\n\n`-f, --force` - force run the init command (in case you have any files in the target directory);\n\n## Configuration\n\nBy default, the configuration file is called `locklift.config.ts`. Here's the basic layout:\n\n```typescript\nconst config: LockliftConfig = {\n  compiler: {\n    // Specify path to your TON-Solidity-Compiler\n    // path: \"/mnt/o/projects/broxus/TON-Solidity-Compiler/build/solc/solc\",\n\n    // Or specify version of compiler\n    version: \"0.61.2\",\n\n    // Specify config for extarnal contracts as in exapmple\n    // This filed for generating types only\n    // externalContracts: {\n    //   \"node_modules/broxus-ton-tokens-contracts/build\": ['TokenRoot', 'TokenWallet']\n    // }\n\n    // Additional comiler params can be added via this field\n    // compilerParams: [\"--tvm-version ton\"],\n  },\n  linker: {\n    // Specify path to your stdlib\n    // lib: \"/mnt/o/projects/broxus/TON-Solidity-Compiler/lib/stdlib_sol.tvm\",\n    // // Specify path to your Linker\n    // path: \"/mnt/o/projects/broxus/TVM-linker/target/release/tvm_linker\",\n\n    // Or specify version of linker\n    version: \"0.15.48\",\n  },\n  networks: {\n    locklift: {\n      blockchainConfig: \"TON\", // or other presets, or we can provide our custom config by {cunstom: \"MY BLOCKCHAIN CONFIG\"}\n      connection: {\n        id: 1001,\n        // @ts-ignore\n        type: \"proxy\",\n        // @ts-ignore\n        data: {},\n      },\n      keys: {\n        // Use everdev to generate your phrase\n        // !!! Never commit it in your repos !!!\n        // phrase: \"action inject penalty envelope rabbit element slim tornado dinner pizza off blood\",\n        amount: 20,\n      },\n    },\n    mainnet: {\n      // Specify connection settings for https://github.com/broxus/everscale-standalone-client/\n      connection: \"mainnet\",\n      // Here, default SafeMultisig wallet is used as a giver\n      giver: {\n        address: \"0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415\",\n        // you can use bip39 phrase instead of key\n        phrase: \"action inject penalty envelope rabbit element slim tornado dinner pizza off blood\",\n        accountId: 0,\n      },\n      keys: {\n        // Use everdev to generate your phrase\n        // !!! Never commit it in your repos !!!\n        // phrase: \"action inject penalty envelope rabbit element slim tornado dinner pizza off blood\",\n        amount: 20,\n      },\n    },\n  },\n  // you can use any settings that mocha framework support\n  mocha: {\n    timeout: 2000000,\n  },\n};\n```\n\n### Note about `networks.locklift.blockchainConfig`\n\nThis field is used to specify the blockchain config. It can be one of the following:\n\n```\nblockchainConfig: \"EVER\" | \"TON\" | { custom: string } | undefined;\n```\n\nFor example we can get our blockchain config from explorers. Lets see an example of tycho config\n\n- [Open tycho-testnet explorer (config contract)](https://testnet.tychoprotocol.com/accounts/-1:5555555555555555555555555555555555555555555555555555555555555555)\n- Just coppy Data of this contract and paste it to `networks.locklift.blockchainConfig.custom`\n\n### Note about Giver settings:\n\nLet's look at `networks.giver` this is giver settings filed. All known wallets and givers will be detected automatically e.g.\n`EverWallet` or `GiverV2` (from local node). You only need to provide giver credentials - (address, secret key, or phrase with account id).\nBut if you want to use something custom you will need to provide `giverFactory`\ncallback for `networks.giver.giverFactory` that callback should return something that implements `Giver` interface\n\n## Getting code of contract\n\nThis command will show you the contract code\n\n```bash\nnpx locklift code -c \u003ccontract name\u003e\n```\n\n## Getting storage fee of contract\n\nThis command will show you storage fee for the given period of time\n\n```bash\nnpx locklift fee -a \u003ccontract address\u003e -n main\n```\n\n## Build contracts\n\nThis command uses the specified TON Solidity compiler and TVM linker to build all project contracts.\n\n```bash\nnpx locklift build\n```\n\n```\nFound 1 sources\nBuilding contracts/Sample.sol\nCompiled contracts/Sample.sol\nLinked contracts/Sample.sol\n```\n\n## Test contracts\n\nThis command runs the project Mocha tests, `test` folder by default. The `locklift` object will be\nset up and included automatically, you don't need to import it manually.\n\n```bash\nnpx locklift test --network local\n```\n\n```\n  Test Sample contract\n    Contracts\n      ✓ Load contract factory\n      ✓ Deploy contract (1491ms)\n      ✓ Interact with contract (1110ms)\n\n\n  3 passing (3s)\n```\n\n### Debugging\n\nYou can print to console in contracts with special library:\n\n```solidity\nimport \"locklift/src/console.sol\";\n\ncontract Sample {\n  function testFunc(uint input) external {\n    tvm.accept();\n\n    console.log(format(\"You called testFunc with input = {}\", input));\n  }\n}\n```\n\nNote: `console.log` functionality working only with tracing e.g:\n\n```typescript\nawait lockLift.tracing.trace(sampleContract.testFunc({ input: 10 }).sendExternal({ pubkey: keyPair.publicKey }));\n```\n\nAnd then you will see this in your terminal:\n\n```\nYou called testFunc with input = 10\n```\n\nNote the `console.log` is just an event, so if your message dropped on the computed phase (e.g. `required` didn't pass),\nyou will not see the log message.\n\n### Tracing\n\nThe tracing module scans the message tree, determines which contracts have been deployed,\nand decodes all method calls. In case of an error in some section of the execution graph,\ntracing will show the chain of calls that led to the error, as well as the error itself.\n\n#### **_Note: If you want to use tracing be sure to provide a tracing endpoint to the config that supports graphql_**\n\n```typescript\n// trace deploy\nconst {contract: deployedContractInstance, tx} = await locklift.tracing.trace(locklift.factory.deployContract(...))\n// trace simple transaction\nconst changeStateTransaction = await locklift.tracing.trace(MyContract.methods.changeCounterState({newState: 10}).sendExternal({publicKey: signer.publicKey}))\n// trace runTarget\nconst accountTransaction = await locklift.tracing.trace(myAccount.runTarget(...))\n```\n\nexample with tracing output\n\n```bash\nnpx locklift test -n local\n```\n\n```\n...\n\n #1 action out of 1\nAddr: 0:785ea492db0bc46e370d9ef3a0cc23fb86f7a734ac7948bb50e25b51b2455de0\nMsgId: 963a963f227d69f2845265335ecee99052411204b767be441755796cc28482f4\n-----------------------------------------------------------------\nTokenWallet.transfer{value: 4.998, bounce: true}(\n    amount: 100\n    recipient: 0:5d0075f4d3b14edb87f78c5928fbaff7aa769a49eedc7368c33c95a6d63bbf17\n    deployWalletValue: 0\n    remainingGasTo: 0:bb0e7143ca4c16a717733ff4a943767efcb4796dd1d808e027f39e7712745efc\n    notify: true\n    payload: te6ccgEBAQEAKAAAS4AXvOIJRF0kuLdJrf7QNzLzvROSLywJoUpcj6w7WfXqVCAAAAAQ\n)\n\t\t⬇\n\t\t⬇\n\t#1 action out of 1\nAddr: 0:b00ef94c1a23a48e14cdd12a689a3f942e8b616d061d74a017385f6edc704588\nMsgId: bcbe2fb9efd98efe02a6cb6452f38f3dce364b5480b7352000a32f7bdfde949a\n-----------------------------------------------------------------\nTokenWallet.acceptTransfer{value: 4.978, bounce: true}(\n    amount: 100\n    sender: 0:bb0e7143ca4c16a717733ff4a943767efcb4796dd1d808e027f39e7712745efc\n    remainingGasTo: 0:bb0e7143ca4c16a717733ff4a943767efcb4796dd1d808e027f39e7712745efc\n    notify: true\n    payload: te6ccgEBAQEAKAAAS4AXvOIJRF0kuLdJrf7QNzLzvROSLywJoUpcj6w7WfXqVCAAAAAQ\n)\n\t\t⬇\n\t\t⬇\n\t#1 action out of 1\nAddr: 0:5d0075f4d3b14edb87f78c5928fbaff7aa769a49eedc7368c33c95a6d63bbf17\nMsgId: 99034783340906fb5b9eb9a379e1fcb08887992ed0183da78e363ef694ba7c52\n-----------------------------------------------------------------\nEverFarmPool.onAcceptTokensTransfer{value: 4.952, bounce: false}(\n    tokenRoot: 0:c87f8def8ff9ab121eeeb533dc813908ec69e420101bda70d64e33e359f13e75\n    amount: 100\n    sender: 0:bb0e7143ca4c16a717733ff4a943767efcb4796dd1d808e027f39e7712745efc\n    senderWallet: 0:785ea492db0bc46e370d9ef3a0cc23fb86f7a734ac7948bb50e25b51b2455de0\n    remainingGasTo: 0:bb0e7143ca4c16a717733ff4a943767efcb4796dd1d808e027f39e7712745efc\n    payload: te6ccgEBAQEAKAAAS4AXvOIJRF0kuLdJrf7QNzLzvROSLywJoUpcj6w7WfXqVCAAAAAQ\n)\n !!! Reverted with 1233 error code on compute phase !!!\n```\n\n### Ignoring errors\n\nBy default, tracing will throw an error on any non-zero code in the execution graph, but\nsometimes in contract, we can expect some specific errors that could be processed later with bounced msgs.\nIn this cases, we don't want tracing to throw errors, because such behavior is expected.\nWe can tell tracing to ignore specific errors on compute or action phases.\n\nWe can ignore errors on specific call:\n\n```typescript\n// Tracing will ignore all 51 and 60 errors on compute phase + 30 error on action phase\n// Here 51 compute and 30 action errors will be ignored for all transacions in msg chain and 60 compute error\n// will be ignored only on specific address\nconst transaction = await locklift.tracing.trace(\n  tokenRoot.methods.sendTokens({ walletOwner: \"\" }).sendExternal({ publicKey: signer.publicKey }),\n  {\n    allowedCodes: {\n      //compute or action phase for all contracts\n      compute: [40],\n      //also you can specify allowed codes for specific contract\n      contracts: {\n        [someAddress.toString()]: {\n          action: [52, 60],\n        },\n      },\n    },\n  },\n);\n```\n\nOr set ignoring by default for all further calls:\n\n```typescript\n// ignore compute(or acton) phase errors for all transactions\nlocklift.tracing.setAllowedCodes({ compute: [52, 60] });\n// ignore more errors for specific address\nlocklift.tracing.setAllowedCodesForAddress(SOME_ADDRESS, { compute: [123], action: [111] });\n\n// remove code from a default list of ignored errors so that only 51 errors will be ignored\n// this affects only global rules, per-address rules are not modified\nlocklift.tracing.removeAllowedCodes({ compute: [60] });\n// remove code from deault list of ignored errors for specific address\nlocklift.tracing.removeAllowedCodesForAddress(SOME_ADDRESS, { compute: [123] });\n```\n\n### Tracing features (EXPERIMENTAL FEATURES)\n\nFor using this feature first of all need to wrap the transaction by tracing, and make **sure that tracing is enabled**.\nOtherwise, the `traceTree` will be **undefined**\n\n#### example\n\n```typescript\nconst { traceTree } = await locklift.tracing.trace(myContract.method.myMethod().send());\n```\n\n#### `tracingTree` methods\n\n1. **Beauty print**\n\n#### example\n\n```typescript\nawait traceTree?.beautyPrint();\n```\n\n#### example output\n\n```shell\nCALL Wallet.sendTransaction{valueReceive: 0,valueSent: 3.9, rest: -3.910662⮯, totalFees: 0.010662}(dest=\"StEverVault(0:5db...a9bcf)\", value=\"3900000000\", bounce=true, flags=\"3\", payload=\"te6c...pQ==\")\n CALL StEverVault.startEmergencyProcess{valueReceive: 3.9,valueSent: 3.867427, rest: 0⮬, totalFees: 0.032573}(_poofNonce=\"50341\")\n  CALL StEverAccount.onStartEmergency{valueReceive: 3.867427,valueSent: 3.857346, rest: 0⮬, totalFees: 0.010081}(_proofNonce=\"50341\")\n   CALL StEverVault.startEmergencyRejected{valueReceive: 3.857346,valueSent: 3.831589, rest: 0⮬, totalFees: 0.025757}(_user=\"Wallet(0:ae6...10a56)\", errcode=\"2004\")\n    EVENT StEverVault.EmergencyProcessRejectedByAccount(emitter=\"Wallet(0:ae6...10a56)\", errcode=\"2004\")\n    TRANSFER Wallet.undefined{valueReceive: 3.831589,valueSent: 0, rest: 3.830589⮬, totalFees: 0.001}()\n\n```\n\nlet's look at random raw in beaty print\n\n`(1)CALL (2)StEverVault.(3)startEmergencyRejected{(4)valueReceive: 3.857346,(5)valueSent: 3.831589, (6)rest: 0⮬, (7)totalFees: 0.025757}((8)_user=\"Wallet(0:ae6...10a56)\", errcode=\"2004\")`\n\n(1) Action type ,it can be (`CALL`, `EVENT`, `BOUNCE`, `TRANSFER`)\n\n(2) Contract name\n\n(3) Method name\n\n(4) How many value(ever) the method received\n\n(5) How many value(ever) the method sent\n\n(6) How many ever left on contract after current transaction step (`valueReceive - valueSent - totalFees`)\n\n(7) Total fees used in current step\n\n(8) Method params, if params are included addresses it can be tried to find associated contract for it\n\n2. **Ever balance diff**\n\nThis method is providing information about changing ever balance for a particular address or addresses\n\n```typescript\nconst balanceChange = traceTree.getBalanceDiff(account.address);\n// -1859458715 nano\n```\n\n3. **Token balance diff**\n\nThis method is providing information about changing token balance by a particular **token wallet**\n\n```typescript\nconst tokenBalanceChange = traceTree?.tokens.getTokenBalanceChange(myUSDTTokenWalletContract.address);\n// -1859458715 measurements depends of token decimals\n```\n\n4. **Getting information about calling methods and emitting events**\n\n```typescript\n// Events\nconst addEvents = traceTree?.findEventsForContract({\n  contract: myContract,\n  name: \"Add\" as const, // 'as const' is important thing for type saving\n});\n\n//Methods calls\nconst depositCalls = traceTree?.findCallsForContract({\n  contract: myContract,\n  name: \"deposit\",\n});\n```\n\n5. **Total gas used**\n\nThis method is providing information about how much gas used after evaluating the full transaction\n\n```typescript\nconst gasUsed = traceTree?.totalGasUsed();\n// 256859 nano\n```\n\n### Tracing testing feature\n\nFor better testing your contracts you can use our `chai` plugin that includes to `locklift` package.\n\nJust add this to your `locklift.config.ts`\n\n```typescript\nimport { lockliftChai } from \"locklift\";\nimport chai from \"chai\";\n\nchai.use(lockliftChai);\n```\n\nThis plugin is providing useful things for testing TVM contract\n\n1. `.emit`\n\nWith this method, you can test emitting events, like this\n\n```typescript\nexpect(traceTree)\n  .to.emit(\"Deposit\")\n  .withNamedArgs({\n    amount: \"150\",\n  })\n  .and.emit(\"AccountDeployed\")\n  .withNamedArgs({\n    user: \"user address\",\n  })\n  .count(1);\n```\n\n`.emit` method gets the event name as a first parameter and an optional parameter with the type\n`type Addressable = Contract | Address | string;`\n\n2. `.call`\n\nWith this method, you can test evaluating contract methods, as this\n\n```typescript\nexpect(traceTree).to.call(\"depositToStrategies\").withNamedArgs({...}).count(2)\n```\n\n`.call` parameters are the same as `.emit`\n\n3. `.error`\n\nWith this method, you test cases with errors like this\n\n```typescript\nexpect(traceTree).to.have.error(1025);\n// expect(traceTree).not.to.have.error(1025);\n```\n\nAll `.error` parameters are optional, so you can test particular errors or all errors that happened or not happened\n\nAnd last but not least you can combine each of these methods e.g.\n\n```typescript\nexpect(traceTree)\n  .to.call(\"deposit\")\n  .withNamedArgs({\n    depositor: \"userAddress\",\n  })\n  .count(1)\n  .and.error(1065)\n  .and.emit(\"Deposit\")\n  .withNamedArgs({\n    depositor: \"userAddress\",\n  })\n  .count(1);\n```\n\n## Network\n\n### Note (BETA)\n\nLocklift network was migrated to the new tycho executor and will be used by default in the next version. But the previous network will be available.\nIf we need to use previous vm, we just need to modify project package.json.\n\n```json\n{\n  \"name\": \"my-locklift-project\",\n  /* existing code */\n  \"devDependencies\": {\n    /* existing code */\n  },\n  \"overrides\": {\n    /* existing code */\n    \"@broxus/locklift-network\": \"^1.0.8\" // or \"@broxus/locklift-network\": \"^2.0.0-beta-rc1\"\n  }\n}\n```\n\n**But for new projects, we recommend using the new(default) network.**\n\nIn this paragraph we are going to explain some features of locklift network.\n\n1. It supports fork mode (see below)\n2. It supports inserting any accounts to the network\n3. Also blockchain can be erased and restored from snapshots (see below)\n\n- `locklift.network.insertWallet(address)` - insert wallet with provided address to the network\n- `locklift.network.insertAccount()` - insert account with provided address,boc,abi to the network\n\n### Snapshots\n\nLocklift network supports snapshots. It allows you to save the current state of the network and restore it later.\n\n```typescript\nconst firstSnapshotId = locklift.network.snapshots.saveSnapshot(); // in this moment our blockchain is empty\n\n// deploy new contract\nconst myContract = await locklift.factory.deployContract(); // params were omitted for simplicity\n\nconst secondSnapshotId = locklift.network.snapshots.saveSnapshot(); // in this moment our blockchain has one contract\n\n// apply the first snapshot\nlocklift.network.snapshots.loadSnapshot(firstSnapshotId); // now our blockchain is empty again\n\n// try to get the contract state\nconst contarctState = await myContract.getFullState().then(res =\u003e res.state);\nexpect(contarctState).to.be.undefined;\n\n// apply the second snapshot and check the contract state\n{\n  locklift.network.snapshots.loadSnapshot(secondSnapshotId); // now our blockchain has one contract again\n  const contarctState = await myContract.getFullState().then(res =\u003e res.state);\n  expect(contarctState).not.to.be.undefined;\n}\n```\n\n### Clear network\n\nFor more precise testing, you can clear the network state. This will remove all contracts and accounts from the network.\n\n```typescript\nlocklift.network.clearBlockchainState();\n```\n\n## Fork\n\nLocklift supports fork mode. In this mode, locklift will execute all accounts locally\nand if the contract doesn't exist in current context, it will download its state.\n\n_Note: it can be used only inside locklift network_\n\nWe are supporting two types of forking:\n\n- Live mode - in this mode, locklift will download the latest state of the contract by provided network config\n- Block mode - in this mode, locklift will download the state of the contract by provided block number(mainnet only)\n\n### Usage\n\nFor using this we need to update our config file\n\n```typescript\nconst config: LockliftConfig = {\n  /// ...\n  networks: {\n    locklift: {\n      connection: {\n        /// ...\n      },\n      keys: {\n        /// ...\n      },\n      fork: {\n        source: {\n          type: \"block\",\n          block: 32438397,\n        },\n        // or\n        // source: {\n        //   type: \"live\"\n        //   connection: 'mainnetJrpc', // or arbitrary network config\n        // },\n        contracts: [\n          {\n            abi: {\n              path: \"path to abi file\", // note: file name will be used for type generation\n            },\n            // We need to provide address or code hash for contract that we want to associate with abi\n            address: \"\",\n\n            // or\n            // codeHash: \"\",\n\n            // or\n            // codeHash:{\n            //   deriveAddress: 'address of contract that we will use for deriving code hash and abi'\n            // }\n          },\n        ],\n      },\n    },\n  },\n  /// ...\n};\n```\n\nNow we can use external contracts as like it was deployed in our network.\nLet's imagine we added `Staking` project to our config\n\n```typescript\n{\n  /// ...\n  fork: {\n    /// ...\n    contracts: [\n      {\n        abi: {\n          path: path.resolve(`externContarcts/Staking.json`), // note: file name will be used for type generation\n        },\n        address: \"0:675a6d63f27e3f24d41d286043a9286b2e3eb6b84fa4c3308cc2833ef6f54d68\",\n      },\n    ];\n  }\n  /// ...\n}\n```\n\n```typescript\nconst stakingVault = locklift.factory.getDeployedContract(\n  \"Staking\", // name of abi file\n  new Address(\"0:675a6d63f27e3f24d41d286043a9286b2e3eb6b84fa4c3308cc2833ef6f54d68\"), // address of contract\n);\n// Now you can interact with this contract.\nconst stakingDetails = await stakingVault.methods.getDetails().call();\n// Let make owner account\nconst ownerAccount = locklift.network.insertWallet(stakingDetails.owner);\n\n// And lets do something as if we were the owner\nconst { traceTree } = await locklift.tracing.trace(\n  stakingVault.methods.makeSomethingAsOwner().send({\n    from: ownerAccount.address,\n    amount: toNano(1),\n  }),\n);\n\nawait traceTree.beautyPrint();\n// And inside the output we will se detailed call trace thanks abi that was provded inside the config.network\n```\n\nAlso, you can add any contracts and used it as like it was deployed in your network.\nSome words about the algorithm of searching contract in fork mode:\n\n1. If you or your contract is trying to interact with a contract that wasn't deployed in your network, locklift will try to find it in fork\n2. If contract wasn't found in fork, it will show a warning\n3. If contract was found in fork locklift will try to apply ABI to this contract\n\n````bash\n## Run script\n\nThis command runs an arbitrary Node JS script with an already configured `locklift` module.\n\n```bash\nnpx locklift run --network local --script scripts/1-deploy-sample.ts\n````\n\n```\nSample deployed at: 0:a56a1882231c9d901a1576ec2187575b01d1e33dd71108525b205784a41ae6d0\n```\n\n# Locklift docs\n\nThis section describes the features of the `locklift` module.\n\n#### `locklift.keystore`\n\nModule provides access to keystore\n\n##### Example\n\n```typescript\nconst signer = await locklift.keystore.getSigner(\"0\");\n```\n\n## Get Balance (`locklift.provider.getBalance`)\n\nGet balance of account\n\n##### Example\n\n```javascript\nconst userBalance = await locklift.provider.getBalance(user.address);\n\nexpect(Number(userBalance)).to.be.above(0, \"Bad user balance\");\n```\n\n## Transactions (`locklift.transactions`)\n\nThe module provides access to high-level control of transaction flow.\n\nThis method allows you to wait until all transactions in the chain are finalized.\n\n```typescript\nconst transaction = await locklift.transactions.waitFinalized(tokenRoot.methods.deployWallet({...}))\n```\n\n## Full contract state (`locklift.provider.getFullContractState`)\n\nGet full account state\n\n##### Example\n\n```typescript\nexpect(await locklift.provider.getFullContractState({ address: addr }).then(res =\u003e res.state?.isDeployed)).to.be.true;\n```\n\n## Testing (`locklift.testing`)\n\nThe module provides access to special testing utils, which available only with the dev node\n\n`locklift.testing.increaseTime`\nwith this method, you can increase local node time by seconds\n\n##### Example\n\n```typescript\n// increase time by 10 seconds\nawait locklift.testing.increaseTime(10);\n// get current offset in seconds\nconst currentOffsetInSeconds = locklift.testing.getTimeOffset();\n```\n\nNote: this method increases your local node and provider time, we can't change the time back.\nSo if you need to reset the offset you will need to restart the local node.\n**After each run locklift makes syncing the provider with the local node.**\nAnd you will see the warning about the current offset, please skip this warning if this is expected behavior,\notherwise, just restart the local node\n\n## Context (`locklift.context`)\n\nThe module provides information about the current context\n\n##### Example\n\n```typescript\nconst networkName = locklift.context.network.name; // network name which provided as --network param with locklift run command\nconst networkConfig = locklift.context.network.config; // network setting related with selected network\n```\n\n## Factory (`locklift.factory`)\n\nThis module provides the factory with getting sources of the contract and functionality for deploying contracts.\nFrom the factory, you can receive contract objects from the project Solidity sources and contracts provided\nin `config.extarnalContracts`.\n\n#### `locklift.factory.getContractArtifacts`\n\nReturns all compilation artifacts based on the .sol file name or name from value `config.extarnalContracts[pathToLib]`.\n\n```typescript\nconst myContractData = await locklift.factory.getContractArtifacts(\"MyContract\");\n```\n\n### Deploy `locklift.factory.deployContract`\n\nDeploy specified contract and returns contract instance and transaction.\n\n```typescript\n// Deploy\nconst {contract: DeployedMyContract, tx} = locklift.factory.deployContract({\n  // name of your contract\n  contract: \"MyContractName\",\n  // public key in init data\n  publicKey: signer.publicKey,\n  // static parameters of contract\n  initParams: {...},\n  // runtime deployment arguments\n  constructoParams: {...},\n  // this value will be transfered from giver to deployable contract\n  value: toNano(2),\n});\n// Ot you can get instance of already deployed contract\nconst GettedMyContract = await locklift.factory.getDeployedContract(\n  \"Wallet\", // name of your contract\n  new Address(\"MyAddress\"),\n);\n// In this example 'DeployedMyContract' and 'GettedMyContract' are the same contract\n```\n\n## Contract\n\nThe contract object includes all methods based on built sources (Abi). It is based\non https://github.com/broxus/everscale-inpage-provider\n\n```typescript\nconst MyContract = locklift.factory.getDeployedContract(\n  \"Wallet\", //name infered from your contracts\n  new Address(\"MyAddress\"),\n);\n// Send External\nawait MyContract.methods.changeCounterState({ newState: 10 }).sendExternal({ publicKey: signer.publicKey });\n// Run getter or view method\nconst counterSatate = await MyContract.methods.getCounterState({}).call();\n// Await event that is still not emitted\nconst futureEvent = await MyContract.waitForEvent({ filter: event =\u003e event.event === \"StateChanged\" });\n// Get past events\nconst pastEvents = await MyContract.getPastEvents({ filter: event =\u003e event.event === \"Deposit\" });\n```\n\n## locklift.factory.accounts\n\nThis module provides the possibility to interact with contracts directly e.g.\n\n```typescript\nmyContract.methods.mint({}).send({\n  //sender account\n  from: myAccountAddress,\n  amount: toNano(20),\n});\n```\n\nFor this flow need to add accounts to the `locklift.factory.accounts`. We are supporting WalletV3, HighLoadWallet,\nMsigAccount\nand other wallets which should provide directly\n\n### Deploy and add new account to the account storage\n\nFor creating and adding a new account need to use `locklift.factory.accounts.addNewAccount` this method sends values and\ndeploys new account\n\n### 1. WalletV3 or HighLoadWallet\n\n```typescript\nconst account = await locklift.factory.accounts.addNewAccount({\n  type: WalletTypes.EverWallet, // or WalletTypes.HighLoadWallet or WalletTypes.WalletV3,\n  //Value which will send to the new account from a giver\n  value: toNano(100000),\n  //owner publicKey\n  publicKey: signer.publicKey,\n});\n```\n\n### 2. Msig like Wallets (e.g. [SafeMultisig like](https://github.com/broxus/ever-contracts/blob/master/contracts/wallets/Account.sol#L2-L3))\n\n_Note: For custom wallets, needs to follow the same rules as for simple deploy(need to pass constructor and init\nparams)_\n\n**Msig like Wallet should implement method sendTransaction\nfrom** [Account](https://github.com/broxus/ever-contracts/blob/master/contracts/wallets/Account.sol#L2-L3))\n\n```typescript\nconst account = await locklift.factory.accounts.addNewAccount({\n  type: WalletTypes.MsigAccount,\n  // Multisig type SafeMultisig supports 2.0 ABI version, multisig2 supports 2.3 ABI version\n  mSigType: \"SafeMultisig\", // or SafeMultisig\n  //Contract should included to the locklift.config.externalContracts or should compiled from contracts folder\n  contract: \"Account\",\n  //Value which will send to the new account from a giver\n  value: toNano(100000),\n  publicKey: signer.publicKey,\n  constructorParams: {},\n  initParams: {\n    _randomNonce: getRandomNonce(),\n  },\n});\n```\n\nAnd then `account.address` can be used as sender.\n\n#### Full example:\n\n```typescript\nconst account = await locklift.factory.accounts.addNewAccount({\n  type: WalletTypes.EverWallet, // or WalletTypes.HighLoadWallet or WalletTypes.WalletV3,\n  //Value which will send to the new account from a giver\n  value: toNano(100000),\n  //owner publicKey\n  publicKey: signer.publicKey,\n  nonce: getRandomNonce(),\n});\n\nawait myContract.methods.mint({}).send({\n  //sender account\n  from: account.address,\n  amount: toNano(20),\n});\n```\n\n### 3. Custom wallets\n\n_Note this is very low level adding account method, so if you need to use something custom would be a better way to\nuse `2. Msig like Wallets`_ method\n\n[MsigAccount](https://github.com/broxus/everscale-standalone-client/blob/dev/src/client/AccountsStorage/Generic.ts#L61-L107)\ncan be used as example for own implementation\n\n#### example\n\n```typescript\nimport {GenericAccount} from 'locklift/everscale-standalone-client'\n\nconst {abi: myMsigAccountAbi} = locklift.factory.getContractArtifacts(\"MyMsigAccount\");\n\n//derived from https://github.com/broxus/everscale-standalone-client/blob/dev/src/client/AccountsStorage/Generic.ts#L61-L107\nclass MyMsigAccount extends GenericAccount {\n  constructor(args: {\n    address: string | Address,\n    publicKey?: string\n  }) {\n    super({abi: myMsigAccountAbi, ...});\n  }\n}\n\nconst signer = await locklift.keystore.getSigner('0')\nconst {contract: myMsigContract} = await locklift.factory.deployContract({\n  contract: \"MyMsigAccount\",\n  constructorParams: {},\n  initParams: {\n    _randomNonce: getRandomNonce(),\n  },\n  value: toNano(10),\n  publicKey: signer.publicKey,\n});\nconst myMsigAccount = new MyMsigAccount({address: myMsigContract.address, publicKey: signer.publicKey})\nlocklift.factory.accounts.storage.addAccount(myMsigAccount)\n\nawait myContract.methods.mint({}).send({\n  //sender account\n  from: myMsigAccount.address,\n  amount: toNano(20),\n});\n\n```\n\n### Using an existing account\n\n```typescript\nconst everWalletAccount = await locklift.factory.accounts.addExistingAccount({\n  address: \"MyAddress\",\n  type: WalletTypes.EverWallet,\n});\n\nconst walletV3Account = await locklift.factory.accounts.addExistingAccount({\n  publicKey: signer.publicKey,\n  type: WalletTypes.WalletV3,\n});\nconst mySafeMultisigAccount = await locklift.factory.accounts.addExistingAccount({\n  publicKey: signer.publicKey,\n  type: WalletTypes.Custom,\n  address: \"MyAddress\",\n});\n\nawait myContract.methods.mint({}).send({\n  //sender account\n  from: mySafeMultisigAccount.address, // walletV3Account.address\n  amount: toNano(20),\n});\n```\n\n## ~~AccountFactory~~ (`locklift.factory.getAccountsFactory`)\n\nthis is deprecated since 2.2.0, use `locklift.factory.accounts` instead\n\nThis module provides the generic account factory. You can provide your own implementation of the account if needed,\nthere is only one constraint - the custom contract should include this method\n\n```typescript\naccountAbiBase = {\n  functions: [\n    {\n      name: \"sendTransaction\",\n      inputs: [\n        { name: \"dest\", type: \"address\" },\n        { name: \"value\", type: \"uint128\" },\n        { name: \"bounce\", type: \"bool\" },\n        { name: \"flags\", type: \"uint8\" },\n        { name: \"payload\", type: \"cell\" },\n      ],\n      outputs: [],\n    },\n  ],\n};\n```\n\n##### Example\n\n```typescript\nlet accountsFactory = locklift.factory.getAccountsFactory(\n  \"Wallet\", // name of contract used as a wallet\n);\n```\n\nNow you can use it for deploying contract or getting deployed ones\n\n### Deploy\n\n```typescript\nconst {contract: MyAccount, tx} = accountsFactory.deployNewAccount({\n  publicKey: signer.publicKey,\n  initParams: {\n    _randomNonce: getRandomNonce(),\n  },\n  constructorParams: {...},\n  value: locklift.utils.toNano(100000)\n});\n```\n\n### Get account by address\n\n```typescript\nconst Account = accountsFactory.getAccount(new Address(\"MyAddress\"), signer.publicKey);\n```\n\n### Account\n\nIn most cases users interact with your contract through wallets with internal messages.\nTo make testing realistic we added `Account` class that allows you to imitate user and send all\ntransactions to contracts through wallet contract.\n\nThis class extends the basic `Contract` functionality by adding special `runTarget` method,\nwhich allows interaction with other contracts, by sending internal messages from \"Account\" contract.\nIt encodes the specified method + params into the internal message, according to the\ntarget contract's ABI and call the Account's external method.\n\nThe basic Account contract can be found\nhere [Account.sol](https://github.com/broxus/ton-contracts/blob/master/contracts/wallets/Account.sol).\n\n```typescript\nconst userAccount1 = accountsFactory.getAccount(new Address(\"MyAddress\"), signer.publicKey);\n// send tokens by interacting with tokenWallet contract\nawait userAccount1.runTarget(\n  {\n    contract: tokenWallet,\n    value: locklift.utils.toNano(5),\n  },\n  tokenWallet =\u003e\n    tokenWallet.methods.transfer({\n      amount: DEPOSIT_AMOUNT,\n      payload: \"\",\n      notify: true,\n      remainingGasTo: userAccount1.address,\n      recipient: bankContract.address,\n      deployWalletValue: 0,\n    }),\n);\n```\n\n## Giver (`locklift.giver`)\n\nThis module allows you to send native tokens.\n`locklift.factory` is using the giver under the hood, for deploying contracts\n\n## Utils\n\nThis module provides some utility functions for more convenient work with Ever objects.\n\n##### Example\n\n````typescript\nimport { toNano, fromNano, getRandomNonce, convertAmount, isValidEverAddress, stringToBytesArray } from \"locklift\";\n\ntoNano(10); // 10000000000\nfromNano(10000000000); // 10```\n````\n\n## Plugins\n\n1. [locklift-verify](https://github.com/broxus/locklift-verifier)\n2. [locklift-deploy](https://github.com/broxus/locklift-deploy)\n3. [locklift-plugin-boilerplate(example of implementation)](https://github.com/broxus/locklift-plugin-boilerplate)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbroxus%2Flocklift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbroxus%2Flocklift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbroxus%2Flocklift/lists"}