├── .gitignore ├── .prettierignore ├── 00-connect-to-blockchain.html ├── 01-read-address-data.html ├── 02-connect-to-contracts.html ├── 03-using-ens.html ├── 04-ercs.html ├── 05-example-app.html ├── 06-public-and-private-keys.html ├── 07-externally-owned-accounts.html ├── 08-crypto-wallet-setup.html ├── 09-test-networks.html ├── README.md ├── boilerplate ├── editor.js └── style.css ├── example_app.html ├── images ├── blockchain-connection-ethersjs.png ├── blockchain-connection.png ├── ecc-keys.png ├── encryption.png ├── ethereum-ecosystem.png ├── externally-owned-account.png └── signature.png ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.html -------------------------------------------------------------------------------- /00-connect-to-blockchain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web3 From Zero - Lesson 0 7 | 8 |

0. Connecting to a Blockchain Network

9 | 10 |

11 | This course will start from zero, so you don't have to install any software for the first lessons. 12 | You don't need a crypto-wallet or crypto dev tools; all you need is your browser and basic 13 | JavaScript know-how. 14 |

15 | 16 |
17 | Note: If you don't know JavaScript yet, because you just started learning how to program, 18 | or you only know other programming languages, you can try 19 | FreeCodeCamp, which offers good JavaScript 20 | courses for free! 21 |
22 | 23 |

Ways to Connect with a Blockchain Network

24 | 25 |

26 | In Web2, you know how to load your data from a server into a frontend. You connect to a backend 27 | with an HTTP API, which gets data from a database. 28 |

29 | 30 |

31 | The same is true for Web3. If you don't have a crypto-wallet, you need an HTTP API to connect 32 | to a blockchain network because these networks use a protocol your browser doesn't understand. 33 | This API is called an remote procedure call endpoint, or RPC for short. This RPC accepts 34 | requests from a browser over HTTP and leads them to a blockchain network. You can only read data 35 | from the blockchain with this connection method. 36 |

37 | 38 |

39 | If you have a crypto-wallet, you can use it in JavaScript with a browser extension. In the case of 40 | Ethereum, the extension will add a global ethereum object into the frontend. With 41 | this object you can use your wallet in your frontend. You can use this connection method to read 42 | and write data to the blockchain, like sending transactions. 43 |

44 | 45 |

46 | If you installed a crypto-wallet browser extension, it will connect to the blockchain network over 47 | an RPC, so the browser doesn't have to use the RPC directly. It will also take care of tasks like 48 | signing, and key management. 49 |

50 | 51 |

52 | In Figure 1, you can see the different types of connections—Web2 and Web3 with and without a 53 | crypto-wallet. 54 |

55 | 56 |
57 | 58 |
59 | Figure 1: Web2 and Web3 "backends" 60 |
61 |
62 | 63 |

64 | In this course, you will start with the read-only connection methods. 65 |

66 | 67 |

You Will Use Ethers.js

68 | 69 |

70 | Ethers.js is software that helps with connecting to the 71 | Ethereum network. You don't have to care if you connect directly over a RPC or use a browser 72 | extension when using Ethers.js. After you start any connection, the functions you call are the same. 73 |

74 | 75 |

