Pay gas fees in selected FAs - #413
Draft
seanyoung wants to merge 6 commits into
Draft
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the ability for a transaction to pay its gas in a selected fungible asset instead of the native token, governed end-to-end by on-chain configuration. A transaction opts in by naming an FA in the new versioned payload; the VM validates it in the prologue, charges the fee in that FA in the epilogue, and routes it into a per-FA governed gas pool. Fully gated behind a new feature flag and inert until governance enables it, so it's a no-op for existing traffic.
What's included
Transaction format
TransactionExtraConfig::V2variant carryinggas_fa_coin: Option<AccountAddress>(the FA metadata object address to pay gas in), plus accessors (gas_fa_coin(),has_gas_fa_coin()) and handling inapi/typesconversion andTransactionMetadata.Feature gate
GAS_PAYABLE_FAfeature flag (RustFeatureFlag, Movefeatures.move, release-builder mapping). The VM (validate_signed_transaction) rejects any transaction carryinggas_fa_coinwithFEATURE_UNDER_GATINGunless the flag is enabled.Surfacing the choice to Move
transaction_context::gas_payment_fungible_asset(): Option<address>accessor + native, withgas_fa_cointhreaded throughUserTransactionContextand a gas-schedule entry for the native.Governed gas pool (per-FA pools + pricing)
governed_gas_poolnow holds a governance-managed registry of accepted gas FAs, each with its own gas price (FA base units per gas unit) and its own pool (the pool account's primary store for that FA — separate balance/accounting per asset).add_accepted_gas_fungible_asset(metadata, gas_price),set_gas_fungible_asset_price,remove_accepted_gas_fungible_asset(all governance-gated), plus views (is_accepted_…,accepted_…,get_gas_fungible_asset_price,gas_fee_in_fa, pool balance) and events.VM wiring (
transaction_validation.move)gas_fa_coin, require the FA is accepted and the payer holds enough of it (gas_used_max × price).gas_used × pricein the FA into its governed gas pool. Wired into both the unified epilogue and the legacyepilogue_gas_payer_extended/epilogue_extendedpaths, so it works whether or not account abstraction is enabled (the latter matters on Movement, where AA is off).Design notes
Coin<T>types that aren't FA-migrated (e.g. MOVE on Movement) live in a typedCoinStorethat no address-keyed path can reach, and runtime coin dispatch would needENABLE_FUNCTION_VALUES(off on Movement). So accepted gas coins must be fungible assets. The native token keeps its existing default gas path.gas_used × gas_price, withgas_priceset by governance per FA — deterministic, no oracle/DEX dependency in the gas hot path. (A keeper-updated market rate can layer on top later without touching the epilogue.)GAS_PAYABLE_FAis enabled and an FA is accepted.Testing
governed_gas_pool,transaction_context): registry add/remove, governance authorization, zero-price rejection, per-FA price get/set,gas_fee_in_fa, multi-FA pool isolation, deposit-when-not-accepted abort, feature-gate abort. Full suite green.e2e-move-tests): FA gas routed to its pool (exactgas_used × price) on both the unified and legacy fee-payer/regular-sender epilogue paths; unaccepted-FA and insufficient-balance transactions discarded by the prologue; gas charged even on an aborted-but-kept transaction; feature-gating and thetransaction_contextaccessor (Some/None/disabled).Limitations / follow-ups
🤖 Generated with Claude Code
Key Areas to Review
Type of Change
Which Components or Systems Does This Change Impact?
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.