Welcome to the new Provenance Blockchain developer documentation portal!
logo
โš ๏ธ
Unfortunately the original version could not be directly used due to extensive osmosis references, an incompatible Cosmos SDK version, and lack of support for IBC v6.x.For additional documentation, please refer to the above link. This explains the logic behind the customization of this module in Provenance. Where not explicitly called out, the Provenance Module adheres to the Osmosis Module.

Summary

The x/ibcratelimit module is a governance-configurable IBC middleware that adds rate limits to IBC transfers as a safety control against bugs or hacks, implementing time-based percentage limits on asset flows through CosmWasm contracts with separate inflow and outflow controls, channel value caching, and support for both per-denomination and per-channel rate limiting to prevent catastrophic fund losses while maintaining controlled bridge liveness.

IBC Rate Limit

The IBC Rate Limit module is responsible for adding a governance-configurable rate limit to IBC transfers. This is a safety control, intended to protect assets on osmosis in event of:
  • a bug/hack on osmosis
  • a bug/hack on the counter-party chain
  • a bug/hack in IBC itself
This is done in exchange for a potential (one-way) bridge liveness tradeoff, in periods of high deposits or withdrawals.
The architecture of this package is a minimal go package which implements an IBC Middleware that wraps the ICS20 transfer app, and calls into a cosmwasm contract.

Motivation

The motivation of IBC-rate-limit comes from the empirical observations of blockchain bridge hacks that a rate limit would have massively reduced the stolen amount of assets in:

Rate Limit Types

We express rate limits in time-based periods. This means, we set rate limits for (say) 6-hour, daily, and weekly intervals. The rate limit for a given time period stores the relevant amount of assets at the start of the rate limit. Rate limits are then defined on percentage terms of the asset. The time windows for rate limits are currently not rolling, they have discrete start/end times.
We allow setting separate rate limits for the inflow and outflow of assets. We do all of our rate limits based on the net flow of assets on a channel pair.
We currently envision creating two kinds of rate limits:
  • Per denomination rate limits - allows safety statements like "Only 30% of Stars on Osmosis can flow out in one day" or "The amount of Atom on Osmosis can at most double per day"
  • Per channel rate limits - Limit the total inflow and outflow on a given IBC channel, based on "USDC" equivalent, using Osmosis as the price oracle
We currently only implement per denomination rate limits for non-native assets.

Go Middleware

The middleware needs to implement the porttypes.Middleware interface and the porttypes.ICS4Wrapper interface. Of those interfaces, just the following methods have custom logic:
  • ICS4Wrapper.SendPacket - forwards to contract, with intent of tracking of value sent via an ibc channel
  • Middleware.OnRecvPacket - forwards to contract, with intent of tracking of value received via an ibc channel
  • Middleware.OnAcknowledgementPacket - forwards to contract, with intent of undoing the tracking of a sent packet if the acknowledgment is not a success
  • OnTimeoutPacket - forwards to contract, with intent of undoing the tracking of a sent packet if the packet times out

Cosmwasm Contract Concepts

The tracking contract uses the following concepts:
  • RateLimit - tracks the value flow transferred and the quota for a path
  • Path - is a (denom, channel) pair
  • Flow - tracks the value that has moved through a path during the current time window
  • Quota - is the percentage of the denom's total value that can be transferred through the path in a given period of time (duration)

Necessary Information

To determine if a packet should be rate limited, we need:
  • Channel: The channel on the Osmosis side: packet.SourceChannel for sends, and packet.DestinationChannel for receives
  • Denom: The denom of the token being transferred as known on the Osmosis side
  • Channel Value: The total value of the channel denominated in Denom
  • Funds: the amount being transferred

Notes on Denom

We always use the denom as represented on Osmosis. For native assets that is the local denom, and for non-native assets it's the "ibc" prefix and the sha256 hash of the denom trace (ibc/...).
Sends:
  • For native denoms, we can just use the denom in the packet. Example result: uosmo
  • For non-native denoms, the contract needs to hash the denom trace and append it to the ibc/ prefix. Example result: ibc/<hash>
Receives:
  • If the chain is a sink for the denom, we build the local denom by prefixing the port and the channel (transfer/local-channel) and hashing that denom. Example result: ibc/<hash>
  • If the chain is the source for the denom:
    • The token is a native token, in which case we just remove the prefix added by the counterparty. Example result: uosmo
    • The token is a non-native token, in which case we remove the extra prefix and hash it. Example result: ibc/<hash>

Channel Value Strategy

For calculating the channel value:
  • For non-native tokens (ibc/...), the channel value should be the supply of those tokens in Osmosis
  • For native tokens, the channel value should be the total amount of tokens in escrow across all ibc channels

Caching

The channel value varies constantly. To have better predictability, and avoid issues of the value growing if there is a potential infinite mint bug, we cache the channel value at the beginning of the period for every quota.

Integration

The rate limit middleware wraps the transferIBCModule and is added as the entry route for IBC transfers. The module is also provided to the underlying transferIBCModule as its ICS4Wrapper.
This integration can be seen in osmosis/app/keepers/keepers.go

Messages

The contract specifies the following messages:

Exec

  • AddPath - Adds a list of quotas for a path
  • RemovePath - Removes a path
  • ResetPathQuota - If a rate limit has been reached, the contract's governance address can reset the quota so that transfers are allowed again

Sudo

Sudo messages can only be executed by the chain:
  • SendPacket - Increments the amount used out of the send quota and checks that the send is allowed. If it isn't, it will return a RateLimitExceeded error
  • RecvPacket - Increments the amount used out of the receive quota and checks that the receive is allowed. If it isn't, it will return a RateLimitExceeded error
  • UndoSend - If a send has failed, the undo message is used to remove its cost from the send quota

Queries

Query

  • GetQuotas - Returns the quotas for a path

Params

The middleware uses the following parameters:
Key
Type
ContractAddress
string
  • ContractAddress - The contract address is the address of an instantiated version of the contract provided under ./contracts/