XES-0001d: Multi Bridge XRP minting #32
AdriaCarrera
started this conversation in
XES Proposals
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
XES-0001d: Multi Bridge XRP minting
Abstract
The XRPL EVM sidechain currently restricts XRP minting to a single authorized address via the
owner_addressfield in the erc20 module'sTokenPairmessage. This limits the protocol to a single bridge provider for cross-chain XRP transfers from XRPL.This specification introduces two independent but complementary protocol changes to support multiple bridge providers minting the same canonical XRP representation on XRPL EVM. First, the
x/erc20module is extended to replace the single-minter authorization model with a set of approved minter addresses. Second, a mint rate limiter constrains minting velocity per bridge, bounding the damage window if a bridge is compromised and buying time for governance response.Together, these changes enable bridge redundancy and competition while mitigating the shared-security risk through velocity-based minting controls.
Motivation
Problem
The XRPL EVM sidechain uses a single bridge provider (Axelar) for cross-chain XRP transfers from XRPL. The erc20 module's
TokenPairmessage stores a singleowner_addressthat is the only address authorized to mint XRP on the EVM side. This creates two problems:Supporting a second bridge (Wormhole) requires that both bridges mint the same canonical XRP asset on XRPL EVM. The alternative — introducing bridge-specific wrapped tokens such as
axlXRPorwmhXRP— would fragment liquidity, degrade user experience, and complicate application integration.Shared Security Risk
Allowing multiple bridges to mint a single fungible asset means the security of that asset becomes approximately as strong as the weakest authorized bridge. If any bridge is compromised, an attacker could mint unbacked XRP, inflating the canonical supply and affecting all holders regardless of which bridge they used. This is the most serious consequence of the multi-minter model and motivates the rate limiter specified in this document.
Why Two Components in One Specification
The multi-minter extension to
x/erc20is the minimal change required to unblock multi-bridge support. However, deploying it alone would expose the protocol to the shared security risk described above without any mitigation. The rate limiter provides security hardening by constraining minting velocity, reducing the damage window if a bridge is compromised and buying time for governance response.Specifying both components together ensures that the multi-minter feature is adopted with a clear commitment to the security control that makes it safe.
Non-Goals
The following are explicitly out of scope:
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Multi-Minter Authorization (
x/erc20)This component extends the erc20 module to support multiple authorized minter addresses per token pair, replacing the current single-owner model.
1.1 Protobuf Changes
The
TokenPairmessage incosmos.evm.erc20.v1MUST be extended with a new field:Field 5 (
owner_address) MUST be marked as deprecated. Field 6 (owner_addresses) is added asrepeated stringto hold the set of authorized minter addresses.A new field number (6) is used rather than reusing field 5 because the wire format of
stringandrepeated stringdiffers in Protocol Buffers. Reusing the field number would break wire compatibility with existing encoded state.1.2 Validation Rules
The
owner_addressesfield MUST satisfy the following invariants:TokenPaircontaining duplicate entries inowner_addresses.contract_owner == OWNER_MODULE, the list MUST contain at least one address.contract_owner == OWNER_EXTERNAL, theowner_addressesfield MUST be empty (external ownership is not affected by this specification).1.3 State Migration
A chain upgrade handler MUST perform the following migration for every stored
TokenPair:contract_owner == OWNER_MODULEandowner_address != "":owner_addresses = [owner_address].owner_addressto"".contract_owner == OWNER_EXTERNALorowner_address == "":The migration MUST be atomic — either all token pairs are migrated successfully, or the upgrade fails and the chain halts.
1.4 Minting Authorization Logic
The
MintCoinsfunction in the erc20 keeper currently performs the following check:This MUST be replaced with:
The existing error type
ErrMinterIsNotOwnerMUST be preserved for backwards compatibility with clients that match on error codes.1.5 Precompile Changes
The ERC-20 precompile's
Mintfunction routes toerc20Keeper.MintCoinsand extracts the minter address fromcontract.Caller(). No changes to the precompile's external ABI are REQUIRED. The authorization change is transparent to EVM callers — the precompile continues to accept the samemint(address,uint256)signature.1.6 Governance Messages
Two new Cosmos SDK messages MUST be introduced to manage the minter set:
MsgAddMinterauthorityMUST be the governance module account address.tokenis the ERC-20 contract address or Cosmos denomination identifying the token pair.minter_addressis the Cosmos SDK account address (bech32-encoded) to add.owner_addresses.contract_owner == OWNER_EXTERNAL.MsgRemoveMinterauthorityMUST be the governance module account address.tokenidentifies the token pair.minter_addressis the address to remove.owner_addresses.owner_addressesempty for a token pair withcontract_owner == OWNER_MODULE.Both messages MUST emit appropriate events containing the token identifier, the affected address, and the resulting
owner_addresseslist.1.7 Ownership Transfer (Deprecated)
The existing
TransferOwnershipandTransferOwnershipProposalfunctions operate on the singleowner_addressfield and are incompatible with the multi-minter model. Both functions MUST be deprecated.TransferOwnershipMUST be removed. Callers SHOULD useMsgAddMinterandMsgRemoveMinterto manage the minter set.TransferOwnershipProposalMUST be removed. Governance SHOULD useMsgAddMinterandMsgRemoveMinterinstead.MsgTransferOwnershipMUST be rejected at the message server with an appropriate error indicating that the function is deprecated and callers should use the new minter management messages.GetOwnerAddresshelper MUST be removed. Callers that need to check ownership SHOULD iterateowner_addressesdirectly.1.8 Query Changes
The
QueryTokenPairandQueryTokenPairsquery responses MUST return theowner_addressesfield. The deprecatedowner_addressfield SHOULD continue to be populated with the first element ofowner_addresses(if non-empty) for backwards compatibility with existing clients, but clients SHOULD migrate to readingowner_addresses.Mint Rate Limiting (via
MintHook)2.1 ERC-20 Mint Hook Interface
The erc20 module MUST define and export a
MintHookinterface:The erc20 keeper MUST accept a list of
MintHookimplementations and call them in order:BeforeMintMUST be called before the bank module'sMintCoinsin the erc20 keeper'sMintCoinsfunction. If any hook returns an error, the mint MUST be rejected.The rate limiting module MUST implement this interface and register itself with the erc20 keeper during app initialization. This design ensures the erc20 module has no knowledge of rate limiting logic — it simply calls its registered hooks. The hook interface also enables future security modules to add pre-mint checks without modifying the erc20 module.
If no hooks are registered (e.g., the rate limiter is not yet activated), the erc20 module MUST proceed with minting as normal (no-op hook path).
2.2 Rate Limit Configuration
A per-minter rate limit configuration MUST be stored on-chain:
minter_addressidentifies the minter this rate limit applies to. This address MUST also be present in the correspondingTokenPair.owner_addresses(see Multi-Minter Authorization).max_amount_per_windowis the maximum amount of XRP (in drops) that this minter MAY mint within the rolling window. String representation for arbitrary precision.window_sizeis the lookback window in blocks (M). For example, 7200 blocks for approximately 24 hours at 12-second block times.bucket_sizeis the granularity of accumulation in blocks (N). Minting amounts are aggregated into fixed-size block buckets.Rate limit configurations MUST be managed via governance. Setting
max_amount_per_window = "0"MUST act as an emergency pause, rejecting all mints for that minter.An OPTIONAL global rate limit configuration MAY be introduced:
If configured, the global rate limit MUST be checked in addition to per-minter limits. A mint MUST be rejected if it would exceed either the per-minter or global limit.
2.3 Bucketed Accumulation
Minting amounts MUST be tracked using fixed-size block buckets:
bucket_start_blockis the first block of this bucket's range. The bucket covers blocks[bucket_start_block, bucket_start_block + bucket_size).minted_amountis the cumulative amount minted by this minter during the bucket's block range.When a mint occurs at block height
H:bucket_start = H - (H % bucket_size).minted_amount.minted_amount = mint_amount.Buckets older than
window_sizeblocks MUST be pruned. Pruning MAY be performed lazily during mint operations or eagerly via anEndBlockhook.2.4 Window Evaluation
To evaluate the rate limit at block height
H:window_start = H - window_size.minted_amountacross all buckets wherebucket_start_block >= window_startfor the given minter.window_total.The mint MUST be rejected if
window_total + mint_amount > max_amount_per_window.This block-based rolling window provides:
bucket_sizeblocks, preventing an attacker from minting2xthe limit at window boundaries.bucket_sizevalues provide finer-grained enforcement at the cost of more state entries. Larger values reduce state overhead with coarser enforcement.2.5 Enforcement Order
Rate limit checks MUST be performed after multi-minter authorization. The full mint validation order is:
owner_addresses? (x/erc20authorization)BeforeMinthook, if active)2.6 Governance Parameters
The following parameters MUST be configurable via governance:
max_amount_per_windowwindow_sizebucket_sizeglobal_max_amount_per_windowglobal_window_sizeglobal_bucket_size2.7 Events
The following events MUST be emitted:
EventRateLimitExceeded: Emitted when a mint is rejected due to rate limiting. MUST includeminter_address,requested_amount,window_total,max_amount_per_window.EventRateLimitConfigUpdated: Emitted when a minter's rate limit configuration is changed via governance.Rationale
Multi-Minter vs. Bridge Aggregator Contract
An alternative to modifying
TokenPairwould be to deploy a bridge aggregator contract that acts as the sole minter and delegates to bridge-specific logic internally. This was rejected because:Block-Based Rolling Window for Rate Limiting
A fixed-window rate limiter (resetting at regular intervals) was considered but rejected because it allows boundary-burst attacks: an attacker can mint the full limit at the end of one window and again at the start of the next. A pure sliding window avoids this but requires per-transaction timestamp tracking.
The block-based rolling window with bucketed accumulation provides a practical middle ground: it rolls forward by
bucket_sizeblocks (no full reset), uses blocks as the native time unit (deterministic across validators), and limits state overhead via aggregation into buckets.Extensibility via Mint Hooks
The rate limiting logic is implemented as a
MintHookrather than being embedded directly in the erc20 module. This separation of concerns means:Two Components in One Document
The two components form a coherent security stack. Multi-minter authorization enables the feature, and the rate limiter constrains the velocity of potential exploitation. Separating them into independent specifications risks the multi-minter extension shipping without a concrete commitment to the security mitigation. Specifying them together signals to reviewers, implementers, and bridge operators that multi-minter support comes with a clearly defined security control.
Considered and Rejected: Collateral Oracle
A third component — a Collateral Oracle (
x/collateral) — was evaluated as a security control. The oracle would be a dedicated on-chain module with an off-chain committee that periodically attests the XRP balance locked in each bridge's door account on XRPL. Each bridge's minting would be capped at the attested locked amount, preventing any bridge from minting more XRP than it has collateral for.After analysis, this mechanism was determined to be ineffective against total collateral extraction in a multi-bridge setting due to a circular flow attack:
The attestation oracle cannot distinguish between legitimate user deposits and attacker-recycled funds. Because minted XRP is fungible on XRPL EVM, cross-bridge exits are always possible, making this circular flow an inherent structural property of the multi-bridge design.
Additionally, the oracle would introduce significant complexity — a new Cosmos SDK module, an off-chain oracle committee, epoch-based consensus, quorum mechanisms, and staleness management — along with new trust assumptions (the oracle committee) and operational overhead. A rate limiter achieves the same practical security outcome (buying time for governance to respond) with far less complexity and no additional trust assumptions.
A detailed analysis of this attack vector is available in
collateral-oracle-analysis.md.Backwards Compatibility
Multi-Minter Authorization (
x/erc20)TokenPairmessage adds a new field (owner_addresses, field 6) and deprecatesowner_address(field 5). Since a new field number is used, this is wire-compatible for decoders that tolerate unknown fields. However, clients that rely onowner_addressbeing populated MUST be updated. As a transitional measure,owner_addressSHOULD be populated with the first element ofowner_addressesin query responses.TokenPairrecords. The upgrade is a coordinated halt-and-restart.mint(address,uint256)function signature does not change. EVM callers are unaffected.ErrMinterIsNotOwnercontinues to be returned for unauthorized minters.Mint Rate Limiting
MinterRateLimit,MintBucket) and new governance parameters. No existing interfaces are modified beyond the addition of theMintHookcall in the erc20 keeper.MintHookimplementations. This is an internal interface change that does not affect the external precompile ABI or Cosmos message interface.Activation
Each component SHOULD be gated behind a distinct chain upgrade handler with a unique upgrade name. The multi-minter extension MUST be activated first. The rate limiter CAN be activated independently but is expected to ship together with the multi-minter extension in a single upgrade for simplicity and reduced operational burden on validators.
Test Cases
Multi-Minter Authorization (
x/erc20)owner_addressesmints XRPowner_addresses, both mint independentlyowner_addressesattempts to mintErrMinterIsNotOwnerMsgAddMinteradds a new address via governanceMsgRemoveMinterremoves an address via governanceMsgRemoveMinterattempts to remove the last addressOWNER_MODULE)MsgAddMinterwith duplicate addressowner_addressmigrated toowner_addresses[0]OWNER_EXTERNAL:owner_addressesremains emptyMint Rate Limiting
EventRateLimitExceededmax_amount_per_window = 0Cross-Component Integration
x/erc20authorizationReference Implementation
Reference implementations will be provided as pull requests to the following repositories:
x/erc20):xrplevm/evm— erc20 module protobuf, keeper, precompile, and state migration changes.xrplevm/evmorxrplevm/node— rate limit state, bucketed accumulation, mint hook implementation, and enforcement logic.Per the XES specification process, this document cannot be promoted to a Candidate Specification until the relevant changes have been merged into the node repository's
mainbranch.Security Considerations
Shared Security Model (Multi-Minter Alone)
With only the multi-minter extension deployed, all authorized bridges share a single security domain. A compromise of any bridge allows the attacker to mint unbounded XRP, diluting the entire canonical supply on XRPL EVM. The security posture becomes approximately as strong as the weakest authorized bridge. This is the primary motivation for the rate limiter, which SHOULD be deployed together with the multi-minter extension.
Cross-Bridge Liquidity Extraction
Because both bridges mint the same fungible XRP, users can deposit through one bridge and withdraw through another. This creates asymmetric pressure on bridge liabilities: one bridge's door account may be drained while the other accumulates excess XRP.
This is a structural property of the single-asset model and is explicitly a non-goal to solve in this specification. Bridge operators SHOULD monitor their door account balances and manage rebalancing off-chain. The circular flow attack described in the Rationale section ("Considered and Rejected: Collateral Oracle") demonstrates that on-chain collateral attestation cannot prevent this cross-bridge extraction.
Rate Limit Gaming
An attacker who compromises a bridge can mint at exactly the rate limit continuously. The rate limiter does not prevent exploitation — it slows it. The value of rate limiting is buying time for governance to respond (e.g., removing the compromised minter via an emergency proposal).
This imposes a constraint on parameter selection: the governance response time MUST be faster than the time it takes for an attacker to exhaust the rate limit and cause material damage. Rate limit parameters SHOULD be calibrated accordingly.
Governance Key Management
Adding and removing minters (
x/erc20) and configuring rate limits are governance-controlled actions. The security of the entire multi-bridge system ultimately depends on the security and responsiveness of governance.Recommendations:
max_amount_per_window = 0) provides an immediate circuit breaker that governance can trigger.State Migration Risk (
x/erc20)The protobuf change from
owner_addresstoowner_addressesrequires a state migration during a chain upgrade. An incorrect migration could result in token pairs with emptyowner_addresses, which would permanently lock minting for those pairs until corrected by a subsequent upgrade. Thorough migration testing on testnets is essential before mainnet deployment.Defense-in-Depth Evaluation Order
When both components are active, mint requests MUST be evaluated in the following order:
x/erc20): Is the sender inowner_addresses?window_total + amount <= max_amount_per_window?A failure at either layer MUST reject the mint. If the rate limiter module is not yet activated, the rate limit check MUST be skipped (no-op). The multi-minter authorization MUST function independently regardless of whether the rate limiter is active.
Beta Was this translation helpful? Give feedback.
All reactions