Are ERC20 tokens already GSN capable?

Hi @LucaAsga,

Welcome to the community :wave:

For a contract to be a GSN recipient it needs three things, whilst OpenZeppelin Contracts (and OpenZeppelin Contracts Ethereum Package) handle msg.sender and msg.data differently, contracts we write need to do all three.

https://docs.openzeppelin.com/contracts/2.x/gsn-strategies
A GSN recipient contract needs the following to work:

  1. It needs to have funds deposited on its RelayHub.
  2. It needs to handle msg.sender and msg.data differently.
  3. It needs to decide how to approve and reject relayed calls.

The reason for the compilation error is that for upgradeable contracts we need to use @openzeppelin/contracts-ethereum-package.

https://docs.openzeppelin.com/sdk/2.5/linking
NOTE: Make sure you install @openzeppelin/contracts-ethereum-package and not the vanilla @openzeppelin/contracts . The latter is set up for general usage, while @openzeppelin/contracts-ethereum-package is tailored for being used with the OpenZeppelin SDK. This means that its contracts are already set up to be upgradeable.

I recently created an issue to add a warning to users: OpenZeppelin/openzeppelin-sdk#1297 .
There is also a plan to remove this requirement to use the Contracts Ethereum Package version: Planning the demise of OpenZeppelin Contracts' evil twin.

Also with upgradeable contracts we need to use initializers rather than constructors.

https://docs.openzeppelin.com/sdk/2.5/writing-contracts
You can use your Solidity contracts in the OpenZeppelin SDK without any modifications, except for their constructors. Due to a requirement of the proxy-based upgradeability system, no constructors can be used in upgradeable contracts.

Simple721Token (GSN enabled)

The following ERC721 is GSN enabled and accepts all relayed calls.
For a production dapp we would want to decide which calls to accept so should implement a GSN Strategy (see https://docs.openzeppelin.com/contracts/2.x/gsn-strategies)

pragma solidity ^0.5.5;

import "@openzeppelin/upgrades/contracts/Initializable.sol";

import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC721/ERC721Full.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC721/ERC721Mintable.sol";

import "@openzeppelin/contracts-ethereum-package/contracts/GSN/GSNRecipient.sol";

contract Simple721Token is Initializable, ERC721Full, ERC721Mintable, GSNRecipient {

    function initialize(address sender) public initializer {
        ERC721.initialize();
        ERC721Metadata.initialize("Token", "TKN");
        ERC721Enumerable.initialize();
        ERC721Mintable.initialize(sender);
    }

    function acceptRelayedCall(
        address relay,
        address from,
        bytes calldata encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes calldata approvalData,
        uint256 maxPossibleCharge
    ) external view returns (uint256, bytes memory) {
        return _approveRelayedCall();
    }

    function _preRelayedCall(bytes memory context) internal returns (bytes32) {
    }

    function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal {
    }
}

Please ask all the questions that you need.