├── .prettierignore ├── logo.png ├── .gitignore ├── .husky └── pre-commit ├── tsconfig.json ├── .prettierrc ├── generators ├── sample │ ├── templates │ │ ├── .prettierrc │ │ ├── contracts │ │ │ └── Sample.tsol │ │ ├── scripts │ │ │ └── 00-deploy-sample.ts │ │ ├── tsconfig.json │ │ ├── test │ │ │ └── sample-test.ts │ │ └── README.md │ └── index.ts ├── tip3 │ ├── templates │ │ ├── .prettierrc │ │ ├── tsconfig.json │ │ ├── scripts │ │ │ ├── 02-burn.ts │ │ │ ├── 00-deploy.ts │ │ │ └── 01-mint.ts │ │ ├── test │ │ │ └── deploy-mint-burn-test.ts │ │ └── README.md │ └── index.ts ├── tip4 │ ├── templates │ │ ├── .prettierrc │ │ ├── tsconfig.json │ │ ├── contracts │ │ │ ├── Nft.tsol │ │ │ └── Collection.tsol │ │ ├── scripts │ │ │ ├── 0-deploy-collection.ts │ │ │ └── 1-mint-nft.ts │ │ ├── README.md │ │ └── test │ │ │ └── deploy-mint-test.ts │ └── index.ts ├── app │ ├── USAGE │ └── index.ts └── locklift │ ├── templates │ └── locklift.config.ts │ └── index.ts ├── .eslintrc.json ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── package.json ├── CONTRIBUTING.md ├── lib └── base.ts ├── LICENSE └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | templates 2 | dist 3 | examples 4 | node_modules -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/venom-blockchain/generator-venom-scaffold/HEAD/logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | 4 | .DS_Store 5 | .vscode 6 | 7 | examples 8 | rnd 9 | TODO.md -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run clean && npm run lint && npm run format && npm run build 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "sourceMap": true, 6 | "outDir": "./dist" 7 | }, 8 | "exclude": ["node_modules", "./*/**/templates", "examples"] 9 | } 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "printWidth": 120, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": false, 7 | "jsxSingleQuote": false, 8 | "trailingComma": "all", 9 | "bracketSpacing": true, 10 | "arrowParens": "avoid" 11 | } 12 | -------------------------------------------------------------------------------- /generators/sample/templates/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "printWidth": 120, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": false, 7 | "jsxSingleQuote": false, 8 | "trailingComma": "all", 9 | "bracketSpacing": true, 10 | "arrowParens": "avoid" 11 | } 12 | -------------------------------------------------------------------------------- /generators/tip3/templates/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "printWidth": 120, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": false, 7 | "jsxSingleQuote": false, 8 | "trailingComma": "all", 9 | "bracketSpacing": true, 10 | "arrowParens": "avoid" 11 | } 12 | -------------------------------------------------------------------------------- /generators/tip4/templates/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "printWidth": 120, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": false, 7 | "jsxSingleQuote": false, 8 | "trailingComma": "all", 9 | "bracketSpacing": true, 10 | "arrowParens": "avoid" 11 | } 12 | -------------------------------------------------------------------------------- /generators/app/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | The Venom scaffold is inspired by the Truffle boxes and aims to help users create a project ready to test, deploy, and execute arbitrary scripts to develop smart contracts on Venom-like blockchains. 3 | 4 | Subgenerators: 5 | yo venom-scaffold:sample [] [options] 6 | yo venom-scaffold:tip3 [] [options] 7 | yo venom-scaffold:tip4 [] [options] 8 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], 7 | "parser": "@typescript-eslint/parser", 8 | "parserOptions": { 9 | "ecmaVersion": "latest", 10 | "sourceType": "module" 11 | }, 12 | "ignorePatterns": ["dist/*", "**/templates/*", "examples"], 13 | "plugins": ["@typescript-eslint"], 14 | "rules": {} 15 | } 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /generators/sample/templates/contracts/Sample.tsol: -------------------------------------------------------------------------------- 1 | pragma ever-solidity >= 0.61.2; 2 | pragma AbiHeader expire; 3 | pragma AbiHeader pubkey; 4 | 5 | 6 | contract Sample { 7 | uint16 static _nonce; 8 | 9 | uint state; 10 | 11 | event StateChange(uint _state); 12 | 13 | constructor(uint _state) public { 14 | tvm.accept(); 15 | 16 | setState(_state); 17 | } 18 | 19 | function setState(uint _state) public { 20 | tvm.accept(); 21 | state = _state; 22 | 23 | emit StateChange(_state); 24 | } 25 | 26 | function getDetails() 27 | external 28 | view 29 | returns ( 30 | uint _state 31 | ) { 32 | return state; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /generators/sample/templates/scripts/00-deploy-sample.ts: -------------------------------------------------------------------------------- 1 | async function main() { 2 | const signer = (await locklift.keystore.getSigner("0"))!; 3 | console.log("Starting Sample contract deployment..."); 4 | 5 | const { contract: sample, tx } = await locklift.factory.deployContract({ 6 | contract: "Sample", 7 | publicKey: signer.publicKey, 8 | initParams: { 9 | _nonce: locklift.utils.getRandomNonce(), 10 | }, 11 | constructorParams: { 12 | _state: 0, 13 | }, 14 | value: locklift.utils.toNano(3), 15 | }); 16 | 17 | console.log(`Sample deployed at: ${sample.address.toString()}`); 18 | } 19 | 20 | main() 21 | .then(() => process.exit(0)) 22 | .catch(e => { 23 | console.log(e); 24 | process.exit(1); 25 | }); 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | 28 | - OS: [e.g. iOS] 29 | - Browser [e.g. chrome, safari] 30 | - Version [e.g. 22] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /generators/tip3/templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, 4 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 5 | 6 | "strict": true /* Enable all strict type-checking options. */, 7 | "types": ["node", "mocha"] /* Type declaration files to be included in compilation. */, 8 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 9 | 10 | "skipLibCheck": true /* Skip type checking of declaration files. */, 11 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /generators/tip4/templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, 4 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 5 | 6 | "strict": true /* Enable all strict type-checking options. */, 7 | "types": ["node", "mocha"] /* Type declaration files to be included in compilation. */, 8 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 9 | 10 | "skipLibCheck": true /* Skip type checking of declaration files. */, 11 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /generators/sample/templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, 4 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 5 | 6 | "strict": true /* Enable all strict type-checking options. */, 7 | "types": ["node", "mocha"] /* Type declaration files to be included in compilation. */, 8 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 9 | 10 | "skipLibCheck": true /* Skip type checking of declaration files. */, 11 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-venom-scaffold", 3 | "version": "0.1.4", 4 | "description": "Yeoman generator to scaffold ready-to-use projects for smart contract developing on Venom-like blockchains.", 5 | "homepage": "https://github.com/venom-blockchain/generator-venom-scaffold", 6 | "files": [ 7 | "dist" 8 | ], 9 | "license": "Apache-2.0", 10 | "main": "dist/generators/app/index.js", 11 | "bin": "dist/generators/app/index.js", 12 | "keywords": [ 13 | "yeoman-generator", 14 | "venom" 15 | ], 16 | "scripts": { 17 | "build": "npm run compile && npm run copy-files", 18 | "compile": "tsc -p .", 19 | "copy-files": "cpy \"generators/**/templates/**\" dist/generators/", 20 | "format": "prettier --write .", 21 | "lint": "npx eslint .", 22 | "clean": "rimraf ./dist", 23 | "prepare": "husky install" 24 | }, 25 | "devDependencies": { 26 | "@types/validate-npm-package-name": "^4.0.0", 27 | "@types/yeoman-generator": "^5.2.11", 28 | "@typescript-eslint/eslint-plugin": "^5.45.0", 29 | "@typescript-eslint/parser": "^5.45.0", 30 | "cpy-cli": "4.2.0", 31 | "eslint": "^8.28.0", 32 | "husky": "^8.0.2", 33 | "path": "^0.12.7", 34 | "prettier": "^2.7.1", 35 | "rimraf": "^3.0.2", 36 | "typescript": "^4.9.3" 37 | }, 38 | "dependencies": { 39 | "validate-npm-package-name": "^5.0.0", 40 | "yeoman-generator": "^5.7.0" 41 | }, 42 | "engines": { 43 | "npm": ">= 4.0.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /generators/app/index.ts: -------------------------------------------------------------------------------- 1 | import BaseGenerator from "../../lib/base"; 2 | 3 | export default class AppGenerator extends BaseGenerator { 4 | answers: { template: "sample" | "tip3" | "tip4" }; 5 | constructor(args, options) { 6 | super(args, options); 7 | this.option("template", { 8 | type: String, 9 | alias: "t", 10 | description: `Template to create project: 'sample' | 'tip3' | 'tip4'`, 11 | }); 12 | if (this.options.help) { 13 | return; 14 | } 15 | } 16 | async initializing() { 17 | this.initialize(); 18 | this.options.initialized = true; 19 | } 20 | 21 | async prompting() { 22 | this.log( 23 | `\n----------------------------------------------------------------\n\tSelect project template\n----------------------------------------------------------------`, 24 | ); 25 | const questions = [ 26 | { 27 | name: "template", 28 | type: "list", 29 | message: "Choose template", 30 | desc: "choose one of the following templates", 31 | choices: [ 32 | { name: "Sample project", value: "sample" }, 33 | { name: "Fungible token (TIP3)", value: "tip3" }, 34 | { name: "Non fungible token (TIP4)", value: "tip4" }, 35 | ], 36 | when: !this.options.template, 37 | }, 38 | ]; 39 | this.answers = await this.prompt(questions); 40 | } 41 | default() { 42 | switch (this.answers.template || this.options.template) { 43 | case "sample": { 44 | this.composeWith(require.resolve("../sample"), this.options); 45 | break; 46 | } 47 | case "tip3": { 48 | this.composeWith(require.resolve("../tip3"), this.options); 49 | break; 50 | } 51 | case "tip4": { 52 | this.composeWith(require.resolve("../tip4"), this.options); 53 | break; 54 | } 55 | default: { 56 | break; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /generators/sample/templates/test/sample-test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { Contract, Signer } from "locklift"; 3 | import { FactorySource } from "../build/factorySource"; 4 | 5 | let sample: Contract; 6 | let signer: Signer; 7 | 8 | describe("Test Sample contract", async function () { 9 | before(async () => { 10 | signer = (await locklift.keystore.getSigner("0"))!; 11 | }); 12 | describe("Contracts", async function () { 13 | it("Load contract factory", async function () { 14 | const sampleData = await locklift.factory.getContractArtifacts("Sample"); 15 | 16 | expect(sampleData.code).not.to.equal(undefined, "Code should be available"); 17 | expect(sampleData.abi).not.to.equal(undefined, "ABI should be available"); 18 | expect(sampleData.tvc).not.to.equal(undefined, "tvc should be available"); 19 | }); 20 | 21 | it("Deploy contract", async function () { 22 | const INIT_STATE = 0; 23 | const { contract } = await locklift.factory.deployContract({ 24 | contract: "Sample", 25 | publicKey: signer.publicKey, 26 | initParams: { 27 | _nonce: locklift.utils.getRandomNonce(), 28 | }, 29 | constructorParams: { 30 | _state: INIT_STATE, 31 | }, 32 | value: locklift.utils.toNano(2), 33 | }); 34 | sample = contract; 35 | 36 | expect(await locklift.provider.getBalance(sample.address).then(balance => Number(balance))).to.be.above(0); 37 | }); 38 | 39 | it("Interact with contract", async function () { 40 | const NEW_STATE = 1; 41 | 42 | await sample.methods.setState({ _state: NEW_STATE }).sendExternal({ publicKey: signer.publicKey }); 43 | 44 | const response = await sample.methods.getDetails({}).call(); 45 | 46 | expect(Number(response._state)).to.be.equal(NEW_STATE, "Wrong state"); 47 | }); 48 | this.afterAll(function () { 49 | console.log(` contract address: ${sample.address.toString()}`); 50 | }); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /generators/tip3/templates/scripts/02-burn.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from "bignumber.js"; 2 | import { Address, WalletTypes } from "locklift"; 3 | import ora from "ora"; 4 | import prompts from "prompts"; 5 | 6 | async function main() { 7 | const spinner = ora(); 8 | const answers = await prompts([ 9 | { 10 | type: "text", 11 | name: "contractAddress", 12 | message: "Contract address", 13 | }, 14 | { 15 | type: "number", 16 | name: "burnAmount", 17 | message: "Burn amount", 18 | }, 19 | { 20 | type: "text", 21 | name: "tokensOwnerAddress", 22 | message: "Tokens owner address", 23 | }, 24 | { 25 | type: "text", 26 | name: "tokensOwnerPublicKey", 27 | message: "Tokens owner public key", 28 | }, 29 | ]); 30 | spinner.start(`Burn tokens...`); 31 | try { 32 | const tokenRoot = locklift.factory.getDeployedContract("TokenRoot", new Address(answers.contractAddress)); 33 | 34 | const { value0: decimals } = await tokenRoot.methods.decimals({ answerId: 0 }).call(); 35 | 36 | const sender = await locklift.factory.accounts.addExistingAccount({ 37 | publicKey: answers.tokensOwnerPublicKey, 38 | type: WalletTypes.WalletV3, 39 | }); 40 | const tx = await tokenRoot.methods 41 | .burnTokens({ 42 | amount: new BigNumber(answers.burnAmount).shiftedBy(Number(decimals)).toFixed(), 43 | walletOwner: new Address(answers.tokensOwnerAddress), 44 | callbackTo: new Address(answers.tokensOwnerAddress), 45 | payload: "", 46 | remainingGasTo: sender.address, 47 | }) 48 | .send({ 49 | from: sender.address, 50 | amount: locklift.utils.toNano(2), 51 | }); 52 | spinner.info(`tx hash: ${tx.id.hash}`); 53 | spinner.succeed(`tokens burned`); 54 | } catch (err) { 55 | spinner.fail(`Failed`); 56 | console.log(err); 57 | } 58 | } 59 | main() 60 | .then(() => process.exit(0)) 61 | .catch(e => { 62 | console.log(e); 63 | process.exit(1); 64 | }); 65 | -------------------------------------------------------------------------------- /generators/tip3/templates/scripts/00-deploy.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from "bignumber.js"; 2 | import { Address, zeroAddress } from "locklift"; 3 | 4 | const ROOT_OWNER_ADDRESS = "<%= props.rootOwnerAddress %>"; 5 | const REMAINING_GAS_TO = "<%= props.remainingGasTo %>"; 6 | const NAME = "<%= props.tokenName %>"; 7 | const SYMBOL = "<%= props.tokenSymbol %>"; 8 | const INITIAL_SUPPLY_TO = "<%= props.initialSupplyTo %>"; 9 | const INITIAL_SUPPLY = "<%= props.initialSupply %>"; 10 | const DECIMALS = <%= props.decimals %>; 11 | const DISABLE_MINT = <%= props.disableMint %>; 12 | const DISABLE_BURN_BY_ROOT = <%= props.disableBurn %>; 13 | const PAUSE_BURN = <%= props.pauseBurn %>; 14 | 15 | async function main() { 16 | console.log("Starting TIP3 contract deployment..."); 17 | 18 | const signer = (await locklift.keystore.getSigner("0"))!; 19 | const tokenWalletContract = locklift.factory.getContractArtifacts("TokenWallet"); 20 | 21 | const { contract: tokenRoot } = await locklift.factory.deployContract({ 22 | contract: "TokenRoot", 23 | publicKey: signer.publicKey, 24 | initParams: { 25 | name_: NAME, 26 | symbol_: SYMBOL, 27 | decimals_: DECIMALS, 28 | rootOwner_: new Address(ROOT_OWNER_ADDRESS), 29 | walletCode_: tokenWalletContract.code, 30 | randomNonce_: locklift.utils.getRandomNonce(), 31 | deployer_: zeroAddress, 32 | }, 33 | constructorParams: { 34 | initialSupplyTo: new Address(INITIAL_SUPPLY_TO), 35 | initialSupply: new BigNumber(INITIAL_SUPPLY).shiftedBy(DECIMALS).toFixed(), 36 | deployWalletValue: locklift.utils.toNano(2), 37 | mintDisabled: DISABLE_MINT, 38 | burnByRootDisabled: DISABLE_BURN_BY_ROOT, 39 | burnPaused: PAUSE_BURN, 40 | remainingGasTo: new Address(REMAINING_GAS_TO), 41 | }, 42 | value: locklift.utils.toNano(4), 43 | }); 44 | 45 | console.log(`TIP3 contract deployed at: ${tokenRoot.address.toString()}`); 46 | } 47 | 48 | main() 49 | .then(() => process.exit(0)) 50 | .catch(e => { 51 | console.log(e); 52 | process.exit(1); 53 | }); 54 | -------------------------------------------------------------------------------- /generators/tip3/templates/scripts/01-mint.ts: -------------------------------------------------------------------------------- 1 | import { Address, WalletTypes, zeroAddress } from "locklift"; 2 | import ora from "ora"; 3 | import prompts from "prompts"; 4 | import BigNumber from "bignumber.js"; 5 | 6 | async function main() { 7 | const spinner = ora(); 8 | const answers = await prompts([ 9 | { 10 | type: "text", 11 | name: "contractAddress", 12 | message: "Contract address", 13 | }, 14 | { 15 | type: "number", 16 | name: "mintAmount", 17 | message: "Mint amount (will be shifted by decimals)", 18 | }, 19 | { 20 | type: "text", 21 | name: "tokensOwnerAddress", 22 | message: "Tokens owner address", 23 | }, 24 | { 25 | type: "text", 26 | name: "tokensOwnerPublicKey", 27 | message: "Tokens owner public key", 28 | }, 29 | ]); 30 | spinner.start(`Mint tokens...`); 31 | try { 32 | const tokenRoot = locklift.factory.getDeployedContract("TokenRoot", new Address(answers.contractAddress)); 33 | 34 | const { value0: decimals } = await tokenRoot.methods.decimals({ answerId: 0 }).call(); 35 | 36 | const sender = await locklift.factory.accounts.addExistingAccount({ 37 | publicKey: answers.tokensOwnerPublicKey, 38 | type: WalletTypes.WalletV3, 39 | }); 40 | const tx = await tokenRoot.methods 41 | .mint({ 42 | amount: new BigNumber(answers.mintAmount).shiftedBy(Number(decimals)).toFixed(), 43 | recipient: new Address(answers.tokensOwnerAddress), 44 | deployWalletValue: locklift.utils.toNano(1), 45 | notify: false, 46 | payload: "", 47 | remainingGasTo: sender.address, 48 | }) 49 | .send({ 50 | from: sender.address, 51 | amount: locklift.utils.toNano(2), 52 | }); 53 | spinner.info(`tx hash: ${tx.id.hash}`); 54 | spinner.succeed(`tokens minted`); 55 | } catch (err) { 56 | spinner.fail(`Failed`); 57 | console.log(err); 58 | } 59 | } 60 | main() 61 | .then(() => process.exit(0)) 62 | .catch(e => { 63 | console.log(e); 64 | process.exit(1); 65 | }); 66 | -------------------------------------------------------------------------------- /generators/tip4/templates/contracts/Nft.tsol: -------------------------------------------------------------------------------- 1 | // ItGold.io Contracts (v1.0.0) 2 | pragma ton-solidity = 0.58.1; 3 | 4 | pragma AbiHeader expire; 5 | pragma AbiHeader time; 6 | pragma AbiHeader pubkey; 7 | 8 | 9 | import "@itgold/everscale-tip/contracts/TIP4_2/TIP4_2Nft.sol"; 10 | import "@itgold/everscale-tip/contracts/TIP4_3/TIP4_3Nft.sol"; 11 | 12 | contract Nft is TIP4_2Nft, TIP4_3Nft { 13 | 14 | constructor( 15 | address owner, 16 | address sendGasTo, 17 | uint128 remainOnNft, 18 | string json, 19 | uint128 indexDeployValue, 20 | uint128 indexDestroyValue, 21 | TvmCell codeIndex 22 | ) TIP4_1Nft( 23 | owner, 24 | sendGasTo, 25 | remainOnNft 26 | ) TIP4_2Nft ( 27 | json 28 | ) TIP4_3Nft ( 29 | indexDeployValue, 30 | indexDestroyValue, 31 | codeIndex 32 | ) public { 33 | tvm.accept(); 34 | } 35 | 36 | function _beforeTransfer( 37 | address to, 38 | address sendGasTo, 39 | mapping(address => CallbackParams) callbacks 40 | ) internal virtual override(TIP4_1Nft, TIP4_3Nft) { 41 | TIP4_3Nft._beforeTransfer(to, sendGasTo, callbacks); 42 | } 43 | 44 | function _afterTransfer( 45 | address to, 46 | address sendGasTo, 47 | mapping(address => CallbackParams) callbacks 48 | ) internal virtual override(TIP4_1Nft, TIP4_3Nft) { 49 | TIP4_3Nft._afterTransfer(to, sendGasTo, callbacks); 50 | } 51 | 52 | 53 | function _beforeChangeOwner( 54 | address oldOwner, 55 | address newOwner, 56 | address sendGasTo, 57 | mapping(address => CallbackParams) callbacks 58 | ) internal virtual override(TIP4_1Nft, TIP4_3Nft) { 59 | TIP4_3Nft._beforeChangeOwner(oldOwner, newOwner, sendGasTo, callbacks); 60 | } 61 | 62 | function _afterChangeOwner( 63 | address oldOwner, 64 | address newOwner, 65 | address sendGasTo, 66 | mapping(address => CallbackParams) callbacks 67 | ) internal virtual override(TIP4_1Nft, TIP4_3Nft) { 68 | TIP4_3Nft._afterChangeOwner(oldOwner, newOwner, sendGasTo, callbacks); 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /generators/tip4/templates/scripts/0-deploy-collection.ts: -------------------------------------------------------------------------------- 1 | import { getRandomNonce, toNano } from "locklift"; 2 | import ora from "ora"; 3 | import prompts from "prompts"; 4 | 5 | async function main() { 6 | const spinner = ora(); 7 | const answers = await prompts([ 8 | { 9 | type: "text", 10 | name: "ownerPubkey", 11 | message: "Owner key", 12 | initial: "", 13 | }, 14 | ]); 15 | spinner.start(`Deploy Collection`); 16 | try { 17 | const Nft = await locklift.factory.getContractArtifacts("Nft"); 18 | const Index = await locklift.factory.getContractArtifacts("Index"); 19 | const IndexBasis = await locklift.factory.getContractArtifacts("IndexBasis"); 20 | 21 | const signer = (await locklift.keystore.getSigner("0"))!; 22 | const { contract: collection, tx } = await locklift.factory.deployContract({ 23 | contract: "Collection", 24 | publicKey: signer.publicKey, 25 | initParams: { 26 | _nonce: getRandomNonce(), 27 | }, 28 | constructorParams: { 29 | codeNft: Nft.code, 30 | codeIndex: Index.code, 31 | json: `{ 32 | "type": "Basic NFT", 33 | "name": "My first NFT collection", 34 | "description": "Awesome NFT collection", 35 | "preview": { 36 | "source": "https://ipfs.io/ipfs/QmUhkHLKyrpnULfSFnuMGs9qAevsTjqCoNUvDppmSCcLVp?filename=logo.png", 37 | "mimetype": "image/png" 38 | }, 39 | "files": [ 40 | { 41 | "source": "https://ipfs.io/ipfs/QmUhkHLKyrpnULfSFnuMGs9qAevsTjqCoNUvDppmSCcLVp?filename=logo.png", 42 | "mimetype": "image/png" 43 | } 44 | ] 45 | }`, 46 | codeIndexBasis: IndexBasis.code, 47 | ownerPubkey: `0x` + answers.ownerPubkey, 48 | }, 49 | value: toNano(2), 50 | }); 51 | spinner.succeed(`Deploy Collection`); 52 | console.log(`Collection deployed at: ${collection.address.toString()}`); 53 | } catch (err) { 54 | spinner.fail(`Failed`); 55 | console.log(err); 56 | } 57 | } 58 | 59 | main() 60 | .then(() => process.exit(0)) 61 | .catch(e => { 62 | console.log(e); 63 | process.exit(1); 64 | }); 65 | -------------------------------------------------------------------------------- /generators/tip4/templates/scripts/1-mint-nft.ts: -------------------------------------------------------------------------------- 1 | import { Address, toNano, WalletTypes } from "locklift"; 2 | import ora from "ora"; 3 | import prompts from "prompts"; 4 | 5 | async function main() { 6 | const spinner = ora(); 7 | const answers = await prompts([ 8 | { 9 | type: "text", 10 | name: "collectionAddr", 11 | message: "Collection address", 12 | }, 13 | ]); 14 | spinner.start(`Mint Nft`); 15 | try { 16 | const signer = (await locklift.keystore.getSigner("0"))!; 17 | // initialize collection contract object by locklift 18 | const collectionInsance = locklift.factory.getDeployedContract("Collection", new Address(answers.collectionAddr)); 19 | 20 | // creating new account for Collection calling (or you can get already deployed by locklift.factory.accounts.addExistingAccount) 21 | const { account: someAccount } = await locklift.factory.accounts.addNewAccount({ 22 | type: WalletTypes.WalletV3, 23 | value: toNano(10), 24 | publicKey: signer.publicKey, 25 | }); 26 | 27 | // get current nft id (totalSupply) for future NFT address calculating 28 | const { count: id } = await collectionInsance.methods.totalSupply({ answerId: 0 }).call(); 29 | spinner.succeed(`id: ${id}`); 30 | await collectionInsance.methods 31 | .mintNft({ 32 | json: `{ 33 | "type": "Basic NFT", 34 | "name": "First NFT", 35 | "description": "Green guy 1", 36 | "preview": { 37 | "source": "https://ipfs.io/ipfs/QmRtVuN6sW7cHq9Pbu4wvtzfSJcbiCwi6qTJF71avMqEEX", 38 | "mimetype": "image/png" 39 | }, 40 | "files": [ 41 | { 42 | "source": "https://ipfs.io/ipfs/QmRtVuN6sW7cHq9Pbu4wvtzfSJcbiCwi6qTJF71avMqEEX", 43 | "mimetype": "image/png" 44 | } 45 | ] 46 | }`, 47 | }) 48 | .send({ from: someAccount.address, amount: toNano(2) }); 49 | 50 | const { nft: nftAddress } = await collectionInsance.methods.nftAddress({ answerId: 0, id: id }).call(); 51 | 52 | spinner.succeed(`NFT: ${nftAddress.toString()}`); 53 | } catch (err) { 54 | spinner.fail(`Failed`); 55 | console.log(err); 56 | } 57 | } 58 | 59 | main() 60 | .then(() => process.exit(0)) 61 | .catch(e => { 62 | console.log(e); 63 | process.exit(1); 64 | }); 65 | -------------------------------------------------------------------------------- /generators/sample/templates/README.md: -------------------------------------------------------------------------------- 1 | Sample project 2 | 3 | # About the project 4 | 5 | This project helps you to create your first contract for Venom blockchain. 6 | For the next steps, you can follow [our tutorials](https://docs.venom.foundation/build/development-guides/). 7 | 8 | > **NOTE:** We highly recommend using [locklift](https://github.com/broxus/locklift/) as a development environment analog of Hardhat or Truffle in Venom/Everscale world. 9 | 10 | # Table of Contents 11 | 12 | - [About the project](#about-the-project) 13 | - [Table of Contents](#table-of-contents) 14 | - [Project structure](#project-structure) 15 | - [`./contracts`](#contracts) 16 | - [`locklift.config.ts`](#lockliftconfigts) 17 | - [`scripts`](#scripts) 18 | - [`test`](#test) 19 | - [Getting started](#getting-started) 20 | - [Build contracts](#build-contracts) 21 | - [Tests](#tests) 22 | - [Deploy](#deploy) 23 | - [Local node](#local-node) 24 | 25 | # Project structure 26 | 27 | Below you will find info about the project structure and the purpose of the main directories and files. 28 | 29 | ## `./contracts` 30 | 31 | Directory for smart contracts. 32 | 33 | ## `locklift.config.ts` 34 | 35 | Locklift config file. You can find the basic layout [here](https://docs.venom.foundation/build/development-guides/setting-up-the-venom-smart-contract-development-environment/#configuration) 36 | 37 | ## `scripts` 38 | 39 | Directory for migrations scripts to deploy and set up your contracts. 40 | 41 | ## `test` 42 | 43 | Directory for tests. 44 | 45 | # Getting started 46 | 47 | After setting up the project with `yo venom-scaffold`, you should already have a project ready for testing and deployment. 48 | 49 | First, let's check configs at `locklift.config.ts` [file](#lockliftconfigts). Be sure that you provide the correct settings for all required networks. 50 | 51 | ## Build contracts 52 | 53 | ```bash 54 | <%= pkgManager %> run build 55 | ``` 56 | 57 | ## Tests 58 | 59 | To test contracts locally, we need to run the [local node](#local-node). 60 | 61 | ```bash 62 | <%= pkgManager %> run run:local-node 63 | ``` 64 | 65 | To run tests on the venom testnet, make sure you have added a giver for that network in `locklift.config.ts`. 66 | 67 | ```bash 68 | <%= pkgManager %> run test:local 69 | <%= pkgManager %> run test:testnet 70 | ``` 71 | 72 | ## Deploy 73 | 74 | ```bash 75 | # deploy on the testnet 76 | <%= pkgManager %> run deploy:testnet 77 | 78 | # deploy on the mainnet 79 | <%= pkgManager %> run deploy:mainnet 80 | ``` 81 | 82 | ### Local node 83 | 84 | [Local node](https://hub.docker.com/r/tonlabs/local-node) is a pre-configured Docker image with a Ganache-like local blockchain designed for dapp debugging and testing. 85 | 86 | Container exposes the specified 80 port with nginx which proxies requests to /graphql to GraphQL API. You can access graphql endpoint at `http://localhost/graphql` 87 | 88 | ```bash 89 | # run 90 | <%= pkgManager %> run run:local-node 91 | 92 | # stop 93 | <%= pkgManager %> run stop:local-node 94 | ``` 95 | -------------------------------------------------------------------------------- /generators/tip4/templates/contracts/Collection.tsol: -------------------------------------------------------------------------------- 1 | pragma ton-solidity = 0.58.1; 2 | 3 | pragma AbiHeader expire; 4 | pragma AbiHeader time; 5 | pragma AbiHeader pubkey; 6 | 7 | 8 | import "@itgold/everscale-tip/contracts/TIP4_2/TIP4_2Collection.sol"; 9 | import "@itgold/everscale-tip/contracts/TIP4_3/TIP4_3Collection.sol"; 10 | import "@itgold/everscale-tip/contracts/access/OwnableExternal.sol"; 11 | import "./Nft.tsol"; 12 | 13 | 14 | contract Collection is TIP4_2Collection, TIP4_3Collection, OwnableExternal { 15 | 16 | /** 17 | * Errors 18 | **/ 19 | uint8 constant sender_is_not_owner = 101; 20 | uint8 constant value_is_less_than_required = 102; 21 | 22 | /// _remainOnNft - the number of crystals that will remain after the entire mint 23 | /// process is completed on the Nft contract 24 | uint128 _remainOnNft = 0.3 ton; 25 | 26 | uint16 static _nonce; 27 | 28 | constructor( 29 | TvmCell codeNft, 30 | uint256 ownerPubkey, 31 | string json, 32 | TvmCell codeIndex, 33 | TvmCell codeIndexBasis 34 | ) OwnableExternal ( 35 | ownerPubkey 36 | ) TIP4_1Collection ( 37 | codeNft 38 | ) TIP4_2Collection ( 39 | json 40 | ) TIP4_3Collection ( 41 | codeIndex, 42 | codeIndexBasis 43 | ) public { 44 | tvm.accept(); 45 | } 46 | 47 | function mintNft(string json) external virtual { 48 | require(msg.value > _remainOnNft + 0.1 ton, value_is_less_than_required); 49 | tvm.rawReserve(0, 4); 50 | 51 | uint256 id = uint256(_totalSupply); 52 | _totalSupply++; 53 | 54 | TvmCell codeNft = _buildNftCode(address(this)); 55 | TvmCell stateNft = _buildNftState(codeNft, id); 56 | address nftAddr = new Nft{ 57 | stateInit: stateNft, 58 | value: 0, 59 | flag: 128 60 | }( 61 | msg.sender, 62 | msg.sender, 63 | _remainOnNft, 64 | json, 65 | _indexDeployValue, 66 | _indexDestroyValue, 67 | _codeIndex 68 | ); 69 | 70 | emit NftCreated( 71 | id, 72 | nftAddr, 73 | msg.sender, 74 | msg.sender, 75 | msg.sender 76 | ); 77 | 78 | } 79 | 80 | function setRemainOnNft(uint128 remainOnNft) external virtual onlyOwner { 81 | require(TIP4_1Collection._isOwner(), sender_is_not_owner); 82 | _remainOnNft = remainOnNft; 83 | } 84 | 85 | function _isOwner() internal override onlyOwner returns(bool){ 86 | return true; 87 | } 88 | 89 | function _buildNftState( 90 | TvmCell code, 91 | uint256 id 92 | ) internal virtual override(TIP4_2Collection,TIP4_3Collection) pure returns (TvmCell) { 93 | return tvm.buildStateInit({ 94 | contr: Nft, 95 | varInit: {_id: id}, 96 | code: code 97 | }); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /generators/sample/index.ts: -------------------------------------------------------------------------------- 1 | import BaseGenerator, { PkgJSONGenerator } from "../../lib/base"; 2 | 3 | export default class SampleGenerator extends BaseGenerator { 4 | constructor(args, options) { 5 | super(args, options); 6 | this.option("compiler", { 7 | type: String, 8 | default: "0.61.2", 9 | description: `Compiler version`, 10 | }); 11 | this.option("linker", { 12 | type: String, 13 | default: "0.15.48", 14 | description: `Compiler version`, 15 | }); 16 | if (this.options.help) { 17 | return; 18 | } 19 | } 20 | initializing() { 21 | if (!this.options.initialized) { 22 | this.initialize(); 23 | } 24 | if (this.options.locklift) { 25 | this.composeWith(require.resolve("../locklift"), this.options); 26 | } 27 | this.pkgJSONGenerator = new PkgJSONGenerator(this.args, this.options); 28 | } 29 | async prompting() { 30 | await this.pkgJSONGenerator._promptPkgJSON(); 31 | } 32 | 33 | writing() { 34 | this.pkgJSONGenerator._writePkgJSON(); 35 | this.fs.copy(this.templatePath("contracts/"), this.destinationPath("./contracts")); 36 | this.fs.copyTpl(this.templatePath("README.md"), this.destinationPath("README.md"), { 37 | pkgManager: this.pkgJSONGenerator.pkgManager, 38 | }); 39 | this.fs.copyTpl(this.templatePath("tsconfig.json"), this.destinationPath("tsconfig.json")); 40 | 41 | if (this.options.locklift) { 42 | const pkgJSONScripts = { 43 | scripts: { 44 | build: "npx locklift build", 45 | "run:local-node": "docker run --rm -d --name local-node -e USER_AGREEMENT=yes -p 80:80 tonlabs/local-node", 46 | "stop:local-node": "docker stop local-node", 47 | "test:local": "npx locklift test --network local", 48 | "test:testnet": "npx locklift test --network test", 49 | "deploy:testnet": "npx locklift run --network test --script scripts/00-deploy-sample.ts", 50 | cleanup: "docker stop local-node && docker rm local-node", 51 | }, 52 | devDependencies: { 53 | "@types/node": "^18.16.0", 54 | prettier: "^2.8.0", 55 | typescript: "^4.7.4", 56 | }, 57 | }; 58 | 59 | this.fs.extendJSON(this.destinationPath("package.json"), pkgJSONScripts); 60 | this.fs.copyTpl(this.templatePath("./scripts/"), this.destinationPath("./scripts")); 61 | this.fs.copyTpl(this.templatePath("./test/"), this.destinationPath("./test")); 62 | this.fs.copyTpl(this.templatePath(".prettierrc"), this.destinationPath(".prettierrc")); 63 | } 64 | } 65 | 66 | async install() { 67 | await this.spawnCommandSync(this.pkgJSONGenerator.pkgManager, ["install"]); 68 | } 69 | 70 | async end() { 71 | if (this.options.locklift) { 72 | const lockliftConfigPath = this.options.lockliftConfigPath || "locklift.config.ts"; 73 | this.spawnCommandSync("npx", ["prettier", "--write", lockliftConfigPath]); 74 | this.spawnCommandSync(this.pkgJSONGenerator.pkgManager, ["run", "build"]); 75 | } 76 | const readmePath = this._findRelativePath(this.env.cwd, this.destinationPath("README.md")); 77 | 78 | this.log( 79 | `\n----------------------------------------------------------------\n\tCongrats! The project was created.\nPlease, follow the instructions in README.md to find the next steps.\nYou can find README at: ${readmePath}\n----------------------------------------------------------------`, 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for your interest in contributing to the venom-scaffolding generator! 4 | 5 | # Issues 6 | 7 | ## Create a new issue 8 | 9 | If you spot a problem with generator, [search if an issue already exists](https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-issues-and-pull-requests#search-by-the-title-body-or-comments). If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/venom-blockchain/generator-venom-scaffold/issues/new/choose). 10 | 11 | ## Solve an issue 12 | 13 | Scan through our [existing issues](https://github.com/venom-blockchain/generator-venom-scaffold/issues) to find one that interests you. If you find an issue to work on, you are welcome to open a PR with a fix. 14 | 15 | # Development 16 | 17 | Before running anything, you'll need to install the dependencies: 18 | 19 | ```bash 20 | # project dependencies 21 | npm install 22 | 23 | # and yo scaffolding tool 24 | npm install --global yo 25 | ``` 26 | 27 | ## Running the venom-scaffold locally 28 | 29 | ```bash 30 | # build the project 31 | npm run build 32 | 33 | # create symlink to project binary 34 | npm link 35 | ``` 36 | 37 | The venom-scaffold now is ready to be ran locally. To do so, run the cmd bellow in any directory. 38 | 39 | ```bash 40 | yo venom-scaffold 41 | ``` 42 | 43 | ## Create branch for your feature and checkout to this branch 44 | 45 | ```bash 46 | git checkout -b feature/my-amazing-subgenerator 47 | ``` 48 | 49 | ## Add new sub generator 50 | 51 | To create new sub generator, you should add it to the ./generators directory. Generator consist of `index.ts`, where you specify questions, how to process templates, etc and `templates` directory, where you store project's template. 52 | For templating, use [esj](https://ejs.co/). Be sure, that you added `README.md` file with description about project details and information about project run and test. The last step is to update `generators/app/index.ts` and `generators/app/USAGE` with new sub-generator 53 | 54 | ## Pull Request 55 | 56 | After you finished sub generator developing, create pull request. 57 | 58 | - Describe the purpose of your changes 59 | - Don't forget to [link PR to issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) if you are solving one. 60 | - Enable the checkbox to [allow maintainer edits](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so the branch can be updated for a merge. 61 | Once you submit your PR, a Docs team member will review your proposal. We may ask questions or request additional information. 62 | - We may ask for changes to be made before a PR can be merged, either using [suggested changes](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/incorporating-feedback-in-your-pull-request) or pull request comments. You can apply suggested changes directly through the UI. You can make any other changes in your fork, then commit them to your branch. 63 | - As you update your PR and apply changes, mark each conversation as [resolved](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request#resolving-conversations). 64 | - If you run into any merge issues, checkout this [git tutorial](https://github.com/skills/resolve-merge-conflicts) to help you resolve merge conflicts and other issues. 65 | 66 | ## Your pull request is merged! 67 | 68 | Congratulations, and thank you on behalf of the venom team! 69 | -------------------------------------------------------------------------------- /generators/tip4/index.ts: -------------------------------------------------------------------------------- 1 | import BaseGenerator, { PkgJSONGenerator } from "../../lib/base"; 2 | 3 | export default class TIP41 extends BaseGenerator { 4 | addLocklift: boolean; 5 | 6 | constructor(args, options) { 7 | super(args, options); 8 | this.option("compiler", { 9 | type: String, 10 | default: "0.58.1", 11 | description: "Compiler version", 12 | }); 13 | this.option("linker", { 14 | type: String, 15 | default: "0.15.48", 16 | description: "Linker version", 17 | }); 18 | } 19 | 20 | initializing() { 21 | if (!this.options.initialized) { 22 | this.initialize(); 23 | } 24 | if (this.options.locklift) { 25 | this.options.externalContracts = "tip4"; 26 | this.composeWith(require.resolve("../locklift"), this.options); 27 | } 28 | this.pkgJSONGenerator = new PkgJSONGenerator(this.args, this.options); 29 | } 30 | async prompting() { 31 | await this.pkgJSONGenerator._promptPkgJSON(); 32 | } 33 | 34 | writing() { 35 | this.pkgJSONGenerator._writePkgJSON(); 36 | 37 | const pkgJson = { 38 | devDependencies: { 39 | "@types/node": "^18.16.0", 40 | prettier: "^2.8.0", 41 | typescript: "^4.7.4", 42 | }, 43 | dependencies: { 44 | "@itgold/everscale-tip": "^1.1.4", 45 | }, 46 | }; 47 | this.fs.extendJSON(this.destinationPath("package.json"), pkgJson); 48 | if (this.options.locklift) { 49 | const pkgJsonScripts = { 50 | scripts: { 51 | build: "npx locklift build", 52 | "run:local-node": "docker run --rm -d --name local-node -e USER_AGREEMENT=yes -p 80:80 tonlabs/local-node", 53 | "stop:local-node": "docker stop local-node", 54 | "test:local": "npx locklift test --network local", 55 | "test:testnet": "npx locklift test --network test", 56 | "deploy:testnet": "npx locklift run --network test --script scripts/0-deploy-collection.ts", 57 | "mint:testnet": "npx locklift run --network test --script scripts/1-mint-nft.ts", 58 | }, 59 | devDependencies: { 60 | "@types/prompts": "^2.4.1", 61 | prompts: "^2.4.2", 62 | ora: "^4.0.0", 63 | }, 64 | }; 65 | this.fs.extendJSON(this.destinationPath("package.json"), pkgJsonScripts); 66 | this.fs.copyTpl(this.templatePath("./scripts/"), this.destinationPath("./scripts")); 67 | this.fs.copyTpl(this.templatePath("./test/"), this.destinationPath("./test")); 68 | } 69 | this.fs.copy(this.templatePath("contracts/"), this.destinationPath("./contracts")); 70 | this.fs.copyTpl(this.templatePath("README.md"), this.destinationPath("README.md"), { 71 | pkgManager: this.pkgJSONGenerator.pkgManager, 72 | }); 73 | this.fs.copyTpl(this.templatePath("tsconfig.json"), this.destinationPath("tsconfig.json")); 74 | this.fs.copyTpl(this.templatePath(".prettierrc"), this.destinationPath(".prettierrc")); 75 | } 76 | async install() { 77 | await this.spawnCommandSync(this.pkgJSONGenerator.pkgManager, ["install"]); 78 | } 79 | 80 | async end() { 81 | if (this.options.locklift) { 82 | const lockliftConfigPath = this.options.lockliftConfigPath || "locklift.config.ts"; 83 | 84 | this.spawnCommandSync("npx", ["prettier", "--write", lockliftConfigPath]); 85 | this.spawnCommandSync(this.pkgJSONGenerator.pkgManager, ["run", "build"]); 86 | } 87 | const readmePath = this._findRelativePath(this.env.cwd, this.destinationPath("README.md")); 88 | 89 | this.log( 90 | `\n----------------------------------------------------------------\n\tCongrats! The project was created.\nPlease, follow the instructions in README.md to find the next steps.\nYou can find README at: ${readmePath}\n----------------------------------------------------------------`, 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /generators/tip4/templates/README.md: -------------------------------------------------------------------------------- 1 | TIP4 Token (NFT) 2 | 3 | # About the project 4 | 5 | This project helps you to create your first [TIP-4 (NFT)](https://docs.venom.foundation/build/development-guides/how-to-create-your-own-non-fungible-tip-4-token/non-fungible-tokens-in-venom-network) token for Venom blockchain. 6 | 7 | What is TIP-4? 8 | Same to Ethereum ERC-721 standard, TIP-4 provides similar functionality for Venom Blockchain. As well as TIP-3, TIP-4 was designed to match the distributed system design of the Venom network. It is cost-effective for its fee-paying model. 9 | 10 | TIP-4 provides the following functionality: 11 | 12 | - minting and burning NFTs 13 | - transferring NFTs from one account to another 14 | - selling your NFTs 15 | 16 | You can find more info about TIP4 token in our [documentation](https://docs.venom.foundation/build/development-guides/how-to-create-your-own-non-fungible-tip-4-token/non-fungible-tokens-in-venom-network). Here you can find detailed information about [TIP4-1](https://github.com/nftalliance/docs/blob/main/src/standard/TIP-4/1.md),[TIP4-2](https://github.com/nftalliance/docs/blob/main/src/standard/TIP-4/2.md), [TIP4-3](https://github.com/nftalliance/docs/blob/main/src/standard/TIP-4/3.md) standards 17 | 18 | # Table of Contents 19 | 20 | - [About the project](#about-the-project) 21 | - [Table of Contents](#table-of-contents) 22 | - [Project structure](#project-structure) 23 | - [`./contracts`](#contracts) 24 | - [`locklift.config.ts`](#lockliftconfigts) 25 | - [`scripts`](#scripts) 26 | - [`test`](#test) 27 | - [Getting started](#getting-started) 28 | - [Build contracts](#build-contracts) 29 | - [Test contracts](#test-contracts) 30 | - [Deploy contracts](#deploy-contracts) 31 | - [Mint NFT](#mint-nft) 32 | - [Local node](#local-node) 33 | - [Next steps](#next-steps) 34 | 35 | # Project structure 36 | 37 | Below you will find info about the project structure and the purpose of the main directories and files. 38 | 39 | ## `./contracts` 40 | 41 | Directory for smart contracts. 42 | 43 | 44 | ## `locklift.config.ts` 45 | 46 | Locklift config file. You can find the basic layout [here](https://docs.venom.foundation/build/development-guides/setting-up-the-venom-smart-contract-development-environment/#configuration) 47 | 48 | ## `scripts` 49 | 50 | Directory for migrations scripts to deploy and set up your contracts. 51 | 52 | ## `test` 53 | 54 | Directory for tests. 55 | 56 | # Getting started 57 | 58 | After setting up the project with `yo venom-scaffold`, you should already have a project ready for testing and deployment. 59 | 60 | First, let's check configs at `locklift.config.ts` [file](#lockliftconfigts). Be sure that you provide the correct settings for all required networks. 61 | 62 | After you check all settings, we are ready to [build](#build-contracts), [test](#test-contracts), [deploy](#deploy-contracts) and [mint](#mint-nft) NFT. 63 | 64 | ## Build contracts 65 | 66 | ```bash 67 | <%= pkgManager %> run build 68 | ``` 69 | 70 | ## Test contracts 71 | 72 | To test contracts locally, we need to run the [local node](#local-node). 73 | 74 | ```bash 75 | <%= pkgManager %> run run:local-node 76 | ``` 77 | 78 | To run tests on the venom testnet, make sure you have added a giver for that network in `locklift.config.ts`. 79 | 80 | ```bash 81 | <%= pkgManager %> run test:local 82 | <%= pkgManager %> run test:testnet 83 | ``` 84 | 85 | ## Deploy contracts 86 | 87 | ```bash 88 | # deploy on the testnet 89 | <%= pkgManager %> run deploy:testnet 90 | 91 | # deploy on the mainnet 92 | <%= pkgManager %> run deploy:mainnet 93 | ``` 94 | 95 | ## Mint NFT 96 | 97 | ```bash 98 | # mint on the testnet 99 | <%= pkgManager %> run mint:testnet 100 | 101 | # deploy on the mainnet 102 | <%= pkgManager %> run mint:mainnet 103 | 104 | ``` 105 | 106 | ## Local node 107 | 108 | [Local node](https://hub.docker.com/r/tonlabs/local-node). is a pre-configured Docker image with a Ganache-like local blockchain that is designed for dapp debugging and testing. 109 | 110 | Container exposes the specified 80 port with nginx which proxies requests to /graphql to GraphQL API. You can access graphql endpoint at `http://localhost/graphql` 111 | 112 | ```bash 113 | # run 114 | <%= pkgManager %> run run:local-node 115 | 116 | # stop 117 | <%= pkgManager %> run stop:local-node 118 | ``` 119 | 120 | # Next steps 121 | 122 | You can check our [documentation about TIP4 tokens](https://docs.venom.foundation/build/development-guides/how-to-create-your-own-non-fungible-tip-4-token/venom-in-action/simple-nft-auction), to find more tutorials 123 | -------------------------------------------------------------------------------- /generators/locklift/templates/locklift.config.ts: -------------------------------------------------------------------------------- 1 | import { LockliftConfig } from "locklift"; 2 | import { FactorySource } from "./build/factorySource"; 3 | 4 | 5 | declare global { 6 | const locklift: import("locklift").Locklift; 7 | } 8 | 9 | const LOCAL_NETWORK_ENDPOINT = "http://localhost/graphql"; 10 | <% if ((blockchain == "venom")) { %> 11 | const VENOM_TESTNET_ENDPOINT = process.env.VENOM_TESTNET_ENDPOINT || "https://jrpc-testnet.venom.foundation/rpc"; 12 | const VENOM_TESTNET_TRACE_ENDPOINT = 13 | process.env.VENOM_TESTNET_TRACE_ENDPOINT || "https://gql-testnet.venom.foundation/graphql"; 14 | <% } %><% if ((blockchain == "everscale")) { %> 15 | const DEV_NET_NETWORK_ENDPOINT = process.env.DEV_NET_NETWORK_ENDPOINT || "https://devnet-sandbox.evercloud.dev/graphql"; 16 | 17 | // Create your own link on https://dashboard.evercloud.dev/ 18 | const MAIN_NET_NETWORK_ENDPOINT = process.env.MAIN_NET_NETWORK_ENDPOINT || "https://mainnet.evercloud.dev/XXX/graphql"; 19 | <% } %> 20 | 21 | const config: LockliftConfig = { 22 | compiler: { 23 | // Specify path to your TON-Solidity-Compiler 24 | // path: "/mnt/o/projects/broxus/TON-Solidity-Compiler/build/solc/solc", 25 | 26 | // Or specify version of compiler 27 | version: "<%= compiler %>", 28 | 29 | <% if (externalContracts === "tip3") { %> 30 | externalContracts: { 31 | "node_modules/tip3/build": ["TokenRoot", "TokenWallet"] 32 | }, 33 | <% } else if (externalContracts === "tip4") { %> 34 | externalContracts: { 35 | "node_modules/@itgold/everscale-tip/contracts/TIP4_3/compiled": [ 36 | "Index", 37 | "IndexBasis", 38 | ], 39 | }, 40 | <% } else { %> 41 | // Specify config for extarnal contracts as in exapmple 42 | // externalContracts: { 43 | // "node_modules/broxus-ton-tokens-contracts/build": ["TokenRoot", "TokenWallet"] 44 | // }, 45 | <% } %> 46 | }, 47 | linker: { 48 | // Specify path to your stdlib 49 | // lib: "/mnt/o/projects/broxus/TON-Solidity-Compiler/lib/stdlib_sol.tvm", 50 | // // Specify path to your Linker 51 | // path: "/mnt/o/projects/broxus/TVM-linker/target/release/tvm_linker", 52 | 53 | // Or specify version of linker 54 | version: "<%= linker %>", 55 | }, 56 | networks: { 57 | local: { 58 | // Specify connection settings for https://github.com/broxus/everscale-standalone-client/ 59 | connection: { 60 | id: 1, 61 | group: "localnet", 62 | type: "graphql", 63 | data: { 64 | endpoints: [LOCAL_NETWORK_ENDPOINT], 65 | latencyDetectionInterval: 1000, 66 | local: true, 67 | }, 68 | }, 69 | // This giver is default local-node giverV2 70 | giver: { 71 | // Check if you need provide custom giver 72 | address: "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415", 73 | key: "172af540e43a524763dd53b26a066d472a97c4de37d5498170564510608250c3", 74 | }, 75 | tracing: { 76 | endpoint: LOCAL_NETWORK_ENDPOINT, 77 | }, 78 | keys: { 79 | // Use everdev to generate your phrase 80 | // !!! Never commit it in your repos !!! 81 | // phrase: "action inject penalty envelope rabbit element slim tornado dinner pizza off blood", 82 | amount: 20, 83 | }, 84 | }, <% if (networks.has("test")) { %> 85 | test: { 86 | connection: <% if ((blockchain == "venom")) { %> { 87 | id: 1000, 88 | type: "jrpc", 89 | group: "dev", 90 | data: { 91 | endpoint: VENOM_TESTNET_ENDPOINT, 92 | }, 93 | },<% } %><% if (blockchain == "everscale") { %>{ 94 | id: 1, 95 | type: "graphql", 96 | group: "dev", 97 | data: { 98 | endpoints: [DEV_NET_NETWORK_ENDPOINT], 99 | latencyDetectionInterval: 1000, 100 | local: false, 101 | }, 102 | },<% } %> 103 | giver: { 104 | address: "<%= networks.get("test").giver.address %>", 105 | key: "<%= networks.get("test").giver.privateKey %>", 106 | }, 107 | tracing: { 108 | endpoint: <% if (blockchain == "everscale") { %>DEV_NET_NETWORK_ENDPOINT, <% } %><% if (blockchain == "venom") { %>VENOM_TESTNET_TRACE_ENDPOINT, <% } %> 109 | }, 110 | keys: { 111 | // Use everdev to generate your phrase 112 | // !!! Never commit it in your repos !!! 113 | phrase: "<%= networks.get("test").signer.phrase %>", 114 | amount: <%= networks.get("test").signer.amount %>, 115 | }, 116 | },<% } %><% if (networks.has("main")) { %> 117 | main: { 118 | // Specify connection settings for https://github.com/broxus/everscale-standalone-client/ 119 | connection: <% if (blockchain == "everscale") { %>{ 120 | id: 1, 121 | type: "graphql", 122 | group: "main", 123 | data: { 124 | endpoints: [MAIN_NET_NETWORK_ENDPOINT], 125 | latencyDetectionInterval: 1000, 126 | local: false, 127 | }, 128 | },<% } %> 129 | // This giver is default Wallet 130 | giver: { 131 | address: "<%= networks.get("main").giver.address %>", 132 | key: "<%= networks.get("main").giver.privateKey %>", 133 | }, 134 | keys: { 135 | // Use everdev to generate your phrase 136 | // !!! Never commit it in your repos !!! 137 | phrase: "<%= networks.get("test").signer.phrase %>", 138 | amount: <%= networks.get("test").signer.amount %>, 139 | }, 140 | },<% } %> 141 | }, 142 | mocha: { 143 | timeout: 2000000, 144 | }, 145 | }; 146 | 147 | export default config; -------------------------------------------------------------------------------- /generators/tip3/templates/test/deploy-mint-burn-test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { Account } from "everscale-standalone-client/nodejs"; 3 | import { Contract, WalletTypes, zeroAddress } from "locklift"; 4 | import * as nt from "nekoton-wasm"; 5 | 6 | import { FactorySource } from "../build/factorySource"; 7 | 8 | const NAME = "Awesome TIP3 token"; 9 | const SYMBOL = "AWESOME-TIP3-TOKEN"; 10 | const INITIAL_SUPPLY = 1000000000; 11 | const ADDITIONAL_MINT = 1000000000; 12 | const BURN_AMOUNT = 1000000000; 13 | const DECIMALS = 6; 14 | const DISABLE_MINT = false; 15 | const DISABLE_BURN_BY_ROOT = false; 16 | const PAUSE_BURN = false; 17 | 18 | let tokenRoot: Contract; 19 | let owner: Account; 20 | let ownerKeys: nt.Ed25519KeyPair; 21 | 22 | describe("Test Awesome token deployment, minting and burning", async function () { 23 | before(async () => { 24 | ownerKeys = nt.ed25519_generateKeyPair(); 25 | locklift.keystore.addKeyPair(ownerKeys); 26 | const { account } = await locklift.factory.accounts.addNewAccount({ 27 | type: WalletTypes.WalletV3, 28 | publicKey: ownerKeys.publicKey, 29 | value: locklift.utils.toNano(2), 30 | }); 31 | owner = account; 32 | }); 33 | it("Load TokenRoot contract factory", async function () { 34 | const tokenRootSampleData = locklift.factory.getContractArtifacts("TokenRoot"); 35 | expect(tokenRootSampleData.code).not.to.equal(undefined, "Code should be available"); 36 | expect(tokenRootSampleData.abi).not.to.equal(undefined, "ABI should be available"); 37 | expect(tokenRootSampleData.tvc).not.to.equal(undefined, "tvc should be available"); 38 | }); 39 | it("Load TokenWallet contract factory", async function () { 40 | const tokenWalletSampleData = locklift.factory.getContractArtifacts("TokenWallet"); 41 | expect(tokenWalletSampleData.code).not.to.equal(undefined, "Code should be available"); 42 | expect(tokenWalletSampleData.abi).not.to.equal(undefined, "ABI should be available"); 43 | expect(tokenWalletSampleData.tvc).not.to.equal(undefined, "tvc should be available"); 44 | }); 45 | it(`Deploy TokenRoot contract`, async function () { 46 | this.timeout(60000); 47 | 48 | const tokenWalletContract = locklift.factory.getContractArtifacts("TokenWallet"); 49 | 50 | const { contract } = await locklift.factory.deployContract({ 51 | contract: "TokenRoot", 52 | publicKey: ownerKeys.publicKey, 53 | initParams: { 54 | name_: NAME, 55 | symbol_: SYMBOL, 56 | decimals_: DECIMALS, 57 | rootOwner_: owner.address, 58 | walletCode_: tokenWalletContract.code, 59 | randomNonce_: locklift.utils.getRandomNonce(), 60 | deployer_: zeroAddress, 61 | }, 62 | constructorParams: { 63 | initialSupplyTo: owner.address, 64 | initialSupply: INITIAL_SUPPLY, 65 | deployWalletValue: locklift.utils.toNano(0.1), 66 | mintDisabled: DISABLE_MINT, 67 | burnByRootDisabled: DISABLE_BURN_BY_ROOT, 68 | burnPaused: PAUSE_BURN, 69 | remainingGasTo: owner.address, 70 | }, 71 | value: locklift.utils.toNano(2), 72 | }); 73 | 74 | tokenRoot = contract; 75 | const { value0: balance } = await tokenRoot.methods.totalSupply({ answerId: 0 }).call(); 76 | 77 | expect(Number(balance)).equal(INITIAL_SUPPLY, "Contract total supply should be the same as initial supply"); 78 | }); 79 | it("Mint tokens", async function () { 80 | this.timeout(30000); 81 | await tokenRoot.methods 82 | .mint({ 83 | amount: ADDITIONAL_MINT, 84 | recipient: owner.address, 85 | deployWalletValue: locklift.utils.toNano(0.1), 86 | notify: false, 87 | payload: "", 88 | remainingGasTo: owner.address, 89 | }) 90 | .send({ 91 | from: owner.address, 92 | amount: locklift.utils.toNano(2), 93 | }); 94 | const { value0: balance } = await tokenRoot.methods.totalSupply({ answerId: 0 }).call(); 95 | 96 | expect(Number(balance)).equal( 97 | INITIAL_SUPPLY + ADDITIONAL_MINT, 98 | "Contract total supply should be the same as initial supply", 99 | ); 100 | }); 101 | it("Burn tokens", async function () { 102 | this.timeout(30000); 103 | await tokenRoot.methods 104 | .burnTokens({ 105 | amount: BURN_AMOUNT, 106 | walletOwner: owner.address, 107 | callbackTo: owner.address, 108 | payload: "", 109 | remainingGasTo: owner.address, 110 | }) 111 | .send({ 112 | from: owner.address, 113 | amount: locklift.utils.toNano(2), 114 | }); 115 | const { value0: balance } = await tokenRoot.methods.totalSupply({ answerId: 0 }).call(); 116 | 117 | expect(Number(balance)).equal( 118 | INITIAL_SUPPLY + ADDITIONAL_MINT - BURN_AMOUNT, 119 | "Contract total supply should be the same as initial supply", 120 | ); 121 | }); 122 | this.afterAll(function () { 123 | console.log(` tokenRoot address: ${tokenRoot.address.toString()}`); 124 | console.log(` owner address: ${owner.address.toString()}`); 125 | console.log(` owner public key: ${ownerKeys.publicKey}`); 126 | console.log(` owner private key: ${ownerKeys.secretKey}`); 127 | }); 128 | }); 129 | -------------------------------------------------------------------------------- /generators/tip3/templates/README.md: -------------------------------------------------------------------------------- 1 | TIP3 Token 2 | 3 | # About the project 4 | 5 | This project helps you to create your first [TIP-3](https://docs.venom.foundation/build/development-guides/how-to-create-your-own-fungible-tip-3-token/fungible-tokens-in-venom-network) token for Venom blockchain. 6 | 7 | What is TIP-3? 8 | Just as ERC-20 is the most popular standard in the Ethereum network, TIP-3 assumes the same role in the Venom network. TIP-3 was designed to match the distributed system design of the Venom network and is cost-effective for its fee-paying model. 9 | 10 | TIP-3 provides the following functionalities 11 | 12 | - transfer tokens from one account to another 13 | - get the current token balance of an account 14 | - get the total supply of the token available on the network 15 | - mint and burn tokens 16 | 17 | You can find more info about TIP3 token in our [documentation](https://docs.venom.foundation/build/development-guides/how-to-create-your-own-fungible-tip-3-token/fungible-tokens-in-venom-network) 18 | 19 | > **NOTE:** We highly recommend using [locklift](https://github.com/broxus/locklift/) as a development environment analog of Hardhat or Truffle in Venom/Everscale world. 20 | 21 | # Table of Contents 22 | 23 | - [About the project](#about-the-project) 24 | - [Table of Contents](#table-of-contents) 25 | - [Project structure](#project-structure) 26 | - [`./contracts`](#contracts) 27 | - [`locklift.config.ts`](#lockliftconfigts) 28 | - [`scripts`](#scripts) 29 | - [`test`](#test) 30 | - [Getting started](#getting-started) 31 | - [Build contracts](#build-contracts) 32 | - [Test contracts](#test-contracts) 33 | - [Deploy contracts](#deploy-contracts) 34 | - [Mint/Burn tokens](#mintburn-tokens) 35 | - [Local node](#local-node) 36 | - [Next steps](#next-steps) 37 | 38 | # Project structure 39 | 40 | Below you will find info about the project structure and the purpose of the main directories and files. 41 | 42 | ## `./contracts` 43 | 44 | Directory for smart contracts. 45 | 46 | 47 | ## `locklift.config.ts` 48 | 49 | Locklift config file. You can find the basic layout [here](https://docs.venom.foundation/build/development-guides/setting-up-the-venom-smart-contract-development-environment/#configuration) 50 | 51 | ## `scripts` 52 | 53 | Directory for migrations scripts to deploy and set up your contracts. 54 | 55 | ## `test` 56 | 57 | Directory for tests. 58 | 59 | # Getting started 60 | 61 | After setting up the project with `yo venom-scaffold`, you should already have a project ready for testing and deployment. 62 | 63 | First, let's check configs at `locklift.config.ts` [file](#lockliftconfigts). Be sure that you provide the correct settings for all required networks. 64 | 65 | Further, let's verify the token's settings in `scripts/00-deploy.ts` file: 66 | 67 | ``` 68 | ROOT_OWNER_ADDRESS - Address of the contract root owner (String) 69 | REMAINING_GAS_TO - `Address to send the remaining gas (String) 70 | NAME - The name of your token. For example `'Awesome TIP3 token'` (String) 71 | SYMBOL - The symbol of your token. For example `'AWESOME-TIP3-TOKEN'` (String) 72 | INITIAL_SUPPLY_TO - Address of initial token supply recipient (String) 73 | INITIAL_SUPPLY - The number of tokens that will be issued immediately after deployment (String) 74 | DECIMALS - The number of decimals that your token should have (Number) 75 | DISABLE_MINT - Disables additional emission of tokens (Boolean) 76 | DISABLE_BURN_BY_ROOT - Disables tokens burning (Boolean) 77 | PAUSE_BURN - Temporarily disables token burning (Boolean) 78 | ``` 79 | 80 | After you check all settings, we are ready to [build](#build-contracts), [test](#test-contracts), and [deploy](#deploy-contracts) contracts. 81 | 82 | ## Build contracts 83 | 84 | ```bash 85 | <%= pkgManager %> run build 86 | ``` 87 | 88 | ## Test contracts 89 | 90 | To test contracts locally, we need to run the [local node](#local-node). 91 | 92 | ```bash 93 | <%= pkgManager %> run run:local-node 94 | ``` 95 | 96 | To run tests on the venom testnet, ensure you have added a giver for that network in `locklift.config.ts`. 97 | 98 | ```bash 99 | <%= pkgManager %> run test:local 100 | <%= pkgManager %> run test:testnet 101 | ``` 102 | 103 | ## Deploy contracts 104 | 105 | ```bash 106 | # deploy on the testnet 107 | <%= pkgManager %> run deploy:testnet 108 | 109 | # deploy on the mainnet 110 | <%= pkgManager %> run deploy:mainnet 111 | ``` 112 | 113 | ## Mint/Burn tokens 114 | 115 | Additionally, you can run scripts to mint or burn tokens if you specify `DISABLE_MINT` and `DISABLE_BURN_BY_ROOT` to `false`. 116 | 117 | ```bash 118 | # mint 119 | <%= pkgManager %> run mint:testnet 120 | <%= pkgManager %> run mint:mainnet 121 | 122 | # burn 123 | <%= pkgManager %> run burn:testnet 124 | <%= pkgManager %> run burn:mainnet 125 | ``` 126 | 127 | ## Local node 128 | 129 | [Local node](https://hub.docker.com/r/tonlabs/local-node) is a pre-configured Docker image with a Ganache-like local blockchain designed for dapp debugging and testing. 130 | 131 | The container exposes the specified 80 port with nginx, which proxies requests to /graphql to GraphQL API. You can access graphql endpoint at `http://localhost/graphql` 132 | 133 | ```bash 134 | # run 135 | <%= pkgManager %> run run:local-node 136 | 137 | # stop 138 | <%= pkgManager %> run stop:local-node 139 | ``` 140 | 141 | # Next steps 142 | 143 | You can check our [documentation about TIP3 tokens](https://docs.venom.foundation/build/development-guides/how-to-create-your-own-fungible-tip-3-token/venom-in-action/simple-tokensale), to find more tutorials 144 | -------------------------------------------------------------------------------- /generators/locklift/index.ts: -------------------------------------------------------------------------------- 1 | import * as Generator from "yeoman-generator"; 2 | import { validateAddress } from "../../lib/base"; 3 | 4 | interface Giver { 5 | address: string; 6 | privateKey: string; 7 | } 8 | 9 | interface Signer { 10 | phrase: string; 11 | amount: number; 12 | } 13 | 14 | interface NetworkConfig { 15 | giver: Giver; 16 | signer: Signer; 17 | connection?: { 18 | group: string; 19 | type: string; 20 | data: { 21 | endpoint: string; 22 | }; 23 | }; 24 | } 25 | 26 | interface Answers { 27 | externalContracts: any; 28 | compiler: string; 29 | linker: string; 30 | networks: Map; 31 | blockchain: "venom" | "everscale"; 32 | } 33 | 34 | function questionsToSettingUpNetwork(network: string) { 35 | return [ 36 | { 37 | name: `giverAddress`, 38 | type: "input", 39 | message: `Provide giver address (${network})`, 40 | validate: validateAddress, 41 | default: "0:0000000000000000000000000000000000000000000000000000000000000000", 42 | }, 43 | { 44 | name: `giverPrivateKey`, 45 | type: "password", 46 | message: `Enter giver's private key (${network})`, 47 | default: "0000000000000000000000000000000000000000000000000000000000000000", 48 | }, 49 | { 50 | name: `signerPhrase`, 51 | type: "password", 52 | message: `Provide signer's seed phrase (${network})`, 53 | default: "phrase", 54 | }, 55 | { 56 | name: `signerKeysAmount`, 57 | type: "number", 58 | message: `Provide amount of signer's key pairs to generate (${network})`, 59 | default: 20, 60 | }, 61 | ]; 62 | } 63 | 64 | export default class extends Generator { 65 | answers: Answers; 66 | 67 | constructor(args, options) { 68 | super(args, options); 69 | } 70 | 71 | initializing() { 72 | this.destinationRoot(this.config.get("path")); 73 | } 74 | 75 | async prompting() { 76 | this.log( 77 | "\n----------------------------------------------------------------\n\tSetting up locklift\n----------------------------------------------------------------", 78 | ); 79 | const setupLocklift = await this.prompt([ 80 | { 81 | name: "setupLocklift", 82 | type: "confirm", 83 | message: "Set up locklift configs now? If not, you can do it manually later.", 84 | default: true, 85 | }, 86 | ]); 87 | 88 | const questions = [ 89 | { 90 | name: "compiler", 91 | type: "input", 92 | message: "Enter compiler version", 93 | default: this.options.compiler || "0.62.0", 94 | when: setupLocklift.setupLocklift, 95 | }, 96 | { 97 | name: "linker", 98 | type: "input", 99 | message: "Enter linker version", 100 | default: this.options.linker || "0.15.48", 101 | when: setupLocklift.setupLocklift, 102 | }, 103 | { 104 | name: "blockchain", 105 | type: "list", 106 | message: "Select blockchain", 107 | choices: [ 108 | { 109 | name: "Venom", 110 | value: "venom", 111 | }, 112 | { 113 | name: "Everscale", 114 | value: "everscale", 115 | }, 116 | ], 117 | when: setupLocklift.setupLocklift, 118 | }, 119 | ]; 120 | 121 | const mainAnswers = await this.prompt(questions); 122 | 123 | const networkAnswers = new Map(); 124 | 125 | if (setupLocklift.setupLocklift) { 126 | let networks: string[] = []; 127 | switch (mainAnswers.blockchain) { 128 | case "venom": 129 | networks = ["test"]; 130 | break; 131 | case "everscale": 132 | networks = ["test", "main"]; 133 | break; 134 | } 135 | for await (const network of networks) { 136 | const answers = await this.prompt(questionsToSettingUpNetwork(network)); 137 | networkAnswers.set(network, { 138 | giver: { 139 | address: answers.giverAddress, 140 | privateKey: answers.giverPrivateKey, 141 | }, 142 | signer: { 143 | phrase: answers.signerPhrase, 144 | amount: answers.signerKeysAmount, 145 | }, 146 | }); 147 | } 148 | } 149 | 150 | this.answers = { 151 | externalContracts: this.options.externalContracts, 152 | compiler: mainAnswers.compiler || this.options.compiler, 153 | linker: mainAnswers.linker || this.options.linker, 154 | networks: networkAnswers, 155 | blockchain: mainAnswers.blockchain, 156 | }; 157 | } 158 | 159 | writing() { 160 | const lockliftConfigPath = this.options.lockliftConfigPath || "locklift.config.ts"; 161 | this.fs.copyTpl(this.templatePath(lockliftConfigPath), this.destinationPath("locklift.config.ts"), { 162 | compiler: this.answers.compiler, 163 | linker: this.answers.linker, 164 | networks: this.answers.networks, 165 | blockchain: this.answers.blockchain, 166 | externalContracts: this.options.externalContracts, 167 | }); 168 | 169 | const pkgJson = { 170 | devDependencies: { 171 | "@types/chai": "^4.3.4", 172 | "@types/mocha": "^10.0.1", 173 | "@types/node": "^18.16.0", 174 | chai: "^4.3.7", 175 | "everscale-standalone-client": "^2.1.20", 176 | locklift: "^2.5.7", 177 | prettier: "^2.8.8", 178 | "ts-mocha": "^10.0.0", 179 | typescript: "^4.7.4", 180 | }, 181 | }; 182 | this.fs.extendJSON(this.destinationPath("package.json"), pkgJson); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /generators/tip4/templates/test/deploy-mint-test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { Account } from "everscale-standalone-client/nodejs"; 3 | import { Address, Contract, WalletTypes, getRandomNonce, toNano } from "locklift"; 4 | import * as nt from "nekoton-wasm"; 5 | 6 | import { FactorySource } from "../build/factorySource"; 7 | 8 | let collection: Contract; 9 | let owner: Account; 10 | let ownerKeys: nt.Ed25519KeyPair; 11 | let nft1Address: Address; 12 | let nft2Address: Address; 13 | 14 | describe("Test NFT Collection deployment and NFT minting", async function () { 15 | before(async () => { 16 | ownerKeys = nt.ed25519_generateKeyPair(); 17 | locklift.keystore.addKeyPair(ownerKeys); 18 | const { account } = await locklift.factory.accounts.addNewAccount({ 19 | type: WalletTypes.WalletV3, 20 | publicKey: ownerKeys.publicKey, 21 | value: locklift.utils.toNano(4), 22 | }); 23 | owner = account; 24 | }); 25 | 26 | it("Load Collection contract factory", async function () { 27 | const contractData = locklift.factory.getContractArtifacts("Collection"); 28 | expect(contractData.code).not.to.equal(undefined, "Code should be available"); 29 | expect(contractData.abi).not.to.equal(undefined, "ABI should be available"); 30 | expect(contractData.tvc).not.to.equal(undefined, "tvc should be available"); 31 | }); 32 | 33 | it("Load Nft contract factory", async function () { 34 | const contractData = locklift.factory.getContractArtifacts("Nft"); 35 | expect(contractData.code).not.to.equal(undefined, "Code should be available"); 36 | expect(contractData.abi).not.to.equal(undefined, "ABI should be available"); 37 | expect(contractData.tvc).not.to.equal(undefined, "tvc should be available"); 38 | }); 39 | 40 | it("Load Index contract factory", async function () { 41 | const contractData = locklift.factory.getContractArtifacts("Index"); 42 | expect(contractData.code).not.to.equal(undefined, "Code should be available"); 43 | expect(contractData.abi).not.to.equal(undefined, "ABI should be available"); 44 | expect(contractData.tvc).not.to.equal(undefined, "tvc should be available"); 45 | }); 46 | 47 | it("Load IndexBasis contract factory", async function () { 48 | const contractData = locklift.factory.getContractArtifacts("IndexBasis"); 49 | expect(contractData.code).not.to.equal(undefined, "Code should be available"); 50 | expect(contractData.abi).not.to.equal(undefined, "ABI should be available"); 51 | expect(contractData.tvc).not.to.equal(undefined, "tvc should be available"); 52 | }); 53 | 54 | it(`Deploy Collection contract`, async function () { 55 | this.timeout(60000); 56 | const Nft = locklift.factory.getContractArtifacts("Nft"); 57 | const Index = await locklift.factory.getContractArtifacts("Index"); 58 | const IndexBasis = await locklift.factory.getContractArtifacts("IndexBasis"); 59 | const signer = (await locklift.keystore.getSigner("0"))!; 60 | 61 | const { contract } = await locklift.factory.deployContract({ 62 | contract: "Collection", 63 | publicKey: signer.publicKey, 64 | initParams: { 65 | _nonce: getRandomNonce(), 66 | }, 67 | constructorParams: { 68 | codeNft: Nft.code, 69 | codeIndex: Index.code, 70 | json: `{ 71 | "type": "Basic NFT", 72 | "name": "My first NFT collection", 73 | "description": "Awesome NFT collection", 74 | "preview": { 75 | "source": "https://ipfs.io/ipfs/QmUhkHLKyrpnULfSFnuMGs9qAevsTjqCoNUvDppmSCcLVp?filename=logo.png", 76 | "mimetype": "image/png" 77 | }, 78 | "files": [ 79 | { 80 | "source": "https://ipfs.io/ipfs/QmUhkHLKyrpnULfSFnuMGs9qAevsTjqCoNUvDppmSCcLVp?filename=logo.png", 81 | "mimetype": "image/png" 82 | } 83 | ] 84 | }`, 85 | codeIndexBasis: IndexBasis.code, 86 | ownerPubkey: `0x` + ownerKeys.publicKey, 87 | }, 88 | value: toNano(2), 89 | }); 90 | collection = contract; 91 | 92 | const { count: id } = await collection.methods.totalSupply({ answerId: 0 }).call(); 93 | 94 | expect(id).equal("0", "Amount of NFT in collection should be 0"); 95 | }); 96 | 97 | it(`Mint NFT 1`, async function () { 98 | this.timeout(60000); 99 | // call mintNft function 100 | await collection.methods 101 | .mintNft({ 102 | json: `{ 103 | "type": "Basic NFT", 104 | "name": "First NFT", 105 | "description": "Green guy 1", 106 | "preview": { 107 | "source": "https://ipfs.io/ipfs/QmRtVuN6sW7cHq9Pbu4wvtzfSJcbiCwi6qTJF71avMqEEX", 108 | "mimetype": "image/png" 109 | }, 110 | "files": [ 111 | { 112 | "source": "https://ipfs.io/ipfs/QmRtVuN6sW7cHq9Pbu4wvtzfSJcbiCwi6qTJF71avMqEEX", 113 | "mimetype": "image/png" 114 | } 115 | ] 116 | }`, 117 | }) 118 | .send({ from: owner.address, amount: locklift.utils.toNano(2) }); 119 | const { count: id } = await collection.methods.totalSupply({ answerId: 0 }).call(); 120 | 121 | const { nft: nftAddress } = await collection.methods.nftAddress({ answerId: 0, id: id }).call(); 122 | nft1Address = nftAddress; 123 | expect(id).equal("1", "NFT id should be 1"); 124 | }); 125 | 126 | it(`Mint NFT 2`, async function () { 127 | this.timeout(60000); 128 | // call mintNft function 129 | await collection.methods 130 | .mintNft({ 131 | json: `{ 132 | "type": "Basic NFT", 133 | "name": "First NFT", 134 | "description": "Green guy 1", 135 | "preview": { 136 | "source": "https://ipfs.io/ipfs/QmRtVuN6sW7cHq9Pbu4wvtzfSJcbiCwi6qTJF71avMqEEX", 137 | "mimetype": "image/png" 138 | }, 139 | "files": [ 140 | { 141 | "source": "https://ipfs.io/ipfs/QmRtVuN6sW7cHq9Pbu4wvtzfSJcbiCwi6qTJF71avMqEEX", 142 | "mimetype": "image/png" 143 | } 144 | ] 145 | }`, 146 | }) 147 | .send({ from: owner.address, amount: locklift.utils.toNano(2) }); 148 | const { count: id } = await collection.methods.totalSupply({ answerId: 0 }).call(); 149 | 150 | const { nft: nftAddress } = await collection.methods.nftAddress({ answerId: 0, id: id }).call(); 151 | nft2Address = nftAddress; 152 | 153 | expect(id).equal("2", "NFT id should be 2"); 154 | }); 155 | 156 | this.afterAll(function () { 157 | console.log(` collection address: ${collection.address.toString()}`); 158 | console.log(` NFT1 address: ${nft1Address.toString()}`); 159 | console.log(` NFT2 address: ${nft2Address.toString()}`); 160 | console.log(` owner address: ${owner.address.toString()}`); 161 | console.log(` owner public key: ${ownerKeys.publicKey}`); 162 | console.log(` owner private key: ${ownerKeys.secretKey}`); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /lib/base.ts: -------------------------------------------------------------------------------- 1 | import * as Generator from "yeoman-generator"; 2 | import * as p from "path"; 3 | import validate = require("validate-npm-package-name"); 4 | 5 | export class PkgJSONGenerator extends Generator { 6 | answers: any; 7 | pkgJSON: any; 8 | pkgManager: "npm" | "yarn"; 9 | 10 | constructor(args, options) { 11 | super(args, options); 12 | 13 | this.contextRoot = this.destinationRoot(this.options.path); 14 | this.pkgJSON = this.fs.readJSON(this.destinationPath("package.json")); 15 | } 16 | 17 | _authorQuestions(): Generator.Questions { 18 | return [ 19 | { 20 | name: "name", 21 | message: "Enter author's Name", 22 | 23 | default: this.user.git.name(), 24 | store: true, 25 | }, 26 | { 27 | name: "email", 28 | message: "Enter author's Email", 29 | 30 | default: this.user.git.email(), 31 | store: true, 32 | }, 33 | { 34 | name: "url", 35 | message: "Enter author's Homepage", 36 | 37 | store: true, 38 | }, 39 | ]; 40 | } 41 | _allQuestions(): Generator.Questions { 42 | return [ 43 | { 44 | name: "pkgManager", 45 | type: "list", 46 | message: "Select package manager", 47 | default: "npm", 48 | choices: [ 49 | { name: "npm", value: "npm" }, 50 | { name: "yarn", value: "yarn" }, 51 | ], 52 | when: !this.options.pkgManager, 53 | }, 54 | { 55 | name: "pkgName", 56 | message: "Enter package name", 57 | default: p.basename(this.destinationPath()), 58 | validate(input: string): boolean { 59 | const isValid = validate(input); 60 | if (isValid.validForNewPackages) { 61 | return true; 62 | } 63 | throw Error("Please provide a valid npm package name"); 64 | }, 65 | when: !this.options.pkgName, 66 | }, 67 | { 68 | name: "description", 69 | message: "Set package description", 70 | when: !this.options.description, 71 | }, 72 | { 73 | name: "homepage", 74 | message: "Set package homepage url", 75 | when: !this.options.homepage, 76 | }, 77 | { 78 | name: "keywords", 79 | message: "Enter package keywords (comma to split)", 80 | filter(words) { 81 | return words.split(/\s*,\s*/g); 82 | }, 83 | when: !this.options.keywords, 84 | }, 85 | { 86 | name: "license", 87 | message: "Set license for your package", 88 | default: "Apache-2.0", 89 | when: !this.options.license, 90 | }, 91 | ]; 92 | } 93 | _notAnsweredQuestions(): Generator.Questions { 94 | const allQuestions = this._allQuestions(); 95 | const questions = []; 96 | for (const q in allQuestions) { 97 | if (Object.prototype.hasOwnProperty.call(allQuestions, q)) { 98 | const element = allQuestions[q]; 99 | if (!(element.name in this.pkgJSON)) { 100 | questions.push(element); 101 | } 102 | } 103 | } 104 | return questions; 105 | } 106 | 107 | async _promptPkgJSON() { 108 | this.log( 109 | "\n----------------------------------------------------------------\n\tSetting up package.JSON\n----------------------------------------------------------------", 110 | ); 111 | const questions = this.pkgJSON ? this._notAnsweredQuestions() : this._allQuestions(); 112 | 113 | this.answers = await this.prompt(questions); 114 | 115 | if (!this.pkgJSON || !("author" in this.pkgJSON)) { 116 | const authorAnswers = await this.prompt(this._authorQuestions()); 117 | this.answers = { ...this.answers, author: authorAnswers }; 118 | } 119 | this.pkgManager = this.answers.pkgManager ? this.answers.pkgManager : this.options.pkgManager; 120 | delete this.answers.pkgManager; 121 | } 122 | 123 | _writePkgJSON() { 124 | const name = this.pkgJSON?.name || this.answers?.pkgName || this.options?.pkgName; 125 | const pkgJSON = { 126 | name: this.pkgJSON?.name || this.answers?.pkgName || this.options?.pkgName, 127 | description: this.pkgJSON?.description || this.answers?.description || this.options?.description, 128 | license: this.pkgJSON?.license || this.answers?.license || this.options?.license, 129 | author: this.pkgJSON?.author || this.answers?.author || this.options?.author, 130 | homepage: this.pkgJSON?.homepage || this.answers?.homepage || this.options?.homepage, 131 | keywords: this.pkgJSON?.keywords || this.answers?.keywords || this.options?.keywords, 132 | ...this.pkgJSON, 133 | }; 134 | 135 | this.fs.extendJSON(this.destinationPath("package.json"), pkgJSON); 136 | } 137 | } 138 | 139 | // https://yeoman.io/authoring/running-context.html 140 | // initializing - Your initialization methods (checking current project state, getting configs, etc) 141 | // prompting - Where you prompt users for options (where you’d call this.prompt()) 142 | // configuring - Saving configurations and configure the project (creating .editorconfig files and other metadata files) 143 | // default - If the method name doesn’t match a priority, it will be pushed to this group. 144 | // writing - Where you write the generator specific files (routes, controllers, etc) 145 | // conflicts - Where conflicts are handled (used internally) 146 | // install - Where installations are run (npm, bower) 147 | // end - Called last, cleanup, say good bye, etc 148 | 149 | export default class BaseGenerator extends Generator { 150 | pkgJSONGenerator: PkgJSONGenerator; 151 | constructor(args, options) { 152 | super(args, options); 153 | 154 | // common arguments 155 | this.argument("path", { 156 | description: "Path to the project folder", 157 | default: ".", 158 | required: false, 159 | type: String, 160 | }); 161 | 162 | // common options 163 | this.option("config", { 164 | type: String, 165 | description: `Path to the config file`, 166 | }); 167 | this.option("locklift", { 168 | type: Boolean, 169 | default: true, 170 | description: "Use Locklift as a development environment?", 171 | }); 172 | this.option("pkg-manager", { 173 | type: String, 174 | description: `Package manager to use (npm|yarn)`, 175 | }); 176 | } 177 | 178 | _readConfigFile(path: string) { 179 | const configPath = p.isAbsolute(path) ? path : p.join(this.contextRoot, path); 180 | 181 | return JSON.parse(this.fs.read(configPath)); 182 | } 183 | 184 | // read configs, update this.options with configs if option is not specified already 185 | _readOptionsFromConfig() { 186 | const configFile = this._readConfigFile(this.options.config); 187 | Object.keys(configFile).map(key => { 188 | this.config.set(key, configFile[key]); 189 | }); 190 | 191 | const configs = this.config.getAll(); 192 | for (const key in configs) { 193 | this.options[key] = configs[key]; 194 | } 195 | } 196 | _findRelativePath(cwd: string, destinationPath: string): string { 197 | return p.relative(cwd, destinationPath); 198 | } 199 | 200 | initialize() { 201 | this.options.path = this.args.join("-"); 202 | if (this.options.config) { 203 | this._readOptionsFromConfig(); 204 | } 205 | this.contextRoot = this.destinationRoot(this.options.path); 206 | } 207 | } 208 | 209 | export function validateAddress(input: string): boolean { 210 | // valid if input is empty 211 | if (input.length == 0) { 212 | return false; 213 | } 214 | if (/^0:([A-Fa-f0-9]{64})/g.test(input)) { 215 | return true; 216 | } 217 | 218 | throw Error( 219 | "Please provide a valid venom address. \nFor example:\n0:0000000000000000000000000000000000000000000000000000000000000000", 220 | ); 221 | } 222 | -------------------------------------------------------------------------------- /generators/tip3/index.ts: -------------------------------------------------------------------------------- 1 | import BaseGenerator, { PkgJSONGenerator, validateAddress } from "../../lib/base"; 2 | import * as Generator from "yeoman-generator"; 3 | import * as fs from "fs"; 4 | 5 | export default class TIP3 extends BaseGenerator { 6 | answers: any; 7 | 8 | constructor(args, options) { 9 | super(args, options); 10 | this.option("compiler", { 11 | type: String, 12 | default: "0.59.0", 13 | description: `Compiler version`, 14 | }); 15 | this.option("linker", { 16 | type: String, 17 | default: "0.15.48", 18 | description: `Linker version`, 19 | }); 20 | 21 | this.option("root-owner-address", { 22 | type: String, 23 | description: `Address of the contract root owner`, 24 | }); 25 | this.option("token-name", { 26 | type: String, 27 | description: `The name of your token`, 28 | }); 29 | this.option("token-symbol", { 30 | type: String, 31 | description: `The symbol of your token`, 32 | }); 33 | this.option("decimals", { 34 | type: Number, 35 | description: `The number of decimals that your token should have`, 36 | }); 37 | this.option("initial-supply", { 38 | type: String, 39 | description: `The number of tokens that will be issued immediately after deployment`, 40 | }); 41 | this.option("initial-supply-to", { 42 | type: String, 43 | description: `Address of initial token supply recipient`, 44 | }); 45 | this.option("disable-mint", { 46 | type: Boolean, 47 | description: `Disables additional emission of tokens`, 48 | }); 49 | this.option("disable-burn", { 50 | type: Boolean, 51 | description: `Disables tokens burning`, 52 | }); 53 | this.option("pause-burn", { 54 | type: Boolean, 55 | description: `Temporarily disables token burning`, 56 | }); 57 | this.option("remaining-gas-to", { 58 | type: String, 59 | description: `Address to send the remaining gas`, 60 | }); 61 | if (this.options.help) { 62 | return; 63 | } 64 | } 65 | _contractQuestions(): Generator.Questions { 66 | return [ 67 | { 68 | name: "rootOwnerAddress", 69 | type: "input", 70 | message: "Enter the address of the contract root owner", 71 | validate: validateAddress, 72 | when: !this.options.rootOwnerAddress, 73 | default: "0:0000000000000000000000000000000000000000000000000000000000000000", 74 | }, 75 | { 76 | name: "tokenName", 77 | type: "input", 78 | message: "Enter the name of your token", 79 | default: "First Venom Token", 80 | when: !this.options.tokenName, 81 | }, 82 | { 83 | name: "tokenSymbol", 84 | type: "input", 85 | message: "Enter the symbol of your token", 86 | default: "FVT", 87 | when: !this.options.tokenSymbol, 88 | }, 89 | { 90 | name: "decimals", 91 | type: "input", 92 | message: "How many decimals will the token have?", 93 | default: 18, 94 | when: !this.options.decimals, 95 | }, 96 | { 97 | name: "initialSupply", 98 | type: "input", 99 | message: 100 | "Specify the number of tokens that will be issued immediately after deployment (will be shifted by decimals)", 101 | default: "1000000000", 102 | when: !this.options.initialSupply, 103 | }, 104 | { 105 | name: "initialSupplyTo", 106 | type: "input", 107 | message: "Enter the address to send initially minted tokens", 108 | validate: validateAddress, 109 | when: !this.options.initialSupplyTo, 110 | default: "0:0000000000000000000000000000000000000000000000000000000000000000", 111 | }, 112 | { 113 | name: "disableMint", 114 | type: "confirm", 115 | message: "Disable additional emission of tokens?", 116 | default: false, 117 | when: !this.options.disableMint, 118 | }, 119 | { 120 | name: "disableBurn", 121 | type: "confirm", 122 | message: "Disable tokens burn?", 123 | default: false, 124 | when: !this.options.disableBurn, 125 | }, 126 | { 127 | name: "pauseBurn", 128 | type: "confirm", 129 | message: "Pause ability to burn tokens? Available only if tokens burning were enabled in the previous step", 130 | default: false, 131 | when: !this.options.pauseBurn, 132 | }, 133 | { 134 | name: "remainingGasTo", 135 | type: "input", 136 | message: "Enter the address to send the remaining gas", 137 | validate: validateAddress, 138 | when: !this.options.remainingGasTo, 139 | default: "0:0000000000000000000000000000000000000000000000000000000000000000", 140 | }, 141 | ]; 142 | } 143 | 144 | initializing() { 145 | if (!this.options.initialized) { 146 | this.initialize(); 147 | } 148 | if (this.options.locklift) { 149 | this.options.externalContracts = "tip3"; 150 | this.composeWith(require.resolve("../locklift"), this.options); 151 | } 152 | this.pkgJSONGenerator = new PkgJSONGenerator(this.args, this.options); 153 | } 154 | 155 | async prompting() { 156 | await this.pkgJSONGenerator._promptPkgJSON(); 157 | this.log( 158 | "\n----------------------------------------------------------------\n\tSetting up tip3 project\n----------------------------------------------------------------", 159 | ); 160 | 161 | if (this.options.locklift) { 162 | const answers = await this.prompt(this._contractQuestions()); 163 | 164 | const contractAnswers = { 165 | rootOwnerAddress: answers.rootOwnerAddress || this.options.rootOwnerAddress, 166 | remainingGasTo: answers.remainingGasTo || this.options.remainingGasTo, 167 | tokenName: answers.tokenName || this.options.tokenName, 168 | tokenSymbol: answers.tokenSymbol || this.options.tokenSymbol, 169 | initialSupplyTo: answers.initialSupplyTo || this.options.initialSupplyTo, 170 | initialSupply: answers.initialSupply || this.options.initialSupply, 171 | decimals: answers.decimals || this.options.decimals, 172 | disableMint: this.options.disableMint === undefined ? answers.disableMint : this.options.disableMint, 173 | disableBurn: this.options.disableBurn === undefined ? answers.disableBurn : this.options.disableBurn, 174 | pauseBurn: this.options.pauseBurn === undefined ? answers.pauseBurn : this.options.pauseBurn, 175 | }; 176 | this.answers = contractAnswers; 177 | } 178 | } 179 | 180 | writing() { 181 | this.pkgJSONGenerator._writePkgJSON(); 182 | 183 | const pkgJson = { 184 | devDependencies: { 185 | "@types/node": "^18.16.0", 186 | prettier: "^2.8.0", 187 | typescript: "^4.7.4", 188 | tip3: "git://github.com/broxus/tip3#v5", 189 | }, 190 | }; 191 | this.fs.extendJSON(this.destinationPath("package.json"), pkgJson); 192 | fs.mkdirSync(this.destinationPath("./contracts")); 193 | this.fs.copyTpl(this.templatePath("README.md"), this.destinationPath("README.md"), { 194 | pkgManager: this.pkgJSONGenerator.pkgManager, 195 | }); 196 | this.fs.copyTpl(this.templatePath("tsconfig.json"), this.destinationPath("tsconfig.json")); 197 | 198 | if (this.options.locklift) { 199 | const pkgJsonScripts = { 200 | scripts: { 201 | build: "npx locklift build", 202 | "run:local-node": "docker run --rm -d --name local-node -e USER_AGREEMENT=yes -p 80:80 tonlabs/local-node", 203 | "stop:local-node": "docker stop local-node", 204 | "test:local": "npx locklift test --network local", 205 | "test:testnet": "npx locklift test --network test", 206 | "deploy:testnet": "npx locklift run --network test --script scripts/00-deploy.ts", 207 | "mint:testnet": "npx locklift run --network test --script scripts/01-mint.ts", 208 | "burn:testnet": "npx locklift run --network test --script scripts/02-burn.ts", 209 | }, 210 | devDependencies: { 211 | "@types/prompts": "^2.4.1", 212 | ora: "^4.0.0", 213 | prompts: "^2.4.2", 214 | "bignumber.js": "^9.1.0", 215 | }, 216 | }; 217 | this.fs.extendJSON(this.destinationPath("package.json"), pkgJsonScripts); 218 | // deploy script 219 | this.fs.copyTpl(this.templatePath("./scripts/"), this.destinationPath("./scripts"), { 220 | props: this.answers, 221 | }); 222 | 223 | this.fs.copyTpl(this.templatePath("./test/"), this.destinationPath("./test"), { 224 | props: this.answers, 225 | }); 226 | this.fs.copyTpl(this.templatePath(".prettierrc"), this.destinationPath(".prettierrc")); 227 | } 228 | } 229 | async install() { 230 | await this.spawnCommandSync(this.pkgJSONGenerator.pkgManager, ["install"]); 231 | } 232 | 233 | async end() { 234 | if (this.options.locklift) { 235 | const lockliftConfigPath = this.options.lockliftConfigPath || "locklift.config.ts"; 236 | this.spawnCommandSync("npx", ["prettier", "--write", lockliftConfigPath]); 237 | this.spawnCommandSync(this.pkgJSONGenerator.pkgManager, ["run", "build"]); 238 | } 239 | 240 | const readmePath = this._findRelativePath(this.env.cwd, this.destinationPath("README.md")); 241 | 242 | this.log( 243 | `\n----------------------------------------------------------------\n\tCongrats! The project was created.\nPlease, follow the instructions in README.md to find the next steps.\nYou can find README at: ${readmePath}\n----------------------------------------------------------------`, 244 | ); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Logo 4 | 5 |

6 | 7 | 8 | 9 | # About The Venom Scaffold 10 | 11 | The Venom scaffold is inspired by the Truffle boxes and aims to help users create a project ready to test, deploy, and execute arbitrary scripts to develop smart contracts on TVM-based blockchains. Under the hood, it's a [yeoman](http://yeoman.io/) generator. 12 | 13 | You can find a list of available templates running: 14 | 15 | ```bash 16 | yo venom-scaffold --help 17 | ``` 18 | 19 | Or run the cli and choose the project template on the first step. 20 | 21 | ```bash 22 | yo venom-scaffold 23 | ``` 24 | 25 | To create your first project, we have a [tutorial](#tip3-tutorial). Follow the instructions and make your first TIP3 token (TIP3 is a token standard, like ERC20 in Ethereum world). 26 | 27 | # Table of Contents 28 | 29 | - [About The Venom Scaffold](#about-the-venom-scaffold) 30 | - [Table of Contents](#table-of-contents) 31 | - [Installation](#installation) 32 | - [Usage](#usage) 33 | - [Get help](#get-help) 34 | - [Configuration](#configuration) 35 | - [TIP3 tutorial](#tip3-tutorial) 36 | - [Choose a project template](#choose-a-project-template) 37 | - [Set up package manager and package.json](#set-up-package-manager-and-packagejson) 38 | - [Configure TIP3 token](#configure-tip3-token) 39 | - [Enter the address of the contract root owner](#enter-the-address-of-the-contract-root-owner) 40 | - [Enter the name of your token](#enter-the-name-of-your-token) 41 | - [Enter the symbol of your token](#enter-the-symbol-of-your-token) 42 | - [Specify the number of tokens that will be issued immediately after deployment](#specify-the-number-of-tokens-that-will-be-issued-immediately-after-deployment) 43 | - [Enter the address to send initially minted tokens](#enter-the-address-to-send-initially-minted-tokens) 44 | - [How many decimals will the token have?](#how-many-decimals-will-the-token-have) 45 | - [Disable additional emission of tokens?](#disable-additional-emission-of-tokens) 46 | - [Disable tokens burn?](#disable-tokens-burn) 47 | - [Pause ability to burn tokens? Available only if tokens burning were enabled in the previous step](#pause-ability-to-burn-tokens-available-only-if-tokens-burning-were-enabled-in-the-previous-step) 48 | - [Enter the address to send remaining gas](#enter-the-address-to-send-remaining-gas) 49 | - [Configure locklift development environment](#configure-locklift-development-environment) 50 | - [Enter compiler version](#enter-compiler-version) 51 | - [Enter linker version](#enter-linker-version) 52 | - [Select blockchain (Use arrow keys)](#select-blockchain-use-arrow-keys) 53 | - [Giver type (testnet | mainnet)](#giver-type-testnet--mainnet) 54 | - [Giver address (testnet | mainnet)](#giver-address-testnet--mainnet) 55 | - [Giver seed phrase (testnet | mainnet)](#giver-seed-phrase-testnet--mainnet) 56 | - [Giver privateKey (testnet | mainnet)](#giver-privatekey-testnet--mainnet) 57 | - [Run project](#run-project) 58 | 59 | 60 | 61 | # Installation 62 | 63 | ```bash 64 | npm install --global yo generator-venom-scaffold 65 | ``` 66 | 67 | # Usage 68 | 69 | The simplest way - is to run cmd and answer the prompt questions. 70 | 71 | ```bash 72 | # run cmd 73 | ❯ yo venom-scaffold 74 | ``` 75 | 76 | After that, go to the `` and follow the instructions in the README.md 77 | 78 | ## Get help 79 | 80 | You can run the generator with the help option to get more info about usage. 81 | Also, you can get a help message for the sub-generator. 82 | 83 | ```bash 84 | # get help for venom-scaffold 85 | ❯ yo venom-scaffold --help 86 | 87 | # get help for venom-scaffold sub-generator 88 | ❯ yo venom-scaffold:tip3 --help 89 | ``` 90 | 91 | ## Configuration 92 | 93 | To set up a project, you can answer the prompt questions, use options or config file. 94 | 95 | You can find the available options with cmd `yo venom-scaffold --help`. To find options for sub-generators, use `yo venom-scaffold: --help`. For example, `yo venom-scaffold:tip3 --help`. 96 | 97 | All options can also be defined using the config file. 98 | 99 | For example, let's set up a project with config.json file. 100 | First, we need to get all available options: 101 | 102 | ```bash 103 | ❯ yo venom-scaffold --help 104 | Usage: 105 | yo venom-scaffold:app [] [options] 106 | 107 | Options: 108 | -h, --help # Print the generator's options and usage 109 | --skip-cache # Do not remember prompt answers Default: false 110 | --skip-install # Do not automatically install dependencies Default: false 111 | --force-install # Fail on install dependencies error Default: false 112 | --ask-answered # Show prompts for already configured options Default: false 113 | --config # Path to the config file 114 | --locklift # Use Locklift as a development environment? Default: true 115 | --pkg-manager # Package manager to use (npm|yarn) 116 | -t, --template # Template to create project: 'sample' | 'tip3' | 'tip4' 117 | 118 | Arguments: 119 | path # Path to the project folder Type: String Required: false 120 | 121 | Description: 122 | The Venom scaffold is inspired by the Truffle boxes and aims to help users create a project ready to test, deploy, and execute arbitrary scripts to develop smart contracts on TVM-based blockchains. 123 | 124 | Subgenerators: 125 | yo venom-scaffold:sample [] [options] 126 | yo venom-scaffold:tip3 [] [options] 127 | yo venom-scaffold:tip4-1 [] [options] 128 | ``` 129 | 130 | Let's create `config.json` file and specify options: 131 | 132 | ```json 133 | { 134 | "locklift": true, 135 | "pkg-manager": "npm", 136 | "template": "tip3", 137 | "path": "my-first-tip3-token" 138 | } 139 | ``` 140 | 141 | To provide config, use options `--config` 142 | 143 | ```bash 144 | yo venom-scaffold --config config.json 145 | ``` 146 | 147 | You can configure sub-generators as well. To get a list of options, you can run cmd: 148 | 149 | ```bash 150 | ❯ yo venom-scaffold:tip3 --help 151 | Usage: 152 | yo venom-scaffold:tip3 [] [options] 153 | 154 | Options: 155 | -h, --help # Print the generator's options and usage 156 | --skip-cache # Do not remember prompt answers Default: false 157 | --skip-install # Do not automatically install dependencies Default: false 158 | --force-install # Fail on install dependencies error Default: false 159 | --ask-answered # Show prompts for already configured options Default: false 160 | --config # Path to the config file 161 | --locklift # Use Locklift as a development environment? Default: true 162 | --pkg-manager # Package manager to use (npm|yarn) 163 | --compiler # Compiler version Default: 0.59.0 164 | --linker # Linker version Default: 0.15.48 165 | --root-owner-address # Address of the contract root owner 166 | --token-name # The name of your token 167 | --token-symbol # The symbol of your token 168 | --initial-supply # The number of tokens that will be issued immediately after deployment 169 | --initial-supply-to # Address of initial token supply recipient 170 | --decimals # The number of decimals that your token should have 171 | --disable-mint # Disables additional emission of tokens 172 | --disable-burn # Disables tokens burning 173 | --pause-burn # Temporarily disables token burning 174 | --remaining-gas-to # Address to send the remaining gas 175 | 176 | Arguments: 177 | path # Path to the project folder Type: String Required: false 178 | ``` 179 | 180 | # TIP3 tutorial 181 | 182 | First, install [yo](https://www.npmjs.com/package/yo), clone venom-scaffold generator, install dependencies and create a symlink to a package folder. Follow the [installation instructions](#installation) to pass this step. 183 | 184 | Awesome! Now we are ready to create your first TIP3 token. 185 | 186 | Cli takes as an argument, indicating which directory to create a new project. By default, it is the current directory. 187 | 188 | In this tutorial, we will create a project in the directory `~/projects/first-tip3-token`. You can choose any directory. 189 | 190 | ```bash 191 | yo venom-scaffold ~/projects/first-tip3-token 192 | ``` 193 | 194 | > **NOTE:** To navigate over list use arrows. To submit answer use `enter`. 195 | 196 | > **NOTE:** If you don't ready to answer some questions, you can leave them empty. A default or empty value will be used in this case. 197 | 198 | Now you should answer some questions to create a project which will fit you. Questions grouped by topic: 199 | 200 | ## Choose a project template 201 | 202 | In this tutorial, we will create TIP3 token, so choose a `Fungible token (TIP3)` at this step. 203 | 204 | ## Set up package manager and package.json 205 | 206 | In this tutorial, we will use npm as a package manager. You can choose yarn as well. Next, you should answer questions to set up `package.json`. 207 | 208 | ## Configure TIP3 token 209 | 210 | In this section, we will configure our token. Let's take a look at each question in more detail. 211 | 212 | ### Enter the address of the contract root owner 213 | 214 | You can create your account with [Venom wallet]("https://venom.foundation/wallet"). The contract root owner can deploy new token wallets and mint/burn tokens. 215 | 216 | > `0:123...baa` 217 | 218 | ### Enter the name of your token 219 | 220 | Name - is a string of arbitrary length, which will be used as a token name. 221 | 222 | > `First Venom Token` 223 | 224 | ### Enter the symbol of your token 225 | 226 | A symbol is a short name of your token. 227 | 228 | > `FVT` 229 | 230 | ### Specify the number of tokens that will be issued immediately after deployment 231 | 232 | Amount of tokens that will be minted immediately after deployment. 233 | 234 | > `1000000000` 235 | 236 | ### Enter the address to send initially minted tokens 237 | 238 | Address of initial token supply recipient. 239 | 240 | > `0:123...baa` 241 | 242 | ### How many decimals will the token have? 243 | 244 | The number of decimals that your token should have. 245 | 246 | > `18` 247 | 248 | ### Disable additional emission of tokens? 249 | 250 | If additional emission of tokens is disabled, you will not have the ability to mint tokens after initial minting 251 | 252 | > `No` 253 | 254 | ### Disable tokens burn? 255 | 256 | If tokens burning are disabled, you will not have the ability to burn tokens. 257 | 258 | > `No` 259 | 260 | ### Pause ability to burn tokens? Available only if tokens burning were enabled in the previous step 261 | 262 | Temporarily disables token burning. In the future, you can enable it with the method `setBurnPaused({answerId:0, paused:false})`. 263 | 264 | > `No` 265 | 266 | ### Enter the address to send remaining gas 267 | 268 | All remaining gas will be sent to this address. 269 | 270 | > `0:123...baa` 271 | 272 | ## Configure locklift development environment 273 | 274 | > **NOTE:** [Locklift](https://github.com/broxus/locklift/) is a development environment like Hardhat or Truffle. We highly recommend using it as a developer tool. 275 | 276 | ### Enter compiler version 277 | 278 | As a compiler, we use [TON-Solidity-Compiler](https://github.com/tonlabs/TON-Solidity-Compiler) - port of the Solidity smart-contract compiler generating TVM bytecode for the Venom blockchain. You can find compiler API here. For TIP3 contracts, we recommend to use version `0.59.0` 279 | 280 | > `0.59.0` 281 | 282 | ### Enter linker version 283 | 284 | [Linker](https://github.com/tonlabs/TVM-linker) takes [TVM](https://test.ton.org/tvm.pdf) assembly source code of TON smart contract, compiles it and links its parts, adds standard selector and runtime and stores it into binary TVC file. 285 | 286 | > `0.15.48` 287 | 288 | ### Select blockchain (Use arrow keys) 289 | 290 | Venom and Everscale use the same virtual machine, compilers, and linkers. So you can deploy contracts in Venom just like in Everscale. 291 | 292 | > `Venom` 293 | 294 | ### Giver type (testnet | mainnet) 295 | 296 | Giver - it's an account that you will use to fund your smart contracts. There are several types of givers that you can use (SimpleWallet, GiverWallet, WalletV3). You can create your giver type. To do this, you need to deploy a contract that implements [Giver interface](https://github.com/broxus/locklift/blob/master/src/internal/factory/giver.ts). 297 | The easiest way to setting up giver is to use a WalletV3 account. The venom wallet uses this type of account. So you can create a new account with venom wallet and use it as a giver. 298 | 299 | > `WalletV3` 300 | 301 | ### Giver address (testnet | mainnet) 302 | 303 | Address of the giver contract. 304 | 305 | > `0:123...baa` 306 | 307 | ### Giver seed phrase (testnet | mainnet) 308 | 309 | Seed phrase of the giver account. You can omit empty this field and provide it manually in `locklift.config.ts` later. 310 | 311 | > `action inject penalty envelope rabbit element slim tornado dinner pizza off blood` 312 | 313 | ### Giver privateKey (testnet | mainnet) 314 | 315 | The private key of the giver account. You can omit empty this field and provide it manually in `locklift.config.ts` later. 316 | 317 | > `172af540e43a524763dd53b26a066d472a97c4de37d5498170564510608250c3` 318 | 319 | ## Run project 320 | 321 | Fantastic, the project is ready! Follow the instructions in the project README to find the next steps. 322 | --------------------------------------------------------------------------------