使用web3.js收發ETH或ERC20Token

    以太坊的轉賬分主要分爲爲ETH轉賬、ERC20轉賬這2種,其轉賬流程,如圖(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{}的代碼對比如下:
圖(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 整個工程的目錄結構如下:

圖(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

    效果如下:

圖(4) 發送0.02個ETH Token

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

    效果如下:

圖(5) 發送0.02 ZTA Token






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章