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