Browse Source

Improved deploy script

master
Tal Kol 2 years ago
parent
commit
5f4bbc7454
  1. 67
      build/deploy.ts
  2. 5
      build/main.deploy.ts
  3. 55
      package-lock.json
  4. 4
      package.json

67
build/deploy.ts

@ -4,17 +4,27 @@
// ./build/ - directory for build artifacts (mycontract.cell) and deploy init data scripts (mycontract.deploy.ts) // ./build/ - directory for build artifacts (mycontract.cell) and deploy init data scripts (mycontract.deploy.ts)
// ./build/deploy.config.json - JSON config file with secret mnemonic of deploying wallet (will be created if not found) // ./build/deploy.config.json - JSON config file with secret mnemonic of deploying wallet (will be created if not found)
import axios from "axios";
import axiosThrottle from "axios-request-throttle";
axiosThrottle.use(axios, { requestsPerSecond: 0.5 }); // required since toncenter jsonRPC limits to 1 req/sec without API key
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import glob from "fast-glob"; import glob from "fast-glob";
import { Address, Cell, CommonMessageInfo, contractAddress, fromNano, InternalMessage, SendMode, StateInit, toNano, TonClient, WalletContract, WalletV3R2Source } from "ton"; import { Cell, CellMessage, CommonMessageInfo, contractAddress, fromNano, InternalMessage, SendMode, StateInit, toNano, TonClient, WalletContract, WalletV3R2Source } from "ton";
import { mnemonicNew, mnemonicToWalletKey } from "ton-crypto"; import { mnemonicNew, mnemonicToWalletKey } from "ton-crypto";
import { BN } from "bn.js";
async function main() { async function main() {
console.log(`=================================================================`); console.log(`=================================================================`);
console.log(`Deploy script running, let's find some contracts to deploy..`); console.log(`Deploy script running, let's find some contracts to deploy..`);
// check some global settings
if (process.env.TESTNET) {
console.log(`\n* We are deploying to 'testnet' (https://t.me/testgiver_ton_bot will give you test TON)`);
} else {
console.log(`\n* We are deploying to 'mainnet'`);
}
// make sure we have a wallet mnemonic to deploy from (or create one if not found) // make sure we have a wallet mnemonic to deploy from (or create one if not found)
const deployConfigJson = `build/deploy.config.json`; const deployConfigJson = `build/deploy.config.json`;
let deployerMnemonic; let deployerMnemonic;
@ -35,7 +45,7 @@ async function main() {
} }
// open the wallet and make sure it has enough TON // open the wallet and make sure it has enough TON
const client = new TonClient({ endpoint: "https://toncenter.com/api/v2/jsonRPC" }); const client = new TonClient({ endpoint: `https://${process.env.TESTNET ? "testnet." : ""}toncenter.com/api/v2/jsonRPC` });
const walletKey = await mnemonicToWalletKey(deployerMnemonic.split(" ")); const walletKey = await mnemonicToWalletKey(deployerMnemonic.split(" "));
const walletContract = WalletContract.create(client, WalletV3R2Source.create({ publicKey: walletKey.publicKey, workchain: 0 })); const walletContract = WalletContract.create(client, WalletV3R2Source.create({ publicKey: walletKey.publicKey, workchain: 0 }));
console.log(` - Wallet address used for deployment is: ${walletContract.address.toFriendly()}`); console.log(` - Wallet address used for deployment is: ${walletContract.address.toFriendly()}`);
@ -60,6 +70,13 @@ async function main() {
} }
const initDataCell = deployInit.initData() as Cell; const initDataCell = deployInit.initData() as Cell;
// prepare the init message
if (typeof deployInit.initMessage !== "function") {
console.log(` - ERROR: '${rootContract}' does not have 'initMessage()' function`);
process.exit(1);
}
const initMessageCell = deployInit.initMessage() as Cell | null;
// prepare the init code cell // prepare the init code cell
const cellArtifact = `build/${contractName}.cell`; const cellArtifact = `build/${contractName}.cell`;
if (!fs.existsSync(cellArtifact)) { if (!fs.existsSync(cellArtifact)) {
@ -68,25 +85,42 @@ async function main() {
} }
const initCodeCell = Cell.fromBoc(fs.readFileSync(cellArtifact))[0]; const initCodeCell = Cell.fromBoc(fs.readFileSync(cellArtifact))[0];
// deploy by sending an internal message to the deploying wallet // make sure the contract was not already deployed
sleep(1000); // to make sure we don't fail due to throttling
const newContractAddress = contractAddress({ workchain: 0, initialData: initDataCell, initialCode: initCodeCell }); const newContractAddress = contractAddress({ workchain: 0, initialData: initDataCell, initialCode: initCodeCell });
console.log(` - About to deploy contract to new address: ${newContractAddress.toFriendly()}`); console.log(` - Based on your init code+data, your new contract address is: ${newContractAddress.toFriendly()}`);
const seqno = await getSeqNo(client, walletContract.address); if (await client.isContractDeployed(newContractAddress)) {
sleep(1000); // to make sure we don't fail due to throttling console.log(` - Looks like the contract is already deployed in this address, skipping`);
const transfer = await walletContract.createTransfer({ continue;
}
// deploy by sending an internal message to the deploying wallet
console.log(` - Let's deploy the contract on-chain..`);
const seqno = await walletContract.getSeqNo();
const transfer = walletContract.createTransfer({
secretKey: walletKey.secretKey, secretKey: walletKey.secretKey,
seqno: seqno, seqno: seqno,
sendMode: SendMode.PAY_GAS_SEPARATLY + SendMode.IGNORE_ERRORS, sendMode: SendMode.PAY_GAS_SEPARATLY + SendMode.IGNORE_ERRORS,
order: new InternalMessage({ order: new InternalMessage({
to: newContractAddress, to: newContractAddress,
value: new BN(0.5), value: toNano(0.1),
bounce: false, bounce: false,
body: new CommonMessageInfo({ stateInit: new StateInit({ data: initDataCell, code: initCodeCell }) }), body: new CommonMessageInfo({
stateInit: new StateInit({ data: initDataCell, code: initCodeCell }),
body: initMessageCell !== null ? new CellMessage(initMessageCell) : null,
}),
}), }),
}); });
await client.sendExternalMessage(walletContract, transfer); await client.sendExternalMessage(walletContract, transfer);
console.log(` - Contract deployed successfully!`); console.log(` - Deploy transaction sent successfully`);
// make sure that the contract was deployed
console.log(` - Waiting 5 seconds to check if the contract was actually deployed..`);
await sleep(5000);
if (await client.isContractDeployed(newContractAddress)) {
console.log(` - SUCCESS! Contract deployed successfully to address: ${newContractAddress.toFriendly()}`);
} else {
console.log(` - FAILURE! Contract address still looks uninitialized: ${newContractAddress.toFriendly()}`);
}
} }
console.log(``); console.log(``);
@ -99,12 +133,3 @@ main();
function sleep(ms: number) { function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
async function getSeqNo(client: TonClient, walletAddress: Address) {
if (await client.isContractDeployed(walletAddress)) {
let res = await client.callGetMethod(walletAddress, "seqno");
return parseInt(res.stack[0][1], 16);
} else {
return 0;
}
}

5
build/main.deploy.ts

@ -8,3 +8,8 @@ export function initData() {
counter: 0, counter: 0,
}); });
} }
// return the op that should be sent to the contract on deployment, can be "null" so send an empty message
export function initMessage() {
return main.increment();
}

