安裝ethers.js
- 只要運行一條簡單的命令
$ npm install ethers
創(chuàng)建錢包
- random方法會隨機生成錢包,并且錢包中包含了助記詞,這里把助記詞提出來,以便每次都生成同樣都錢包。
// demo1.js
const ethers = require('ethers');
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
// const randomWallet = ethers.Wallet.createRandom();
// console.log( randomWallet.signingKey.mnemonic);
// 助記詞由以上隨機函數(shù)生成,為了保持賬號統(tǒng)一,這里記錄了兩組助記詞
const mnemonic1 = 'utility opinion husband upset finger side round exhaust arm allow pilot hospital';
const mnemonic2 = 'method expand rule tool impact wedding just body slogan offer rate pass';
// 根據(jù)兩組助記詞生成兩個錢包對象
const _wallet1 = ethers.Wallet.fromMnemonic(mnemonic1);
// address1 0xBe255696870b84C69F6e2b902177Cf2a2cB57B58
// privateKey1 0x056ef7c6a165f877a5aedb3cfe24b2bbcdd6c680d12df9a82092705fc03ce37f
const _wallet2 = ethers.Wallet.fromMnemonic(mnemonic2);
// address2 0xbe79D5B66A5D44607F91E312ec5E35b8c92db5bf
// privateKey2 0x8544e404dea9123dd6fe1b6b35702a738284e055223c0e2afd41ec7694a2bfda
給賬號充值
- 現(xiàn)在給賬號充值一點ETH測試轉(zhuǎn)賬,
- 這里選擇測試網(wǎng)rinkeby
- 水龍頭地址
- 發(fā)一條帶有自己地址推文,粘貼在水龍頭頁面的輸入框即可,如下圖所示。
- 這里都鏈接只支持Facebook、Twitter、google puls,請科學(xué)上網(wǎng)。

