├── style.css ├── README.md ├── mint-usdc.html ├── script ├── mint-usdc.js ├── app.js └── transfer-usdc.js ├── .gitignore └── index.html /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | font-family: 'Nunito Sans', sans-serif; 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building Dapps With Ethers.js 2 | 3 | > Learn how to build your first Dapp with Ethers.js
4 | > https://blog.logrocket.com/building-dapp-ethers-js/ 5 | 6 | ## Info 7 | 8 | Repo include the source-code for a dapp built with ethers.js, with the following functionalities: 9 | - Connect to Metamask or other ETH based wallet 10 | - Read USDC balance 11 | - Transfer USDC to other accounts 12 | 13 | ## Setup 14 | 15 | ```bash 16 | $ git clone https://github.com/AsaoluElijah/first-dapp.git 17 | $ cd first-dapp 18 | # switch to front-end branch 19 | $ git switch front-end 20 | $ code . # open with vscode 21 | ``` 22 | ## Screenshot 23 | 24 | ![](https://blog.logrocket.com/wp-content/uploads/2021/10/ethers-js-dapp-final-output.png) 25 | -------------------------------------------------------------------------------- /mint-usdc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mint USDC 8 | 14 | 15 | 16 |
17 |

Mint USDC

18 |

Click the button below to mint usdc

