ethers.js 合约
ethers.js使用TypeScript写的框架, 用来访问eth网络。
支持多种方式连接eth node JSON-RPC, INFURA, Etherscan, Alchemy, Ankr or MetaMask
// JsonRpcProvider实现了Provider接口, Provider中包含一些read方法 e.g. getBalance, getBlockNumber, getBlock, 也包含call方法调用
// Provider继承自ContractRunner、EventEmitterable、NameResolver
// ContractRunner是合约运行的基础, 包含了estimateGas估算gas、call、sendTransaction, 注意provider未实现sendTransaction该方法需要私钥签名才能执行
const provider = new ethers.JsonRpcProvider("http://127.0.0.1:8545");
// 获取区块高度
const blockNum = await provider.getBlockNumber()
const abiERC20 = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function totalSupply() view returns (uint256)",
"function balanceOf(address) view returns (uint)",
];
const provider = new ethers.JsonRpcProvider("https://goerli.infura.io/v3/52e90a56caa54252808c7d6c3add8a0f");
const baseWallet = ethers.HDNodeWallet.createRandom();
// 绑定wallet和provider(可以发送交易)
const wallet = baseWallet.connect(provider);
// 合约地址
const addressDAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
// 创建合约实例
const contractDAI = new ethers.Contract(addressDAI, abiERC20, wallet);
// 调用合约方法
const totalSupply = await contractDAI.totalSupply();
可以使用Interface加载abi结构, 然后编码function, topics, eventlog等
const abiERC20 = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function totalSupply() view returns (uint256)",
"function balanceOf(address) view returns (uint)",
"event Transfer(address indexed from, address indexed to, uint256 value)",
];
const abi = new ethers.Interface(abiERC20);
const functionData = abi.encodeFunctionData('balanceOf',['0x6B175474E89094C44Da98b954EedeAC495271d0F']);
const filterTopics = abi.encodeFilterTopics('Transfer',['0x6B175474E89094C44Da98b954EedeAC495271d0F','0x6B175474E89094C44Da98b954EedeAC495271d0F'])
const eventLog = abi.encodeEventLog('Transfer',['0x6B175474E89094C44Da98b954EedeAC495271d0F','0x6B175474E89094C44Da98b954EedeAC495271d0F', 123])
const provider = new ethers.JsonRpcProvider("https://goerli.infura.io/v3/52e90a56caa54252808c7d6c3add8a0f");
const baseWallet = ethers.HDNodeWallet.createRandom();
// 绑定wallet和provider(可以发送交易)
const wallet = baseWallet.connect(provider);
const tx = {
to: xxx,
data: functionData // 上面编码出来的data
}
const response = await wallet.sendTransaction(tx);
const provider = new ethers.JsonRpcProvider("https://goerli.infura.io/v3/52e90a56caa54252808c7d6c3add8a0f");
const baseWallet = ethers.HDNodeWallet.createRandom();
// 绑定wallet和provider(可以发送交易)
const wallet = baseWallet.connect(provider);
const tx = {
to: xxx,
data: functionData // 上面编码出来的data
}
// 如果不想真实发送交易到网络中可以使用call调用, 只在目标机器执行并返回结果
const response = await wallet.call(tx);
使用SigningKey进行私钥签名、验证签名、生成公钥、地址. 数据转换过程privateKey -> publicKey -> address.
const { ethers,SigningKey } = require("ethers");
// 生成私钥
const privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
// 创建一个 ethers.js 的签名器对象
const signingKey = new ethers.SigningKey(privateKey);
// 将消息进行哈希运算
const message = "Hello, world!";
const messageHash = ethers.keccak256(ethers.toUtf8Bytes(message));
// 生成 r s v
const signature = signingKey.sign(messageHash);
const { r, s, v } = ethers.Signature.from(signature);
console.log("r: " + r);
console.log("s: " + s);
console.log("v: " + v);
// public key验证
const recoverPublicKey = SigningKey.recoverPublicKey(messageHash, signature);
console.log(`public key 验证:${recoverPublicKey === signingKey.publicKey}`);
// address验证
const address = ethers.computeAddress(signingKey.publicKey);
const recoveredAddress = ethers.recoverAddress(messageHash, signature);
console.log(`address 验证:${address === recoveredAddress}`);
上述代码中的SigningKey主要是管理私钥、公钥、以及数字签名的. Wallet包含SigningKey 除了上述功能还管理账户地址(通过publicKey生成), 查看余额, 发送交易等功能.
1.生成Mnemonic
1).生成随机种子Entropy
2).根据种子+wordList生成助记词(种子相当于index wordList相当于array), 可选password 在用Mnemonic生成seed时会用到.
3).最后组装成Mnemonic
2.生成HDNodeWallet
1).使用Mnemonic生成seed Mnemonic.computedSeed(使用PBKDF2函数和HMAC-SHA512算法,把助记词转换成一个种子seed)
2).使用种子生成HDWallet确定性钱包, 在这个钱包中可以根据路径派生出多个地址(每个地址都是独立的私钥)
使用ethers.js v6版本代码例子如下:
const { ethers,wordlists } = require("ethers");
const mnemonic = ethers.Mnemonic.fromEntropy("0xd4e409e44611be1a7e93a0c2ade7a131","123", wordlists.zh_cn)
const seed = mnemonic.computeSeed();
// path:'m'
let hdNodeWallet = ethers.HDNodeWallet.fromSeed(seed)
let basePath = "m/44'/60'/0'/0";
let wallet = hdNodeWallet.derivePath(basePath+'/0');
console.log(wallet)
wallet = hdNodeWallet.derivePath(basePath+'/1');
console.log(wallet)
wallet = hdNodeWallet.derivePath(basePath+'/2');
console.log(wallet)
可以查询合约中的event事件,
使用provider过滤
const logs = await provider.getLogs({
fromBlock: 8876717,
toBlock: 8876813,
address: '0x39c72916169b0d9eb22610a90f612d09302aa234', // 合约地址
topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'] // topics编码信息
});
使用合约过滤查询
const events = await erc20Contract.queryFilter('Transfer', fromBlock, toBlock);
使用provider监听 block, pending, transaction, event, orphan等
case "block": case "pending": case "debug": case "network": {return { type: _event, tag: _event }
{ type: "transaction", tag: getTag("tx", { hash }), hash }
{ type: "orphan", tag: getTag("orphan", event), filter: copy(event) }
{ filter, tag: getTag("event", filter), type: "event" }
代码
provider.on('pending',async (txHash)=>{
});
使用contract监听事件
await erc20Contract.on('Transfer', (from, to, amount) => {
console.log(`from:${from} to:${to} amount:${amount}`);
});
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!