Overview
In blockchain ecosystems, transaction fees are typically paid in the network's native currency. For The Root Network (TRN), this means users need XRP to pay for transaction fees. However, this requirement can create friction for users who hold other tokens but lack the native currency for gas payments. To address this challenge, we've implemented the Fee Proxy
pallet, which enables users to pay transaction fees using any token - given that it has sufficient liquidity against XRP in TRN's on-chain Decentralized Exchange (DEX).
Understanding Fee Proxy
The Fee Proxy pallet is a critical infrastructure component that intercepts transaction fee payments and enables dynamic token conversion for gas fees. This means users can execute transactions on TRN using any token in their wallet, as long as there's adequate liquidity for that token against XRP in the on-chain AMM.
Key Features
- Flexible Fee Payment: Users can pay transaction fees in any token with XRP liquidity
- Automatic Token Conversion: Seamless conversion of chosen payment token to XRP for gas fees
- DEX/AMM Integration: Utilizes TRN's on-chain AMM for efficient token swaps; this is a natural price oracle since arbitragers are incentivised to balance the price/value of the token(s)
- Additional utilization of the AMM - which further incentivises liquidity from liquidity providers
- EVM Compatibility: Supports both substrate extrinsics and EVM transactions
How It Works
In traditional blockchains, users must hold the native currency (like ETH for Ethereum) to pay for transaction fees. However, TRN implements a novel gas abstraction mechanism that allows users to pay transaction fees using any token that has sufficient liquidity against the native currency (XRP).
The Role of the DEX in Fee Abstraction
At the heart of this mechanism lies our Uniswap V2-based Automated Market Maker (AMM) implemented as a Substrate pallet. The AMM serves two crucial functions:
- It provides real-time price discovery for tokens through liquidity pools
- It enables the actual swap of user's chosen payment token to the native currency
When a user initiates a transaction using a non-native token for fees, the system leverages the AMM's constant product formula (x * y = k
) to determine the exact amount of the chosen token needed to cover the gas costs.The price discovery occurs automatically through the existing liquidity pools (specifically of the token and XRP), ensuring that fees are priced fairly according to current market conditions.
Price Discovery and Market Equilibrium
The accuracy and reliability of our gas abstraction system heavily depend on maintaining correct price discovery in the AMM pools.
This is achieved through a combination of market forces and arbitrage opportunities:
Arbitrage Mechanisms
When the price of a token in our AMM pools deviates from external market prices, arbitrage opportunities emerge.
Trading bots and arbitrageurs are incentivized to:
- Buy tokens from our pools when prices are lower than external markets
- Sell tokens to our pools when prices are higher than external markets
This constant arbitrage activity helps maintain price alignment with broader market rates, ensuring that users paying gas fees in alternative tokens are charged fair market rates.
Dynamic Pool Rebalancing
The AMM's constant product formula naturally creates price movements as pool ratios change:
- Large token swaps for gas payments can temporarily impact pool ratios
- This creates immediate arbitrage opportunities
- Arbitrageurs quickly restore the balance by taking opposing positions
- The resulting equilibrium reflects the true market price
For example, if many users pay gas fees using TOKEN-A, gradually depleting the TOKEN-A supply in the pool:
- The pool ratio shifts, making TOKEN-A more expensive in terms of XRP
- Arbitrageurs notice the price discrepancy
- They buy XRP from external markets and trade it for TOKEN-A in our pools
- This action replenishes the TOKEN-A supply and stabilizes prices
Economic Incentives
The system's stability is reinforced by several economic incentives:
- Arbitrageurs earn profits by correcting price discrepancies
- Liquidity providers earn fees from all swaps, including gas payment conversions
- Users are protected by specifying
max_payment
limits on their transactions
This creates a self-sustaining ecosystem where market participants are naturally incentivized to maintain accurate price discovery, ensuring the gas abstraction mechanism remains reliable and cost-effective for users.
Integration with The Root Network
The Fee Proxy pallet implements the OnChargeTransaction
trait, which is the core mechanism for handling transaction fee payments on Substrate-based chain.The Fee Proxy pallet is deeply integrated with TRN's infrastructure:
Transaction Payment Configuration
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = FeeProxy;
// ... other configuration parameters
}
EVM Configuration
impl pallet_evm::Config for Runtime {
type Runner = FeePreferencesRunner<Self, Self, Futurepass>;
type OnChargeTransaction = FutureverseEVMCurrencyAdapter<Self::Currency, TxFeePot>;
// ... other configuration parameters
}
The trait implementations (FeeProxy
and FeePreferencesRunner
) highlighted above allow the FeeProxy components to hook into relevant pallets which deal with withdrawal of funds/XRP for a transaction. The fee proxy itself integrates with the Dex pallet to perform the swap.
The flexibility and ergonomics of substrate allow us to achieve all these integrations in a clean way.
Substrate Layer Implementation
Fee proxy pallet
The pallet handles fee calculation and token conversion through several key steps.When a user initiates a transaction with fee preferences, the following process occurs:
- Gas Estimation: Calculate required gas based on transaction parameters
- The user specifies their preferred payment token and maximum payment amount
- XRP Fee Calculation: Convert gas requirements to XRP amount
- The pallet calculates the required XRP amount for gas fees
- Token Amount Calculation: Determine required payment token amount based on AMM rates
- The specified payment token is swapped for XRP through the AMM internally within the on-chain protocol code
- Swap Execution: Perform the token swap through the AMM
- Fee Payment: Use converted XRP for transaction execution
- The underlying transaction is executed using the converted XRP for gas fees
The entry point to executing a fee-proxy transaction is the following extrinsic in the FeeProxy pallet:
// Execute a transfer while paying fees in a custom token
fee_proxy.call_with_fee_preferences(
origin,
payment_asset_id,// The token to pay fees with
max_payment,// Maximum amount willing to pay with token
Box::new(transfer_call)// The actual transaction to execute
)
The fee abstraction is implemented through a specialized extrinsic called fee_proxy.call_with_fee_preferences
.
This proxy acts as a wrapper around the actual transaction, handling the token conversion process transparently.
How it works:
- The user specifies their preferred payment token (
payment_asset_id
) and the maximum amount they're willing to pay (max_payment
). - Before executing the main transaction, the system queries the AMM to calculate the required amount of payment token based on:
- The estimated gas cost in native currency (XRP)
- The current exchange rate from the liquidity pool
- The system performs an atomic swap through the DEX pallet, converting the user's token to XRP
- The actual transaction (
transfer_call
) is executed using the swapped XRP for gas fees - Any unused tokens are refunded back to the user
This mechanism ensures that while the blockchain continues to use XRP for actual gas payments internally, users enjoy the flexibility of paying with their token of choice, as long as there's sufficient liquidity in the corresponding AMM pool.
Flow
EVM Layer Integration
The Fee Proxy functionality is also accessible through an EVM precompile, allowing smart contracts and EVM transactions to utilize the same flexible fee payment system. The precompile interface is straightforward:
interface FeeProxy {
function callWithFeePreferences(
address asset,// Token address to pay fees with
address target,// Target contract address
bytes calldata// Encoded function call data
) external;
}
When using the EVM interface, the gas parameters (gasLimit
, maxFeePerGas
, and maxPriorityFeePerGas
) determine the maximum gas cost in XRP, which is then converted to the equivalent amount in the chosen payment token based on current AMM rates.
The caller is responsible for performing the calculations (required gas/XRP) - which can be done via the estimateGas
RPC call, then converting this to amount of tokens required (and ensuring that they possess the required amount).
Flow
Caveats to the EVM integration
Integrating the fee-proxy with the EVM proved to be a bit more difficult than anticipated. This is due to the fact that Ethereum based transaction flows take a different route in the code compared to Substrate extrinsics; resulting in slightly different implementations of the fee-proxy for the 2 different transaction flows.
The major difference however was the usage of the fee-proxy with frontend/browser wallets. Before allowing a user to execute a transaction; wallets (such as MetaMask) make an Eth RPC call to first simulate the transaction; but in this process, the transaction validation can fail due to the user having a 0 XRP balance. This is a state which should be accounted for; i.e. the user should still be able to execute a transaction while having no XRP, if they have another token to pay gas with.
^ To address this behaviour, we needed to make a change in frontier (our EVM implementation); essentially allowing custom logic (providing a trait) for the transaction validation.
The implementation for this trait is in the runtime:
pub struct HandleTxValidation<E: From<InvalidEvmTransactionError>>(PhantomData<E>);
impl<E: From<InvalidEvmTransactionError>> fp_evm::HandleTxValidation<E> for HandleTxValidation<E> {
fn with_balance_for(
evm_config: &CheckEvmTransaction<E>,
who: &fp_evm::Account,
) -> Result<(), E> {
let decoded_override_destination = H160::from_low_u64_be(FEE_PROXY_ADDRESS);
// If we are not overriding with a fee preference, proceed with calculating a fee
if evm_config.transaction.to != Some(decoded_override_destination) {
// call default trait function instead
<() as fp_evm::HandleTxValidation<E>>::with_balance_for(evm_config, who)?
}
Ok(())
}
}
Here we essentially check the target address of the the transaction, and if it is targeted towards the fee-proxy precompile address, then we simply allow the balance validation to go through.
With this change we have made frontier pallet transaction handling logic more flexible, while providing our own custom override for transaction validation.
Use Cases and Benefits
- Enhanced User Experience
- Users can transact without holding XRP
- Seamless fee payment in preferred tokens
- Reduced friction for new users
- DApp Integration
- DApps can incentivise and potentially subsidise gas fees for their users by via providing liquidity for their tokens against XRP
- Eases usecases for gas sponsorships; for example any app can setup a liquidity pool with its token and XRP; then allow users to pre-buy (or buy at a discount) these tokens - which could be used for transaction fee payment
- Simplified onboarding for new users as they could potentially interact with dapps even though they may not have the native currency at hand
- Better UX for multi-token applications
- DApps can incentivise and potentially subsidise gas fees for their users by via providing liquidity for their tokens against XRP
- Additional utility to all assets
- Since any token can be used to pay for transactions; this essentially gives native utility to all tokens to be used as gas tokens
- Cross-Chain Interactions
- Easier integration with other chains and bridges
- Simplified token management for cross-chain applications
Future Improvements
Several potential enhancements could further improve the Fee Proxy system:
- Gas Token Aggregation
- Support for multi-hop swaps through multiple AMM pools
- Optimal routing for better rates
- Fee Abstraction
- Account abstraction integration for more flexible fee payment models
- Support for meta-transactions
- Advanced Fee Strategies
- Dynamic fee token selection based on market conditions
- Batch transaction optimization
Conclusion
The Fee Proxy pallet represents a significant step forward in improving blockchain accessibility by removing the requirement for users to hold native tokens for gas fees. By leveraging TRN's on-chain AMM and implementing robust safety measures, the pallet provides a secure and efficient solution for flexible fee payment.
This innovation not only enhances user experience but also opens up new possibilities for DApp developers and cross-chain applications. As The Root Network continues to evolve, the Fee Proxy pallet will play a crucial role in fostering broader adoption and usability of blockchain technology.
To learn more about The Root Network's features and custom pallets, visit our documentation. Stay updated with our latest developments by following us on X and joining our Discord community.