19 | 20 |
21 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /script/mint-usdc.js: -------------------------------------------------------------------------------- 1 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any"); 2 | 3 | const usdc = { 4 | address: "0x68ec573C119826db2eaEA1Efbfc2970cDaC869c4", 5 | abi: [ 6 | "function name() view returns (string)", 7 | "function symbol() view returns (string)", 8 | "function gimmeSome() external", 9 | "function balanceOf(address _owner) public view returns (uint256 balance)", 10 | "function transfer(address _to, uint256 _value) public returns (bool success)", 11 | ], 12 | }; 13 | 14 | async function mintUsdc() { 15 | await provider.send("eth_requestAccounts", []); 16 | const signer = provider.getSigner(); 17 | let userAddress = await signer.getAddress(); 18 | const usdcContract = new ethers.Contract(usdc.address, usdc.abi, signer); 19 | 20 | const tx = await usdcContract.gimmeSome({ gasPrice: 20e9 }); 21 | console.log(`Transaction hash: ${tx.hash}`); 22 | 23 | const receipt = await tx.wait(); 24 | console.log(`Transaction confirmed in block ${receipt.blockNumber}`); 25 | console.log(`Gas used: ${receipt.gasUsed.toString()}`); 26 | } 27 | -------------------------------------------------------------------------------- /script/app.js: -------------------------------------------------------------------------------- 1 | const provider = new ethers.providers.Web3Provider(window.ethereum, "any"); 2 | 3 | const usdc = { 4 | address: "0x68ec573C119826db2eaEA1Efbfc2970cDaC869c4", 5 | abi: [ 6 | "function name() view returns (string)", 7 | "function symbol() view returns (string)", 8 | "function gimmeSome() external", 9 | "function balanceOf(address _owner) public view returns (uint256 balance)", 10 | "function transfer(address _to, uint256 _value) public returns (bool success)", 11 | ], 12 | }; 13 | 14 | async function main() { 15 | /*======= 16 | CONNECT TO METAMASK 17 | =======*/ 18 | await provider.send("eth_requestAccounts", []); 19 | const signer = provider.getSigner(); 20 | let userAddress = await signer.getAddress(); 21 | document.getElementById("userAddress").innerText = 22 | userAddress.slice(0, 8) + "..."; 23 | 24 | /*====== 25 | INITIALIZING CONTRACT 26 | ======*/ 27 | const usdcContract = new ethers.Contract(usdc.address, usdc.abi, signer); 28 | 29 | let contractName = await usdcContract.name(); 30 | // document.getElementById("contractName").innerText = contractName; 31 | let usdcBalance = await usdcContract.balanceOf(userAddress); 32 | usdcBalance = ethers.utils.formatUnits(usdcBalance, 6); 33 | document.getElementById("usdcBalance").innerText = usdcBalance; 34 | } 35 | main(); 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /script/transfer-usdc.js: -------------------------------------------------------------------------------- 1 | async function transferUsdc() { 2 | let receiver = document.getElementById("receiver").value; 3 | let amount = document.getElementById("amount").value; 4 | let response; 5 | 6 | await provider.send("eth_requestAccounts", []); 7 | const signer = provider.getSigner(); 8 | let userAddress = await signer.getAddress(); 9 | 10 | const usdcContract = new ethers.Contract(usdc.address, usdc.abi, signer); 11 | 12 | try { 13 | receiver = ethers.utils.getAddress(receiver); 14 | } catch { 15 | response = `Invalid address: ${receiver}`; 16 | document.getElementById("transferResponse").innerText = response; 17 | document.getElementById("transferResponse").style.display = "block"; 18 | } 19 | 20 | try { 21 | amount = ethers.utils.parseUnits(amount, 6); 22 | if (amount.isNegative()) { 23 | throw new Error(); 24 | } 25 | } catch { 26 | console.error(`Invalid amount: ${amount}`); 27 | response = `Invalid amount: ${amount}`; 28 | document.getElementById("transferResponse").innerText = response; 29 | document.getElementById("transferResponse").style.display = "block"; 30 | } 31 | 32 | const balance = await usdcContract.balanceOf(userAddress); 33 | 34 | if (balance.lt(amount)) { 35 | let amountFormatted = ethers.utils.formatUnits(amount, 6); 36 | let balanceFormatted = ethers.utils.formatUnits(balance, 6); 37 | console.error( 38 | `Insufficient balance receiver send ${amountFormatted} (You have ${balanceFormatted})` 39 | ); 40 | 41 | response = `Insufficient balance receiver send ${amountFormatted} (You have ${balanceFormatted})`; 42 | document.getElementById("transferResponse").innerText = response; 43 | document.getElementById("transferResponse").style.display = "block"; 44 | } 45 | let amountFormatted = ethers.utils.formatUnits(amount, 6); 46 | 47 | console.log(`Transferring ${amountFormatted} USDC receiver ${receiver}...`); 48 | 49 | response = `Transferring ${amountFormatted} USDC receiver ${receiver.slice( 50 | 0, 51 | 6 52 | )}...`; 53 | document.getElementById("transferResponse").innerText = response; 54 | document.getElementById("transferResponse").style.display = "block"; 55 | 56 | const tx = await usdcContract.transfer(receiver, amount, { gasPrice: 20e9 }); 57 | console.log(`Transaction hash: ${tx.hash}`); 58 | document.getElementById( 59 | "transferResponse" 60 | ).innerText += `Transaction hash: ${tx.hash}`; 61 | 62 | const receipt = await tx.wait(); 63 | console.log(`Transaction confirmed in block ${receipt.blockNumber}`); 64 | document.getElementById( 65 | "transferResponse" 66 | ).innerText += `Transaction confirmed in block ${receipt.blockNumber}`; 67 | } 68 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My First Dapp 8 | 9 | 10 | 14 | 20 | 21 | 22 | 23 |
24 |
25 |
26 |
27 |
28 |

You have:

29 |
30 |

0.00

31 | USDC 34 |
35 |
36 | 0x..add-here 47 |
48 |
49 |

50 | visit here to mint usdc 51 |

52 |
53 |
54 |
Transfer Usdt
55 | 62 |
67 |
68 | 69 | 75 |
76 |
77 | 78 | 79 |
80 |
81 | 84 |
85 |
86 |
87 |
88 |
89 |
90 | 91 | 95 | 96 | 97 | 98 | --------------------------------------------------------------------------------