This page describes the IBC token routing problem and the algorithm Skip Go API uses to select / recommend token denoms and IBC paths
tl;dr
The routing problem:
Skip Go API solves this problem by:
IBC transfers data over “channels” that connect two chains. Channels are identified by human-readable port names (e.g. “transfer”) and channel IDs (e.g. channel-1). For example, consider a transfer channel between Terra2 and Axelar:
Notice that both chains maintain their own channel IDs for the channel, which might not be the same. As an analogy, you might think of the different chains as cities and the channel as a road connecting them. IBC packets are cars driving across the road
When transferring a fungible token from one chain to another over a channel, the denomination of the token on the destination chain is uniquely and predictably determined by the source denomination + the channel(s) over which the token was transferred. Specifically the denomination algorithm is:
hash
is typically the sha256 hash function
Continuing the example from above, the denom of this version of WETH.axl on Terra2 is:
Now that you understand that IBC denoms get their names from their paths, you understand the crux of the routing problem: The same asset transferred to the same destination over two different paths will have different denominations.
Continuing the example from above, WETH.axl transferred directly from Axelar to Terra2 will have a different denom than WETH.axl transferred through Osmosis:
To make matters worse, multiple channels can exist between the same two chains (IBC is permissionless afterall), and IBC uses channel identifiers—not chain identifiers—to construct denoms. That means two different versions of the same asset will exist on the destination chain even when tokens are transferred from the same source chain, if they’re transferred over two different channels:
Why don’t we just consider them equivalent anyway and move on?
Some folks who don’t work with bridges on a regular basis view this path tagging as a bug, or might think we should just consider these different versions of the same asset as fungible anyway. But that’s not advisable!
The route-based denom construction is a critical security feature because the chain where the token has been transferred to is effectively trusting the validator set of the chain from which the token was transferred.
Applied to the example here, this trust model means using the purple version of WETH.axl implies trusting the Osmosis validator set AND the Axelar validator set, while using the blue version of WETH.axl only requires trusting the Axelar validator set.
Right now, there are about 70 IBC-enabled chains. At least one channel exists between almost every pair in this set. This dense graph of channels contains a very large number of different paths between almost any two chains, which creates many opportunities for “token winding” or “mis-pathing”, where a user sends an asset through a suboptimal path of channels from one chain to another and ends up with an illiquid / unusable version of their token.
Mis-pathing almost always produces a practically useless + illiquid version of their token on the destination chain because there’s usually only 1 useful version of a given asset on a given destination chain (if that). (There are over 50 versions of ATOM on JUNO!)
As a result, we need to be very careful to send the user through the correct sequence of channels. The next section explains our token routing algorithm.
Insight about routing: The correct route depends on the chains + the asset in question
Notice that the correct route for a particular asset A on a particular chain Chain-1 to another chain Chain-2 depends not only on the channels that exist between chain-1 and chain-2, but also on what asset-A is.
This is because asset A is defined by its path from its origin. Consider the following two cases:
Ultimately, we use a very simple routing algorithm:
A few notes about our data collection: