Vert Finance: Architecture of a Cryptocurrency to Fiat Exchange
My final year project for my undergraduate degree was a Web3 product. The Web3 product helps you exchange almost any cryptocurrency directly to fiat in your bank account. Don’t bother asking me how I pulled off creating a Web3 application as a Computer Engineering student at a Nigerian University.
The application is live on the BNB Smartchain mainnet and testnet and only supports the Nigerian Naira, but I can only make the testnet version available because no real funds are sent to your account. I cannot make the mainnet application available because of the Central Bank of Nigeria’s directive to banks not to associate with cryptocurrency companies. Regardless, the mainnet version works. You can set it up on your end, I have made the code open source. You can fork it and also use parts of it as yours. In this piece, I will explain how the product works and why I made some design choices.
Architecture
The Decentralized Application (DApp) has a frontend, backend and smart contract. The user enters the token and token amount he wants to exchange. The amount can be entered in a token amount or directly in naira. The amount for the other field is generated automatically. He proceeds to enter his bank details and confirms the transaction. The transaction uses the Vert Router smart contract to exchange the token selected for a stablecoin and sends it to a receiver address (chosen by Vert Finance). After the swap, the frontend sends the transaction details to the backend. The backend verifies the transaction and sends the fiat amount to the user’s bank account if it is valid. The backend relies on the naira Vert Finance already has on an exchange to complete the transaction. It saves the transaction details on a database for historical purposes and verification of future transactions.
That was a high-level overview. Let us dive deeper into each part of the dapp.
Frontend
On the frontend, the user enters the token he wants to exchange and a token amount to exchange or the amount of naira he wants to receive. The other input field generates automatically from the user’s input using the exchange rates. The frontend fetches the USD/NGN exchange rate from the backend. The current USD(Token/USD) price of the token is fetched from Pancakeswap. The frontend uses Uniswap redux multicall to make multiple calls to the blockchain to find the most efficient swap path between the token and a stablecoin. We swap the token to a stablecoin to ensure its value is maintained. It uses the Pancakeswap SDK to handle path data and conversions between token and fiat amounts. I also took inspiration from Pancakeswap and Uniswap frontend code to implement processes like input validation.
On the next page, he selects a bank and enters his bank account number. The bank account name is resolved from the backend using this data. If the account is correct, he can proceed. On proceeding, he sees a summary of the transaction. If he accepts the summary, a blockchain transaction uses the Vert smart contract to swap his token for a stablecoin. The frontend sends the swap details to the backend and instructs it to send naira to the account number. The frontend monitors the transaction progress on the backend using Websocket, thus allowing the user to monitor the transaction progress. It uses socket.io to set up and manage the WebSocket connection. After the transaction is complete, the user gets a transaction summary.
The frontend is built using WAGMI, Reactjs and Typescript. WAGMI is a Typescript library that provides React hooks to perform Web3 operations like checking Ethereum account balances. The original frontend is deployed on Vercel and connects to the BNB Smartchain testnet. The code is open-source and available on GitHub.
Smart Contract
Vert uses only one smart contract called Vert Router. The smart contract is a modification of the original Pancakeswap router contract. It takes the token, exchanges it on Pancakeswap to a stablecoin and sends it to an address. Vert Finance owns the address. It is one of the swap arguments. Anyone can call the contract to complete a swap, so the address distinguishes swaps done on the Vert Finance frontend from other swaps. The backend uses this address to verify the swap transaction and get the amount of stablecoin the user sent.
The smart contract also collects dust, which may serve as a source of revenue for Vert Finance. The dust is the difference between the lowest swap execution price and the actual execution price of the swap. The slippage tolerance determines the lowest execution price. If a user wants to swap 1 ETH for 10,000 USDC with a slippage of 1%, the lowest price he will accept is 9,900 USDC ((99/100) * 10000). If the swap occurs at a 9,950 USDC execution price, Vert takes the extra 50 USDC. The frontend handles the slippage to ensure the user always gets the naira amount he agreed to.
The smart contract was written in Solidity using the Foundry development environment. It is deployed and verified on BNB Smartchain and BNB Testnet. The code is open-source and available on GitHub.
Backend
The backend receives the transaction details from the frontend. These details include the transaction hash of the swap transaction, transaction sender, bank details of the user and the USD/NGN exchange rate. The backend first verifies the swap transaction, saves the transaction hash and waits for seven block confirmations before sending the naira. The swap transaction is verified by checking if the transaction hash already exists on the database, the transaction sender, the contract it interacted with and the receiver. It uses a SellEvent
the contract emits for verification. The backend returns an error response on verification failure.
Note: The verification done here does not verify if the bank details passed are the actual bank details of the user. The user’s private key can be used to verify the details by verifying a signature derived from signing the data with the private key. This prevents an attack where an attacker can monitor the contract for transactions and immediately send his bank details once he sees one but with the actual transaction hash and transaction sender. This attacker will get the naira in his bank account while the user’s request to the backend will fail because the backend will think that the swap transaction has already been processed.
After the transaction gets its block confirmations, the rate sent is verified. The backend needs the exchange rate to know the rate the user agreed to, ensuring he gets the naira amount he wants. The rate sent is signed. The backend signed it before initially sending it to the frontend. The backend verifies the signature. If the verification fails, the current exchange rate is used instead of the one sent from the frontend. This prevents attacks where the attacker sends a fake exchange rate that inflates the USD/NGN exchange rate, thus giving him a large amount of naira for a small amount of USD.
Finally, the backend tells an exchange or liquidity provider where Vert Finance holds naira to send naira to the user’s bank account. Vert must ensure it always has enough naira liquidity to satisfy user requests. All through the verification and final transaction steps, the backend emits events through the WebSocket API to inform the frontend of its progress.
The backend is written in Typescript, Expressjs, Viem and Nodejs. Viem is the Web3 Library the backend uses to interact with the blockchain. The code is open-source and available on GitHub.
Vert Finance is a proof of concept of a product allowing anyone to access fiat regardless of the cryptocurrency they have in their wallet. It would be an actual product if the Central Bank of Nigeria were not limiting banks. Regardless, cryptocurrency products are inevitable in countries like Nigeria where the faith in the value of the local currency reduces every passing day. Every Nigerian needs a way to preserve their wealth. Stablecoins have proven to be more stable than the Nigerian Naira.
Thanks for taking the time to read this. You can clap, share or ask any questions using the comment section. I can’t wait to see what you do with the code.
Written with malice 😈 by nonseodion.