diff --git a/basic/01-web3js-deploy/README-cn.md b/basic/01-web3js-deploy/README-cn.md index 86c4031e7..b2235013b 100644 --- a/basic/01-web3js-deploy/README-cn.md +++ b/basic/01-web3js-deploy/README-cn.md @@ -5,9 +5,9 @@ - 本样例发送交易到 Infura , 需要创建相应的 Infura Project, 可以参考如下资料进行创建 https://ithelp.ithome.com.tw/articles/10202794 在成功创建 Infura Project 后,可以获取相应的PROJECT ID -- 本样例中,需要自己来生成私钥。可通过多种方式来生成私钥。常见的方式是通过Metamask。可参考《精通以太坊》或其他文档安装: https://www.bookstack.cn/read/ethereum_book-zh/spilt.4.77adf5064f4455e8.md 安装完成后,连接到 Goerli 测试网络,点击账户详情-导出私钥,获得创建的测试账号的私钥PRIVATE_KEY。 +- 本样例中,需要自己来生成私钥。可通过多种方式来生成私钥。常见的方式是通过Metamask。可参考《精通以太坊》或其他文档安装: https://www.bookstack.cn/read/ethereum_book-zh/spilt.4.77adf5064f4455e8.md 安装完成后,连接到 Sepolia 测试网络,点击账户详情-导出私钥,获得创建的测试账号的私钥PRIVATE_KEY。 -- 给 goerli 测试网络中的测试账号充值。上一步开立的账号中,余额为0, 可通过faucets来充值: https://faucets.chain.link/ 每次冲入0.1Eth。 +- 给 sepolia 测试网络中的测试账号充值。上一步开立的账号中,余额为0, 可通过faucets来充值: https://faucets.chain.link/ 每次冲入0.1Eth。 - 为方便代码测试, 在 .env 中放入私钥和Infura Project ID,格式为 "PRIVATE_KEY=xxxx" "INFURA_ID=yyyyyyyy", index.js代码会自动从中读取, 样例文件可参考 .env.example @@ -92,13 +92,13 @@ const abi = contractFile.abi; 4) 构造 web3 对象 通过 web3 对象可以很方便的发送相应的交易到区块链网络, 同时获取区块链的处理结果. -构造 web3 对象时, 主要需要传入一个参数, 就是对应的区块链网络, 包括 goerli 等测试网络, 或是 mainnet 主网. -这里我们使用 goerli 测试网络. 如果没有 goerli 网络的测试币, 可以切换到其他的测试网络. +构造 web3 对象时, 主要需要传入一个参数, 就是对应的区块链网络, 包括 sepolia 等测试网络, 或是 mainnet 主网. +这里我们使用 sepolia 测试网络. 如果没有 sepolia 网络的测试币, 可以切换到其他的测试网络. 同时需要注意的是, 这里我们通过 infura 向对应的区块链网络发送交易, 而 INFURA_ID 这个变量值也需要配置在 .env 文件中, 具体如何获取 infura_id, 可自行搜索查找相关文档 ```js -// Create web3 with goerli provider,you can change goerli to other testnet +// Create web3 with sepolia provider,you can change sepolia to other testnet const web3 = new Web3( - "https://goerli.infura.io/v3/" + process.env.INFURA_ID + "https://sepolia.infura.io/v3/" + process.env.INFURA_ID ); ``` diff --git a/basic/01-web3js-deploy/README.md b/basic/01-web3js-deploy/README.md index 30d8de7e7..fd8fa80b4 100644 --- a/basic/01-web3js-deploy/README.md +++ b/basic/01-web3js-deploy/README.md @@ -1,29 +1,36 @@ [中文](./README-cn.md) / English + # Abstract + Through this basic task, you can learn the processes of compiling and deploying a smart contract, as well as learn how to use the basic APIs of `web3js`. # Preparation -- You need to create a project on [Infura](https://infura.io), and get the `PROJECT ID`, change your `ENDPOINTS` to `Goerli`; + +- You need to create a project on [Infura](https://infura.io), and get the `PROJECT ID`, change your `ENDPOINTS` to `Sepolia`; - Create an account on `MetaMask`, which is a browser extension; - 1. Get a wallet `address`, and the private key; - 2. Go `Settings` - `advanced` and open `Show test networks`; - - Select `Goerli`, and record this address - 3. Top up your account through [faucets](https://faucets.chain.link) or others web services; - 4. Wait for minutes, and see the balance on `MetaMask` + + 1. Get a wallet `address`, and the private key; + 2. Go `Settings` - `advanced` and open `Show test networks`; + - Select `Sepolia`, and record this address + 3. Top up your account through [faucets](https://faucets.chain.link) or others web services; + 4. Wait for minutes, and see the balance on `MetaMask` - Create a `.env` file, and add the following lines: - ```text - PRIVATE_KEY=YOUR_PRIVATE_KEY - INFURA_ID=YOUR_PROJECT_ID - ``` - | Note: You can check the `.env.example` file. + + ```text + PRIVATE_KEY=YOUR_PRIVATE_KEY + INFURA_ID=YOUR_PROJECT_ID + ``` + + | Note: You can check the `.env.example` file. - If you know Chinese, you can check these tasks on [BILIBILI](https://www.bilibili.com/video/BV1Y44y1r7E6/). # Getting Started ## Understanding The Functions of the [Smart Contract](Incrementer.sol) + - `Constructor`: The constructor function of the smart contract, which is called when the contract is deployed, at the same time it will initialize the `number` to `_initialNumber`; - `increment`: The function of incrementing the `number` by given `_value`; - `rest`: The function of resetting the `number` to 0; @@ -34,43 +41,51 @@ Through this basic task, you can learn the processes of compiling and deploying 1. Install dependencies: `npm install` 2. Copy the configuration file: `cp .env.example .env` 3. Edit the configuration file: `vim .env`, copy your project ID and private key to the `.env` file - ```text - PRIVATE_KEY=YOUR_PRIVATE_KEY - INFURA_ID=YOUR_PROJECT_ID - ``` + ```text + PRIVATE_KEY=YOUR_PRIVATE_KEY + INFURA_ID=YOUR_PROJECT_ID + ``` 4. Run the `index.js` file: `node index.js` # Interpret the Code in `index.js` + `index.js` contains the most important part of this task, which includes the following functions: + ## 1. Load the configuration file + For security sake, the private key is not hard-coded, but it can be read as environment variables. When run this task, the `dotenv` plugin will automatically read the configurations in the `.env` file and load them as environment variables, and then you can use the private key and other environment variables via `process.env` . Here is the code: + ```js -require("dotenv").config(); +require('dotenv').config(); const privatekey = process.env.PRIVATE_KEY; ``` ## 2. Compile the smart contract file + You can not use `.sol` files directly, you need to compile it to binary file firstly. + ### Load the smart contract file `Incrementer.sol` into `source` variable. + ```js // Load contract -const source = fs.readFileSync("Incrementer.sol", "utf8"); +const source = fs.readFileSync('Incrementer.sol', 'utf8'); ``` + #### Compile the smart contract file ```js const input = { - language: "Solidity", + language: 'Solidity', sources: { - "Incrementer.sol": { + 'Incrementer.sol': { content: source, }, }, settings: { outputSelection: { - "*": { - "*": ["*"], + '*': { + '*': ['*'], }, }, }, @@ -78,78 +93,73 @@ const input = { const tempFile = JSON.parse(solc.compile(JSON.stringify(input))); ``` + | Note: The version of solidity in this task is `0.8.0`, different versions may have different compile ways. ## 3. Get the `bytecode` and `abi` + ```js -const contractFile = tempFile.contracts["Incrementer.sol"]["Incrementer"]; +const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer']; // Get bin & abi const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; -``` +``` ## 4. Create the `web3` instance + `web3` is the main API of the `web3js` library. It is used to interact with the blockchain. + ```js -// Create web3 with goerli provider,you can change goerli to other testnet -const web3 = new Web3( - "https://goerli.infura.io/v3/" + process.env.INFURA_ID -); +// Create web3 with sepolia provider,you can change sepolia to other testnet +const web3 = new Web3('https://sepolia.infura.io/v3/' + process.env.INFURA_ID); ``` + | Note: The `INFURA_ID` is the `PROJECT ID` of the `Infura` project you created in **Preparation** part. ## 5. Get the `account` address + On blockchain, each user has a `address`, which is unique for others, and you can get the `address` by the private key. In this task, you can use to `web3.eth.accounts.privateKeyToAccount` API to get your `account` address by passing the private key as a parameter. + ```js // Create account from privatekey -const account = web3.eth.accounts.privateKeyToAccount(privatekey); -const account_from = { - privateKey: privatekey, - accountAddress: account.address, -}; +const accounts = web3.eth.accounts.wallet.add(privatekey); ``` ## 6. Get contract instance + In the 3rd step, you got the `bytecode` and `abi`, so you can create the contract instance by the `abi` + ```js // Create contract instance const deployContract = new web3.eth.Contract(abi); ``` ## 7. Create the `deploy` transaction + ```js // Create Tx const deployTx = deployContract.deploy({ - data: bytecode, - arguments: [5], + data: '0x' + bytecode, + arguments: [0], // Pass arguments to the contract constructor on deployment(_initialNumber in Incremental.sol) }); - -``` -## 8. Sign the `deploy` transaction -Use your private key to sign the `deploy` transaction. -```js -const deployTransaction = await web3.eth.accounts.signTransaction( - { - data: deployTx.encodeABI(), - gas: 8000000, - }, - account_from.privateKey -); ``` +## 8. Deploy your smart contract + +Use your private key to sign the `deploy` transaction. -## 9. Deploy your smart contract -Send your `deploy` transaction to the blockchain. You will receive a receipt, and get this contract address from the receipt. ```js -const deployReceipt = await web3.eth.sendSignedTransaction( - deployTransaction.rawTransaction -); -console.log(`Contract deployed at address: ${deployReceipt.contractAddress}`); +const tx = await deployTx.send({ + from: accounts[0].address, + gas, + // gasPrice: 10000000000, +}); ``` # References + - Web3js Official Documents: https://web3js.readthedocs.io/en/v1.2.11/getting-started.html -- Code and Examples: https://docs.moonbeam.network/getting-started/local-node/deploy-contract/ +- Code and Examples: https://docs.moonbeam.network/getting-started/local-node/deploy-contract/ - How to use web3js: https://www.dappuniversity.com/articles/web3-js-intro - Nodejs APIs Documents: http://nodejs.cn/api/fs.html diff --git a/basic/01-web3js-deploy/index.js b/basic/01-web3js-deploy/index.js index 9876939d9..2df2986b1 100644 --- a/basic/01-web3js-deploy/index.js +++ b/basic/01-web3js-deploy/index.js @@ -1,10 +1,11 @@ -let Web3 = require('web3'); +let { Web3 } = require('web3'); let solc = require('solc'); let fs = require('fs'); // Get privatekey from environment require('dotenv').config(); -const privatekey = process.env.PRIVATE_KEY; +let privatekey = process.env.PRIVATE_KEY; +if (privatekey.slice(0, 2) !== '0x') privatekey = '0x' + privatekey; // Load contract const source = fs.readFileSync('Incrementer.sol', 'utf8'); @@ -26,22 +27,18 @@ const input = { }, }; -const tempFile = JSON.parse(solc.compile(JSON.stringify(input))); -const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer']; +const compiledCode = JSON.parse(solc.compile(JSON.stringify(input))); +const contractFile = compiledCode.contracts['Incrementer.sol']['Incrementer']; // Get bin & abi const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; -// Create web3 with goerli provider,you can change goerli to other testnet -const web3 = new Web3('https://goerli.infura.io/v3/' + process.env.INFURA_ID); +// Create web3 with sepolia provider,you can change sepolia to other testnet +const web3 = new Web3('https://sepolia.infura.io/v3/' + process.env.INFURA_ID); // Create account from privatekey -const account = web3.eth.accounts.privateKeyToAccount(privatekey); -const account_from = { - privateKey: privatekey, - accountAddress: account.address, -}; +const accounts = web3.eth.accounts.wallet.add(privatekey); /* -- Deploy Contract -- @@ -52,24 +49,29 @@ const Deploy = async () => { // Create Tx const deployTx = deployContract.deploy({ - data: bytecode, + data: '0x' + bytecode, arguments: [0], // Pass arguments to the contract constructor on deployment(_initialNumber in Incremental.sol) }); - // Sign Tx - const deployTransaction = await web3.eth.accounts.signTransaction( - { - data: deployTx.encodeABI(), - gas: 8000000, - }, - account_from.privateKey - ); - - const deployReceipt = await web3.eth.sendSignedTransaction(deployTransaction.rawTransaction); + // optionally, estimate the gas that will be used for development and log it + const gas = await deployTx.estimateGas({ + from: accounts, + }); + console.log('estimated gas:', gas); - // Your deployed contrac can be viewed at: https://goerli.etherscan.io/address/${deployReceipt.contractAddress} - // You can change goerli in above url to your selected testnet. - console.log(`Contract deployed at address: ${deployReceipt.contractAddress}`); + try { + // Deploy the contract to the Ganache network + // Your deployed contrac can be viewed at: https://sepolia.etherscan.io/address/${tx.options.address} + // You can change sepolia in above url to your selected testnet. + const tx = await deployTx.send({ + from: accounts[0].address, + gas, + // gasPrice: 10000000000, + }); + console.log('Contract deployed at address: ' + tx.options.address); + } catch (error) { + console.error(error); + } }; // We recommend this pattern to be able to use async/await everywhere diff --git a/basic/01-web3js-deploy/package.json b/basic/01-web3js-deploy/package.json index 304a07714..0a1a2abd2 100644 --- a/basic/01-web3js-deploy/package.json +++ b/basic/01-web3js-deploy/package.json @@ -9,10 +9,8 @@ "author": "", "license": "ISC", "dependencies": { - "dotenv": "^10.0.0", - "fs": "0.0.1-security", - "ganache-cli": "^6.12.2", + "dotenv": "^16.3.1", "solc": "0.8.0", - "web3": "^1.3.5" + "web3": "^4.0.3" } } diff --git a/docs/imgs/wechat-group-helper.png b/docs/imgs/wechat-group-helper.png index 5393a46c3..954d3c4c4 100644 Binary files a/docs/imgs/wechat-group-helper.png and b/docs/imgs/wechat-group-helper.png differ