Commit 5f1d8e19 by Nicolás Venturo Committed by Francisco Giordano

Improve GSN documentation (#1900)

* Improve IRelayRecipient docs

* Fix link

* Update IRelayHub docs to the docsite format

* Update IRelayRecipient docs to the dociste format

* Fix typo

* Improve GSN readme

* Fix link

* Update GSNRecipient docs

* Apply suggestions from code review

Co-Authored-By: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com>

* Apply suggestions from code review

Co-Authored-By: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com>

* Apply suggestions from code review

Co-Authored-By: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com>
(cherry picked from commit d8642286)
parent 89a90fda
......@@ -2,7 +2,7 @@ pragma solidity ^0.5.0;
import "./Context.sol";
/*
/**
* @dev Enables GSN support on `Context` contracts by recognizing calls from
* RelayHub and extracting the actual sender and call data from the received
* calldata.
......
......@@ -5,23 +5,22 @@ import "./GSNContext.sol";
import "./bouncers/GSNBouncerBase.sol";
import "./IRelayHub.sol";
/*
* @dev Base GSN recipient contract, adding the recipient interface and enabling
* GSN support. Not all interface methods are implemented, derived contracts
* must do so themselves.
/**
* @dev Base GSN recipient contract: includes the {IRelayRecipient} interface and enables GSN support on all contracts
* in the inheritance tree.
*
* Not all interface methods are implemented (e.g. {acceptRelayedCall}, derived contracts must provide one themselves.
*/
contract GSNRecipient is IRelayRecipient, GSNContext, GSNBouncerBase {
/**
* @dev Returns the RelayHub address for this recipient contract.
* @dev Returns the `RelayHub` address for this recipient contract.
*/
function getHubAddr() public view returns (address) {
return _relayHub;
}
/**
* @dev This function returns the version string of the RelayHub for which
* this recipient implementation was built. It's not currently used, but
* may be used by tooling.
* @dev Returns the version string of the `RelayHub` for which this recipient implementation was built.
*/
// This function is view for future-proofing, it may require reading from
// storage in the future.
......@@ -31,9 +30,9 @@ contract GSNRecipient is IRelayRecipient, GSNContext, GSNBouncerBase {
}
/**
* @dev Triggers a withdraw of the recipient's deposits in RelayHub. Can
* be used by derived contracts to expose the functionality in an external
* interface.
* @dev Withdraws the recipient's deposits in `RelayHub`.
*
* Derived contracts should expose this in an external interface with proper access control.
*/
function _withdrawDeposits(uint256 amount, address payable payee) internal {
IRelayHub(_relayHub).withdraw(amount, payee);
......
pragma solidity ^0.5.0;
/*
* @dev Interface for a contract that will be called via the GSN from RelayHub.
/**
* @dev Base interface for a contract that will be called via the GSN from {IRelayHub}. Do not use directly, inherit from
* {GSNRecipient} instead.
*/
contract IRelayRecipient {
/**
* @dev Returns the address of the RelayHub instance this recipient interacts with.
* @dev Returns the address of the {IRelayHub} instance this recipient interacts with.
*/
function getHubAddr() public view returns (address);
/**
* @dev Called by {IRelayHub} to validate if this recipient accepts being charged for a relayed call. Note that the
* recipient will be charged regardless of the execution result of the relayed call (i.e. if it reverts or not).
*
* The relay request was originated by `from` and will be served by `relay`. `encodedFunction` is the relayed call
* calldata, so its first four bytes are the function selector. The relayed call will be forwarded `gasLimit` gas,
* and the transaction executed with a gas price of at least `gasPrice`. `relay`'s fee is `transactionFee`, and the
* recipient will be charged at most `maxPossibleCharge` (in wei). `nonce` is the sender's (`from`) nonce for
* replay attack protection in {IRelayHub}, and `approvalData` is a optional parameter that can be used to hold a signature
* over all or some of the previous values.
*
* Returns a tuple, where the first value is used to indicate approval (0) or rejection (custom non-zero error code,
* values 1 to 10 are reserved) and the second one is data to be passed to the other {IRelayRecipient} functions.
*
* {acceptRelayedCall} is called with 50k gas: if it runs out during execution, the request will be considered
* rejected. A regular revert will also trigger a rejection.
*/
function acceptRelayedCall(
address relay,
address from,
......@@ -24,7 +42,32 @@ contract IRelayRecipient {
view
returns (uint256, bytes memory);
/**
* @dev Called by {IRelayHub} on approved relay call requests, before the relayed call is executed. This allows to e.g.
* pre-charge the sender of the transaction.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}.
*
* Returns a value to be passed to {postRelayedCall}.
*
* {preRelayedCall} is called with 100k gas: if it runs out during exection or otherwise reverts, the relayed call
* will not be executed, but the recipient will still be charged for the transaction's cost.
*/
function preRelayedCall(bytes calldata context) external returns (bytes32);
function postRelayedCall(bytes calldata context, bool success, uint actualCharge, bytes32 preRetVal) external;
/**
* @dev Called by {IRelayHub} on approved relay call requests, after the relayed call is executed. This allows to e.g.
* charge the user for the relayed call costs, return any overcharges from {preRelayedCall}, or perform
* contract-specific bookkeeping.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}. `success` is the execution status of
* the relayed call. `actualCharge` is an estimate of how much the recipient will be charged for the transaction,
* not including any gas used by {postRelayedCall} itself. `preRetVal` is {preRelayedCall}'s return value.
*
*
* {postRelayedCall} is called with 100k gas: if it runs out during execution or otherwise reverts, the relayed call
* and the call to {preRelayedCall} will be reverted retroactively, but the recipient will still be charged for the
* transaction's cost.
*/
function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external;
}
= Gas Station Network
= Gas Station Network (GSN)
NOTE: This feature is being released in the next version of OpenZeppelin Contracts, available right now through `npm install @openzeppelin/contracts@next`.
This set of contracts provide all the tools required to make a contract callable via the https://gsn.openzeppelin.com[Gas Station Network].
TIP: If you're new to the GSN, head over to our xref:openzeppelin::gsn/what-is-the-gsn.adoc[overview of the system] and basic guide to xref:ROOT:gsn.adoc[creating a GSN-capable contract].
The core contract a recipient must inherit from is {GSNRecipient}: it includes all necessary interfaces, as well as some helper methods to make interacting with the GSN easier.
Utilities to make writing xref:ROOT:gsn-bouncers.adoc[GSN Bouncers] easy are available in {GSNBouncerBase}, or you can simply use one of our pre-made bouncers:
* {GSNBouncerERC20Fee} charges the end user for gas costs in an application-specific xref:ROOT:tokens.adoc#ERC20[ERC20 token]
* {GSNBouncerSignature} accepts all relayed calls that have been signed by a trusted third party (e.g. a private key in a backend)
TIP: Check out our guide on the xref:ROOT:gsn.adoc[basics of the GSN] as well as the xref:ROOT:gsn-bouncers.adoc[more advanced topics].
You can also take a look at the two contract interfaces that make up the GSN protocol: {IRelayRecipient} and {IRelayHub}, but you won't need to use those directly.
NOTE: This feature is being released in the next version of OpenZeppelin Contracts, available right now through `npm install @openzeppelin/contracts@next`.
== Recipient
......@@ -10,5 +21,11 @@ TIP: Check out our guide on the xref:ROOT:gsn.adoc[basics of the GSN] as well as
== Bouncers
{{GSNBouncerBase}}
{{GSNBouncerERC20Fee}}
{{GSNBouncerSignature}}
== Protocol
{{IRelayRecipient}}
{{IRelayHub}}
......@@ -2,7 +2,7 @@ pragma solidity ^0.5.0;
import "../IRelayRecipient.sol";
/*
/**
* @dev Base contract used to implement GSNBouncers.
*
* > This contract does not perform all required tasks to implement a GSN
......
......@@ -2,7 +2,7 @@
This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-20[ERC20 Token Standard].
TIP: For an overview of ERC20 tokens and a walkthrough on how to create a token contract read our xref:ROOT:tokens.adoc#erc20[ERC20 guide].
TIP: For an overview of ERC20 tokens and a walkthrough on how to create a token contract read our xref:ROOT:tokens.adoc#ERC20[ERC20 guide].
There a few core contracts that implement the behavior specified in the EIP:
......
= Writing GSN-capable contracts
The https://gsn.ethereum.org[Gas Station Network] allows you to build apps where you pay for your users transactions, so they do not need to hold Ether to pay for gas, easing their onboarding process. In this guide, we will learn how to write smart contracts that can receive transactions from the GSN, by using OpenZeppelin Contracts.
The https://gsn.openzeppelin.com[Gas Station Network] allows you to build apps where you pay for your users transactions, so they do not need to hold Ether to pay for gas, easing their onboarding process. In this guide, we will learn how to write smart contracts that can receive transactions from the GSN, by using OpenZeppelin Contracts.
If you're new to the GSN, you probably want to first take a look at the xref:openzeppelin::gsn/what-is-the-gsn.adoc[light overview of the system], to get a clearer picture of how gasless transactions are achieved. Otherwise, strap in!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment