使用web3.js收发ETH或ERC20Token

    以太坊的转账分主要分为为ETH转账、ERC20转账这2种,其转账流程,如图(1)所示:


使用web3.js收发ETH或ERC20Token_第1张图片

图(1) 以太坊转账流程图

1、初始化原始交易单rawTx{}

    ETH和ERC20这2种类型的代币,主要区别,发生在第3步"初始化原始的交易单rawTx{}"时,设置to字段和value字段有差别,如下表所示:

rawTx ETH ERC20 说明
from fromAddress fromAddress Token发送人
nonce web3.utils.toHex(nonceNum) web3.utils.toHex(nonceNum) 交易的nonce值
gasLimit web3.utils.toHex(8000000) web3.utils.toHex(8000000) 区块的gas个数上限
gasPrice web3.utils.toHex(10e9) web3.utils.toHex(10e9) 单步计算所需的gas
to toAddress contractAddress 当币种为ETH时,填Token接收人;当币种为ERC20时,填合约地址
value web3.utils.toHex(sendNum) “0x0” 当币种为ETH时,填ETH的个数; 当币种为ERC20时,置空
data contractObj.methods.transfer(toAddress, sendNum).encodeABI() contractObj.methods.transfer(toAddress, sendNum).encodeABI() 发送Token,并编码
chainId 0x04 0x04 网段为Rinkeby

    初始化rawTx{}的代码对比如下:
使用web3.js收发ETH或ERC20Token_第2张图片
图(2) 初始化rawTx{}

2、查询余额

2.1 查询账户的ETH余额

function getEthBalance(fromAddress, bookmark) {
    web3.eth.getBalance(fromAddress).then(
        function (wei) {
            balance = web3.utils.fromWei(wei, 'ether')
            console.log(bookmark + balance);
        }
    )
}

2.2 查询账户的某种ERC20余额

function getERC20Balance(fromAddress,contractObj,bookmark) {
    contractObj.methods.balanceOf(fromAddress).call().then(
        function (wei) {
            balance = web3.utils.fromWei(wei, 'ether');
            console.log(bookmark + balance);
    });
}

    对比如下:

图(3) 获取ETH或者ERC20的余额

3、使用web3.js来发送Token

3.1 创建sendToken工程

    3.1.1 创建一个文件夹名称为sendToken

mkdir sendToken

    3.1.2 用npm和truffle初始化该该工程

cd sendToken
npm init -y
truffle init

    3.1.3 修改sendToken\package.json文件,改成如下:
    //package.json

{
  "name": "sendToken",
  "version": "1.0.0",
  "description": "",
  "main": "truffle-config.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@openzeppelin/contracts": "^2.5.0",
    "@truffle/hdwallet-provider": "^1.1.1",
    "bignumber": "^1.1.0",
    "bignumber.js": "^8.1.1",
    "chai": "^4.2.0",
    "chai-as-promised": "^7.1.1",
    "eslint": "^5.15.0",
    "ethereumjs-tx": "^1.3.7",
    "request": "^2.88.2",
    "web3": "^1.3.0"
  },
  "devDependencies": {
    "@babel/core": "^7.12.3",
    "@babel/preset-env": "^7.12.1"
  }
}

    3.1.4 安装依赖包

npm install

    3.1.5 新建一个文件夹名称为myabi,然后在sendToken\myabi\目录下,新建一个ZTA_abi.json文件,该文件存放ZTA合约的abi

    3.1.6 新建一个文件夹名称为projectConfig,然后在sendToken\projectConfig\目下,如下几个文件:
    net.infuraKey 存放Infura节点的Key值
    net.mnemonic 存放账户的助记词
    net.prikey 存放账户的私钥

    3.1.7 整个工程的目录结构如下:

使用web3.js收发ETH或ERC20Token_第3张图片
图(3) sendToken的目录结构

3.2 发送ETH

    将如下代码保存到sendToken\test\1.sendEth.js里,该代码是发送0.02ETH
    //1.sendEth.js

var Tx = require('ethereumjs-tx');
var Web3 = require('web3')

var fs = require('fs');
const infuraKey = fs.readFileSync("./projectConfig/net.infuraKey").toString().trim();
var web3 = new Web3(new Web3.providers.HttpProvider(`https://rinkeby.infura.io/v3/` + infuraKey))

// web3 version 
console.log(`web3 version: ${web3.version}`)


function getEthBalance(fromAddress, bookmark) {
    web3.eth.getBalance(fromAddress).then(
        function (wei) {
            balance = web3.utils.fromWei(wei, 'ether')
            console.log(bookmark + balance);
        }
    )
}

function getPriKey(prikeyPath) {
    const privKeyFile = fs.readFileSync(prikeyPath).toString().trim();
    const privKey = new Buffer.from(privKeyFile, 'hex');    
    return privKey
}

function getEthRawTx(fromAddress,toAddress,contractObj,sendNum,nonceNum, privKey) {
    //raw Tx
    var rawTransaction = {
        "from": fromAddress,
        "nonce": web3.utils.toHex(nonceNum),
        "gasLimit": web3.utils.toHex(8000000),
        "gasPrice": web3.utils.toHex(10e9),
        "to": toAddress,
        "value": web3.utils.toHex(sendNum),
        "data": contractObj.methods.transfer(toAddress, sendNum).encodeABI(),
        "chainId": 0x04 //4:Rinkeby, 3:Ropsten, 1:mainnet
    };

    var tx = new Tx(rawTransaction);
    tx.sign(privKey);
    var serializedTx = tx.serialize();
    return serializedTx;
}

async function signTransaction(fromAddress,toAddress,contractObj,sendNum,nonceNum, privKey) {
    var serializedTx = getEthRawTx(fromAddress,toAddress,contractObj,sendNum,nonceNum, privKey)

    // Comment out these three lines if you don't really want to send the TX right now
    console.log(`Attempting to send signed tx:  ${serializedTx.toString('hex')}`);
    var receipt = await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'));
    console.log(`Receipt info:  ${JSON.stringify(receipt, null, '\t')}`);
}

function sleep(delay) {
    return new Promise(reslove => {
      setTimeout(reslove, delay)
    })
}

//an async function 
const sendEth = async () => {

    //the number of sended token
    //20 milli = 0.02 ether
    var transferAmount = web3.utils.toWei('20', 'milli');

    var myAddress = "0x1d75...a5f";
    var destAddress = "0x8a40....23fb";

    // get the nonce
    var nonceCnt = await web3.eth.getTransactionCount(myAddress);
    console.log(`num transactions so far: ${nonceCnt}`);


    var abiArray = JSON.parse(fs.readFileSync("./myabi/ZTA_abi.json"));
    var contractAddress = "0xAc194f047E43Ee0Ee10026C0B7AAA66489a0Ec45";
    var contract = new web3.eth.Contract(abiArray, contractAddress, { from: myAddress });

    // begin eth numbers of myAddress
    await getEthBalance(myAddress, "Balance before send: ");

    const privkey = getPriKey("./projectConfig/net.prikey")
    await signTransaction(myAddress,destAddress,contract,transferAmount,nonceCnt, privkey)

    sleep(100) //100ms

    // end eth numbers of myAddress
    await getEthBalance(myAddress, "Balance After send: ");
}

sendEth();



    执行该nodejs脚本

node test\1.sendETH.js

    效果如下:

使用web3.js收发ETH或ERC20Token_第4张图片
图(4) 发送0.02个ETH Token

    也可以直接调用web3来发送ETH,即不调用合约来发送ETH,代码如下:
    //3.sendETHv2.js

var Tx = require('ethereumjs-tx');
var Web3 = require('web3')

var fs = require('fs');
const infuraKey = fs.readFileSync("./projectConfig/net.infuraKey").toString().trim();
var web3 = new Web3(new Web3.providers.HttpProvider(`https://rinkeby.infura.io/v3/` + infuraKey))

// web3 version 
console.log(`web3 version: ${web3.version}`)


function getEthBalance(fromAddress, bookmark) {
    web3.eth.getBalance(fromAddress).then(
        function (wei) {
            balance = web3.utils.fromWei(wei, 'ether')
            console.log(bookmark + balance);
    });
}

function getPriKey(prikeyPath) {
    const privKeyFile = fs.readFileSync(prikeyPath).toString().trim();
    const privKey = new Buffer.from(privKeyFile, 'hex');    
    return privKey
}

function getEthRawTx(fromAddress,toAddress,sendNum,nonceNum, privKey) {
    //raw Tx
    var rawTransaction = {
        "from": fromAddress,
        "nonce": web3.utils.toHex(nonceNum),
        "gasLimit": web3.utils.toHex(8000000),
        "gasPrice": web3.utils.toHex(10e9),
        "to": toAddress,
        "value": web3.utils.toHex(sendNum),
        "data": '',
        "chainId": 0x04 //4:Rinkeby, 3:Ropsten, 1:mainnet
    };

    var tx = new Tx(rawTransaction);
    tx.sign(privKey);
    var serializedTx = tx.serialize();
    return serializedTx;
}

async function signTransaction(fromAddress,toAddress,sendNum,nonceNum, privKey) {
    var serializedTx = getEthRawTx(fromAddress,toAddress,sendNum,nonceNum, privKey)

    // Comment out these three lines if you don't really want to send the TX right now
    console.log(`Attempting to send signed tx:  ${serializedTx.toString('hex')}`);
    var receipt = await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'));
    console.log(`Receipt info:  ${JSON.stringify(receipt, null, '\t')}`);
}

