Who pays for gas and how much?

Background on Oyster

Oyster allows Users to post computation Requests on any chain that the Oyster relay contracts are deployed on (called the Request Chain). These Requests and their corresponding Responses are bridged to/from a Common Chain (Arbitrum One) through actors called Gateways. Executors (worker nodes) only listen for Requests on the Common Chain and submit responses back on to the Common Chain.

This separation of concerns between Gateways and Executors simplifies cross-chain execution as Executors need not concern themselves with registering on multiple chains (and maintaining appropriate gas tokens for them) while Users can seamlessly create Requests on any chain without worrying about which chain Oyster performs its protocol logic for paying, staking and slashing Executors. Gateways, in effect, act as a bridge/relay node. The gas price on the Common Chain is assumed to be negligible in Oyster.

Summary of the problem

While this separation is specific to Oyster’s design, the broader question should be relevant to all coprocessor designs. Whether it is the Gateway or Executor’s responsibility to return Responses to the User on the Request Chain, the actor submitting the transaction is required to pay for the gas that will be consumed.

The answer to who ultimately pays for it is obvious - this cost has to be passed down to the User in a sustainable ecosystem. However, gas prices fluctuate in most chains. So, the more interesting question to answer is who determines the value and how?

Considerations

Some properties that would be good to have about this conundrum are:
There should be some predictability in what the gas price will be from the User’s end before he places the Request so that he knows whether or not a Response can be expected within the time limit and also such that he can pre-pay or fund his wallet with an appropriate number of gas tokens
The User should be able to set a maximum cap to the gas price he would be willing to pay. This can be set implicitly by only funding the wallet with only the desired number of tokens, however, this solution doesn’t scale for the case when there are multiple concurrent Requests.

Possible approaches

As the only relevant actors as far as this question is concerned, either the Gateway, Executor or the User has to determine the gas price that should be picked for the Response transaction. If the Gateway or the Executor picks the gas price, it can provide a fixed quote to the Users in advance and then make it their responsibility to get the transaction included by deadline no matter what.

Case 1: Gateways pick the gas price

In Oyster, Gateways are only expected to maintain gas tokens in different chains, bridge data, and get reimbursed for it. They may also maintain payment tokens in the Common Chain (to pay Executors) and reimburse themselves from the different Request Chains (through payments made by Users) but that’s a concern for another forum post.

If Gateways were to quote gas prices in advance, it would require them to participate in gas futures markets of different chains to hedge it out. This would require Gateways to be actually smart and creative and thus lead to increased expectations from Gateway operators.

Moreover, such a solution would require the existence of such futures markets for every chain Oyster coprocessors are to be available on.

Case 2: Executors pick the gas price

In Oyster, Executors are expected to not be concerned with Request Chains and thus their native gas tokens at all.

Again, such a solution would require the existence of such futures markets for every chain Oyster coprocessors are to be available on.

Case 3: Users pick the gas price

Pushing the choice to the Users seems like the most flexible and less demanding solution from the protocol’s perspective. It also removes the constraint that Oyster only be available on chains for which gas futures exist. Users can provide a gas price cap and some futures market if they want to out-of-protocol.

In this case, Gateways can use the gas price cap provided by Users as guidance and if they are confident in being able to get the Response transaction included with a lower gas price, the excess can be distributed back to the User and the Gateway in some proportion.

An easy issue to foresee here is that a Gateway might claim to have made a transaction at a certain gas price (could be even the max specified by the User). However, if the min gas price to include a transaction in the deadline block number is higher than the max set by the User, there would be no way for the Gateway to prove that it indeed signs and propagates such a transaction, leading to traditional speaker-listener problems. Similar issues might also occur when the block gas price isn’t higher than the max set by the User, but the transaction still doesn’t get included due to RPC, P2P or any other sequencer/validator errors/delays.

2 Likes

Should there be an option where the result is posted to the common chain and it’s up to the user to fetch it from there? Or is this a bad design?

Since a user setting a maximum gas fee lower than the actual cost will inevitably lead to failure, wouldn’t it be better to give users the choice of fetching the result themselves?

1 Like

In the current Oyster design, Executors post Responses on the Common Chain. Users are free to pick the Responses directly from the Common Chain or listening for events there. However, coprocessor Requests could originate from smart contracts on another Request Chain where there’s no off-chain entity to pick/listen for Responses. So, the User contract needs to either implement its own cross-chain messaging/bridging solution (may be through something like Axelar, LayerZero, Wormhole) or Oyster needs to make that available as convenience feature (through Gateways).

1 Like