Fuel Station: Gas Paymaster on Fuel ⛽️

Fuel Station: Gas Paymaster on Fuel :fuelpump:


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, where x 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.

11 Likes

This is an excellent write-up and also a clever way to make use of dynamic predicate data!

While I think the design is broadly sound, I have a few follow-ups:

  1. What is the recommended behavior for the paymaster when an intent is never consumed? Could this be a DOS vector to lock-up all rentable UTXOs?
  2. Beyond the protocol design, is there any research yet into how this could be incorporated into existing wallets and apps from an SDK, API or RPC perspective?
1 Like

@Voxelot thanks for feedback!

On your questions:

  1. On DOS

We can leverage an expiry policy, and we can make the intent expire after a certain number of blocks! Now, that being said, the paymaster, if they feel a user has timed out, can sign a new intent and send it to the next user { in no scenario, a double spend will happen! }

Initially, Paymaster can run per application { i.e with some access control tokens }, where the application has a reputation at stake to not behave in this manner! and if not done, then they paymaster can just stop providing them services.

Long term, if this becomes an issue, then applications can probably stake some money to avail these services { and can be slashed if found behaving not in good faith + the paymaster would have a reputation at stake to not play this system }

  1. For the DX and integrations into tools

I think that is something which we would have to figure out post implementation of a prototype! We would have to sit the tooling team to figure out an idea DX for developers to use it.

Lemme know how it sounds :]

I really appreciate that this mechanism is non-custodial, on other chains I have found that gas stations are a critical part of the user experience, and do a lot to enable account abstraction, but these other solutions rely heavily on centralization in their design.

In that vein I think that self-hosting of this solution would be interesting, having at minimum a terraform module or similar to enable teams to setup this infra on AWS Lambda or other serverless platform could go far to ensure long-term decentralization of this service.

Do you have any plans on being able to pay for gas in an asset other than Fuel? Where a transaction could use a USDC utxo, swap into Eth during the transaction, and then use an utxo created within the transaction itself to pay gas?

@mattjurenka, thanks for viewing this!

Agreed with you on self-hosting! We can produce a good docker image for it, and then also some easy to launch infra for self hosting in the long term :]

Great Topic, make fuel great