The goal of this challenge is to get some insight into how you handle the challenges of Web3 frontends, particularly in blockchain interaction, state management and error state handling.
This repo contains a set of smart contracts that have been deployed on Avalanche Fuji testnet. The contracts include:
FooToken.sol- a standard ERC20 contractBarToken.sol- a standard ERC20 contractExchange.sol- a contract that can swap FOO for BAR
These contracts represent a simplified decentralized exchange (DEX), where FOO tokens can be swapped for BAR tokens and the other way around. Unlike real DEX's, the FooBar exchange only swaps tokens at a fixed exchange rate (which can only be updated by the smart contract owner).
The goal is to create a frontend UI that allows users to interact with the exchange contract to swap FOO and BAR tokens. Initially, users will not have any tokens they can use on the exchange, therefore, an initial function has been created on the FOO token, that allows first time users to request a default minting of 100 tokens. In Solidity, the function looks like this:
function fund() public returns (uint);
function funded(address user) public view returns (bool);The fund() function will only mint tokens to users who have not already recieved them, therefore the utility method
funded(address user) should be used to determine whether the user has already claimed their free tokens.
Once users have some FOO tokens, they can call the relevant function on the Exchange.sol contract:
function swap(address fromToken, address toToken, uint256 amount) public returns (uint256);The swap function can only be called if the user has approved the Exchange contract to spend their FOO or BAR
tokens. This can be done using the standard ERC20 approve(spender, amount) functions on the tokens (see below for
some examples).
To summarize, with this frontend, users should be able to:
- Connect their Metamask wallet
- Request an initial minting of FOO tokens
- View their balance of FOO tokens
- View their balance of BAR tokens
- Swap FOO tokens for BAR tokens and vice versa
Some notes on what we are looking for in this assignment:
- Don't worry too much about styling and UI beautification, the page should be readable and navigable, but doesn't need to be flashy
- The project should be written in React/NextJS, preferably in Typescript
- We are particularly interested in how you organize the project, how state is managed, and how components are broken down.
- Your solution should be submitted as a link to a git repository, with a small README detailing the decisions you made, how you approached the problem, and a justification of which external tools, components, and libraries you chose to use.
You can connect to the smart contracts using the ABI's generated in this repo upon building.
yarn install
hardhat export --network avax_fuji --export addresses/avax-testnet.jsonThis should create a folder structure with a JSON containing all the ABI's:
ls ./build/addresses
avax-testnet.json <--- ABI's are in hereAlternatively, this repository can be installed directly in the NextJS/React project using:
yarn add git+https://github.com/scottrmalley/web3-frontend-challenge.gitThen the contracts and addresses can be directly imported via:
import { ethers } from "ethers";
import { AVAX_FUJI, FooToken__factory, BarToken__factory, Exchange__factory } from "web3-frontend-challenge";
const provider = new ethers.providers.JsonRpcProvider("https://api.avax-test.network/ext/bc/C/rpc");
// this will be replaced with metamask in the frontend
const wallet = new ethers.Wallet("<private-key>", provider);
const fooToken = FooToken__factory.connect(AVAX_FUJI.contracts.FooToken.address, provider);
const exchange = Exchange__factory.connect(AVAX_FUJI.contracts.Exchange.address, provider);
const barToken = BarToken__factory.connect(AVAX_FUJI.contracts.BarToken.address, provider);
// initial funding of wallet with foo tokens
const fundTx = await fooToken.connect(wallet).fund();
// approve exchange contract
const amount = ethers.utils.parseUnits("10.0");
const approveTx = await fooToken.connect(wallet).approve(AVAX_FUJI.contracts.Exchange.address, amount);
// swap tokens
const swapTx = await exchange.connect(wallet)
.swap(AVAX_FUJI.contracts.FooToken.address, AVAX_FUJI.contracts.BarToken.address, amount);
// check bar token address balance
console.log(`balance: ${await barToken.balanceOf(wallet.address)}`);For reference, the smart contracts are deployed at:
- FooToken:
0xf1140386b245bad8aD4D586e93fe462ffA70Ba84 - BarToken:
0xe8001631598233B7eC1178650fDcEdEe5C2CC8d9 - Exchange:
0xa07a16529A6712411036A2310365bFeB6C2dB072
If you need to setup Metamask with the Avalanche Fuji you can use the following:
- Network Name: Avalanche Testnet C-Chain
- Network URL: https://api.avax-test.network/ext/bc/C/rpc
- Chain ID: 43113
- Currency Symbol: AVAX
- Block Explorer URL: https://testnet.snowtrace.io/
To get testnet AVAX for gas fees, you can use the Fuji Faucet at: https://faucet.avax.network/