如何通过Node调用Web3智能合约?

如何通过Node调用Web3智能合约?

目录

[TOC]

1、基础开发环境准备
1.1、安装 CNPM
1.2、Ganache CLI v7.1.0
1.2.1、什么是 Ganache?
1.2.2、Ganache 官网地址
1.2.3、Ganache 安装
1.3、Truffle 5.5.14
1.3.1、什么是Truffle
1.3.2、Truffle 官网地址
1.3.3、Truffle 安装
1.4、Solidity 0.8.14 (solc-js)
1.4.1、什么是 Solidity
1.4.2、Solidity 官网
1.4.3、Solidity 安装
1.5、Node v18.1.0
1.5.1、什么是Node
1.5.2、Node 官网
1.5.3、Node 安装
1.6、Web3.js v1.5.3
1.6.1、什么是Web3
1.6.2、Web3 官网
1.6.3、Web3 安装
2、启动 Ganache 客户端
3、编写智能合约
4、编译、部署智能合约
5、使用 Truffle 命令行调用合约
6、使用 Nodejs 调用合约
6.1、安装 truffle-contract 包
6.2、创建 Nodejs 运行文件 web3.js
6.3、使用 nodejs 运行合约

1、基础开发环境准备

1.1、安装 CNPM

  NPM由于源服务器在国外下载 Node 包经常超时,CNPM 使用国内镜像,通过以下命令安装 CNPM

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

1.2、Ganache CLI v7.1.0

1.2.1、什么是 Ganache?

  在很早之前的文章中,部署智能合约,还需要用到 TestRPCTruffle 团队最近用 Ganache 替换了 TestRPC

  Ganace 是一种为快速以太坊开发创建本地区块链的工具。是一个以太坊模拟器,它使开发以太坊应用程序更快、更容易、更安全。它包括所有流行的 RPC 功能和特性(如事件),并且可以确定性地运行以使开发变得轻而易举。

  • 零配置主网分叉
  • 分叉任何以太坊网络而无需等待同步
  • 以太坊 JSON-RPC 支持
  • 快照/恢复状态
  • 即时、按需或间隔地挖掘块
  • 快进时间
  • 模拟任何帐户(不需要私钥!)
  • 通过 HTTP/WebSockets 侦听 JSON-RPC 2.0 请求
  • Node.js 中的编程使用
  • 待交易

1.2.2、Ganache 官网地址

  https://github.com/trufflesuite/ganache
  

1.2.3、Ganache 安装

# 安装最新版
$ npm install ganache --global

# 安装指定版
$ npm install ganache@7.1.0 --global
$ ganache --version
ganache v7.1.0 (@ganache/cli: 0.2.0, @ganache/core: 0.2.0)

1.3、Truffle 5.5.14

1.3.1、什么是Truffle

  Truffle 是以太坊的开发环境、测试框架和资产管道,旨在让以太坊开发人员的生活更轻松。您可以获得:

  • 内置智能合约编译、链接、部署和二进制管理。
  • 使用 Mocha 和 Chai 进行自动化合约测试。
  • 可配置的构建管道,支持自定义构建过程。
  • 可编写脚本的部署和迁移框架。
  • 用于部署到许多公共和专用网络的网络管理。
  • 用于直接合同通信的交互式控制台。
  • 在开发过程中即时重建资产。
  • 在 Truffle 环境中执行脚本的外部脚本运行器。

1.3.2、Truffle 官网地址

  https://github.com/trufflesuite/truffle

1.3.3、Truffle 安装

# 安装最新版
$ npm install -g truffle

# 安装指定版
$ npm install -g truffle@5.5.14
$ truffle version
Truffle v5.5.14 (core: 5.5.14)
Ganache v^7.1.0
Solidity v0.5.16 (solc-js)
Node v18.1.0
Web3.js v1.5.3

1.4、Solidity 0.8.14 (solc-js)

1.4.1、什么是 Solidity

  Solidity 是一种静态类型的花括号编程语言,旨在开发在以太坊虚拟机上运行的智能合约。智能合约是在点对点网络中执行的程序,没有人对执行具有特殊权限,因此它们允许实现价值代币、所有权、投票和其他类型的逻辑。

  部署合约时,您应该使用最新发布的 Solidity 版本。

1.4.2、Solidity 官网

  https://github.com/ethereum/solidity

1.4.3、Solidity 安装

# 安装最新版
$ npm install -g solc

# 安装指定版
$ npm install -g solc@0.8.14
$ solc --version
solc, the solidity compiler commandline interface
Version: 0.8.14+commit.80d49f37.Darwin.appleclang

# mac 下的安装方式
$ brew update
$ brew upgrade
$ brew tap ethereum/ethereum
$ brew install solidity

