# Ethers.js入门 **Published by:** [MarkTang's Blog](https://paragraph.com/@marktang-s-blog/) **Published on:** 2022-08-26 **URL:** https://paragraph.com/@marktang-s-blog/ethers-js ## Content Ethers.js入门术语解释Provider: Provider 是一个为连接到以太坊网络提供抽象的类,提供对blockchain及其状态的只读访问 Signer: Signer是一个类,通常以某种方式直接或间接地接触到一个私钥,它可以签署消息和交易,以授权网络向你的账户收取以太坊来执行操作 Contract: Contract是一个抽象概念,它代表了与以太坊网络上特定合约的连接,因此,应用程序可以像普通的JavaScript对象一样使用它连接方式及操作Connecting to Ethereum: MetaMask在Ethereum上进行实验和开始开发的最快速和最简单的方法是使用MetaMask,它是一个浏览器扩展// Web3Provider包装了一个标准的Web3 provider,MetaMask为每个页面注入了window.ethereum const provider = new ethers.providers.Web3Provider(window.ethereum); // MetaMask Plugin 还允许签名transactions 来发送ether和支付以改变链上的状态,所以需要 signer const signer = provider.getSigner(); Connecting to Ethereum: RPCJSON-RPC API是另一种常用的与Ethereum交互的方式,在所有主要的以太坊节点实现(Geth, Parity)以及许多第三方网络服务(Infura)中都有// 如果你不指定一个 url地址,会默认为: http://localhost:8545 const provider = new ethers.providers.JsonRpcProvider(); // 也允许签名transactions const signer = provider.getSigner(); Querying the Blockchain一旦你有了Provider,你就有了与Blockchain的只读连接,可以用它来查询当前状态,获取历史日志,查询部署的代码等等// Look up the current block number await provider.getBlockNumber(); // 137223 // Get the balance of an account (by address or ENS name, if supported by network) balance = await provider.getBalance("ethers.eth"); // { BigNumber: "2337132817842795605" } ethers.utils.formatEther(balance); // '2.337132817842795605' ethers.utils.parseEther("1.0"); // { BigNumber: "1000000000000000000" } Note: ENS(Ethereum Name Service)之于以太坊就像是DNS对于因特网,ENS允许用户使用个性化的以太坊域名为自己注册,比如用“vitalik.eth”来替代密码地址‘0x32b724f073ec346edd64b0cc67757e4f6fe42950’。ENS一直在迭代开发中,ENS不仅仅用于以太坊地址,未来ENS将覆盖以太坊的各个方面Writing to the Blockchain// Send 1 ether to an ens name. const tx = signer.sendTransaction({ to: "marktang.firefly.eth", value: ethers.utils.parseEther("1.0") }); Contracts合约是在Ethereum blockchain上运行的代码的一种抽象Contract类为了与链上合约进行通信,需要知道有哪些方法可以调用,这需要传入ABI文件 这个类是一个meta-class,在运行时构造的,传入ABI给构造函数时,它用ABI来决定要添加哪些方法 ABI由 Solidity或Vyper编译成,但你可以在代码中使用人类可读的ABI,如:// You can also use an ENS name for the contract address const daiAddress = "dai.tokens.ethers.eth"; // The ERC-20 Contract ABI, which is a common contract interface // for tokens (this is the Human-Readable ABI format) const daiAbi = [ // Some details about the token "function name() view returns (string)", "function symbol() view returns (string)", // Get the account balance "function balanceOf(address) view returns (uint)", // Send some of your tokens to someone else "function transfer(address to, uint amount)", // An event triggered whenever anyone transfers to someone else "event Transfer(address indexed from, address indexed to, uint amount)" ]; // The Contract object const daiContract = new ethers.Contract(daiAddress, daiAbi, provider); Read-Only Methods// Get the ERC-20 token name await daiContract.name() // 'Dai Stablecoin' // Get the ERC-20 token symbol (for tickers and UIs) await daiContract.symbol() // 'DAI' // Get the balance of an address balance = await daiContract.balanceOf("ricmoo.firefly.eth") // { BigNumber: "18190624174838529547383" } // Format the DAI for displaying to the user ethers.utils.formatUnits(balance, 18) // '18190.624174838529547383' State Changing Methods// DAI 合约目前连接到Provider,但是Provider是 read-only的 // 需要连接到一个Signer,这样就可以付费发送一些改变状态的交易 const daiWithSigner = contract.connect(signer); // Each DAI has 18 decimal places const dai = ethers.utils.parseUnits("1.0", 18); // Send 1 DAI to "ricmoo.firefly.eth" tx = daiWithSigner.transfer("ricmoo.firefly.eth", dai); Listening to Events// Receive an event when ANY transfer occurs daiContract.on("Transfer", (from, to, amount, event) => { console.log(`${ from } sent ${ formatEther(amount) } to ${ to}`); // 事件对象包含逐字记录数据、EventFragment和获取块、交易和接收的函数以及事件函数 }); // @Todo: I don't know if Can I get all transactions here. // A filter for when a specific address receives tokens myAddress = "0x8ba1f109551bD432803012645Ac136ddd64DBA72"; filter = daiContract.filters.Transfer(null, myAddress) // { // address: 'dai.tokens.ethers.eth', // topics: [ // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // null, // '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72' // ] // } // Receive an event when that filter occurs daiContract.on(filter, (from, to, amount, event) => { // The to will always be "address" console.log(`I got ${ formatEther(amount) } from ${ from }.`); }); Query Historic Events// Get the address of the Signer myAddress = await signer.getAddress() // '0x8ba1f109551bD432803012645Ac136ddd64DBA72' // Filter for all token transfers from me filterFrom = daiContract.filters.Transfer(myAddress, null); // { // address: 'dai.tokens.ethers.eth', // topics: [ // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72' // ] // } // Filter for all token transfers to me filterTo = daiContract.filters.Transfer(null, myAddress); // { // address: 'dai.tokens.ethers.eth', // topics: [ // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // null, // '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72' // ] // } // List all transfers sent from me a specific block range 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 // } // ] // List all transfers sent in the last 10,000 blocks await daiContract.queryFilter(filterFrom, -10000) // List all transfers ever sent to me await daiContract.queryFilter(filterTo) Signing Messages// To sign a simple string, which are used for // logging into a service, such as CryptoKitties, // pass the string in. signature = await signer.signMessage("Hello World"); // '0x5a77beb84677b221d7110b08605a2658dd6c1e88a2ba9293436e587dbf6479d4798d0ca34ba2113bdb51ad97cd831975ccaccaf5f6fbd5d566fe662f11e2ca411b' // // A common case is also signing a hash, which is 32 // bytes. It is important to note, that to sign binary // data it MUST be an Array (or TypedArray) // // This string is 66 characters long message = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" // This array representation is 32 bytes long 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 ] // To sign a hash, you most often want to sign the bytes signature = await signer.signMessage(messageBytes) // '0xe099cce5e80dec1d8464d00c4156855d1c14cc4f83473deee7ab8e60be770f4b5ea04e90e7b7102ac5b493f7822b0ad10dc26bfda0761530a58e5f461f90b2fd1b' ## Publication Information - [MarkTang's Blog](https://paragraph.com/@marktang-s-blog/): Publication homepage - [All Posts](https://paragraph.com/@marktang-s-blog/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@marktang-s-blog): Subscribe to updates - [Twitter](https://twitter.com/MarkTan43749744): Follow on Twitter