Fuel Station: Gas Paymaster on Fuel
This post discusses a gas paymaster on the Fuel network that can pay/sponsor gas in Fuel transactions.
We present Fuel Station, a non-custodial gas paymaster that works with all Fuel wallets and requires no user upgrades.
Fuel’s transaction model
Fuel leverages the UTXO model, which gives us an exciting edge while designing our non-custodial gas paymaster.
Because of the UTXO model, multiple parties can construct fuel transactions. This means a given transaction can have various inputs/outputs and be owned by different addresses.
Renting coins on demand
Fuel transactions require at least a single Eth Input coin to cover the gas costs.
Since multiple parties can create fuel transactions, this coin can come from any other party, in our case, the paymaster.
The paymaster runs a “Paymaster Client,” which creates thousands of coins locked behind predicates that work on intent-based authorization.
The user of the paymaster can rent any of these coins to a user to cover its gas cost by expressing an intent on how they prefer this coin to be spent, which acts as an agreement between the lender and the borrower of this coin, in our case, the paymaster and the user respectively.
How does authorization work?
The paymaster rents its coin, locking it behind a predicate, where an intent expressed by the paymaster controls the predicate.
A public key embedded as a configurable constant is used to verify signatures over this intent, and the input coin’s UTXO ID, being part of this intent, protects against replay attacks.
The intent object looks like the following:
Intent = {
inputCoinUTXOID: b256,
expectedOutputCoins: Array<{
assetId: b256,
amount: u64,
outputAddress: b256,
}>
}
NOTE: The amount in expectedOutputCoins
is the minimum amount of coins required to allow for some flexibility.
This way, a given paymaster can provide:
-
Which input coin is it willing to lend, identified
inputCoinUTXOID
this provides replay protection since post transaction, this UTXO won’t exist. -
The output coins it wants in the transaction, allowing the paymaster to ensure only a certain amount of ETH is used, and optionally, some other coins are provided for repayment.
The predicate does the following checks:
- Checks the paymaster signs the intent object
- Checks all the expected outputs are present in the transaction
- Checks only the specified Input coin is being spent
Example Interaction
Let’s look at an example interaction between a user and a paymaster.
The paymaster’s user first performs a local simulation, realizes the total gas required for this transaction, and then adds some extra padding for the predicate execution of the gas coin provided by the paymaster.
For example, let’s imagine the total estimate cumulatively comes out to be 100_000 gas, and the gas price is 2.
So, the total units the user requires becomes = 100_000 * 2 = 200_000.
NOTE: In Fuel, 1_000_000_000 units = 1 Eth
The user then requests the paymaster, saying, “I want 200_000
units.” The paymaster then looks for coins that can provide up to this many units.
For now, let’s think the paymaster finds a 500_000 unit coin. The paymaster returns the predicate address that controls this coin, along with an intent saying:
- I want the user to return at least 300_000 units of Ethereum Asset.
The user creates a transaction with this coin, and then the predicate ensures that the user can never spend more than 200_000 units as part of this transaction!
The above scenario is one in which the paymaster pays out of its own pocket, which apps optimizing for UX might do!
The paymaster can also add another expected output, asking for some x
amounts of a stablecoin (or any coin) to be sent to a specific address. This ensures that it recovers the units it lent and an optional fee!
In that case, the paymaster’s intent becomes:
- I want the user to return at least 300_000 units of Ethereum Asset.
- I want
x
units USDC, wherex
is the rate of 200_000 units, along with some optional fees added!
Some interesting properties of the solution:
- The whole solution is non-custodial, i.e., there is no requirement for anyone to the custody of some funds with the paymaster to enable this
- This can work with all Fuel wallets and apps, and they are not required to move to a smart contract or predicate-based account.
Next steps
We will develop a prototype for the Paymaster client and demo some transfers via Paymaster. This should provide real working examples of the proposed solution. We will share more information soon.
Post-prototyping, the paymaster should become more production-ready and be maintained. External teams could maintain it and provide it as a service, or teams can optionally decide to host the solution themselves or probably even hack their own clients!
Requirements for new policies to determine msg_sender
One change we require on the Fuel protocol is adding a new transaction policy, which can dictate the sender of the transaction’s message.
Right now, the message sender requires all transaction inputs to come from a single address; if not, it is undefined.
This means that for our solution to work almost everywhere, we need a new policy where a transaction can signal who the message owner is. Our client team is currently working on this.