🚰
Coding a Faucet
To try the programmatic signing of Evmos’ messages we are going to create a coin faucet.
The faucet will provide 3 endpoints, one to get the faucet’s account balance another one to request coins, and the last one will return the wallet address.
Implementation
For the current step, we are going to create just an API and we are going to call it from a browser after connecting Metamask to a web page.
Requirements
Node v18.12.0+
Metamask Wallet
Evmos coins
Set up the Wallet
Create the Metamask Wallet and save your seed phrase.
For this workshop, we are going to use a seed phrase that will be public and after the workshop, we are not going to use it again.
DO NOT expose your wallet to the Internet, any user with your seed phrase can steal your coins!
Add the Evmos network to your Metamask extension using Chainlist
Found your Wallet
Send coins to your newly created wallet.
Dependencies
nvm use v18.12.0 # only if you are using nvm to manage your node installation cd /tmp mkdir faucet cd faucet yarn init -y yarn add evmosjs yarn add @hanchon/evmos-ts-wallet yarn add express yarn add cors yarn add -D @types/express yarn add -D @types/cors yarn add -D typescript
Bash
Code
We are going to create two files, the first one is going to be just for our seed phrase, and the other one will have the API code:
constants.ts
export const seed = "place your mnemonics here";
TypeScript
api.ts
import express from "express"; import { Request, Response } from "express"; import cors from "cors"; import { provider, addressConverter, transactions } from "evmosjs"; import { Wallet } from "@ethersproject/wallet"; import { MAINNET_CHAIN, getSender, MAINNET_FEE, signTransactionUsingEIP712, broadcast, } from "@hanchon/evmos-ts-wallet"; import { seed } from "./constants"; // Create the api const app = express(); app.use(cors()); // Expose it at 8080 const port = 8080; // Set up the wallet const wallet = Wallet.fromMnemonic(seed); // Set up testnet settings const denom = "aevmos"; const url = "https://rest.bd.evmos.org:1317"; // Address endpoint app.get("/address", async (_: Request, res: Response) => { res.send( `{"eth":"${wallet.address}","evmos":"${addressConverter.ethToEvmos( wallet.address )}"}` ); }); // Create the balance endpoint app.get("/balance", async (_: Request, res: Response) => { const endpoint = provider.generateEndpointBalanceByDenom( addressConverter.ethToEvmos(wallet.address), denom ); const balance: provider.BalanceByDenomResponse = await ( await fetch(`${url}${endpoint}`) ).json(); res.send(`{"balance":"${balance.balance?.amount || "0"} aevmos"}`); }); // Faucet endpoint app.get("/faucet/:address", async (req: Request, res: Response) => { let address = req.params.address; // The address must be in evmos1 format if (address.startsWith("0x")) { address = addressConverter.ethToEvmos(address); } // Create the message send params const params: transactions.MessageSendParams = { destinationAddress: address, amount: "1000000000000000", denom, }; // Get our wallet information const sender = await getSender(wallet, url); // Create the transaction const tx = transactions.createMessageSend( MAINNET_CHAIN, sender, MAINNET_FEE, "workshop faucet", params ); // Sign the transaction const signedTx = await signTransactionUsingEIP712( wallet, sender.accountAddress, tx, MAINNET_CHAIN ); // Broadcast it const txRes = await broadcast(signedTx, url); res.send(JSON.stringify(txRes)); }); // Start the server app.listen(port, () => { console.log(`Server started at http://localhost:${port}`); });
TypeScript
Run the API
NOTE: we are just passing the flag --esModuleInterop to avoid setting up the tsconfig.json file.
nvm use v18.12.0 # only if you are using nvm to manage your node installation tsc --esModuleInterop api.ts && node api.js
Bash