Bridging the Gap: Better Token Standards for Cross-chain Assets
Taking ERC20 tokens cross-chain is broken. Today, bridges are often slow and expensive, have security vulnerabilities (as evidenced most recently by the Multichain hack), and fragment liquidity when each bridge creates its own version of the bridged token liquidity (and communities) when they create their own versions of tokens.
Bridging in its current state worked as a necessary stopgap solution, but for web3 to move forward, we need a better way. L2s are booming. Independent chains are still being built. The future is decidedly cross-chain.
Recently I set out to find exactly what solutions are being built to fix the problems related to taking tokens cross-chain. In this article, I’ll look at two of the better proposals—OFT and xERC20, compare their merits, and shed light on why xERC20 emerged as my top pick. I’ll also walk you through a few code samples to show how it works.
First, let’s look at the problem: why the current way we move tokens across chains isn’t the right long-term solution.
Web3 Bridges Explained
What is a web3 bridge
A bridge is a “gateway” between blockchains that allows you to transfer tokens and data between those chains. Bridges don’t actually move the token between chains; rather, they use various mechanisms to burn/wrap/mint comparable tokens on each chain.
You’ve probably used a bridge to transfer ERC20 tokens (such as WETH, DAI, USDT, etc.) between Ethereum, Polygon, BNB, and others. Protocols such as Across, Connext, and Stargate are some of the largest bridges by volume.
But as we’ve said, the current way we create tokens that can move across chains is a highly flawed process.
Why the current method is flawed
When you decide to create a cross-chain token, you currently have three choices for your strategy:
1 - Build your own bridges
2 - Use the target chain’s canonical bridge
3 - Use third-party bridges
Unfortunately, all three choices are fundamentally flawed.
Building your own bridges is perhaps an idealistic choice, but it’s easy to see why it can’t really work. Not only would building a custom bridge on each supported chain be technically challenging, incredibly expensive, and time-consuming, but you would be taking on all the security risks yourself.
Bridges are already rife with potential vulnerabilities. According to Chainalysis, attacks on bridges account for 69% of total funds stolen in 2022.
Similar to not building your own custom wallet, you probably don’t want to build your own custom bridges.
Using the chain’s canonical bridge is a choice some teams make. (By canonical, we mean the official bridge created by the chain to connect with Ethereum.) The upside to this choice is that you have a reduced security risk and can more easily identify the official version of the token created on the chain. The downside is this: canonical bridges are slow, expensive, and only work with their specific chain/L2. This means that if a token needs to be moved between L2s, it will first have to go through Ethereum before reaching its final destination—a very expensive and time-consuming process. Bridging tokens back from an L2 to Ethereum can take days and involve multiple gas-fee payments. For transferring an ERC20 token, this would include two extra transactions - one on the source chain to convert ERC20 to the native token and another on the destination. It’s a terrible and often unusable experience.
Using a specific third-party bridge also has benefits but, ultimately, is not a great solution. While bridges can be fast and cheap, they each use unique bridging mechanisms, which are often centralized. This means you suddenly have multiple and varied security risks. And even worse, each bridge creates its own representation of your token. If a user moves your token via the canonical bridges and a third-party bridge, you’ll end up with different versions. You can quickly end up with half a dozen or more versions of your token. (You’ve probably seen the result of this with USDC—a.USDC, USDC.e, etc.)
If the adopted version of a token on a chain is the one minted by the canonical bridge, you need high liquidity on third-party bridges to make sure users receive the version of the asset they're interested in—the one they can use in that ecosystem.
With most bridges, when tokens are transferred, the tokens on the source chain are locked in the bridge contract, and the bridge mints an equivalent amount of tokens from their representation contract on the destination chain. This not only locks you (as the token creator) into the bridge’s model forever but also creates a significant security risk. A bug in the bridge’s contracts could give hackers the ability to mint a high (or even unlimited) number of unbacked tokens.
Simply put, third-party bridges have a lot of issues.
The current best solution
A common solution is for a team to go with the canonical bridge and then rely on liquidity providers to provide a layer on top that absorbs the risk and enables fast transfers. This works pretty well for token teams that can provide high liquidity. But this approach ultimately fails for long-tail tokens. Most projects just don’t have the liquidity and usage of mainstream tokens such as ETH.
So what do teams do? They either spend a lot of money to incentivize liquidity (which, if you are a long-tail token, you probably don’t have), or they make the most common choice: they give up and go with a proprietary standard such as Multichain. Teams know they shouldn't, but they don’t have much choice. And, again, we know how that often turns out.
There aren't many good choices for a team that wants to take their token cross-chain. Options are high-risk, expensive, fragmented, and slow.
But enough about the problems. What we really need is a solution that offers fungibility, security, and minimal liquidity requirements. Let’s look at some possibilities.
Emerging solutions for creating cross-chain tokens
I looked at two newer solutions that I hoped would mitigate these problems: the xERC20 token standard suggested by Connext (as a public EIP) and the LayerZero OFT.
Let’s look at each and compare.
The Omnichain Fungible Token (OFT) standard is a token standard developed and used by the LayerZero team. The OFT standard allows the token issuer to transfer tokens quickly and cheaply across chains that have been integrated with LayerZero (it works with only LayerZero smart contracts).
OFT uses contract-to-contract communication to transfer OFTs directly between chains. Using the standard, the protocol burns an OFT token on the first chain and sends a receipt to the second chain, which then mints an equivalent number.
This solution works well because it maintains a static supply of the token (and only one version of the token) across chains. From their documentation: “It’s like the ERC-20 standard, only instead of allowing composability on different apps, it allows composability on 14 blockchains.”
The xERC20 standard suggested by Connext is an extension to ERC20 that defines a standard for bridging tokens. “The approach allows tokens to be minted and burned across chains by multiple bridges (canonical or 3rd-party) while giving token issuers the ability to granularly control their security preferences for each bridge using rate limits.”
xERC20 ensures that all whitelisted bridges can lock, burn, and mint your token … and, most importantly that they all use the same version of your token (the canonical version).
xERC20 also defines a lockbox that wraps tokens so that existing tokens that don’t implement the standard can still adhere to the requirements (similar to how WETH works).
xERC20 effectively creates tokens that can be transferred with no slippage and without multiple nonfungible representations.
An added benefit of xERC20 is that it also gives you sovereignty over your token. With the standard, you can define not only what bridges can work with your token but also how many tokens they can burn/mint. We’ll look at this in more detail in a minute.
How do these two solutions compare?
Comparing xERC20 to OFT
First, both of these solutions are an improvement over the current state of moving tokens across chains. I was excited to see senior teams working on better solutions, and I can’t wait to see where these ideas go next. I applaud any team working to solve these incredibly difficult web3 challenges.
Both of these solutions solve some of the main issues—they create a way to move tokens across chains with minimized security risk, less dependence on liquidity, and a single version of the token. And they do all this quickly and cheaply. That’s a huge win.
The first main difference between xERC20 and OFT, and the main reason I prefer xERC20, is that xERC20 is an open standard. It doesn’t lock you in with one specific bridge, so you avoid any risk of being trapped forever if something goes wrong with it.
The OFT standard is specific to LayerZero. It works really well! But it only works with LayerZero. And unlike xERC20, where the token creator maintains ownership of their token contracts on each chain, OFTs require the token issuer to relinquish ownership of the token contracts (which are deployed and owned by LayerZero). In the end, tokens that implement OFT are still tokens issued by LayerZero—effectively a third-party bridge. So they inherit many of the problems we outlined around third-party bridges above.
The second main difference, and one I find very interesting, is how xERC20 gives control of the bridging back to the team behind the token. It allows teams to decide which bridges can mint/burn the token, and it lets teams set rate limits (by bridge) on the number of tokens that can be minted/burned. Token teams can now specify their risk tolerance on a bridge-by-bridge basis.
Debating the pros and cons of this feature could be an entire article in itself! Giving control to the token issuer might rub some the wrong way. Control, maybe, should stay with the bridge.
But maybe giving control to the token team creates better incentives. If the token team can pull the ability to mint/burn the token, then maybe the bridge now needs to work a little harder to provide a minimum level of service and security. Maybe this drives healthy competition between the bridges. Maybe it makes better bridges. It’s something to think about.
xERC20 | OFT | |
Cross-bridge interoperability? | Yes, since this would be an ERC standard, all bridges could become compatible with it. | No, works only with LayerZero smart contract and 14 chains that LayerZero supports. |
Control of tokens issued? | Yes, allows to set bridge-specific max. Limits on the amount of tokens issued in a period of time. | No. |
How to implement xERC20
It’s pretty easy to make your ERC20 token compatible with xERC20.
The first and easiest option is to upgrade (or create) your contracts to implement the relevant functions (burn/mint/etc.). The steps are:
Inherit from ERC20:
contract XERC20 is ERC20 {
// ... code goes here ...
}
Create and maintain a mapping for limits associated with each bridge:
mapping(address => Bridge) public bridges;
// Bridge can be a struct representing bridges with any additional
// configs that the token issue may want to maintain
Implement the minting and burning logic:
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
Implement the bridge limits (these will update the mapping introduced above):
function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external onlyOwner {
_changeMinterLimit(_mintingLimit, _bridge);
_changeBurnerLimit(_burningLimit, _bridge);
}
function mintingMaxLimitOf(address _bridge) public view returns (uint256 _limit) {
_limit = bridges[_bridge].minterParams.maxLimit;
}
function burningMaxLimitOf(address _bridge) public view returns (uint256 _limit) {
_limit = bridges[_bridge].burnerParams.maxLimit;
}
If your token contract is not upgradeable (or you don’t want to upgrade), you can use the Lockbox contract to wrap your original token into a new token compatible with the xERC20 standard. Since the wrapping logic is reliable and well-tested (it’s based on the ETH-WETH pair), this option is considered trusted.
Using xERC20 with Connext
xERC20 is an open standard, and anyone can create an implementation. Connext already offers support for the standard. (Remember that xERC20 standard is permissionless and works with canonical bridges, but select bridges must be approved by the issuer before transfers.)
At a high level, you can use Connext by following these steps:
An implementation of the token on a “home” chain must be deployed.
A mintable and burnable representation of the token must be deployed on destination chains (the bridge must have permission to burn and mint this representation).
The token representation addresses must be added to the mainnet allowlist config file and the Chaindata mappings by submitting a PR.
Once the PRs are approved by the Connext team, the tokens can be transferred across chains using the bridge.
Status of xERC20 and OFT
It’s early in the life of the xERC20 standard, but progress is quickly being made. The standard has been audited and is already live with a few projects. The EIP to adopt the standard has been created, and implementation has begun. Alchemix recently announced support for the xERC20 standard. And Defi Wonderland has published a suggested implementation on their GitHub. This implementation has an interface for the xERC20 contract with eight core functions that the token issuer must implement. These are functions related to setting the Lockbox contract (setLockbox), issuance limits for bridges (setLimits, mintingMaxLimitOf, burningMaxLimitOf, etc.), and the core mint and burn functions.
OFT has been in production for some time and is stable (since it’s a closed standard, it doesn’t need to go through any adoption or voting process). V1 is available and supports EVM chains only. V2 supports non-EVM chains (such as Aptos).
Conclusion
The multichain hack woke up a lot of people to the fundamental problems with the current state of bridging. I’m really excited to see teams working on the next evolution of cross-chain tokens. Fixing the issues is obviously necessary for wider adoption of web3. For too long, we’ve accepted the current faulty system — we need the kinds of solutions offered by OFT and xERC20 now. I recommend you check them both out, participate in discussions, and support these innovative teams.
Have a really great day!
Subscribe to my newsletter
Read articles from John Vester directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
John Vester
John Vester
Information Technology professional with 30+ years expertise in application design and architecture, feature development, project management, system administration and team supervision. Currently focusing on enterprise architecture/application design utilizing object-oriented programming languages and frameworks.