76 | Figure 2 shows how Ethers.js fits between your frontend and the Ethereum network. (The image is 77 | not 100% true, because Ethers.js comes with an integrated crypto-wallet, but we won't use it in 78 | the first part of this course.) 79 |

80 | 81 |
82 | 83 |
84 | Figure 2: Blockchain connection with Ethers.js 85 |
86 |
87 | 88 |

89 | Ethers.js is an ECMAScript module on the NPM package registry. This means, you can 90 | import it directly in the browser with the unpkg CDN. 91 |

92 | 93 |
 94 | import {ethers} from "//unpkg.com/ethers@5.5.1/dist/ethers.esm.min.js
 95 | 
96 | 97 |

Connecting to the Ethereum Network

98 | 99 |

100 | You have to create a provider object to connect to the Ethereum network. Providers are the 101 | abstraction Ethers.js uses to normalize RPC use. 102 |

103 | 104 |

105 | You can create such an provider by calling the getDefaultProvider method of the 106 | ethers object you imported before. 107 |

108 | 109 |
110 | Note: This tutorial features a code editor. Here you can write JavaScript code and run it 111 | with the press of a button. The Ethers.js library is imported for you and you can use 112 | await for asynchronous requests. It also has a print function you can 113 | use for output. 114 |
115 | 116 |

117 | The first example is already written to show you how the editor works. Just press the 118 | Execute-button and check the output. 119 |

120 | 121 | 122 | const provider = ethers.getDefaultProvider() 123 | print(provider) 124 | 125 | 126 |

127 | Try it yourself! 128 |

129 | 130 |

131 | To read data from the Etherum network, you can call the getBlock method of the 132 | ethers object. It returns a promise that resolves to an object that has the block's 133 | data, so you need to await it. After you got the block, you can look at its data with 134 | the print function. 135 |

136 | 137 | 138 | const provider = ethers.getDefaultProvider() 139 | // Write your code here! 140 |

141 | const block = await provider.getBlock() 142 | print(block) 143 |

144 |
145 | 146 |

147 | If it worked, you see the block data in the output. This data is all blockchain-specific and 148 | doesn't tell us anything interesting yet. At least, you see that the connection worked, and you 149 | read data from it! 150 |

151 | 152 |

153 | Ethers.js comes pre-configured with a shared RPC you can use for free to read data from the 154 | blockchain. This RPC has a request limit, so it can happen that you don't get a response if you 155 | send too many requests. But for this course, it should be enough. 156 |

157 | 158 |

What did You Learn?

159 | 160 |

161 | In this lesson, you learned how Web2 and Web3 backends are different, while both use HTTP APIs. 162 | We call these APIs RPCs in Web3 because they allow us to remotely call procedures of a blockchain 163 | network. 164 |

165 | 166 |

167 | You also learned how to use a blockchain network with the help of Ethers.js. You didn't have to 168 | install anything, just call a few methods and see what happens. 169 |

170 | 171 |

172 | In the next lesson you will learn how to read address data. 173 |

174 | -------------------------------------------------------------------------------- /01-read-address-data.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web3 From Zero - Lesson 1 7 |

1. Reading Address Data

8 | 9 |

10 | Addresses are the bread and butter of blockchain networks. What IPs are for the Internet, 11 | addresses are for the blockchain. Addresses point to smart contracts and externally owned 12 | accounts (EOAs). 13 |

14 | 15 |

16 | An address number of the length of 20 bytes build from a public key and is usually shown as 40 hex 17 | digits. They look something like this 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045. 18 |

19 | 20 |
21 | Note: An address is used to send and receive data or money, in the form of tokens. Your 22 | money is gone when you send tokens to the wrong address because of a fault. Always check you have 23 | the correct address. No one can help you to get your money back! 24 |
25 | 26 |

27 | An EOA is an address controlled by a private/public key pair owner from outside the Ethereum 28 | network; thus, the name externally owned account. Usually, you use a crypto-wallet to 29 | manage keys and addresses. 30 |

31 | 32 |

33 | A smart contract is software running on the nodes (computers) that make up the blockchain network. 34 | The owner of a smart contract can be another smart contract or an EOA. That's why a smart contract 35 | isn't externally owned. 36 |

37 | 38 |

39 | These addresses, both smart contracts and EOAs, have data tied to them. The Ethereum blockchain 40 | stores this data, and you can read and write it if you have the right permissions. In this lesson, 41 | you will just read data. As you can see in Figure 1, you can't write on the blockchain without a 42 | crypto-wallet. 43 |

44 | 45 |
46 | 47 |
48 | Figure 1: Blockchain connection with Ethers.js 49 |
50 |
51 | 52 | 53 |

Reading the Transaction Count of an Address

54 | 55 |

56 | To read data, you need an Ethers.js provider but also an address. Let's start with the transaction 57 | (TX) count. It's a simple number stored on the blockchain for every address that was part of such 58 | a TX. Ethereum adds 1 to the number if another TX with that address happens. 59 |

60 | 61 |

62 | Ethers.js providers offer a getTransactionCount method that returns a promise that 63 | resolves to a TX count, so you have to await it. 64 |

65 | 66 |

67 | Try it out in the editor! Call the method and print its output. The method expects an 68 | address as string argument, so here a few you can use: 69 |

70 | 71 | 85 | 86 | 87 | const address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" 88 | const provider = ethers.getDefaultProvider() 89 | // Write your code here! 90 |

91 | const transactionCount = await provider.getTransactionCount(address) 92 | print(transactionCount) 93 |

94 |
95 | 96 |

Reading the Balance at an Address

97 | 98 |

99 | Reading the balance of an address is a bit harder than reading the TX count. 100 |

101 | 102 |

103 | Smart contracts and EOAs, have an Ether balance, the native money or the native token of 104 | the Ethereum network. Ether is what you have to pay to do TXs on the Ethereum network. 105 |

106 | 107 |

108 | Using a provider's getBalance method, you can read the Ether balance of an address. 109 | Again, this method returns a promise, so you have to await it. 110 |

111 | 112 |

113 | Try it out in the editor! Call the method and print its output. The method expects an 114 | address as string argument, so here a few you can use: 115 |

116 | 117 | 131 | 132 | 133 | const provider = ethers.getDefaultProvider() 134 | // Write your code here! 135 |

136 | const balance = await provider.getBalance( 137 | "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" 138 | ) 139 | print(balance) 140 |

141 |
142 | 143 |

144 | We got the balance, but why does it look like that? 145 |

146 | 147 |

The BigNumber Type

148 | 149 |

150 | Ethers.js wrapped the balance in its own BigNumber type, because the number can be 151 | too big for JavaScript's Number type to store. You have to change the balance to a 152 | string with the right number of decimal points to display it in a clear way. 153 |

154 | 155 |

156 | One of the biggest things that make Ethereum different from JavaScript are number types. For a 157 | long time, every number was of type Number in JavaScript, which is a double-precision 158 | (64bit) floating-point . Every number was stored like that, because some time ago it got a 159 | new number type called 160 | 161 | BigInt for very large integer numbers. 162 |

163 | 164 |

165 | Everything is an integer number in Solidity, the language used to make smart contracts for 166 | Ethereum. Solidity is concerned with money, and floating-point has problems that can cost you 167 | money, so they went for integer numbers only. Solidity always stores numbers as integers, and the 168 | most used type is uint256 (also known as uint) which can store 78 169 | decimal digits. JavaScript's Number type can only store 16 digits. 170 |

171 | 172 |

173 | Tokens can have more than 16 digits, so they're too big for Number. Addresses are 174 | also stored as integers and are 20 byte big (40 hex digits). 20 byte are 160 bit, so they don't 175 | fit into the 64 bit Number type either. That's why you use a String to 176 | store addresses in JavaScript. 177 |

178 | 179 |

180 | Since Ethers.js wants to keep working with older browsers that don't support BigInt, 181 | they made their own integer type called BigNumber. It comes with 182 | 183 | methods for basic arithmetics, but can also be converted to String or 184 | BigInt when needed. 185 |

186 | 187 |

Converting to a Readable Format

188 | 189 |

190 | The last exercise gave you a BigNumber object that isn't easy to understand. While 191 | it's enough to work with the value inside of our code, you should change it to a 192 | String before you show it to a user. 193 |

194 | 195 |

196 | To do so, you can use 197 | utility 198 | functions Ethers.js includes. The formatUnits function will automatically convert 199 | a BigNumber to a string with the right decimal points. Which is handy to 200 | display a balance to a user. 201 |

202 | 203 |

204 | Try to convert the BigNumber to a string and print it! 205 |

206 | 207 |

208 | The formatUnits function can be found in the ethers.utils object. This 209 | time it returns the output right away, so no await needed. 210 |

211 | 212 | 213 | const address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" 214 | const provider = ethers.getDefaultProvider() 215 | const balance = await provider.getBalance(address) 216 | // Write your code here! 217 |

218 | const readableBalance = ethers.utils.formatUnits(balance) + " ETH" 219 | print(readableBalance) 220 |

221 |
222 | 223 |

Conclusion

224 | 225 |

226 | In this lesson, you learned that addresses are the heart of the Ethereum blockchain and point to 227 | externally owned accounts and smart contracts. 228 |

229 | 230 |

231 | Addresses are 160 bits or 20 bytes integer numbers usually shown as 40 hex digits, and JavaScript 232 | can't store them in its Number type because it's only 8 bytes big. The same is true 233 | for token balances, which can have more than the 16 digits a Number could store. 234 |

235 | 236 |

237 | In the next lesson, you will learn how to use smart 238 | contracts from the frontend. 239 |

-------------------------------------------------------------------------------- /02-connect-to-contracts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web3 From Zero - Lesson 2 7 |

2. Connecting to Smart Contract

8 | 9 |

10 | Smart contracts are the main feature that distinguishes Ethereum from Bitcoin. A smart contract is 11 | a program running on the Ethereum network, and it can access the blockchain data. 12 |

13 | 14 |

15 | You write smart contracts in the Solidity programming language. Like Java, Solidity gets compiled 16 | to a bytecode that runs in a virtual machine. In this case, it's called the Ethereum Virtual 17 | Machine, or EVM for short. 18 |

19 | 20 |

Interacting with Smart Contracts

21 | 22 |

To interact with a smart contract from JavaScript, you need three things:

23 | 24 |
    25 |
  1. The address that points to the smart contract
  2. 26 |
  3. The full or partial Application Binary Interface of the contract
  4. 27 |
  5. A provider that is connected to the Ethereum network
  6. 28 |
29 | 30 |

31 | In the last lesson, you learned, every EOA and smart contract has an address; this is how you find 32 | the contract on the blockchain. 33 |

34 | 35 |
 36 | const address = "0x25ed58c027921E14D86380eA2646E3a1B5C55A8b"
 37 | 
38 |
39 | 40 |

41 | To figure out what functions a contract has to offer, you need an Application Binary Interface, or short ABI, a list 42 | of function signatures of functions you want to call later. Ethers.js uses the ABI to determine what arguments a 43 | function expects and what values it returned when it finished its work. 44 |

45 | 46 |

47 | When using Ethers.js, you can define the ABI as an array of strings, where the strings are 48 | Solidity function signatures, just like you would write them in the Solidity programming language. 49 |

50 | 51 |

Here is an example of an ABI for one function:

52 | 53 |
 54 | const abi = [
 55 |   "function ownerOf(uint256 tokenId) external view returns (address owner)",
 56 | ]
 57 | 
58 |
59 | 60 |

61 | Functions get defined with the function keyword followed by a name and then the 62 | arguments in paratheses. Solidity is statically typed and doesn't support floating points but 63 | integer types of different sizes. 64 |

65 | 66 |

67 | In the example above the function takes one argument of type uint256 and it's named 68 | tokenId. 69 |

70 | 71 |

72 | The external keyword is an access modifier that marks the function as callable from 73 | outside of the contract. 74 |

75 | 76 |

77 | The view keyword is crucial too because it tells the EVM that the function won't 78 | modify any on-chain state; it will just read it. view enables you to call the 79 | function without having a wallet because the Ethereum RPC you use can read all data from its local 80 | copy of the blockchain. 81 |

82 |

83 | The returns keyword tells you what you get back when you call the function. In this 84 | case, it's the owner's address of a token. 85 |

86 | 87 |

88 | The next step is to create a new contract instance and call the ownerOf function 89 | defined by the ABI! 90 |

91 | 92 |

Try it yourself in the editor!

93 | 94 | 95 | const contractAddress = "0x25ed58c027921E14D86380eA2646E3a1B5C55A8b" 96 | const contractAbi = [ 97 | "function ownerOf(uint256 tokenId) external view returns (address owner)" 98 | ] 99 | const provider = ethers.getDefaultProvider() 100 | // Write your code here! 101 |

102 | const smartContract = new ethers.Contract( 103 | contractAddress, 104 | contractAbi, 105 | provider, 106 | ) 107 | const owner = await smartContract.ownerOf(2) 108 | print(owner) 109 |

110 |
111 | 112 |

113 | The owner of the contract, like everything on the blockchain, is located at an address, and this 114 | is just what the function returned. The address could point to another contract that created our 115 | contract, as so called factory contract. The address could also point to an EOA, which is the case 116 | in this example. 117 |

118 | 119 |

Conclusion

120 | 121 |

122 | This lesson taught you about smart contract interaction. How to find them on the blockchain with 123 | the help of a provider and an address and how to call its functions with an ABI. 124 |

125 | 126 |

127 | An ABI is just an array of strings, these strings are function signatures like you would write 128 | them in Solidity, the programming language powering Ethereum. 129 |

130 | 131 |

132 | If you found these addresses a bit cumbersome to work with, I have good news for you. 133 | The next lesson is about the blockchain equivalent of DNS: 134 | The Etherum Name Service. 135 |

-------------------------------------------------------------------------------- /03-using-ens.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Web3 From Zero - Lesson 3 8 |

3. Using the Ethereum Name Service

9 | 10 |

11 | In the previous lesson, you learned about smart contracts and how to connect to them. The next 12 | step is to make this work easier with ENS. 13 |

14 | 15 |

16 | You learned that addresses are to the blockchain what IPs are to the internet. The same goes for 17 | the Ethereum Name Service, short ENS. It's the blockchain equivalent of the Domain Name Service, 18 | or DNS. 19 |

20 | 21 |

22 | ENS can be used to make addresses more accessible for humans. This way you can connect to EOAs and 23 | smart contracts with a human readable string. 24 |

25 | 26 |

27 | You can register ENS domains just like regular domains at the ENS 28 | service website. 29 |

30 | 31 |

Reading a Contract's Balance

32 | 33 |

34 | Ethers.js works transparently with ENS, so we can simply replace the address from the last lesson 35 | with an ENS domain that resolves to that address. In case of that address a corresponding domain 36 | is devdao.eth. 37 |

38 | 39 |

40 | Try it in the editor. Fetch the balance of the Developer DAO NFT contract and print it. But use 41 | the devdao.eth ENS domain instead of the address! 42 |

43 | 44 | 45 | const provider = ethers.getDefaultProvider() 46 | // write your code here! 47 |

48 | const balance = await provider.getBalance("devdao.eth") 49 | print(ethers.utils.formatUnits(balance) + " ETH") 50 |

51 |
52 | 53 |
54 | Note: Keep in mind, the target blockchain address of a ENS domain can change. So if 55 | you want to make sure that the same address is called every time, use the 56 | address directly. 57 |
58 | 59 |

Conclusion

60 | 61 |

62 | ENS domains are a usability imporvement for the blockchain. Just like DNS domains were for the 63 | internet in general. Remembering devdao.eth is much easier than a big hex number. 64 |

65 | 66 |

67 | Ethers.js works transparently with ENS domains, so you can usually drop-in a domain in places 68 | where you need an address. 69 |

70 | 71 |

72 | In the next lesson, we will learn about Ethereum Request for Comments, or short ERCs. 73 |

-------------------------------------------------------------------------------- /04-ercs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Web3 From Zero - Lesson 4 8 |

4. Ethereum Request for Comment

9 | 10 |

11 | When building decentralized systems, one of the most crucial parts is how they interact. You 12 | learned that a smart contract has public functions, but you also need an ABI to 13 | call them. 14 |

15 | 16 |

17 | You might be able to reverse engineer the ABI in some way, for example, by reading the 18 | source code. But sadly, not all smart contracts are open source. This makes the task quite 19 | cumbersome. 20 |

21 | 22 |

Enter Ethereum Request for Comments

23 | 24 |

25 | Luckily the creators of Ethereum saw this problem early on and focused on interopt between smart 26 | contracts. The result is the Ethereum request for comments or short ERCs. They can contain specs 27 | for interfaces a smart contract has to implement. 28 |

29 | 30 |

31 | The process goes as follows: Things aren't going smoothly for some reason or another, and users 32 | want to solve it. They write an Ethereum Improvement Proposal (EIP) and layout what could be 33 | better. Next, the Ethereum Committee will approve the EIP if it's okay and create an ERC based on 34 | the EIP. 35 |

36 | 37 |

38 | This process leads to new ways for smart contract interopt and makes it easier to mix and match 39 | smart contracts in Web3 applications. 40 |

41 | 42 |

ERC-20 & ERC-721 Token Standards

43 | 44 |

45 | The most prominent ERCs are ERC-20 for 46 | fungible tokens, commonly known as cryptocurrencies or simply tokens, and 47 | ERC-721 for non-fungible tokens, known as 48 | NFTs. 49 |

50 | 51 |

52 | While critical functions of smart contracts are usually bound to specific addresses, many are 53 | external without any permissions so that you can call them via Ethers.js. 54 |

55 | 56 |

Creating an ERC-721 Read-Only ABI

57 | 58 |

59 | If you know the address of a smart contract that mints NFTs, you can go and search for an ERC-721 60 | ABI and use it together with the address to call it. 61 |

62 | 63 |

64 | The standardized Solidity interface for an ERC-721 contract looks like this: 65 |

66 | 67 |
 68 | interface ERC721 {
 69 |     event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
 70 |     event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
 71 |     event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
 72 | 
 73 |     function balanceOf(address _owner) external view returns (uint256);
 74 |     function ownerOf(uint256 _tokenId) external view returns (address);
 75 |     function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
 76 |     function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
 77 |     function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
 78 |     function approve(address _approved, uint256 _tokenId) external payable;
 79 |     function setApprovalForAll(address _operator, bool _approved) external;
 80 |     function getApproved(uint256 _tokenId) external view returns (address);
 81 |     function isApprovedForAll(address _owner, address _operator) external view returns (bool);
 82 | }
 83 | 
84 |
85 | 86 |

87 | We learned in lesson 2 that we can convert this to an ABI for Ethers.js by simply copying the 88 | function signatures as strings into a JavaScript array. 89 |

90 | 91 |
 92 | const erc721Abi = [
 93 |   "function balanceOf(address _owner) external view returns (uint256)",
 94 |   "function ownerOf(uint256 _tokenId) external view returns (address)",
 95 |   "function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable",
 96 |   "function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable",
 97 |   "function transferFrom(address _from, address _to, uint256 _tokenId) external payable",
 98 |   "function approve(address _approved, uint256 _tokenId) external payable",
 99 |   "function setApprovalForAll(address _operator, bool _approved) external",
100 |   "function getApproved(uint256 _tokenId) external view returns (address)",
101 |   "function isApprovedForAll(address _owner, address _operator) external view returns (bool)",
102 | ]
103 | 
104 |
105 | 106 |

107 | Now, since we don't have covered wallets yet, we are only able to call the view 108 | functions, so let's throw the rest out. 109 |

110 | 111 |
112 | const erc721ReadOnlyAbi = [
113 |   "function balanceOf(address _owner) external view returns (uint256)",
114 |   "function ownerOf(uint256 _tokenId) external view returns (address)",
115 |   "function getApproved(uint256 _tokenId) external view returns (address)",
116 |   "function isApprovedForAll(address _owner, address _operator) external view returns (bool)",
117 | ]
118 | 
119 |
120 | 121 |

122 | Try to get the owner of tokenId 5666 for the NFT contract located at 123 | 0x25ed58c027921E14D86380eA2646E3a1B5C55A8b, using the ABI we defined above and 124 | print the result! 125 |

126 | 127 |

128 | You can use the lookupAddress method of the provider to get the ENS domain that points to an address. 129 | Try that for the owner address of the token. 130 |

131 | 132 | 133 | const provider = ethers.getDefaultProvider() 134 | // Write your code here! 135 |

136 | const erc721ReadOnlyAbi = [ 137 | "function balanceOf(address _owner) external view returns (uint256)", 138 | "function ownerOf(uint256 _tokenId) external view returns (address)", 139 | "function getApproved(uint256 _tokenId) external view returns (address)", 140 | "function isApprovedForAll(address _owner, address _operator) external view returns (bool)", 141 | ] 142 | 143 | const contractAddress = "0x25ed58c027921E14D86380eA2646E3a1B5C55A8b" 144 | 145 | const smartContract = new ethers.Contract( 146 | contractAddress, 147 | erc721ReadOnlyAbi, 148 | provider 149 | ) 150 | 151 | const ownerAddress = await smartContract.ownerOf(5666) 152 | 153 | const ownerDomain = await provider.lookupAddress(ownerAddress) 154 | 155 | print(ownerDomain) 156 |

157 |
158 | 159 |

Summary

160 | 161 |

162 | In this lesson you learned about ERCs. How they standardize interfaces and behavior to help you 163 | using these contracts and also allow other contrats to interact with them. 164 |

165 | 166 |

167 | We also converted a Solitidy interface defined in the ERC-721 to a ABI you can use with Ethers.js. 168 |

169 | 170 |

171 | In the next lesson, you will build your very first Web3 app! 172 |

-------------------------------------------------------------------------------- /05-example-app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Web3 From Zero - Lesson 5 6 | 7 |

5. Building an Example App

8 | 9 |

10 | Now that you know how to connect to the Ethereum network with its smart contracts and find 11 | out which functions a smart contract provides, you can finally implement our first small app! 12 |

13 | 14 |

Building the App

15 | 16 |

This lesson is more hands-on, which means you have to build your app on your own!

17 | 18 |

19 | Since you didn't learn about wallets, you can't change anything on the blockchain, but 20 | you can read what's already been written on it by other people around the world. But you get some 21 | pointers, so you know how to start. Also, I've already written the app so that you can check out a 22 | working example. 23 |

24 | 25 |

NFT Owner Finder

26 | 27 |

28 | The app is an NFT owner finder. A frontend (a simple HTML page is 29 | enough) for the ERC271 specification. You already used this spec in the previous lesson. 30 |

31 | 32 |

33 | The idea is a user can enter a contract address and token ID, and the app will ask the 34 | Ethereum network for the address of the token owner. 35 |

36 | 37 |

38 | Bonus points for additional information you display in that app: 39 |

40 | 41 | 53 | 54 |

Conclusion

55 | 56 |

57 | This lesson concludes the first part of this course. You learned most of the things you can do 58 | without your wallet. 59 |

60 | 61 |

62 | You learned about the basic architecture of the Ethereum network how to connect to it via public 63 | RPCs and Ethers.js and how to do fundamental interactions with smart contracts on the chain. 64 |

65 | 66 |

67 | You also got introduced to the Ethereum Name Service, which makes interactions with addresses 68 | easier. 69 |

70 | 71 |

72 | In this final lesson, you even build your first app! 73 |

74 | 75 |

What's Next?

76 | 77 |

78 | The next part of this course will introduce you to wallets and transactions, so you can finally 79 | make a change! You will do all this with test networks, so you don't have to pay the enormous gas 80 | fees currently hampering the Ethereum network. 81 |

-------------------------------------------------------------------------------- /06-public-and-private-keys.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Web3 From Zero - Lesson 6 6 | 7 |

6. Public & Private Keys

8 | 9 |

10 | I wanted to start part two of this course with crypto-wallets. Because they will be the software, 11 | you need to install and set up for part II. But I thought the keys are only a part of the things a 12 | crypto-wallet manages for you and the most important part. So, I think keys should have their own 13 | lesson. 14 |

15 | 16 |
17 | This lesson won't go into the details of elliptic curve cryptography (ECC). There are better 18 | resources to understand this topic. If you want to learn the technical details, I recommend 19 | the free ebook Practical Cryptography for Developers that has 20 | 21 | a part that explains ECC 22 | . 23 |
24 | 25 |

Security Best Practices

26 | 27 |

28 | If I learned one thing about cryptography, it's that you should never ever give away your 29 | private key or seed phrase. If you don't understand anything from the book I linked before 30 | or written in this lesson, at least keep that small piece of know-how in mind. 31 |

32 | 33 |

34 | This rule means you should only ever type your private key in a secure crypto-wallet app and never 35 | in a text file on your PC or smartphone. It's too long for the usual human to remember without 36 | much work, so for backup write it down on paper. This way no one who uses your computers 37 | can read it from your hard drive. 38 |

39 | 40 |

41 | In some countries, you might fear that the government will be after your keys, but the more likely 42 | threat is your house burning down or water damage. So, make sure you have copies at different safe 43 | locations. 44 |

45 | 46 |

47 | If you need a private key for development and tests that you will hard-code in a source file, make 48 | sure you don't use this development key for your everyday crypto dealings. This way, it's not so 49 | bad when your key ends up on GitHub, S3, etc. 50 |

51 | 52 |

53 | The same goes for your seed phrase, which is a way to write down a private key as a list of short 54 | words. As a developer, you work directly with private keys, but end-users use their private key in 55 | the form of a seed phrase when they move it around between crypto-wallets and paper. 56 |

57 | 58 |

59 | It's also good to know that you shouldn't show people your addresses and public keys without a 60 | good reason. While no one can directly steal your tokens without your private key, an attacker 61 | can send tokens to your address for phishing. These could lead you to some web apps that try to 62 | scam you into using your private key to do something dumb. 63 |

64 | 65 |

What are Keys?

66 | 67 |

68 | A key, private or public, is just some kind of data. In the specific case of ECC, these two keys 69 | are very big numbers. So big that you will store them as string or 70 | BigIntegerin JavaScript. 71 |

72 | 73 |
74 | 75 |
76 | Figure 1: ECC Keys 77 |
78 |
79 | 80 |

Private Key

81 | 82 |

83 | A private key for ECC is a randomly generated integer that can look something like this in hexadecimal:
84 | 57cfa2d774eab59998a0b87d641b504aaefeae12f244db08d77e019e6d90afb9 85 |

86 | 87 |

88 | In Ethereum and many other blockchain networks, this key must be smaller than a special prime 89 | number. 90 |

91 | 92 |

93 | This big prime number looks like this in hexadecimal:
94 | fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f 95 |

96 | 97 |

98 | The reason why this exact prime number is used is out of the scope of this course (you can 99 | read about it in the book I linked above). But the limit set by that prime number is important! 100 | Not every random integer is a valid private key, and if you want to generate your own, it has to 101 | be smaller than that prime number. 102 |

103 | 104 |
105 |   let privateKey
106 | 
107 |   do {
108 |     privateKey = generateRandomInteger()
109 |   } while(privateKey > 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn)
110 | 
111 | 112 |

Public Key

113 | 114 |

115 | A public key for ECC is two integers that are concatenated together. Both of these integers can 116 | have the private key length, but they aren't random. These two numbers are calculated from the 117 | private key. 118 |

119 | 120 |

121 | A public key can look like this:
122 | 0453a07319d6d7a34d1bf3363415a316c0f5cd4cb5fe49f414b1c9d7b420169b652cf466ed56ec01733a9726ee27017ad66e384eefc2d6897aa61d3157cc1273eb 123 |

124 | 125 |

126 | The function used to calculate a public key from a private key is based on a specific algorithm 127 | and some predefined parameters. All systems interacting with the Ethereum network have to use the 128 | same algorithm and parameters to get the same results. 129 |

130 | 131 |
132 |   let privateKey
133 | 
134 |   do {
135 |     privateKey = generateRandomInteger()
136 |   } while(privateKey > 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn)
137 | 
138 |   const publicKey = generatePublicKey(privateKey)
139 | 
140 | 141 |

Seed Phrase

142 | 143 |

144 | A seed phrase, also known as a secret recovery phrase, is a list of 12-24 short random words used 145 | to generate one or more private keys and, in turn, public keys and addresses in the end. 146 |

147 | 148 |

149 | A seed phrase could look like this:
150 | forget wing follow flip swallow achieve correct view dinner witness hybrid proud 151 |

152 | 153 |

154 | While you can generate a private key directly, many crypto-wallet apps use a seed phrase to 155 | generate them for you. Many people use multiple addresses, and if you're developing with Ethereum 156 | and using it for day-to-day things, you will at least need two addresses and two private keys. 157 |

158 | 159 |

160 | The idea of a seed phrase is that it's a random list of words, but the algorithm to generate 161 | multiple private keys from that phrase is deterministic. This allows to generate multiple keys 162 | from one phrase and recover all these keys from one seed phrase. Otherwise, you would have to 163 | write down every single private key on its own. 164 |

165 | 166 |
167 |   const seedPhrase = [
168 |     "forget", "wing", "follow",
169 |     "flip", "swallow", "achieve",
170 |     "correct", "view", "dinner",
171 |     "witness", "hybrid", "proud"
172 |   ]
173 | 
174 |   const keyGenerator = initKeyGenerator(seedPhrase)
175 |   
176 |   const keys = []
177 |   for(let i = 0; i < 10; ++i) {
178 |     const privateKey = keyGenerator(i)
179 |     const publicKey = generatePublicKey(privateKey)
180 |     const address = keccak256(publicKey).toString().slice(0,20)
181 |     keys.push({ privateKey, publicKey, address})
182 |   }
183 | 
184 |
185 | 186 |

187 | The downside of this is that if your seed phrase gets stolen, all private keys generated from it 188 | are stolen too. This means everything true for your private key is also true ten-fold for your 189 | seed phrase because it's the same as multiple private keys. 190 |

191 | 192 |

193 | Never write your seed phrase down on your PC or smartphone outside of a crypto-wallet app, 194 | never store it in an S3 bucket, or GitHub, etc. To recover your keys when you lose your 195 | smartphone or laptop, or they break, you can write the seed phrase on a piece of paper and store 196 | it in a safe location. 197 |

198 | 199 |

What are the Keys Used for?

200 | 201 |

202 | So, you know what the keys are and how you should handle them, but what exactly is their purpose? 203 |

204 | 205 |

206 | Private and public keys are used for different tasks. Their usage follows from the fact that 207 | everyone can have your public keys, and no one should ever have your private keys. 208 |

209 | 210 |

Signing Messages with the Private Key

211 | 212 |

213 | The private key is used mainly to sign data. Signing means you attach a signature to the data. 214 | A signature is created with a signature algorithm that uses your private key and the data that 215 | needs to be signed. 216 |

217 | 218 |

219 | The idea is that the signature data can't be generated without having the private key. 220 |

221 | 222 |

223 | A signature could look like this in its Base64 version:
224 | MEQCIEamErEp0wjW2nBCwPJyMWB1UEb8UHaEFeUDko88MOs/AiB5daIS5j1stXRetBsEWbvd0TeoYsfucmADmxFUxbE2oQ== 225 |

226 | 227 | 228 |

229 | The public key is used to verify that signature. If you sign something with a private key, the 230 | related public key, in combination with a signing algorithm, the signature, and the signed data, 231 | will either lead to a "yes, this signature is from the correct private key" or not. 232 |

233 | 234 |

235 | Since you are the only one who has your private keys, you are the only one who can create these 236 | signatures. If your keys get stolen, other people can pretend they are the original owners (i. e. 237 | you). If you lose your private key, you can't create correct signatures anymore, and systems with 238 | your public key won't believe that you are indeed who you pretend to be. 239 |

240 | 241 |

242 | In Figure 2, you see how the three parts interact with each other. 243 |

244 | 245 |
246 | 247 |
248 | Figure 2: Signing and verification 249 |
250 |
251 | 252 |

Enctypting Messages with the Public Key

253 | 254 |

255 | You learned you can use the public key to verify a signature, but that's not all it can do. The 256 | public key can also encrypt a message that only the corresponding private key can decrypt. 257 |

258 | 259 |

260 | If you want to use asymetric encryption to communicate privately, you have to exchange public keys. 261 | Everyone with your public key can then send you messages that only you can read. 262 |

263 | 264 |

265 | Figure 3 shows the simplified process. For performance reasons, the message in that picture is 266 | usually not the actual data you want to send, but a symmetric encryption key that will be 267 | exchanged with the private key holder and then used to encrypt/decrypt all messages flowing 268 | between the two parties. 269 |

270 | 271 |
272 | 273 |
274 | Figure 3: Encryption and decryption 275 |
276 |
277 | 278 |

Conclusion

279 | 280 |

281 | In this lesson, you learned that keys are just numbers. Very big numbers, that have specific 282 | properties. They are often displayed in hexadecimal, which makes things a bit confusing for 283 | beginners. 284 |

285 | 286 |

287 | These keys are used together with ECC-based algorithms and in the case of Ethereum, with a 288 | specific set of parameters that are the same in the whole Ethereum network to ensure, all 289 | participants have the same results when signing and verifying data. 290 |

291 | 292 |

293 | In the next lesson, you will learn more about 294 | externally owned accounts, and how they relate to the keys we discussed here. 295 |

-------------------------------------------------------------------------------- /07-externally-owned-accounts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web3 From Zero - Lesson 7 7 | 8 |

7. Externally Owned Accounts

9 | 10 |

11 | In the last lesson we talked about keys, what they are, how they are used, and how they relate to 12 | each other. 13 |

14 | 15 |

16 | In this lesson, you will learn how keys are related to addresses and how they together form the 17 | basis for externally owned accounts (EOAs). 18 |

19 | 20 |

Address Recap

21 | 22 |

23 | In Part I, you learned that addresses are to a blockchain are like IPs are to the internet, but 24 | how are addresses related to keys? 25 |

26 | 27 |

28 | An address is a 20 byte (160 bit) long integer that gets calculated from the public key and it can 29 | look like this:
30 | 0xdd00Cc906B93419814443Bb913949d503B3DF3c4 31 |

32 | 33 |
34 | 35 |
36 | Figure 1: ECC Keys 37 |
38 |
39 | 40 |

41 | The 0x usually indicates a hex number, and the length was chosen to allow for enough addresses in 42 | the future while still being short enough for everyday usage. 43 |

44 | 45 |

46 | The public key gets hashed with 47 | 48 | Keccak-256 49 | , and the first 20 bytes of this hash become the address for an EOA controlled by the related 50 | key pair. 51 |

52 | 53 |

Exercise: Create an Address from a Public Key With Ethers

54 | 55 |

56 | Ethers comes with a few utility functions that allow you to create an address from a public key 57 | step by step. 58 |

59 | 60 |

61 | The example comes with a random pair of keys, and you have to create the address yourself. Keep in 62 | mind that the public key comes with a 0x04 prefix that indicates its in the 63 | uncompressed version and is not part of the key. 64 |

65 | 66 |

67 | The functions you need are: 68 |

69 | 70 | 74 | 75 |

76 | You can look at wallet.address to check if the key is correct. 77 |

78 | 79 | 80 | const { hexDataSlice, keccak256 } = ethers.utils 81 | const { address, privateKey, publicKey } = ethers.Wallet.createRandom() 82 | 83 | // Write your code here! 84 |

85 | const keyWithoutPrefix = hexDataSlice(publicKey, 1) // remove 0x04 86 | const hashedKey = keccak256(keyWithoutPrefix) 87 | const myAddress = hexDataSlice(hashedKey, 12) 88 | print(address) 89 | print(myAddress) 90 |

91 |
92 | 93 |

94 | Ethereum uses letter casing in the address as a checksum. While the addresses work independently 95 | of casing, it is sometimes used to check the integrity of an address. 96 |

97 | 98 |

How do Addresses Relate to Externally Owned Accounts?

99 | 100 |

101 | As the name implies, an EOA is an account that is controlled from outside the blockchain network. 102 | The private key that was used to create the address isn't on chain and the person owning it is 103 | also external to the blockchain network. 104 |

105 | 106 |

107 | The arrows in figure 2 show who controls which address and where, in relation to the blockchain 108 | network, each controller is located. 109 |

110 | 111 |
112 | 113 |
114 | Figure 2: Externally Owned Account 115 |
116 |
117 | 118 |

119 | The address controlled by an external private key is an EOA, the other addresses are controlled by 120 | smart contracts, and thus, not EOA. 121 |

122 | 123 |

Spending Tokens

124 | 125 |

126 | Now, that we know how keys relate to addresses and what EOAs are, let's look at an example. Say 127 | you want to send tokens from one address to another. 128 |

129 | 130 |

131 | You have to send your address, the target address, and the amount of tokens you want to spend, to 132 | the Ethereum network. You have to send your public key too, so the nodes on the network can verify 133 | that it's a legit transaction. 134 |

135 | 136 |

137 | The transaction is checked for two facts. 138 |

139 | 140 |
    141 |
  1. Does the transaction include the correct public key?
  2. 142 |
  3. Do you own the private key related to this public key?
  4. 143 |
144 | 145 |

146 | Since your address is generated from your public key, the Ethereum nodes know if you send a key 147 | that doesn't belong to your address. They can run the hash algorithm on the public key, look at 148 | the first 20 bytes, and compare them to your address. 149 |

150 | 151 |

152 | The next step is to verify that you also have the correct private key. Only private key owners can 153 | spend money of an address. 154 |

155 | 156 |

157 | To check this, the nodes will send you a random message and you will sign it with the private key 158 | you used to generate the public key. Since they already have your public key, they can use it to 159 | check if your signature is correct. If you used the wrong private key to sign, this check will 160 | fail and your trasaction will be rejected. 161 |

162 | 163 |

164 | There is still risk here. The Ethereum network will take any vaild address as a target for your 165 | transaction. If you make a typo, your funds may end up at an address that no one has a private key 166 | for and they are lost. 167 |

168 | 169 |

Receiving Tokens

170 | 171 |

172 | Receiving tokens is more easy, but doesn't come without risk either. 173 |

174 | 175 |

176 | Anyone can send funds to any valid address. So, if someone knows your address, they can send you 177 | tokens, wether you like it or not. 178 |

179 | 180 |

181 | The usual case is that you sold a good or service, and someone will pay you by sending tokens to 182 | your address. You have to make sure your address doesn't have any typos, but that's it. 183 |

184 | 185 |

186 | Special cases are airdrops. When a project or person does an airdrop, it means they send tokens to 187 | addresses that have specific criteria. Like, used a service, or held a special NFT before some 188 | date. 189 |

190 | 191 |

192 | Usually an airdrop is a good thing, because you get free tokens. But scammers use airdrops to 193 | phish you. They randomly send you some token which might lead you to investigate. You can end up 194 | on a suspicious site that asks you for your private key or to sign a scam transaction. 195 |

196 | 197 |

Summary

198 | 199 |

200 | EOAs are addresses controlled by an external private key instead of a on-chain smart contract. 201 |

202 | 203 |

204 | The relation between private key, public key, and address allows the blockchain network to verify 205 | all transactions can only come from controllers of the correct private keys. 206 |

207 | 208 |

209 | Sending tokens around still bears the risk of typos. Also, when you lose your private key or it 210 | gets stolen, all tokens on that address are lost. This is especially crucial for developers! Make 211 | sure you always use private keys dedicated to development only, so if you accidentally upload them 212 | to a public code repository, nothing of value is stolen. 213 |

214 | 215 |

216 | In the next lesson, you will learn about wallets and 217 | how to set up your own via Ethers.js. 218 |

-------------------------------------------------------------------------------- /08-crypto-wallet-setup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web3 From Zero - Lesson 8 7 | 8 |

8. Crypto Wallet Setup

9 | 10 |

11 | We know how public key cryptography works, even if just in essence. We know that a EOA is a 12 | blockchain address that is controlled by the holder of a related public/private key pair. But how 13 | come crypto wallets into play? 14 |

15 | 16 |

What is a Crypto Wallet?

17 | 18 |

19 | A crypto wallet, or simply wallet, is a mechanism to manage your keys, some are even able to 20 | manage your blockchain connections. 21 |

22 | 23 |

24 | There are different types of wallets, so let's get a small overview on the essentials. 25 |

26 | 27 |

1. Wallet App

28 | 29 |

30 | A wallet app is a dedicated application that manages your keys and blockchain connections. Some 31 | can connect to different types of blockchains, some only understand one specific blockchain 32 | network. 33 |

34 | 35 |

36 | Since a wallet app is software, it comes with the danger of being hacked if it's installed on a 37 | device that has an internet connection. 38 |

39 | 40 |

41 | MetaMask is probably the most popular wallet app for the Ethereum network. You can enter your keys 42 | into it, or even let it generate keys for your with a seed phrase. It allows you to add and remove 43 | RPCs for different chains, and comes preconfigured with Ethereum mainnet and it's test networks. 44 |

45 | 46 |

47 | To connect a wallet app with a Web3 app, you either need a browser extension that links the wallet 48 | you installed on your PC or Mac with the browser or, if you're using the mobile version, you need 49 | to scan a QR code displayed on the Web3 app. 50 |

51 | 52 |

2. Paper Wallet

53 | 54 |

55 | A paper wallet is simply a piece of paper with all your keys, addresses, or your seed phrase 56 | written down. It can't do much, since it's not software, but at least you don't have to remember 57 | all this information on your own. 58 |

59 | 60 |

61 | With a paper wallet you can't send any tokens, but if you tell people one of the addresses you 62 | written on it, you can at least receive them. 63 |

64 | 65 |

66 | Also, it can't get hacked online, because it can't be connected to the internet. This makes 67 | paper wallet quite safe. Depending on the material of the wallet and the risk of burglaries in 68 | your location, it can be susceptible to other problems. Also, like everything else, you can simply 69 | lose it. 70 |

71 | 72 |

3. Hardware Wallets

73 | 74 |

75 | Hardware wallets are devices that store your keys, addresses, and seed phrases. They keep your 76 | private keys always on the device and never make them public. If you need to sign a message with a 77 | private key, you have to send the message to the wallet and it will respond with the signature. 78 |

79 | 80 |

81 | Hardware wallets have standardized interfaces and work in tandem with wallet apps. So, you can see 82 | them as an extension of a wallet app that makes it more secure. 83 |

84 | 85 |

4. Programmatic Wallet

86 | 87 |

88 | Since all these digital wallets talk to each other and DApps via standardized interfaces, it might 89 | not come as a surprise that there is an API for this. 90 |

91 | 92 |

93 | What a software library is to an app, is a programmatic wallet to an wallet app. It's just a piece 94 | of software that is controlled with code; no UI, no CLI, just code. 95 |

96 | 97 |

98 | Ethers.js offers such a programmatic wallet with its concepts of Singers, which are an abstraction 99 | over different account types. One of them is Wallet. 100 |

101 | 102 |

103 | Wallet is a class you can create an object from that works directly with an RPC. This 104 | way you can actually write something on the blockchain without installing additional software! 105 |

106 | 107 |

Recap of the Blockchain Network Connection

108 | 109 |

110 | In Part 1 of this course, we talked about how crypto wallets form a layer between your browser and 111 | the blockchain network of your choice. Figure 1 shows where a wallet is usually located in the 112 | stack. 113 |

114 | 115 |

116 | The blockchain connection with wallet part of the image shows that the wallet handles the 117 | connection to the RPC, and the browser doesn't know anything about it. 118 |

119 | 120 |
121 | 122 |
123 | Figure 1: Blockchain connection with Ethers.js 124 |
125 |
126 | 127 |

128 | As you just learned, Ethers.js can work as a wallet too! So, we can connect to a RPC with 129 | Ethers.js and also use it to sign transactions, which are the mechanism to write on the 130 | blockchain. 131 |

132 | 133 |

Creating a Development Key

134 | 135 |

136 | If you're developing with a blockchain, never use private keys that control addresses with your 137 | personal assets on it! Create one or more development keys, via a seed phrase or the random key 138 | generator of Ethers.js. 139 |

140 | 141 |

142 | If you have to do transactions in development that require tokens, be it for deployments or simply 143 | to test your code, you need to save the keys somewhere for later use. If you don't need any tokens 144 | for an action, you can just take a new random Wallet every time. 145 |

146 | 147 |

148 | The following example creates a random Wallet every time you run it. Copy one of the 149 | private keys and use it as your development key. 150 |

151 | 152 | 153 | const wallet = ethers.Wallet.createRandom() 154 | print(wallet.privateKey) 155 | 156 | 157 |
158 | Note: You shouldn't copy your private keys around and save them in an insecure way, but 159 | since a development key doesn't have any tokens, it's not a problem if it gets stolen. Just create 160 | a new one and delete the old one if that happens. 161 |
162 | 163 |

Using a Development Key

164 | 165 |

166 | Let's use that key! Try to construct a new Wallet object, pass it your copied private 167 | key from above, and print the public key and address it generates. 168 |

169 | 170 |

171 | Also, copy the address, so you have it handy for the later lessons. 172 |

173 | 174 | 175 | // Write your code here! 176 |

177 | const wallet = new ethers.Wallet( 178 | "0x350690562a6c31051d2c9f085e0b91be0a4ac0a3c206998c89ff3cfedf3524d0" 179 | ) 180 | 181 | print(wallet.publicKey) 182 | print(wallet.address) 183 |

184 |
185 | 186 |

Connecting a Wallet with a Provider

187 | 188 |

189 | Now, that you can create wallets from an existing private key, let's try to connect a wallet to a 190 | provider. 191 |

192 | 193 |

194 | To establish a connection the wallet object offers a connect method which will create 195 | a new wallet that is connected to the provider. 196 |

197 | 198 |

199 | Try to create a connected wallet and use it's getGasPrice method to check if the 200 | connection works. Keep in mind that this method is asynchronous, and the price will be a 201 | BigNum object. 202 |

203 | 204 | 205 | // Write your code here! 206 |

207 | const wallet = new ethers.Wallet( 208 | "0x350690562a6c31051d2c9f085e0b91be0a4ac0a3c206998c89ff3cfedf3524d0" 209 | ) 210 | 211 | const connectedWallet = wallet.connect(ethers.getDefaultProvider()) 212 | 213 | const gasPrice = await connectedWallet.getGasPrice() 214 | 215 | print(ethers.utils.formatEther(gasPrice) + " ETH") 216 |

217 |
218 | 219 |

Summary

220 | 221 |

222 | In this lesson, you learned about different types of wallets, and that you can use a programmatic 223 | wallet for development. This way, you don't have to install any additional software. 224 |

225 | 226 |

227 | You also learned how to connect a wallet with a provider, which will be important for the 228 | following lessons. As I said before, you need a wallet to send transactions to a blockchain 229 | network. 230 |

231 | 232 |

233 | In the next lesson, you will learn about test networks and how 234 | to request test tokens from token faucets. 235 |

-------------------------------------------------------------------------------- /09-test-networks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web3 From Zero - Lesson 9 7 | 8 |

9. Test Networks

9 | 10 |

11 | Building software requires you to test before you release. The usual development process goes from 12 | running things on your local computer, to running it on a test system, to running it on the 13 | production system. 14 |

15 | 16 |

17 | This process also holds true for Web3 development. You install a local blockchain network on your 18 | own machine to test the basic functionality of your smart contracts and later you deploy the 19 | system onto a test network, to make sure it still works togeher with many other smart contracts 20 | you might use in your application. 21 |

22 | 23 |

24 | Test networks enable testing on real infrastructure without spending real tokens, and in turn, 25 | real money. A TX on the Ethereum network can easily cost $10, so when you're just testing and 26 | sending hundreds of TXS a day, this can get costly quick! With free test tokens that's not an 27 | issue anymore. 28 |

29 | 30 |

31 | Also, if you accidentally push a development key to a public repository, you won't lose anything 32 | but the worthless test tokens you put on that address. 33 |

34 | 35 |

36 | This is why you had to copy a private key in the previous lesson. You need an address you can 37 | reuse so you can get tokens on it and spend them for gas or to do transactions that require 38 | payment. 39 |

40 | 41 |
42 | Note: We will go into the details of gas costs later. This lesson is just about connecting 43 | to a test network and getting our first tokens! 44 |
45 | 46 |

Connecting to a Test Network

47 | 48 |

49 | In Part I of this course, you learned how to use providers to connect to a blockchain network. You 50 | simply called the ethers.getDefaultProvider method and got a provider to read data 51 | from the chain. 52 |

53 | 54 |

55 | The default provider connects, by default, to the Ethereum main network. Which is the production 56 | environment of Ethereum. If you want to connect to a test network, you have to use the first 57 | parameter of that method. In our case it will be "goerli". 58 |

59 | 60 |
61 | Note: Görli is one of Ethereum test networks, Ethers.js knows about it, so we can simply 62 | use the name. For other networks that are compatible with Ethers.js, you need more configuration. 63 |
64 | 65 |

66 | The code is similar to the last lesson, but this time, I want you to call getChainId 67 | to ensure you're connected to the test network. The correct ID is 5. 68 |

69 | 70 | 71 | // Write your code here! 72 | 73 |

74 | const wallet = new ethers.Wallet( 75 | "0x350690562a6c31051d2c9f085e0b91be0a4ac0a3c206998c89ff3cfedf3524d0" 76 | ) 77 | 78 | const provider = ethers.getDefaultProvider("goerli") 79 | 80 | const connectedWallet = wallet.connect(provider) 81 | 82 | const chainId = await connectedWallet.getChainId() 83 | 84 | print(chainId) 85 |

86 |
87 | 88 |

Getting Test Tokens

89 | 90 |

91 | Now that you know how to connect to a test network, we will go back to the question why I asked 92 | you to copy a private key and address. 93 |

94 | 95 |

96 | On blockchain networks you have to pay for writing actions, which means sending transactions. If 97 | you send an TX from an address that doesn't own enough of the networks native token, your TX won't 98 | get executed. So, if you create random private keys for development all the time, they will never 99 | have any tokens to pay for anything. 100 |

101 | 102 |

103 | To fix this, you create one or more private key for development, load them up with tokens, and 104 | use them to pay for your TXS. While you have to buy tokens on the main network, you can get them 105 | for free from a token faucet. 106 |

107 | 108 |

109 | A faucet is a website, where you enter the address of your development account, and it will send 110 | you test network tokens for free. 111 |

112 | 113 |

114 | Choose one of the following faucets to request test tokens for the address that belongs to the 115 | private key you copied in the last lesson. 116 |

117 | 118 | 128 | 129 |

130 | If your choosen faucet accepted your request, you want to check out if it worked and you got your 131 | tokens. You can do this in multiple ways. One is to go on 132 | Etherscan, a blockchain explorer, 133 | enter the address you used in the faucet and search for it. 134 |

135 | 136 |
137 | Note: Etherscan is a search engine for addresses. Everything on-chain is public and you can 138 | browse it freely. 139 |
140 | 141 |

142 | The second way is to check the balance programmatically with Ethers.js. So, try it yourself. 143 | Connect to the Görli testnet, and call the getBalance method on your wallet. It is 144 | asynchronous and returns a BigNum. 145 |

146 | 147 | 148 | // Write your code here! 149 |

150 | const wallet = new ethers.Wallet( 151 | "0x350690562a6c31051d2c9f085e0b91be0a4ac0a3c206998c89ff3cfedf3524d0" 152 | ) 153 | 154 | const provider = ethers.getDefaultProvider("goerli") 155 | 156 | const connectedWallet = wallet.connect(provider) 157 | 158 | const balance = await connectedWallet.getBalance() 159 | 160 | print(`${connectedWallet.address} owns ${ethers.utils.formatEther(balance)} ETH`) 161 |

162 |
163 | 164 |

165 | If everything went correctly, the balance of your address should be higher than 0. 166 |

167 | 168 |

Summary

169 | 170 |

171 | In this lesson you learned what tests networks are and how they fit inside your development 172 | processes. Main networks are the production environment of blockchain networks, and test networks 173 | are, well, the test environments. 174 |

175 | 176 |

177 | You also learned that these test networks come with their own test tokens and how to request them 178 | from one of the multiple faucets out there. 179 |

-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A basic introduction to Web3 and its concepts. 2 | 3 | The target audience is **frontend developers**, who have at least an average grasp of JavaScript and 4 | Web2 technology. 5 | 6 | > If you don't know much about Web development, because you come from another industry or you're 7 | > just beginning your programmer journey, I strongly recommend checking out 8 | > [FreeCodeCamp](https://www.freecodecamp.org/learn/). After finishing the Web design, JavaScript 9 | > algorithms, and front end development courses, you should be up to speed to take this Web3 course. 10 | 11 | **This course is in progress and help is appreciated!** 12 | 13 | ## Lessons 14 | 15 | This course goes step by step through the Web3 concepts from a Web apps point of view. So, (almost) 16 | **no Solidity or dev-tools are required** for the first two parts. 17 | 18 | You are **just writing JavaScript for the browser**. 19 | 20 | There is even a small code editor that lets you **try out code right on the page**. 21 | 22 | Every part finishes with an example app where you can apply your new knowledge right away. 23 | 24 | ### Part I: Reading Data from a Blockchain Network 25 | 26 | The first part is about the basics, connecting to a blockchain network, reading data, etc. 27 | You only need a modern browser and that's it. 28 | 29 | - [00 Connecting to a Blockchain Network](https://kay-is.github.io/web3-from-zero/00-connect-to-blockchain.html) 30 | - [01 Reading an Address Data](https://kay-is.github.io/web3-from-zero/01-read-address-data.html) 31 | - [02 Connecting to Smart Contracts](https://kay-is.github.io/web3-from-zero/02-connect-to-contracts.html) 32 | - [03 Using the Ethereum Name Service](https://kay-is.github.io/web3-from-zero/03-using-ens.html) 33 | - [04 Ethereum Request for Comment](https://kay-is.github.io/web3-from-zero/04-ercs.html) 34 | - [05 First Example App](https://kay-is.github.io/web3-from-zero/05-example-app.html) 35 | 36 | ### Part II: Writing Data to a Blockchain Network (WIP) 37 | 38 | The second part is about getting more interactive, you will need to install a wallet extension to 39 | your browser and create your first accounts. 40 | 41 | - [06 Public & Private Keys](https://kay-is.github.io/web3-from-zero/06-public-and-private-keys.html) 42 | - [07 Externally Owned Accounts](https://kay-is.github.io/web3-from-zero/07-externally-owned-accounts.html) 43 | - [08 Crypto Wallet Setup](https://kay-is.github.io/web3-from-zero/08-crypto-wallet-setup.html) 44 | - [09 Test Networks](https://kay-is.github.io/web3-from-zero/09-test-networks.html) 45 | - 10 Sending Transactions 46 | - 11 Second Example App 47 | 48 | ## Ethereum Edition 49 | 50 | This is the Ethereum edition, which uses the Ethereum network as an example. 51 | 52 | The Ethereum ecosystem is a vast landscape if you're just starting out, you might be dazzled by all the networks, dev environments, wallets, and whatnot. 53 | 54 | ![Ethereum Ecosystem](images/ethereum-ecosystem.png) 55 | 56 | This introduction will help you to make sense of this all, talking about one concept per lesson. 57 | -------------------------------------------------------------------------------- /boilerplate/editor.js: -------------------------------------------------------------------------------- 1 | import { ethers } from "//unpkg.com/ethers@5.5.1/dist/ethers.esm.min.js" 2 | 3 | window.ethers = ethers 4 | 5 | document.addEventListener("copy", (e) => { 6 | const text_only = document.getSelection().toString() 7 | const clipdata = e.clipboardData || window.clipboardData 8 | clipdata.setData("text/plain", text_only) 9 | clipdata.setData("text/html", text_only) 10 | e.preventDefault() 11 | }) 12 | 13 | const clearHtmlCode = (code) => 14 | code 15 | .trim() 16 | .split("\n") 17 | .map((line) => line.trim()) 18 | .join("\n") 19 | 20 | customElements.define( 21 | "code-editor", 22 | class CodeEditor extends HTMLElement { 23 | connectedCallback() { 24 | const hintElement = this.querySelector("p") 25 | let codeHint = null 26 | if (hintElement) { 27 | codeHint = clearHtmlCode(hintElement.innerHTML) 28 | this.removeChild(hintElement) 29 | } 30 | 31 | const code = clearHtmlCode(this.innerHTML) 32 | 33 | this.innerHTML = ` 34 |
${code}
35 |
36 | 37 | 40 |
41 | Result 42 |

43 |       
` 44 | 45 | this.querySelector("[data-editor-execute]").addEventListener( 46 | "click", 47 | this.executeCode 48 | ) 49 | 50 | if (hintElement) { 51 | let hinted = false 52 | this.querySelector("[data-editor-hint]").addEventListener( 53 | "click", 54 | (e) => { 55 | if (hinted) return 56 | e.target.parentNode.parentNode.querySelector( 57 | "[data-editor-input]" 58 | ).innerHTML += "\n" + codeHint 59 | hinted = true 60 | } 61 | ) 62 | } 63 | } 64 | 65 | executeCode(e) { 66 | const parent = e.target.parentNode.parentNode 67 | const code = parent.querySelector("[data-editor-input]").innerHTML.trim() 68 | const outputElement = parent.querySelector("[data-editor-result]") 69 | 70 | outputElement.innerHTML = "Executing..." 71 | 72 | let cleared = false 73 | const print = (data) => { 74 | const content = JSON.stringify(data, null, 2) + "\n" 75 | if (cleared) { 76 | outputElement.innerHTML += content 77 | return 78 | } 79 | outputElement.innerHTML = content 80 | cleared = true 81 | } 82 | 83 | eval(` 84 | async function editorCode() { 85 | ${code} 86 | } 87 | editorCode() 88 | `) 89 | } 90 | } 91 | ) 92 | -------------------------------------------------------------------------------- /boilerplate/style.css: -------------------------------------------------------------------------------- 1 | /* @import url("//unpkg.com/sakura.css/css/sakura-ink.css"); */ 2 | @import url("//unpkg.com/bamboo.css@1.3.7/dist/dark.min.css"); 3 | 4 | body { 5 | max-width: 80ch; 6 | } 7 | 8 | figure { 9 | display: flex; 10 | flex-direction: column; 11 | align-items: center; 12 | } 13 | figure > figcaption { 14 | text-align: center; 15 | font-size: smaller; 16 | } 17 | figure > img { 18 | margin-bottom: 0.5rem; 19 | } 20 | 21 | [data-editor-execute] { 22 | float: left; 23 | width: 80%; 24 | margin-top: 0; 25 | font-size: large; 26 | font-weight: bold; 27 | height: 50px; 28 | } 29 | [data-editor-hint] { 30 | width: 20%; 31 | margin-top: 0; 32 | font-size: large; 33 | font-weight: bold; 34 | height: 50px; 35 | background-color: dimgray; 36 | border-color: dimgray; 37 | } 38 | 39 | pre { 40 | margin-bottom: 0; 41 | max-height: 400px; 42 | color: lightgray; 43 | } 44 | 45 | pre > code { 46 | color: white; 47 | font-size: 1em; 48 | } 49 | -------------------------------------------------------------------------------- /example_app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | NFT <-> Owner 12 | 13 |

NFT Owner Finder

14 | 15 |

16 | Please enter the address of a smart contract that implements the ERC271 specification. 17 |

18 | 19 |
20 | 24 | 25 |
26 | 30 | 31 |
32 | 33 |
34 | 35 | 39 | 43 | 47 | 51 | 52 | 98 | -------------------------------------------------------------------------------- /images/blockchain-connection-ethersjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kay-is/web3-from-zero/59ebf6c72ac7096f201139d2ab9b8456eb0e3152/images/blockchain-connection-ethersjs.png -------------------------------------------------------------------------------- /images/blockchain-connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kay-is/web3-from-zero/59ebf6c72ac7096f201139d2ab9b8456eb0e3152/images/blockchain-connection.png -------------------------------------------------------------------------------- /images/ecc-keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kay-is/web3-from-zero/59ebf6c72ac7096f201139d2ab9b8456eb0e3152/images/ecc-keys.png -------------------------------------------------------------------------------- /images/encryption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kay-is/web3-from-zero/59ebf6c72ac7096f201139d2ab9b8456eb0e3152/images/encryption.png -------------------------------------------------------------------------------- /images/ethereum-ecosystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kay-is/web3-from-zero/59ebf6c72ac7096f201139d2ab9b8456eb0e3152/images/ethereum-ecosystem.png -------------------------------------------------------------------------------- /images/externally-owned-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kay-is/web3-from-zero/59ebf6c72ac7096f201139d2ab9b8456eb0e3152/images/externally-owned-account.png -------------------------------------------------------------------------------- /images/signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kay-is/web3-from-zero/59ebf6c72ac7096f201139d2ab9b8456eb0e3152/images/signature.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web3-from-zero", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "web3-from-zero", 9 | "version": "1.0.0", 10 | "license": "ISC" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web3-from-zero", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "http-server -c-1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/kay-is/web3-from-zero.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/kay-is/web3-from-zero/issues" 18 | }, 19 | "homepage": "https://github.com/kay-is/web3-from-zero#readme" 20 | } 21 | --------------------------------------------------------------------------------