55
package-lock.json generated

@ -12,6 +12,7 @@
"@types/bn.js": "^5.1.0", "@types/bn.js": "^5.1.0",
"@types/chai": "^4.3.0", "@types/chai": "^4.3.0",
"@types/mocha": "^9.0.0", "@types/mocha": "^9.0.0",
"axios-request-throttle": "^1.0.0",
"chai": "^4.3.4", "chai": "^4.3.4",
"chai-bn": "^0.3.1", "chai-bn": "^0.3.1",
"fast-glob": "^3.2.11", "fast-glob": "^3.2.11",
@ -112,6 +113,16 @@
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true "dev": true
}, },
"node_modules/@types/axios": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz",
"integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=",
"deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!",
"dev": true,
"dependencies": {
"axios": "*"
}
},
"node_modules/@types/bn.js": { "node_modules/@types/bn.js": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz",
@ -242,6 +253,19 @@
"follow-redirects": "^1.14.7" "follow-redirects": "^1.14.7"
} }
}, },
"node_modules/axios-request-throttle": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/axios-request-throttle/-/axios-request-throttle-1.0.0.tgz",
"integrity": "sha512-NYh7kZkgSJZyIohqrvQEzr4uygqbxXb769kbphkwgYNAJm5eDg33mqHLA2pwHKC1uqbTfNpmjmzWdUdo+ptBWg==",
"dev": true,
"dependencies": {
"@types/axios": "^0.14.0",
"promise-throttle": "^1.1.2"
},
"peerDependencies": {
"axios": "*"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -1158,6 +1182,12 @@
"url": "https://github.com/prettier/prettier?sponsor=1" "url": "https://github.com/prettier/prettier?sponsor=1"
} }
}, },
"node_modules/promise-throttle": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/promise-throttle/-/promise-throttle-1.1.2.tgz",
"integrity": "sha512-dij7vjyXNewuuN/gyr+TX2KRjw48mbV5FEtgyXaIoJjGYAKT0au23/voNvy9eS4UNJjx2KUdEcO5Yyfc1h7vWQ==",
"dev": true
},
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -1744,6 +1774,15 @@
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true "dev": true
}, },
"@types/axios": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz",
"integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=",
"dev": true,
"requires": {
"axios": "*"
}
},
"@types/bn.js": { "@types/bn.js": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz",
@ -1847,6 +1886,16 @@
"follow-redirects": "^1.14.7" "follow-redirects": "^1.14.7"
} }
}, },
"axios-request-throttle": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/axios-request-throttle/-/axios-request-throttle-1.0.0.tgz",
"integrity": "sha512-NYh7kZkgSJZyIohqrvQEzr4uygqbxXb769kbphkwgYNAJm5eDg33mqHLA2pwHKC1uqbTfNpmjmzWdUdo+ptBWg==",
"dev": true,
"requires": {
"@types/axios": "^0.14.0",
"promise-throttle": "^1.1.2"
}
},
"balanced-match": { "balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -2512,6 +2561,12 @@
"integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==",
"dev": true "dev": true
}, },
"promise-throttle": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/promise-throttle/-/promise-throttle-1.1.2.tgz",
"integrity": "sha512-dij7vjyXNewuuN/gyr+TX2KRjw48mbV5FEtgyXaIoJjGYAKT0au23/voNvy9eS4UNJjx2KUdEcO5Yyfc1h7vWQ==",
"dev": true
},
"queue-microtask": { "queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",

4
package.json

@ -8,12 +8,14 @@
"prettier": "npx prettier --write '{test,contracts,build}/**/*.{ts,js,json}'", "prettier": "npx prettier --write '{test,contracts,build}/**/*.{ts,js,json}'",
"test": "mocha --exit test/**/*.spec.ts", "test": "mocha --exit test/**/*.spec.ts",
"build": "ts-node ./build/build.ts", "build": "ts-node ./build/build.ts",
"deploy": "ts-node ./build/deploy.ts" "deploy": "ts-node ./build/deploy.ts",
"deploy:testnet": "export TESTNET=1 && ts-node ./build/deploy.ts"
}, },
"devDependencies": { "devDependencies": {
"@types/bn.js": "^5.1.0", "@types/bn.js": "^5.1.0",
"@types/chai": "^4.3.0", "@types/chai": "^4.3.0",
"@types/mocha": "^9.0.0", "@types/mocha": "^9.0.0",
"axios-request-throttle": "^1.0.0",
"chai": "^4.3.4", "chai": "^4.3.4",
"chai-bn": "^0.3.1", "chai-bn": "^0.3.1",
"fast-glob": "^3.2.11", "fast-glob": "^3.2.11",

Loading…
Cancel
Save