1.5、Node v18.1.0

1.5.1、什么是Node

  Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。

1.5.2、Node 官网

  https://nodejs.org/

1.5.3、Node 安装

  可以在官网下载指定版本进行安装:https://nodejs.org/en/download/

# mac下的安装方法
$ brew link node
$ brew uninstall node
$ brew install node
$ node -v
v18.1.0

1.6、Web3.js v1.5.3

1.6.1、什么是Web3

  连接到通用JSON-RPC规范的以太坊JavaScript API

  您需要运行本地或远程以太坊节点才能使用此库。

1.6.2、Web3 官网

  http://web3js.readthedocs.io/

1.6.3、Web3 安装

# 安装最新版
$ npm install web3

# 安装指定版
$ npm install web3@01.7.3

2、启动 Ganache 客户端

  新开一个命令行窗口

$ ganache
This version of µWS is not compatible with your Node.js build:

Error: Cannot find module './uws_darwin_x64_108.node'
Falling back to a NodeJS implementation; performance may be degraded.


ganache v7.1.0 (@ganache/cli: 0.2.0, @ganache/core: 0.2.0)
Starting RPC server

Available Accounts
==================
(0) 0xa9DE17A703e2e47c818b6699990ea11b0e4F7624 (1000 ETH)
(1) 0xe6D134D6F75C6073Bf4a92096FB41Cd905fF0E2B (1000 ETH)
(2) 0x4ab6D3aFe828e7Ed0297762DdeC41524E62f3999 (1000 ETH)
(3) 0xbd76f47c26f632d1769CfD06d3Cc5f49E31d2968 (1000 ETH)
(4) 0xE92Cfe299F1242D3837E684AeEF4C3359adc8169 (1000 ETH)
(5) 0xec9464e7f253e5e70d982261C79719717636ab7C (1000 ETH)
(6) 0xf95a9F5901828C654E3e5cFbe82ba9CBB2Be5eB7 (1000 ETH)
(7) 0xb04E050b685E481773fb7972c4b276421f1F2416 (1000 ETH)
(8) 0x2c148D4AA6D3C79029B08307F805A153C6c24D07 (1000 ETH)
(9) 0x3FC2195844d7eD7fa14c598EbcD3Ee8418FeC2A6 (1000 ETH)

Private Keys
==================
(0) 0x9b6b5bb42878eacd4afd07f470ff5db23b644844a1a18c4bec071f10da3889eb
(1) 0x82f82f18e7aec4a34dae2e5ee3b7f42aa62c8af94dc94ebfdf9d6b895e2cea3b
(2) 0x45ff2f59668a72829267d28d2aaee261078ea8c3345c4a7849a2e2e86201240a
(3) 0xcd70d4dc101a7d4f0d68e8e5b48a5a1e9665f6906d041175ed42cc54ea1ae2b2
(4) 0x84800acc6dafb6b9ebfe0e264c2d66e1ceee4cd2909922053bdcfb01649ac09f
(5) 0x6d54ff52d10329663ce020ca79f808c60cff8e92aabc0fd5bf1218b4b8d58c07
(6) 0x2a01ad391ccd28fc49f17fc88f60ff50951064a98f77082b413f5680a9c5b6a2
(7) 0xae3f913a35264a229cec067cf093079431b2bbf2977f20853e725ed18b4d3a44
(8) 0xa672f5912dfe8dc4c6218a51bdbfb34868c1f3af449f3d19da7f354eaa5cc113
(9) 0xc1e0b02ad1ae23695779417390f1ad0ae55af0e3a18bfec3c00e4284e6fb28d5

HD Wallet
==================
Mnemonic:      any ivory index thank tiger divide vivid over rice link marriage fork
Base HD Path:  m/44'/60'/0'/0/{account_index}

Default Gas Price
==================
2000000000

BlockGas Limit
==================
30000000

Call Gas Limit
==================
50000000

Chain Id
==================
1337

RPC Listening on 127.0.0.1:8545

记住这里本地开放的地址和端口 127.0.0.1:8545

3、编写智能合约

  创建一个目录 _test_node_web3

$ mkdir _test_node_web3
cd _test_node_web3

  
  使用以下命令对合约进行初始化,truffle init 初始化命令的项目中不包含智能合约

$ truffle init
Starting init...
================

> Copying project files to /Users/lion/my_project/_javascript/_test_node_web3

Init successful, sweet!

Try our scaffold commands to get started:
  $ truffle create contract YourContractName # scaffold a contract
  $ truffle create test YourTestName         # scaffold a test

http://trufflesuite.com/docs

$ tree 
.
|____migrations # 可编写脚本的部署文件的目录
| |____1_initial_migration.js
|____test # 用于测试应用程序和合约的测试文件目录
| |____.gitkeep
|____contracts # Solidity 合约目录
| |____Migrations.sol
|____truffle-config.js # truffle 配置文件

  
  后面可以使用truffle compile对合约进行编译,使用truffle migrate对合约进行部署。
  

  在 contracts 目录创建一个 MSHK.sol 文件,内容如下:

 $ cat ./contracts/MSHK.sol
 // SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.4.22 <0.9.0;

contract MSHK{
    function hello() external view returns (string memory){
        return "Hi mshk.top!";
    }
}

  修改 truffle-config.js 文件,取消掉下面关于networks部分的注释,文件的完整代码如下:

$ cat ./truffle-config.js
/**
 * Use this file to configure your truffle project. It's seeded with some
 * common settings for different networks and features like migrations,
 * compilation and testing. Uncomment the ones you need or modify
 * them to suit your project as necessary.
 *
 * More information about configuration can be found at:
 *
 * https://trufflesuite.com/docs/truffle/reference/configuration
 *
 * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
 * to sign your transactions before they're sent to a remote public node. Infura accounts
 * are available for free at: infura.io/register.
 *
 * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
 * public/private key pairs. If you're publishing your code to GitHub make sure you load this
 * phrase from a file you've .gitignored so it doesn't accidentally become public.
 *
 */

// const HDWalletProvider = require('@truffle/hdwallet-provider');
//
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();

module.exports = {
  /**
   * Networks define how you connect to your ethereum client and let you set the
   * defaults web3 uses to send transactions. If you don't specify one truffle
   * will spin up a development blockchain for you on port 9545 when you
   * run `develop` or `test`. You can ask a truffle command to use a specific
   * network from the command line, e.g
   *
   * $ truffle test --network <network-name>
   */

  networks: {
    // Useful for testing. The `development` name is special - truffle uses it by default
    // if it's defined here and no other network is specified at the command line.
    // You should run a client (like ganache, geth, or parity) in a separate terminal
    // tab if you use this network and you must also set the `host`, `port` and `network_id`
    // options below to some value.
    //
    development: {
     host: "127.0.0.1",     // Localhost (default: none)
     port: 8545,            // Standard Ethereum port (default: none)
     network_id: "*",       // Any network (default: none)
    },
    // Another network with more advanced options...
    // advanced: {
    // port: 8777,             // Custom port
    // network_id: 1342,       // Custom network
    // gas: 8500000,           // Gas sent with each transaction (default: ~6700000)
    // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei)
    // from: <address>,        // Account to send txs from (default: accounts[0])
    // websocket: true        // Enable EventEmitter interface for web3 (default: false)
    // },
    // Useful for deploying to a public network.
    // NB: It's important to wrap the provider as a function.
    // ropsten: {
    // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
    // network_id: 3,       // Ropsten's id
    // gas: 5500000,        // Ropsten has a lower block limit than mainnet
    // confirmations: 2,    // # of confs to wait between deployments. (default: 0)
    // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50)
    // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets )
    // },
    // Useful for private networks
    // private: {
    // provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
    // network_id: 2111,   // This network is yours, in the cloud.
    // production: true    // Treats this network as if it was a public net. (default: false)
    // }
  },

  // Set default mocha options here, use special reporters etc.
  mocha: {
    // timeout: 100000
  },

  // Configure your compilers
  compilers: {
    solc: {
      version: "0.8.13",      // Fetch exact version from solc-bin (default: truffle's version)
      // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
      // settings: {          // See the solidity docs for advice about optimization and evmVersion
      //  optimizer: {
      //    enabled: false,
      //    runs: 200
      //  },
      //  evmVersion: "byzantium"
      // }
    }
  },

  // Truffle DB is currently disabled by default; to enable it, change enabled:
  // false to enabled: true. The default storage location can also be
  // overridden by specifying the adapter settings, as shown in the commented code below.
  //
  // NOTE: It is not possible to migrate your contracts to truffle DB and you should
  // make a backup of your artifacts to a safe location before enabling this feature.
  //
  // After you backed up your artifacts you can utilize db by running migrate as follows:
  // $ truffle migrate --reset --compile-all
  //
  // db: {
    // enabled: false,
    // host: "127.0.0.1",
    // adapter: {
    //   name: "sqlite",
    //   settings: {
    //     directory: ".db"
    //   }
    // }
  // }
};

networks -> development 部分的 host和port要和 ganache 开放的 host:port 对应上

  修改 1_initial_migration.js 文件,将刚编写的合约加入进去,完整代码如下:

$ cat migrations/1_initial_migration.js
const Migrations = artifacts.require("Migrations");

//引入自定义合约
var MSHK = artifacts.require("./hello.sol");

