The blockchain world has, at present, lots of independent running networks/chains where each chain has some unique capabilities and tradeoffs. These chains support asset native to that particular chain, and in the process, limit dApp to a single chain. In a similar scenario, to use dApp, you will have to buy the asset native for that particular chain or will have to do cross-chain swapping. Getting your ETH on the Ethereum network exchanged for MATIC on the polygon network is an example of cross-chain swapping. Cross-chain swapping may involve multiple transactions; hence, you may lose your tokens for each transaction as gas fees.
Bridges can reduce the cost of cross-chain swaps as they use approaches like Lock and Mint where they lock assets on the source chain and mint the assets on the destination chain. Bridges help to reduce the number of transactions required for swapping the assets between 2 chains.
To support multiple chains and assets, we can integrate Web3 bridges with the needed apps. There are many Web3 bridges, each supporting a few chains but it is not feasible to integrate a new bridge whenever we want to support a new chain. However, some projects aggregate the bridges and the DEX. You can integrate such projects to build a cross-chain Web3 app.
Here is a list of some of the bridge and DEX aggregators:
In this blog, I will show you how to build a cross-chain Web3 apps using LI.FI protocol.
LI.FI
It provides swapping between assets of the same chain as well as assets between different chains. Also, it uses bridges and DEX aggregators to provide this functionality. LI.FI finds the best route for asset swapping amongst the bridge and DEX.
LI.FI widget provides a simple yet customizable UI that you can quickly integrate with your frontend application. If you need more customization, you can use the LI.FI SDK.
If you have created a new token and it is not listed on any DEX or a bridge, then there won’t be a route available for swapping the asset in the LI.FI widget. The reason is that the LI.FI protocol needs to know the value of your token so that it can swap any token for the desired token.
To make your token available on LI.FI, you need to list the token on any bridge or DEX.
For the demo, I am using Uniswap to provide liquidity for our custom token. Uniswap is a DEX that provides functionality to buy tokens, create a pool, etc.
Demo Project
Let’s call the demo project Celebstar. It tokenizes celebrity popularity. Fans can invest in/purchase their favorite celebrity’s tokens here. Tokenomics for every celebrity token is driven by a bonding curve.
The price of each celebrity token is defined in terms of our custom ERC20 token named TAL. Fans can purchase the celebrity tokens using TAL tokens. LI.FI widget is configured so that the user can buy the TAL token using any token on any chain supported by LI.FI. For example, user can use MATIC on the polygon network to buy the TAL on the Ethereum network.
Once the user buys the TAL token, they can then buy the celebrity tokens. If they want to sell the celebrity token, they will get the TAL tokens as per the price of the celebrity token at that time.
Tools/Projects Used:
- Solidity and Hardhat
- React
- LI.FI
- UniSwap V2
Steps involved:
- Create & deploy ERC20 token
- Create & deploy the celebstar contract
- Create a liquidity pool on Uniswap
- Integrate LI.FI widget with your celebstar frontend application
- Buy TAL tokens using LI.FI widget
- Buy celebrity tokens
Create TAL token contract:
TAL token is a simple ERC20 contract. Refer the link for details on creating an ERC20 token contract.
Deploy TAL token:
Deploy TAL token on a network. Note down the deployed token contract address as we need it for the celebstar contract. Check out this link for more details on deploying the smart contracts using Hardhat.
Create celebstar contract:
The celebstar contract has mint and burn functions to buy and sell the celebrity tokens. The contract uses the TAL token for minting the celebrity token.
A simplified version of the contract is as below:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./BondingCurve/CurveBondedToken.sol";
contract CelebStar is CurveBondedToken {
using SafeMath for uint256;
uint256 private _currentTokenID = 0;
IERC20 private talContract;
uint256 public collectedOperationsFee = 0;
// OPERATION_FEE_PERCENTAGE is in 3 decimal digits
// So value 100 means the percentage is 100 * 10^-3 = 0.1%
uint32 public constant OPERATION_FEE_PERCENTAGE = 100;
enum ClaimStatusCode {
InsufficientBalance,
TransferFailed
}
constructor(
uint256 _reserveRatio,
address _talContractAddress,
address _oracleClientAddress
) CurveBondedToken(_reserveRatio) CelebStarRewards(_oracleClientAddress) {
talContract = IERC20(_talContractAddress);
}
function mint(uint256 _id, uint256 _deposit) external payable {
require(_id < _currentTokenID, "Invalid token id.");
// Before minting user should approve this contract to send the base tokens amounting to the _deposit.
uint256 operationFee = collectOperationFee(_deposit);
uint256 depositAfterFee = _deposit.sub(operationFee);
// This function will calculate and deposit the amount of celebrity tokens that can be bought at the current price of the celebrity token
_curvedMint(_id, depositAfterFee);
require(
talContract.transferFrom(_msgSender(), address(this), _deposit),
"TAL token transfer failed."
);
}
function burn(uint256 _id, uint256 _amount) external {
require(_id < _currentTokenID, "Invalid token id.");
// This function will calculate the amount of TAL tokens recevied after selling the celebrity tokens
uint256 returnAmount = _curvedBurn(_id, _amount);
uint256 operationFee = collectOperationFee(returnAmount);
uint256 returnAmountAfterFee = returnAmount.sub(operationFee);
require(
talContract.transfer(_msgSender(), returnAmountAfterFee),
"TAL token transfer failed."
);
}
function collectOperationFee(uint256 amount)
internal
returns (uint256 operationFee)
{
operationFee = calculateOperationFee(amount);
collectedOperationsFee = collectedOperationsFee.add(operationFee);
}
function calculateOperationFee(uint256 _amount) public pure returns(uint256 operationFee) {
return _amount.mul(OPERATION_FEE_PERCENTAGE).div(10**5);
}
function getCountOfRegisteredCelebrities() external view returns(uint256) {
return _currentTokenID;
}
}
Check the full contract code here.
Deploy celebstar contract:
Deploy the celebstar contract on a network. Note down that contract address. We need this address for our frontend application to interact with the contract.
Create a liquidity pool on Uniswap V2:
To create a liquidity pool for TAL tokens on Uniswap, you can visit Etherscan. Do this using the TAL contract owner account as the total supply of TAL tokens is deposited in the contract owner’s account after the contract is deployed.
The screenshots show the value of the TAL token w.r.t ETH. Approve and supply the token. Once this is done, a liquidity pool will be created which the LI.FI widget will use to swap the assets.
Integrate LI.FI widget with your frontend application:
Follow this section to integrate the LI.FI widget in your frontend application.
Once the widget is integrated, we can select the source chain asset and the destination chain asset. Our application wants the destination chain as Goerli and the asset as TAL tokens.
After setting these things up, LI.FI will list the possible routes. As we have created a liquidity pool on Uniswap, we will see a route via Uniswap. We can select any other route as well if available. Once the transaction is done, we will get the equivalent amount of TAL tokens as per the price of our token.
As we have set the value of the TAL token as 5000 tokens per ETH. We should get ~50 TAL tokens for 0.01 ETH. We can see the same in the below screenshot.
Using the TAL token, we can now buy the celebrity tokens.
This screenshot shows the swapping of assets on the same chain because I am using the testnet and there isn’t enough liquidity provided by the bridges on testnets. But if you use the mainnet, you will get enough liquidity for cross-chain swapping. See the below screenshot.
Fees:
LI.FI does not charge fees for the transactions. If you want to charge users for using the LI.FI’s cross-chain swapping functionality, then LIFI takes a 15% cut of the charges.
Conclusion
Using cross-chain bridge and DEX aggregators like LI.FI, we can create a cross-chain Web3 app. The users of our app will not have to worry about going to another DEX or a bridge to buy the tokens for our app. This will make the dApp experience seamless for our users.