function sleep(delay) {
    return new Promise(reslove => {
      setTimeout(reslove, delay)
    })
}

//an async function 
const sendEth = async () => {

    //the number of sended token
    //20 milli = 0.02 ether
    var transferAmount = web3.utils.toWei('20', 'milli');

    var myAddress = "0x1d75...a5f";
    var destAddress = "0x8a40....23fb";

    // get the nonce
    var nonceCnt = await web3.eth.getTransactionCount(myAddress);
    console.log(`num transactions so far: ${nonceCnt}`);

    // begin eth numbers of myAddress
    await getEthBalance(myAddress, "Balance before send: ");

    const privkey = getPriKey("./projectConfig/net.prikey")
    await signTransaction(myAddress,destAddress,transferAmount,nonceCnt, privkey)

    sleep(100) //100ms

    // end eth numbers of myAddress
    await getEthBalance(myAddress, "Balance After send: ");
}

sendEth();


3.3 发送ERC20

    将如下代码保存到sendToken\test\2.sendERC20.js里,该代码是发送0.02 ZTA
    //2.sendERC20.js

var Tx = require('ethereumjs-tx');
var Web3 = require('web3')

var fs = require('fs');
const infuraKey = fs.readFileSync("./projectConfig/net.infuraKey").toString().trim();
var web3 = new Web3(new Web3.providers.HttpProvider(`https://rinkeby.infura.io/v3/` + infuraKey))

// web3 version 
console.log(`web3 version: ${web3.version}`)

function getERC20Balance(fromAddress,contractObj,bookmark) {
    contractObj.methods.balanceOf(fromAddress).call().then(
        function (wei) {
            balance = web3.utils.fromWei(wei, 'ether');
            console.log(bookmark + balance);
    });
}

function getPriKey(prikeyPath) {
    const privKeyFile = fs.readFileSync(prikeyPath).toString().trim();
    const privKey = new Buffer.from(privKeyFile, 'hex');    
    return privKey
}


function getERC20RawTx(fromAddress,toAddress,contractAddress,contractObj,sendNum,nonceNum, privKey) {
    //raw Tx
    var rawTransaction = {
        "from": fromAddress,
        "nonce": web3.utils.toHex(nonceNum),
        "gasLimit": web3.utils.toHex(8000000),
        "gasPrice": web3.utils.toHex(10e9),
        "to": contractAddress,
        "value": "0x0",
        "data": contractObj.methods.transfer(toAddress, sendNum).encodeABI(),
        "chainId": 0x04 //4:Rinkeby, 3:Ropsten, 1:mainnet
    };

    var tx = new Tx(rawTransaction);
    tx.sign(privKey);
    var serializedTx = tx.serialize();
    return serializedTx;
}

async function signERC20Transaction(fromAddress,toAddress,contractAddress,contractObj,sendNum,nonceNum, privKey) {
    var serializedTx = getERC20RawTx(fromAddress,toAddress,contractAddress,contractObj,sendNum,nonceNum, privKey)

    // Comment out these three lines if you don't really want to send the TX right now
    console.log(`Attempting to send signed tx:  ${serializedTx.toString('hex')}`);
    var receipt = await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'));
    console.log(`Receipt info:  ${JSON.stringify(receipt, null, '\t')}`);
}

function sleep(delay) {
    return new Promise(reslove => {
      setTimeout(reslove, delay)
    })
}

//an async function 
const sendERC20 = async () => {

    //the number of sended token
    //20 milli = 0.02 ether
    var transferAmount = web3.utils.toWei('20', 'milli');

    var myAddress = "0x1d75...a5f";
    var destAddress = "0x8a40....23fb";

    // get the nonce
    var nonceCnt = await web3.eth.getTransactionCount(myAddress);
    console.log(`num transactions so far: ${nonceCnt}`);

    var abiArray = JSON.parse(fs.readFileSync("./myabi/ZTA_abi.json"));
    var contractAddress = "0xAc194f047E43Ee0Ee10026C0B7AAA66489a0Ec45";
    var contract = new web3.eth.Contract(abiArray, contractAddress, { from: myAddress });

    // begin token numbers
    await getERC20Balance(myAddress,contract,"Balance before send: ");

    const privkey = getPriKey("./projectConfig/net.prikey")
    await signERC20Transaction(myAddress,destAddress,contractAddress,contract,transferAmount,nonceCnt, privkey)

    sleep(100)  //100ms

    // end token numbers
    await getERC20Balance(myAddress,contract,"Balance before send: ");
}

sendERC20();

    执行该nodejs脚本

node test\2.sendERC20.js

    效果如下:

使用web3.js收发ETH或ERC20Token_第5张图片
图(5) 发送0.02 ZTA Token

你可能感兴趣的:(区块链,truffle,ETH转账,ERC20转账,web3.js,Token,区块链)