IBC is an exceptionally well designed protocol that enables permissionless deployment of fast, secure communication channels with extensible messaging overlays. But more than that, it’s a lingua franca of the Interchain, a network that now comprises over 110 sovereign applications.
Skip’s first foray into turning IBC into a platform that developers can build on was the Skip Go API, which enables developers to link app chains together, creating unified cross-chain user experiences. We also built an open source cross-chain transfer and swap front-end, the Skip Go App (previously ibc.fun), to show other developers the kind of seamless multi-chain workflows one can achieve with our intelligent routing.
That said, developers building IBC-enabled applications still face which are outside of the IBC protocol itself. In this article we’ll focus on three of these:
Fee denominations - Most Cosmos chains accept their own staking token to pay for transaction fees, often leaving users in a situation where they want to take an action, but have funds in the wrong denomination to make a fee payment.
Fee pricing - Problems with payment in alternative denominations are compounded by the fact that most Cosmos chains do not have an in-protocol mechanism for transaction fee price discovery.
Hiring relayers - “Relayer incentivization” has been a long-debated and lamented topic since before the launch of IBC, and remains an unsolved problem to this day. Relayers are typically paid through a variety of out of band arrangements, none of which scale well as the ecosystem continues to grow.
Interestingly, the seemingly unrelated work that Skip has been doing to build an enshrined oracle, Skip Connect (previously Slinky), can become extremely useful in tackling these problems.
Skip Connect was originally created as an enshrined oracle for importing external data into a chain without relying on an intermediary network. Instead it leverages the chain’s own validator set and using ABCI++ to program the consensus process itself to collect, validate, and secure data—and soon a lot more.
Skip Connect is comprised of two components, a set of Cosmos SDK modules which are incorporated into the chain binary, as well as a sidecar process that each validator is required to run in tandem.
The side-car you can imagine as a container for running co-localized services. For price feeds this comprises three operations:
Querying data providers such as the Binance API or an Ethereum node for Uniswap prices.
Perform local aggregation over different providers to get a single price for each asset pair.
Submitting locally aggregated prices to the co-localized node.
Once the validator passes a local view of prices to their own node, the Skip Connect module—running as part of the chain binary—performs the following operations to reach consensus on a final set of prices:
Submits locally aggregated data to the P2P network via vote extensions and collects other validators’ price data
Aggregates received data, asking each validator to compute the stake-weighted median of the prices received by other validators
Skip Connect will soon have a new programmable provider system, allowing developers to extend consensus and execution to arbitrary off-chain jobs. With programmable providers, a set of standard interfaces will facilitate 2-way communication between the on-chain components and off-chain extensions, so jobs can drive on-chain functionality through ABCI++.
We’re glossing over a few details, but the following diagram captures the Skip Connect high-level control flow. It should be noted that Skip Connect isn’t opinionated about where data originates or how it reaches the sidecar. Data can be “pulled” in from providers or “pushed” into the Sidecar.
Finally, in order make it practical for validators to run Connect across many chains without creating an enormous amount of overhead, Skip has architected Connect such that one sidecar instance can serve data feeds to multiple nodes. This 1-to-n
configuration reduces validator overhead by minimizing operational costs and monitoring requirements, while simplifying the deployment of cross-chain messaging services, i.e. relaying. And because validators will share one logical sidecar instance across many chains, we can use this to our advantage, turning the sidecar into a latent cross-chain distribution network.
In the course of building Skip Go we’ve become acutely aware of several critical transaction workflows where users still tend to get “stuck.” Most of these boil down to users having a token that doesn’t happen to be accepted for payment on whatever chain they’re trying to use. Fortunately we can use Skip Connect to start solving these user pain points.
We’ll first look at how Skip Connect can help users pay for transaction fees locally using alternative denominations, then we’ll use this this idea that a networked set of Skip Connect instances can be used to distribute information to extend this to the cross-chain setting.
Problem: I want to send my stATOM on the Cosmos Hub to a friend, but I don’t have ATOM to pay the transaction fee.
Solving this problem will require multiplying a known transaction fee by a fresh exchange rate for whatever token the user has on-hand.
To do accomplish this we’ll first need to make the accepted fee denominated in the native gas token available within the state machine. EIP-1559 was designed for exactly this purpose, providing an in-protocol “base fee.” Skip has been collaborating with the Informal and Binary teams to add EIP-1559 functionality to the Cosmos Hub and upstream this work to the Cosmos SDK, making this in-protocol fee model widely available to Cosmos SDK-based chains.
In our example at the top, we also need an exchange rate between ATOM:stATOM, which Connect can provide on a block-by-block basis. We’ll assume for now that the chain already has a mapping between the stATOM IBC denom and the stATOM price feed. This association could be made via on-chain governance or adding a Skip Connect provider that calls the Skip Go API using the /v1/fungible/assets
endpoint. Validators would then deliver denom data as part of their submitted VoteExension
.
With the correct denom mapping in-hand, we then modify the AnteHandler
to take our ATOM-denominated base fee computed, and multiply that fee by the most recent exchange rate provided by the ATOM:stATOM price reported by Skip Connect. The transaction fee denominated in stATOM is then:
Problem: I want to move my ATOM on the Hub to Neutron without relying on a third-party relayer; however, I don’t have NTRN on Neutron to pay the destination chain transaction fee.
One long-standing UX goal that remains out of reach of the the IBC protocol has been allowing users to relay packets without engaging a distinct third party relayer. The critical issue that makes this impractical today is that users must already have the required fee token on the destination chain in order to submit a transaction with the RecvPacket
themselves. In our example above, the user finds themself in a chicken-and-egg scenario, where they must somehow have NTRN in their Neutron account to pay the destination fee, but sending themselves the required NTRN tokens from another chain itself requires an IBC transfer. We must introduce a third party relayer simply to solve the inventory problem of having the correct fee token.
To be more precise with our example above, Neutron also happens to accept ATOM as a fee token, however users must have ATOM on Neutron first in order to pay the transaction fee. And it’s not currently possible to send IBC tokens while simultaneously using those tokens in the ICS-20 packet to pay the transaction fee on the destination chain.
When we look a little deeper into what’s going on here the tokens needed for fee payment do not yet exist on the destination chain prior to the RecvPacket
landing. Moreover, even if we wanted to deduct the fee directly from tokens generated transiently from the ICS-20 packet during block execution, the ICS-20 tokens the spec does not include a field for specifying how many tokens are eligible to be used for fee payment out of the sent amount. We can use Skip Connect to design around these issues, however we’ll first need to know a few details about how EIP-1559 and ICS-29 work, because our solution will require functionality from both.
EIP-1559 - Is the in-protocol fee controller originally developed for Ethereum (I actually contributed in small part to this work several years ago) and now used by numerous blockchains. The mechanism includes two fee components:
A base fee, which is deterministically calculated from the fractional utilization of previous blocks. In Ethereum the base fee is burned, however this isn’t strictly necessary, as long as the base fee is not given directly to the proposer. For instance Cosmos SDK chains could send the fee to the distribution module.
A tip, which should be a small payment given to the proposer. Just enough to ensure the proposer is incentivized to include the transaction in the block.
ICS-29 - This is a recent IBC application standard for including fees that can be used to pay relayers performing the service of relaying packets. When a user submits a transaction to initiate the outgoing IBC message, they can specify three additional fees that relayers are eligible to claim, representing actions at different points in the transaction lifecycle, a ReceiveFee
, AckFee
, and TimeoutFee
. In delivering the packet the relayer constructs a transaction that includes their own payment address. This allows them to claim the fee for the corresponding action on the origin chain upon delivery of the acknowledgment packet.
Historically, Skip has been somewhat critical of the ICS-29 design because validators could engage in a form of cross-chain MEV stealing by silently replacing relayer payment addresses with their own before proposing the block. However, what we’d like to do here is repurpose ICS-29, and instead encourage proposers to take the relay fee in order to pay themselves. Let’s see how this works.
Transaction sequence
The upcoming destination chain proposer running Connect computes stake-weighted prices from prices reported by $2/3+$ stake in the VoteExtensions
of the previous block.
Their Skip Connect instance detects an outgoing IBC request on the origin chain, then using their stake-weighted price, determines if the ICS-29 fee exceeds the base fee + an acceptable tip amount after price conversion.
Assuming the fee amount is sufficient, destination chain proposer builds an IBC packet with origin chain light client proof and relays this information locally from their origin chain node to the destination chain node.
The proposer then constructs and proposes a destination chain block with a transaction containing this IBC packet, adding their own address to claim the ICS-29 relay fee. Additionally, in the metadata of the transaction they include information about the fee denomination and a fresh price to convert to the destination chain fee denomination. We enable this special transaction to be marked for zero fee execution (destination chain base fee is ignored), and instead indicate to the state machine that the gas expended by this transaction should be recorded for future use.
All other validators confirm the validity of the attested state pertaining to the ICS-29 fee escrowed on the origin chain, along with the conversion price contained in the transaction metadata. If the converted fee amount exceeds the amount they would expect to pay for transaction inclusion on the destination chain then they will confirm the block is valid and the block will be included in the chain.
With the receive packet included, the destination chain proposer can retrieve their ICS-29 payment on the origin chain by delivering an acknowledgment packet which includes their own address in the relayer payment field.
Because the destination chain proposer now owes the destination chain a quantity equivalent to the base fee during that block, this amount is then prorated from their future block rewards.
In summary, we let this overlapping validator who is about to propose a destination block, construct and relay a packet between their own nodes using Skip Connect as a local delivery system. We then use Connect to read information about escrowed ICS-29 fee tokens on the origin chain, along with the price required to convert those tokens to the denom required by the destination. We get around the denomination mismatch by allowing the transaction fee for the IBC packet to be paid lazily through a deduction in the proposers future block rewards. The proposer then pays themselves by claiming the ICS-29 fee on the origin chain.
Not every application needs an oracle. So we don’t expect every Cosmos SDK chains to have Skip Connect enabled. However, we don’t actually need chains on both sides to have the Skip Connect module to get this same benefit.
By recognizing that validators on one Skip Connect chain also run nodes on other non-Connect chains, we can extend automatic relaying of IBC packets to non-Connect networks. If the relay fee of inbound packets is amortized into the EIP-1559 tip, simply allow validators to optionally register other chains where they actively validate to watch for outgoing IBC packets and pick up the associated fees by relaying between their existing nodes. Relaying outbound packets will still require validators to hold a small amount of inventory on the destination chain, but we have some other tricks up our sleeve that can help—maybe the subject of a future blog post.
With this asymmetric setup, very few Skip Connect deployments are required to provide automatic relay functionality to all Cosmos SDK chains because coverage scales with validator overlap, which is exceptionally high. Cosmostation, for example, runs validators on 61 Cosmos SDK chains!
In some sense I’ve been working on blockchain fees for almost 5 years now. First with contributions to EIP-1559, then running the Cosmos fee market working group circa 2021, and now at Skip—where every day we try to chip away at one more piece of the UX to help make transacting across chains feel seamless. I gave a talk on this subject last year that includes some other fun ideas if you’re interested.
While this post describes a system that doesn’t yet exist, we’re hard at work putting the foundational pieces in place. The Skip team is also collaborating with the IBC, Cosmos SDK, and Comet core dev teams on several other initiatives that will help complete the cross-chain user experience. We’re excited to engage validators, chains, front-ends, and wallets to start threading all the components together soon. In the near future you should be able to use any token on any chain to transact on any other. Enabling user experiences with that kind of seamless composability is where we think things start to get really interesting for the Interchain.
Sam Hart is the Head of Product and Strategy at Skip, where he helps build next generation cross-chain infrastructure for application-specific blockchains. Skip has two product lines, the first is Skip Go, the simplest, most reliable way to route across any chain or DEX, and includes a developer API, a multi-chain swap and transfer app, and an embeddable widget. The second is Skip Connect, a high performance enshrined oracle that provides block-by-block data at chain-level security.
Sam is also co-founder of Timewave, a protocol-to-protocol lending market, and a member of the research collective Other Internet. Prior to working at Skip he spent several years at the Interchain Foundation helping to bring the IBC network to life. You can find Sam on X at @hxrts.