forked from ethers-io/ethers.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgetting-started.wrm
350 lines (239 loc) · 10.7 KB
/
getting-started.wrm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
_section: Getting Started @<getting-started>
_subsection: Installing @<installing>
Ethers' various Classes and Functions are available to import
manually from sub-packages under the [@ethersproject](link-ethers-npm)
organization but for most projects, the umbrella package is the
easiest way to get started.
_code: @lang<shell>
/home/ricmoo> npm install --save ethers
_subsection: Importing @<importing>
_heading: Node.js
_code: node.js require @lang<script>
const { ethers } = require("ethers");
_code: ES6 or TypeScript @lang<script>
import { ethers } from "ethers";
_heading: Web Browser
It is generally better practice (for security reasons) to copy the
[ethers library](link-ethers-js) to your own webserver and serve it
yourself.
For quick demos or prototyping though, you can load it in your
Web Applications from our CDN.
_code: ES6 in the Browser @lang<html>
<script type="module">
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.2.esm.min.js";
// Your code here...
</script>
_code: ES3 (UMD) in the Browser @lang<html>
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"
type="application/javascript"></script>
_subsection: Common Terminology @<getting-started--glossary>
This section needs work...
_table: Common Terms
$Provider: A Provider (in ethers) is a class which provides an abstraction
for a connection to the Ethereum Network. It provides read-only
access to the Blockchain and its status.
$Signer: A Signer is a class which (usually) in some way directly or
indirectly has access to a private key, which can sign messages
and transactions to authorize the network to charge your account
ether to perform operations.
$Contract: A Contract is an abstraction which represents a connection to a
specific contract on the Ethereum Network, so that applications
can use it like a normal JavaScript object.
| **Provider** | $Provider |
| **Signer** | $Signer |
| **Contract** | $Contract |
_subsection: Connecting to Ethereum: MetaMask @<getting-started--connecting>
The quickest and easiest way to experiment and begin developing on
Ethereum is to use [[link-metamask]], which is a browser extension
that provides:
- A connection to the Ethereum network (a [[Provider]])
- Holds your private key and can sign things (a [[Signer]])
_code: Connecting to MetaMask @lang<script>
// A Web3Provider wraps a standard Web3 provider, which is
// what MetaMask injects as window.ethereum into each page
const provider = new ethers.providers.Web3Provider(window.ethereum)
// MetaMask requires requesting permission to connect users accounts
await provider.send("eth_requestAccounts", []);
// The MetaMask plugin also allows signing transactions to
// send ether and pay to change state within the blockchain.
// For this, you need the account signer...
const signer = provider.getSigner()
_subsection: Connecting to Ethereum: RPC @<getting-started--connecting-rpc>
The [JSON-RPC API](link-jsonrpc) is another popular method for interacting
with Ethereum and is available in all major Ethereum node implementations
(e.g. [[link-geth]] and [[link-parity]]) as well as many
third-party web services (e.g. [[link-infura]]). It typically provides:
- A connection to the Ethereum network (a [[Provider]])
- Holds your private key and can sign things (a [[Signer]])
_code: Connecting to an RPC client @lang<script>
// If you don't specify a //url//, Ethers connects to the default
// (i.e. ``http:/\/localhost:8545``)
const provider = new ethers.providers.JsonRpcProvider();
// The provider also allows signing transactions to
// send ether and pay to change state within the blockchain.
// For this, we need the account signer...
const signer = provider.getSigner()
_heading: Querying the Blockchain @<getting-started--querying>
Once you have a [[Provider]], you have a read-only connection to the
blockchain, which you can use to query the current state, fetch historic
logs, look up deployed code and so on.
_code: Basic Queries @lang<javascript>
// Look up the current block number
//_result:
await provider.getBlockNumber()
//_log:
// Get the balance of an account (by address or ENS name, if supported by network)
//_result:
balance = await provider.getBalance("ethers.eth")
//_log:
// Often you need to format the output to something more user-friendly,
// such as in ether (instead of wei)
//_result:
ethers.utils.formatEther(balance)
//_log:
// If a user enters a string in an input field, you may need
// to convert it from ether (as a string) to wei (as a BigNumber)
//_result:
ethers.utils.parseEther("1.0")
//_log:
_heading: Writing to the Blockchain @<getting-started--sending>
_code: Sending Ether @lang<script>
// Send 1 ether to an ens name.
const tx = signer.sendTransaction({
to: "ricmoo.firefly.eth",
value: ethers.utils.parseEther("1.0")
});
_subsection: Contracts @<getting-started--contracts>
A Contract is an abstraction of program code which lives on the
Ethereum blockchain.
The [[Contract]] object makes it easier to use an on-chain
Contract as a normal JavaScript object, with the methods
mapped to encoding and decoding data for you.
If you are familiar with Databases, this is similar to an //Object Relational Mapper// (ORM).
In order to communicate with the Contract on-chain, this class
needs to know what methods are available and how to encode and
decode the data, which is what the //Application Binary Interface// (ABI)
provides.
This class is a //meta-class//, which means its methods are constructed
at runtime, and when you pass in the ABI to the constructor it uses it
to determine which methods to add.
While an on-chain Contract may have many methods available, you can safely ignore
any methods you don't need or use, providing a smaller subset of the ABI to
the contract.
An ABI often comes from the Solidity or Vyper compiler, but you can use the
Human-Readable ABI in code, which the following examples use.
_code: Connecting to the DAI Contract @lang<javascript>
// 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);
//_hide: _page.daiAbi = daiAbi;
//_hide: _page.daiContract = daiContract;
_heading: Read-Only Methods @<getting-started--reading>
_code: Querying the DAI Contract @lang<javascript>
//_hide: const daiContract = _page.daiContract;
// Get the ERC-20 token name
//_result:
await daiContract.name()
//_log:
// Get the ERC-20 token symbol (for tickers and UIs)
//_result:
await daiContract.symbol()
//_log:
// Get the balance of an address
balance = await daiContract.balanceOf("ricmoo.firefly.eth")
//_log: balance
// Format the DAI for displaying to the user
//_result:
ethers.utils.formatUnits(balance, 18)
//_log:
_heading: State Changing Methods @<getting-started--writing>
_code: Sending DAI @lang<script>
// The DAI Contract is currently connected to the Provider,
// which is read-only. You need to connect to a Signer, so
// that you can pay to send state-changing transactions.
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);
_heading: Listening to Events @<getting-started--events>
_code: Listening to Events @lang<javascript>
//_hide: const daiContract = _page.daiContract;
//_hide: const formatEther = ethers.utils.formatEther;
// Receive an event when ANY transfer occurs
daiContract.on("Transfer", (from, to, amount, event) => {
console.log(`${ from } sent ${ formatEther(amount) } to ${ to}`);
// The event object contains the verbatim log data, the
// EventFragment and functions to fetch the block,
// transaction and receipt and event functions
});
// A filter for when a specific address receives tokens
myAddress = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
filter = daiContract.filters.Transfer(null, myAddress)
//_log: filter
// 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 }.`);
});
//_hide: daiContract.removeAllListeners(); /* Don't want to block the docs from compiling... */
_heading: Query Historic Events @<getting-started--history>
_code: Filtering Historic Events @lang<javascript>
//_hide: const signer = new ethers.VoidSigner("0x8ba1f109551bD432803012645Ac136ddd64DBA72");
//_hide: const daiContract = _page.daiContract;
// Get the address of the Signer
myAddress = await signer.getAddress()
//_log: myAddress
// Filter for all token transfers from me
filterFrom = daiContract.filters.Transfer(myAddress, null);
//_log: filterFrom
// Filter for all token transfers to me
filterTo = daiContract.filters.Transfer(null, myAddress);
//_log: filterTo
// List all transfers sent from me in a specific block range
//_result:
await daiContract.queryFilter(filterFrom, 9843470, 9843480)
//_log:
//
// The following have had the results omitted due to the
// number of entries; but they provide some useful examples
//
// 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)
_subsection: Signing Messages @<getting-started--signing>
_code: Signing Messages @lang<javascript>
//_hide: const signer = ethers.Wallet.createRandom();
// 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");
//_log: signature
//
// 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);
//_log: messageBytes
// To sign a hash, you most often want to sign the bytes
signature = await signer.signMessage(messageBytes)
//_log: signature