module.exports = function (deployer) {
  deployer.deploy(Migrations);

  //部署引入的自定义合约
  deployer.deploy(MSHK);
};

4、编译、部署智能合约

# 编译合约
$ truffle compile
Compiling your contracts...
===========================
> Compiling ./contracts/hello.sol
> Artifacts written to /Users/xxx/my_project/_javascript/_test_node_web3/build/contracts
> Compiled successfully using:
   - solc: 0.8.13+commit.abaa5c0e.Emscripten.clang

# 部署合约
$ truffle migrate
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'development'
> Network id:      1653062486470
> Block gas limit: 30000000 (0x1c9c380)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x4f8fe14a4781e2df029bee024574183b753dfeb7185362138af2a6262fa98e50
   > Blocks: 0            Seconds: 0
   > contract address:    0xa2FAd5B05Ed53297742EB463b27D79C356c90669
   > block number:        4
   > block timestamp:     1653065405
   > account:             0xa9DE17A703e2e47c818b6699990ea11b0e4F7624
   > balance:             999.99779616791952947
   > gas used:            250154 (0x3d12a)
   > gas price:           3.088591196 gwei
   > value sent:          0 ETH
   > total cost:          0.000772623442044184 ETH


   Deploying 'MSHK'
   ----------------
   > transaction hash:    0x81a97c518d529343bd2f8cd0b121d414092b5e0b067e54c335bbc6014640ca2d
   > Blocks: 0            Seconds: 0
   > contract address:    0x6bd71EB83493628D34DE3fA04501d731F3674566
   > block number:        5
   > block timestamp:     1653065405
   > account:             0xa9DE17A703e2e47c818b6699990ea11b0e4F7624
   > balance:             999.997388772852822442
   > gas used:            135067 (0x20f9b)
   > gas price:           3.016244284 gwei
   > value sent:          0 ETH
   > total cost:          0.000407395066707028 ETH

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:     0.001180018508751212 ETH

Summary
=======
> Total deployments:   2
> Final cost:          0.001180018508751212 ETH

如果已部署过合约,可使用使用truffle migrate --reset来强制重编译并发布所有合约

  

5、使用 Truffle 命令行调用合约

$ truffle console
truffle(development)> var contract;
undefined
truffle(development)> MSHK.deployed().then(function(instance){contract=instance});
undefined
truffle(development)> contract.hello()
'Hi mshk.top!'
truffle(development)> contract.hello.call()
'Hi mshk.top!'

var contractjavascript语法一样,表示声明一个contract变量。MSHK.deployed().then(function(instance){contract=instance});表示,将MSHK合约主体,传递给contract变量。后面我们就可以直接使用变量contract调用hello()方法,得到我们想要的结果。

6、使用 Nodejs 调用合约

  先使用 npm init 对目录进行初始化

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (_test_node_web3) node_web3
version: (1.0.0)
description: sample
entry point: (truffle-config.js)
test command:
git repository:
keywords: mshk mshk.top
author: lion<lion.net@163.com>
license: (ISC)
About to write to /Users/lion/my_project/_javascript/_test_node_web3/package.json:

{
  "name": "node_web3",
  "version": "1.0.0",
  "description": "sample",
  "main": "truffle-config.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "mshk",
    "mshk.top"
  ],
  "author": "lion <lion.net@163.com>",
  "license": "ISC"
}


Is this OK? (yes)

6.1、安装 truffle-contract 包

$ npm install truffle-contract --save
npm WARN deprecated mkdirp-promise@5.0.1: This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@2.0.1: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated uuid@3.3.2: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated truffle-interface-adapter@0.2.5: WARNING: This package has been renamed to @truffle/interface-adapter.
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated truffle-contract@4.0.31: WARNING: This package has been renamed to @truffle/contract.

added 350 packages in 1m

6.2、创建 Nodejs 运行文件 web3.js

  在根目录创建 web3.js,文件内容如下:

$ cat web3.js
//引用web3
var Web3 = require('web3');
var contract = require("truffle-contract");

// 此处为 Ganache RPC 地址
var provider = new Web3.providers.HttpProvider("http://127.0.0.1:8545");

//使用truffle-contract包的contract()方法
//请务必使用你自己编译的Test.json文件内容
var MSHK = contract(
    **将 ./build/contracts/MSHK.json 文件中的内容全部复制到这里**
);

MSHK.setProvider(provider);

MSHK.deployed().then(function(instance){
    return instance.hello();
}).then(function(result){
    console.log(result);
});

6.3、使用 nodejs 运行合约

  运行node web3.js,可以看到调用合约的结果

$ node web3.js
Hi mshk.top!

博文作者:迦壹
博客地址:如何通过Node调用Web3智能合约?
转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作!


One thought on “如何通过Node调用Web3智能合约?

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注