Gas can lead to UX problems, “Gasless” transactions may hold the solution.

{This post is a continuation of a previous post.}

The concept of gas is unfamiliar to most non-technical users. However the idea of paying a transaction fee is not. Many traditional brick and mortar banks charge a fixed transaction fee for each debit card transaction, or roll these fees into a fixed quarterly “maintenance” fee. Indeed such is the perceived UX problem, some chains have moved to the reverse model where the executed contract pays for the gas, rather than the transaction sender.

Gas costs can be translated into monetary cost by the equation: Cost in $ = $/ETH * Gas Price * Gas Amount. The gas amount depends on the complexity of the transaction, the gas price is a user chosen value which typically dictates how long the transaction will take to be included in a block. The time of the day has a strong influence on the level of network congestion, thus if the transaction is not urgent, a low gas price can be set and the transaction is likely to be included eventually.

Key pairs that do not have any associated Ether cannot send transactions directly on the Ethereum network due to their lack of ability to pay for gas, but fear not, several mechanisms have been devised to side step this problem. Some of these mechanisms tie in nicely with the concept of throwaway keys, previously discussed here. The ability to sign a transaction adhering to ERC-191 and send this transaction to a Ether/Gas rich node which can then broadcast this signed transaction to the network, is a powerful concept. This relayer can be economically incentivized to broadcast these transactions, via the payment of some ERC-20 tokens, or even replication of the traditional “maintenance” fee model (users pay a particular quarterly fee for transactions).

Identity Based Gas Relay

One of these gasless transaction models is described in Status IdentityGasRelay.sol. This contract inherits Identity.sol which is analysed in detail in this previous post. The nonce field inherited from Identity.sol is checked against the passed _nonce and incremented in order to maintain resistance against replay attacks and to ensure the transaction is synchronised with the Identity contract.

MANAGEMENT and ACTION keys are used to ensure the transaction signer has sufficient permission to carry out the requested transaction, while the purposeThreshold mapping is utilised to ensure a sufficient number of signatories has been reached for that key purpose. isKeyPurpose() , which was used extensively in Identity.sol is again used to ensure the key is of the purpose expected. Similar to the Identity contract, it is intended that an individual instance of this contract is deployed for each user (this is in contrast to uPort’s ERC-1056 Lightweight Identity proposal).

How it works

The main functionality of this Gas Relay is realised through two main functions: callGasRelayed(...) and approveAndCallGasRelayed(...) . The overall structure of these functions is similar:

Perform sanity checks Calculate the hash of what should be signed Ensure the signature(s) are correct Send the transaction, emit events to confirm to observers Refund the caller appropriately

Both these callGasRelayed(...) and approveAndCallGasRelayed(...) take similar parameters: the transaction to be relayed destination address, the transactions value, the transactions data, the current nonce, the gas price to be refunded to the caller of this function. These functions are intended to be called by the “gas rich” relayer, and asuch logic is built into these functions to refund the caller for this gas expenditure, either in the form of Ether, or if specified an ERC-20 token of some type.

Both of these externally callable functions begins by performing some sanity and security checks: ensuring the function call has sufficient gas compared to the amount expected to be used, ensuring the nonce’s match, and in the case of approveAndCallRelayed if the refunding ERC-20 token address is valid.

The signHash is then calculated. This is a keccak hash of the passed parameters, adhering to ERC-191: signHash = keccak256(“\x19Ethereum Signed Message:

32”, _hash); . This signHash will be used to ensure the transaction was signed by the appropriate keys.

The primary difference between these two functions lies within the checks that are carried out to ensure the signing key has the correct permissioning. callGasRelayed() allows the signatures to be from either MANAGEMENT or ACTION keys:

// callGasRelayed(...)

...

verifySignatures(

_to == address(this) ? MANAGEMENT_KEY : ACTION_KEY,

signHash,

_messageSignatures

);

...

callGasRelayed then continues to execute the transaction with a low level call: _to.call.value(_value)(_data) and emits a ExecutedGasRelayed event, indicating the success of this call. In contrast, approveAndCallGasRelayed does not allow MANAGEMENT keys to be used: