IBC Rate Limits
The x/ibc-rate-limit middleware: per channel and denom caps on supply shift, unique senders, and per-address transfers, plus the governance messages.
x/ibc-rate-limit is IBC middleware that caps token flow over IBC channels so that a burst of inflows or outflows cannot destabilize supply. Governance sets the limits per channel and denom. Node operators and integrators need this page to understand why a transfer was rejected and how limits are shaped.
{
"channel_id": "channel-2",
"denom": "ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349",
"supply_shift_limits": [
{ "max_amount": "1000000000000", "timeframe_type": "TIMEFRAME_TYPE_DAY", "timeframe_duration": "1" }
],
"unique_sender_limits": [
{ "max_unique_senders": "500", "timeframe_type": "TIMEFRAME_TYPE_HOUR", "timeframe_duration": "1" }
],
"address_limits": [
{ "max_transfers": "20", "max_amount": "100000000000", "timeframe_type": "TIMEFRAME_TYPE_DAY", "timeframe_duration": "1" }
]
}How It Works
The module wraps the transfer application. Its hooks:
- Check limits before an inbound packet is processed (
OnRecvPacketOverride). - Check limits before an outbound packet is sent (
SendPacketOverride). - Record transfer statistics after a successful transfer.
Three kinds of limit exist:
- Supply shift: the absolute value of net flow (inflows minus outflows) over a timeframe.
- Unique senders: how many distinct addresses may send through a channel in a timeframe.
- Per address: how many transfers and how much total amount one address may send in a timeframe.
Each config targets one channel_id and denom. An empty channel_id applies to every channel; denom is required. Configs are checked in order and the first match is used. If no config matches, the transfer is allowed. Inside a matching config every listed limit is checked; if any would be exceeded, the transfer is rejected.
Timeframes:
timeframe_type | timeframe_duration means |
|---|---|
TIMEFRAME_TYPE_BLOCK | number of blocks |
TIMEFRAME_TYPE_HOUR | hours, converted to blocks using block time |
TIMEFRAME_TYPE_DAY | days, converted to blocks using block time |
A max_amount, max_unique_senders, or max_transfers of 0 disables that particular limit.
Params
message Params {
// Configurations are checked in order, and the first matching config is used
// If no config matches, the transfer is allowed (no rate limit)
repeated RateLimitConfig rate_limits = 1;
}
message RateLimitConfig {
string channel_id = 1; // empty = all channels
string denom = 2; // required
repeated TimeframeLimit supply_shift_limits = 5;
repeated UniqueSenderLimit unique_sender_limits = 6;
repeated AddressLimit address_limits = 7;
}
message TimeframeLimit {
string max_amount = 1; // math.Int as string; 0 disables
TimeframeType timeframe_type = 2;
int64 timeframe_duration = 3;
}
message UniqueSenderLimit {
int64 max_unique_senders = 1; // 0 disables
TimeframeType timeframe_type = 2;
int64 timeframe_duration = 3;
}
message AddressLimit {
int64 max_transfers = 1; // 0 disables
string max_amount = 2; // 0 disables
TimeframeType timeframe_type = 3;
int64 timeframe_duration = 4;
}Tracked state per channel: ChannelFlow.net_flow (positive means more inflow than outflow), ChannelFlowWindow (window_start height and window_duration in blocks), UniqueSenders.senders, and AddressTransferData (transfer_count, total_amount).
Messages
Both messages are signed by the module authority, which defaults to the x/gov module account (bb10d07y265gmmuvt4z0w9aw880jnsr700jelmk2z on mainnet). Submit them inside a governance proposal.
MsgUpdateRateLimit
Adds or replaces one config. If a config with the same channel_id and denom exists, it is updated in place; otherwise the config is appended.
{
"@type": "/ibcratelimit.MsgUpdateRateLimit",
"authority": "bb10d07y265gmmuvt4z0w9aw880jnsr700jelmk2z",
"rate_limit": {
"channel_id": "channel-40",
"denom": "ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8",
"supply_shift_limits": [
{ "max_amount": "5000000000000", "timeframe_type": "TIMEFRAME_TYPE_DAY", "timeframe_duration": "1" }
],
"unique_sender_limits": [],
"address_limits": []
}
}| Field | Type | Required | Description |
|---|---|---|---|
authority | string | yes | Module authority (governance account) |
rate_limit | RateLimitConfig | yes | Config to add or update |
MsgUpdateParams
Replaces the whole parameter set. All parameters must be supplied.
{
"@type": "/ibcratelimit.MsgUpdateParams",
"authority": "bb10d07y265gmmuvt4z0w9aw880jnsr700jelmk2z",
"params": {
"rate_limits": [
{
"channel_id": "",
"denom": "ubadge",
"supply_shift_limits": [
{ "max_amount": "100000000000000", "timeframe_type": "TIMEFRAME_TYPE_DAY", "timeframe_duration": "1" }
],
"unique_sender_limits": [],
"address_limits": []
}
]
}
}| Field | Type | Required | Description |
|---|---|---|---|
authority | string | yes | Module authority (governance account) |
params.rate_limits | RateLimitConfig[] | yes | Full ordered list of configs |
The module has no query service. Read the live configuration from the module's genesis export or from the governance proposal that set it.