屏幕快照 2018-12-05 下午10.45.29.png
錢包對象鏈接網(wǎng)絡(luò)
- 設(shè)定一個provider,參數(shù)填入
rinkeby即可,如果鏈接正式網(wǎng),就不需要填寫參數(shù)。
let provider = ethers.getDefaultProvider('rinkeby');
const wallet1 = _wallet1.connect(provider);
const wallet2 = _wallet2.connect(provider);
查詢一下賬號余額
- 一切正常的話可以顯示余額
const getBalance = async () => {
// 返回的余額單位是ether,要轉(zhuǎn)換成ETH
const _balance1 = await wallet1.getBalance();
// 第一次獲取是18.75, 總之這里是非零就說明水龍頭轉(zhuǎn)賬成功,并且連接測試網(wǎng)成功了
const balance1 = ethers.utils.formatEther(_balance1);
const _balance2 = await wallet2.getBalance();
const balance2 = ethers.utils.formatEther(_balance2);
console.log(balance1, balance2);
};
getBalance();
轉(zhuǎn)賬測試
- 填寫接收者的地址,發(fā)出對象就可以了,非常簡單,
- 有一點注意都是,金額需要用
parseEther進行轉(zhuǎn)行,因為在區(qū)塊鏈網(wǎng)絡(luò)中都用ether這個單位。 - 一切順利都話,會打印出交易結(jié)果。
const transfer = async () => {
let tx = {
// 這里寫一個接收人的地址,就寫我們的wallet2吧
to: "0xbe79D5B66A5D44607F91E312ec5E35b8c92db5bf",
// 填寫一個金額
value: ethers.utils.parseEther('2.33')
};
// 廣播轉(zhuǎn)賬信息
const result = await wallet1.sendTransaction(tx);
console.log(result);
};
transfer();
// 轉(zhuǎn)賬結(jié)束后,查詢一下余額,數(shù)正確,沒毛病
getBalance().then();
合約部署
- 在部署合約之前,需要把一個智能合約進行編譯。
- 準備好一份solidty合約,這里用到的是一份在
contracts目錄下,名為SimpleStorage.sol的合約。 - 分別編譯完
bytecode與abi后,會在contracts生成__SimpleStorage_sol_SimpleStorage.abi與__SimpleStorage_sol_SimpleStorage.bin文件。 - 在node讀取兩個編譯后的文件,上傳區(qū)塊就可以了。
// ./contracts/SimpleStorage.sol
// 這個合約只有簡單寫入與讀取功能,還有一個通知前端的事件。
pragma solidity ^0.5.1;
contract SimpleStorage {
event ValueChanged(address indexed author, string oldValue, string newValue);
string _value;
constructor(string memory value) public {
emit ValueChanged(msg.sender, _value, value);
_value = value;
}
function getValue() view public returns (string memory) {
return _value;
}
function setValue(string memory value) public {
emit ValueChanged(msg.sender, _value, value);
_value = value;
}
}
- 運行命令
$ npm install solc
// 編譯bytecode
../node_modules/solc/solcjs ./SimpleStorage.sol --bin
// 編譯abi
../node_modules/solc/solcjs ./SimpleStorage.sol --abi
如果命令出錯,提示丟失
smtchecker.js,運行cp ./fixBug/smtchecker.js ./node_modules/solc/
- 設(shè)置好
abibytecode和錢包把對象發(fā)到區(qū)塊鏈上, - 如果一切順利,會打印出部署成后的地址,以及交易哈希。
// demo4.js
const ethers = require('ethers');
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
const bytecodePath = './contracts/__SimpleStorage_sol_SimpleStorage.bin';
const abiPath = './contracts/__SimpleStorage_sol_SimpleStorage.abi';
const mnemonic1 = 'utility opinion husband upset finger side round exhaust arm allow pilot hospital';
const _wallet1 = ethers.Wallet.fromMnemonic(mnemonic1);
let provider = ethers.getDefaultProvider('rinkeby');
const wallet1 = _wallet1.connect(provider);
const deploy = async () => {
const bytecode = await readFile(bytecodePath,{encoding: 'utf8'});
const abi = await readFile(abiPath,{encoding: 'utf8'});
let factory = new ethers.ContractFactory(abi, bytecode, wallet1);
let contract = await factory.deploy("Hello World");
console.log('contract.address',contract.address);
await contract.deployed();
console.log('hash',contract.deployTransaction.hash);
};
deploy();
合約執(zhí)行
- 合約執(zhí)行分兩類,收費和免費,
收費的一般都是修改數(shù)據(jù),免費的一般都是查看數(shù)據(jù)。 - 合約的調(diào)用是通過api,部署了那些abi就可以在node中調(diào)用那些函數(shù)
- 可以查看
__SimpleStorage_sol_SimpleStorage.abi文件都有具體有那些方法,目前的例子有getValue/setValue - 順利運行后,會看到打印當前值和設(shè)置值'KKKK'
// 以上代碼運行后,合約地址為0x5Dbcdb3d61Bf83d5Fb6C926F23717A0138f536d9
const contractAddress = '0x5Dbcdb3d61Bf83d5Fb6C926F23717A0138f536d9';
const getContractValue = async () => {
const abi = await readFile(abiPath,{encoding: 'utf8'});
const contract = new ethers.Contract(contractAddress, abi, provider);
const currentValue = await contract.getValue();
console.log(currentValue);
};
getContractValue();
const setContractValue = async (value) => {
const abi = await readFile(abiPath,{encoding: 'utf8'});
const contract = new ethers.Contract(contractAddress, abi, provider);
const currentValue = await contract.getValue();
console.log('currentValue', currentValue);
const contractWithSigner = contract.connect(wallet1);
const tx = await contractWithSigner.setValue(value);
console.log('tx.hash',tx.hash);
await tx.wait();
const netValue = await contract.getValue();
console.log('netValue', netValue);
};
setContractValue('KKKK').catch();
合約監(jiān)聽
- 在合約中還有一個 ValueChanged事件,提供監(jiān)聽合約的變化
- 運行監(jiān)聽代碼后,只要合約的值產(chǎn)生變化,會返回到前端。
// demo3.js
const ethers = require('ethers');
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
const provider = ethers.getDefaultProvider('rinkeby');
const contractAddress = '0x5Dbcdb3d61Bf83d5Fb6C926F23717A0138f536d9';
const listening = async ()=> {
const abi = await readFile('./contracts/SimpleStorage_sol_SimpleStorage.abi',{encoding: 'utf8'});
const contract = new ethers.Contract(contractAddress, abi, provider);
// 監(jiān)聽合約的事件,
contract.on("ValueChanged", (author, oldValue, newValue, event) => {
// Called when anyone changes the value
console.log('author', author);
// "0x14791697260E4c9A71f18484C9f997B308e59325"
console.log('oldValue', oldValue);
// "Hello World"
console.log('newValue', newValue);
// "Ilike turtles."
// See Event Emitter below for all properties on Event
console.log('blockNumber', event.blockNumber);
// 4115004
});
};
listening().catch(console.log);