# BasePaymaster
An abstract base class to be inherited by a concrete Paymaster. A subclass must implement:
- preRelayedCall
- postRelayedCall
# Functions
# getRelayHub()
→ address
(public)
# Return values
The address of the RelayHub
that is trusted by this Paymaster to execute the requests.
# supportsInterface(bytes4 interfaceId)
→ bool
(public)
Returns true if this contract implements the interface defined by
interfaceId
. See the corresponding
https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
to learn more about how these ids are created.
This function call must use less than 30 000 gas.
# getGasAndDataLimits()
→ struct IPaymaster.GasAndDataLimits limits
(public)
Return the Gas Limits for Paymaster's functions and maximum msg.data length values for this Paymaster. This function allows different paymasters to have different properties without changes to the RelayHub.
# Return values
An instance of the GasAndDataLimits
struct
# acceptanceBudget
If the transactions consumes more than acceptanceBudget
this Paymaster will be charged for gas no matter what.
Transaction that gets rejected after consuming more than acceptanceBudget
gas is on this Paymaster's expense.
Should be set to an amount gas this Paymaster expects to spend deciding whether to accept or reject a request.
This includes gas consumed by calculations in the preRelayedCall
, Forwarder
and the recipient contract.
⚠️ Warning ⚠️ As long this value is above preRelayedCallGasLimit
(see defaults in BasePaymaster
), the Paymaster is guaranteed it will never pay for rejected transactions.
If this value is below preRelayedCallGasLimit
, it might might make Paymaster open to a "griefing" attack.
The relayers should prefer lower acceptanceBudget
, as it improves their chances of being compensated.
From a Relay's point of view, this is the highest gas value a bad Paymaster may cost the relay,
since the paymaster will pay anything above that value regardless of whether the transaction succeeds or reverts.
Specifying value too high might make the call rejected by relayers (see maxAcceptanceBudget
in server config).
# preRelayedCallGasLimit
The max gas usage of preRelayedCall. Any revert of the preRelayedCall
is a request rejection by the paymaster.
As long as acceptanceBudget
is above preRelayedCallGasLimit
, any such revert is not payed by the paymaster.
# postRelayedCallGasLimit
The max gas usage of postRelayedCall. The Paymaster is not charged for the maximum, only for actually used gas. Note that an OOG will revert the inner transaction, but the paymaster will be charged for it anyway.
# _verifyForwarder(struct GsnTypes.RelayRequest relayRequest)
(internal)
this method must be called from preRelayedCall to validate that the forwarder is approved by the paymaster as well as by the recipient contract.
# _verifyRelayHubOnly()
(internal)
# _verifyValue(struct GsnTypes.RelayRequest relayRequest)
(internal)
# _verifyPaymasterData(struct GsnTypes.RelayRequest relayRequest)
(internal)
# _verifyApprovalData(bytes approvalData)
(internal)
# setRelayHub(contract IRelayHub hub)
(public)
The owner of the Paymaster can change the instance of the RelayHub this Paymaster works with. ⚠️ Warning ⚠️ The deposit on the previous RelayHub must be withdrawn first.
# setTrustedForwarder(address forwarder)
(public)
The owner of the Paymaster can change the instance of the Forwarder this Paymaster works with. the Recipients must trust this Forwarder as well in order for the configuration to remain functional.
# getTrustedForwarder()
→ address
(public)
# receive()
(external)
Any native Ether transferred into the paymaster is transferred as a deposit to the RelayHub. This way, we don't need to understand the RelayHub API in order to replenish the paymaster.
# withdrawRelayHubDepositTo(uint256 amount, address payable target)
(public)
Withdraw deposit from the RelayHub.
amount: The amount to be subtracted from the sender.
target: The target to which the amount will be transferred.
# preRelayedCall(struct GsnTypes.RelayRequest relayRequest, bytes signature, bytes approvalData, uint256 maxPossibleGas)
→ bytes, bool
(external)
Called by the Relay in view mode and later by the RelayHub
on-chain to validate that
the Paymaster agrees to pay for this call.
The request is considered to be rejected by the Paymaster in one of the following conditions:
preRelayedCall()
method reverts- the
Forwarder
reverts because of nonce or signature error - the
Paymaster
returnedrejectOnRecipientRevert: true
and the recipient contract reverted (and all that did not consume more thanacceptanceBudget
gas).
In any of the above cases, all Paymaster calls and the recipient call are reverted.
In any other case the Paymaster will pay for the gas cost of the transaction.
Note that even if postRelayedCall
is reverted the Paymaster will be charged.
relayRequest: - the full relay request structure
signature: - user's EIP712-compatible signature of the relayRequest
.
Note that in most cases the paymaster shouldn't try use it at all. It is always checked
by the forwarder immediately after preRelayedCall returns.
approvalData: - extra dapp-specific data (e.g. signature from trusted party)
maxPossibleGas: - based on values returned from getGasAndDataLimits
the RelayHub will calculate the maximum possible amount of gas the user may be charged for.
In order to convert this value to wei, the Paymaster has to call "relayHub.calculateCharge()"
# Return values
byte array to be passed to postRelayedCall. Can contain any data needed by this Paymaster in any form or be empty if no extra data is needed.
flag that allows a Paymaster to "delegate" the rejection to the recipient code.
It also means the Paymaster trust the recipient to reject fast: both preRelayedCall,
forwarder check and recipient checks must fit into the GasLimits.acceptanceBudget,
otherwise the TX is paid by the Paymaster.
true
if the Paymaster wants to reject the TX if the recipient reverts.
false
if the Paymaster wants rejects by the recipient to be completed on chain and paid by the Paymaster.
# _preRelayedCall(struct GsnTypes.RelayRequest, bytes, bytes, uint256)
→ bytes, bool
(internal)
internal logic the paymasters need to provide to select which transactions they are willing to pay for
see the documentation for IPaymaster::preRelayedCall
for details
# postRelayedCall(bytes context, bool success, uint256 gasUseWithoutPost, struct GsnTypes.RelayData relayData)
(external)
This method is called after the actual relayed function call. It may be used to record the transaction (e.g. charge the caller by some contract logic) for this call.
Revert in this functions causes a revert of the client's relayed call (and preRelayedCall(), but the Paymaster is still committed to pay the relay for the entire transaction.
context: The call context, as returned by the preRelayedCall
success: true
if the relayed call succeeded, false if it reverted
gasUseWithoutPost: The actual amount of gas used by the entire transaction, EXCEPT the gas used by the postRelayedCall itself.
relayData: The relay params of the request. can be used by relayHub.calculateCharge()
# _postRelayedCall(bytes, bool, uint256, struct GsnTypes.RelayData)
(internal)
internal logic the paymasters need to provide if they need to take some action after the transaction
see the documentation for IPaymaster::postRelayedCall
for details