ERC721+ GSN + remote minting

Hi everybody,

I’m new to the community, but I’m an old-time “OpenZeppelin user” :slight_smile:

I would like to now if it’s possibile to pay for the gas of the minting operation of an ERC721 token by using the GSN in order to allow the contract creator to create new tokens without using Metamask et similia.

Don’t know really if this is the right section, feel free to close this topic or move if it is not compliant.

Thank you very much,

1 Like

Hi @paolo.rollo,

Welcome to the community forum :wave:

You can definitely mint via the GSN.

GSN Strategies covers the pre-built strategies and how to create your own custom strategy.

Building a GSN powered (d)app from scratch is great to start playing with a GSN dapp (this uses OpenZeppelin SDK and upgradeable contracts)

If you were creating an ERC721 token then you could do something similar to the following contract. Where acceptRelayedCall checks if the caller is a minter, and if it isn’t, rejects the call by returning _rejectRelayedCall with an error code, and if it is a minter accepts by returning _approveRelayedCall. That way only minters would have calls via the GSN approved.

If you have an existing ERC721 token, then you could create a minter contract that you give the minter role to, and only acceptRelayedCall from a white listed sender.

Please note, I haven’t tested the code below, so it would need appropriate testing and auditing.

pragma solidity ^0.5.5;

import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721MetadataMintable.sol";

import "@openzeppelin/contracts/GSN/GSNRecipient.sol";

contract SimpleERC721 is ERC721Full, ERC721MetadataMintable, GSNRecipient {
    enum GSNRecipientSimpleERC721ErrorCodes {

    constructor() ERC721Full("Token", "TKN") public {

    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) {
        if (!isMinter(_msgSender())) {
            return _rejectRelayedCall(uint256(GSNRecipientSimpleERC721ErrorCodes.NOT_MINTER));

        return _approveRelayedCall();

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

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

Thank you very much for the fast reply @abcoathup!

Just another small question: is it possibile to pay the gas without using an ERC20 token? In other words, can it really be 100% free for the end user?

1 Like

Hi @paolo.rollo,

The GSNRecipientERC20Fee is a strategy that uses an ERC20 token, but you can use any strategy you need for your use case.

The sample ERC721 contract above just checks if the user requesting the relayed call is a minter, and if they are then any transactions on the contract are accepted via the GSN for them. Which means that the minter isn’t paying for gas, doesn’t need an ERC20 token, it is 100% free for the minter.

As an example you can have a look at the demo GSN Chat App which is 100% free for the end user:

Hi @paolo.rollo,

Feel free to ask all the questions that you need.

If you have a moment it would be great to introduce yourself or share what you are working on with the community.