以太坊中各种类和函数都可以从@ethersproject下的子库中手动进行导入,但对于大多数项目来说,用完整的总库是最简单的入门方式。
/home/ricmoo> npm install --save ethers
const { ethers } = require("ethers");
import { ethers } from "ethers";
出于安全,通常较好的方式是将这个库复制到你的web服务器中来进行各种操作。
但若想快速构建实例展示,可以将我们的CDN加载到你的web应用程序中。
<script type="module">
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.2.esm.min.js";
// Your code here...
</script>
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"
type="application/javascript"></script>
这部分将会不断完善...
Provider | Provider(提供者)是一个用于连接以太坊网络的抽象类,提供了只读形式来访问区块链网络和获取链上状态。 | |
Signer | Signer(签名器)通常是以某种方式直接或间接访问私钥,可以签名消息和在已授权网络中管理你账户中的以太币来进行交易。 | |
Contract | Contract(合约)是一个运行在以太坊网络上表示现实中特定合约的抽象,应用可以像使用JavaScript对象一样使用它。 | |
Common Terms | |
在以太坊上去开发和测试的最快、最简单的方法是使用MetaMask, 它是一个基于浏览器的扩展程序,提供了:
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
JSON-RPC API 另一种与以太坊交互的比较流行的方式,用在所有主要的以太坊节点 (如 Geth 和 Parity) 以及许多第三方web服务 (如 INFURA)。 它通常提供了:
const provider = new ethers.providers.JsonRpcProvider();
const signer = provider.getSigner()
当你有了Provider之后, 你就可以通过只读的方式连接区块链, 此外,你还可以使用它来查询当前状态、获取历史日志、查找部署的代码等等。
await provider.getBlockNumber()
// 16383845
balance = await provider.getBalance("ethers.eth")
// { BigNumber: "182334002436162568" }
ethers.utils.formatEther(balance)
// '0.182334002436162568'
ethers.utils.parseEther("1.0")
// { BigNumber: "1000000000000000000" }
const tx = signer.sendTransaction({
to: "ricmoo.firefly.eth",
value: ethers.utils.parseEther("1.0")
});
合约(Contract)是以太坊区块链中程序代码的抽象。
合约 (Contract) 对象使得链上的合约可以简单地作为一个普通的JavaScript对象, 通过映射的方法来编码和解码数据。
如果你熟悉数据库, 你会发现这与对象关系映射器 (ORM)是相似的。
为了与链上的合约进行通信,这个类需要知道哪些方法是可用的,以及如何编码和解码数据,这些通过应用程序二进制接口 (ABI)来提供。
这个类是一个 元类(meta-class), 这意味着它的方法是在运行时构造的, 当你将ABI传递给构造函数时,它来确定要添加哪些方法。
尽管链上的合约有许多可用的方法,但是你可以安全地忽略你认为不需要或者不使用的方法,这样合约里面的ABI就是一个较小的子集。
ABI通常来自于Solidity或Vyper编译器,但是你可以在代码中使用人类可读的ABI格式(Human-Readable),如下例所示:
const daiAddress = "dai.tokens.ethers.eth";
const daiAbi = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function balanceOf(address) view returns (uint)",
"function transfer(address to, uint amount)",
"event Transfer(address indexed from, address indexed to, uint amount)"
];
const daiContract = new ethers.Contract(daiAddress, daiAbi, provider);
await daiContract.name()
// 'Dai Stablecoin'
await daiContract.symbol()
// 'DAI'
balance = await daiContract.balanceOf("ricmoo.firefly.eth")
// { BigNumber: "2413468059122458201631" }
ethers.utils.formatUnits(balance, 18)
// '2413.468059122458201631'
const daiWithSigner = contract.connect(signer);
const dai = ethers.utils.parseUnits("1.0", 18);
tx = daiWithSigner.transfer("ricmoo.firefly.eth", dai);
daiContract.on("Transfer", (from, to, amount, event) => {
console.log(`${ from } sent ${ formatEther(amount) } to ${ to}`);
});
myAddress = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
filter = daiContract.filters.Transfer(null, myAddress)
// {
// address: 'dai.tokens.ethers.eth',
// topics: [
// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
// null,
// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72'
// ]
// }
daiContract.on(filter, (from, to, amount, event) => {
console.log(`I got ${ formatEther(amount) } from ${ from }.`);
});
myAddress = await signer.getAddress()
// '0x8ba1f109551bD432803012645Ac136ddd64DBA72'
filterFrom = daiContract.filters.Transfer(myAddress, null);
// {
// address: 'dai.tokens.ethers.eth',
// topics: [
// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72'
// ]
// }
filterTo = daiContract.filters.Transfer(null, myAddress);
// {
// address: 'dai.tokens.ethers.eth',
// topics: [
// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
// null,
// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72'
// ]
// }
await daiContract.queryFilter(filterFrom, 9843470, 9843480)
// [
// {
// address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
// args: [
// '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
// '0x8B3765eDA5207fB21690874B722ae276B96260E0',
// { BigNumber: "4750000000000000000" },
// amount: { BigNumber: "4750000000000000000" },
// from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
// to: '0x8B3765eDA5207fB21690874B722ae276B96260E0'
// ],
// blockHash: '0x8462eb2fbcef5aa4861266f59ad5f47b9aa6525d767d713920fdbdfb6b0c0b78',
// blockNumber: 9843476,
// data: '0x00000000000000000000000000000000000000000000000041eb63d55b1b0000',
// decode: [Function],
// event: 'Transfer',
// eventSignature: 'Transfer(address,address,uint256)',
// getBlock: [Function],
// getTransaction: [Function],
// getTransactionReceipt: [Function],
// logIndex: 69,
// removeListener: [Function],
// removed: false,
// topics: [
// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72',
// '0x0000000000000000000000008b3765eda5207fb21690874b722ae276b96260e0'
// ],
// transactionHash: '0x1be23554545030e1ce47391a41098a46ff426382ed740db62d63d7676ff6fcf1',
// transactionIndex: 81
// },
// {
// address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
// args: [
// '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
// '0x00De4B13153673BCAE2616b67bf822500d325Fc3',
// { BigNumber: "250000000000000000" },
// amount: { BigNumber: "250000000000000000" },
// from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
// to: '0x00De4B13153673BCAE2616b67bf822500d325Fc3'
// ],
// blockHash: '0x8462eb2fbcef5aa4861266f59ad5f47b9aa6525d767d713920fdbdfb6b0c0b78',
// blockNumber: 9843476,
// data: '0x00000000000000000000000000000000000000000000000003782dace9d90000',
// decode: [Function],
// event: 'Transfer',
// eventSignature: 'Transfer(address,address,uint256)',
// getBlock: [Function],
// getTransaction: [Function],
// getTransactionReceipt: [Function],
// logIndex: 70,
// removeListener: [Function],
// removed: false,
// topics: [
// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72',
// '0x00000000000000000000000000de4b13153673bcae2616b67bf822500d325fc3'
// ],
// transactionHash: '0x1be23554545030e1ce47391a41098a46ff426382ed740db62d63d7676ff6fcf1',
// transactionIndex: 81
// }
// ]
await daiContract.queryFilter(filterFrom, -10000)
await daiContract.queryFilter(filterTo)
signature = await signer.signMessage("Hello World");
// '0x776d4dbf69ee5ed47b3250c56dbcec7ac3a59fb64447a480dcbfe05e2431547b02cf5200876ea6a9e018680dda31a9283cb0230196782f3d48dba450f0176d141b'
message = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
messageBytes = ethers.utils.arrayify(message);
// Uint8Array [ 221, 242, 82, 173, 27, 226, 200, 155, 105, 194, 176, 104, 252, 55, 141, 170, 149, 43, 167, 241, 99, 196, 161, 22, 40, 245, 90, 77, 245, 35, 179, 239 ]
signature = await signer.signMessage(messageBytes)
// '0xc848253c4c267c12d6c039c0a367b9a1c3bc683300bad5f1f9455df67cbc36c17ddf1e28a705420cf19b0a634f86dd13f6eee8eea2b0316f9741785aa31a74d31b'