Is it safe to charge a user inside a function being called using GSN?

I have a GSN wrapped function which should charge a caller with ERC20 tokens using #transferFrom() call and assumes that tokens are pre-approved by a caller.

function _preRelayedCall(bytes memory _context) internal returns (bytes32) {
  (address from, bytes4 signature) = abi.decode(_context, (address,bytes4));

  if (signature == ThisContract(0).myFunction.selector) {
    IERC20(address(token)).transferFrom(from, address(this), gsnFee);
  }
}

I see that there is a 100K limitation for _preRelayedCall() method https://github.com/opengsn/gsn/blob/13fa9d029bfa8858519e25ca6f16e717d695bdab/contracts/RelayHub.sol#L48. But my ERC20 token is kind-of MiniMe token and caches balances within each call and has some additional logic. So my #transferFrom() call consumes more than 100K gas. The fee is constant and doesn’t depend on gas consumed.

The only solution I have now is to charge a user inside the function being wrapped using GSN like this:

function myFunction() external {
	if (msg.sender == getHubAddr()) {
	    IERC20(address(token)).transferFrom(from, address(this), gsnFee);
	}

	// Do the rest of its logic
}

Meanwhile, the existing GSNRecipientERC20Fee implementation charges fee inside _preRelayed/_postRelayed hooks.

So the question is…

Is it safe to charge users inside a function being called by GSN, not inside _preRelayed/_postRelayed and can there be any implications? Or maybe there is a way to provide a custom amount of gas for these hooks?

1 Like

Hi @chebykin,

Welcome to the community :wave:

If I understand correctly, you are planning to charge a flat fee in tokens for calling via the GSN.

You will need a GSN Strategy to decide which relayed calls to accept and which to reject. Otherwise a malicious user could send relayed calls to drain the funds used for GSN calls from the recipient contract.

A strategy could be to check that the user has enough tokens to cover the token fee that you are charging for using the GSN. Though if the relayed call failed, you would still pay the relayer but wouldn’t get to charge the user.

@abcoathup Thanks for the explanation, I’ve got the idea. So my approach won’t work. Am I right that there is no way to change the hardcoded value of 100K limit for preRelay/postRelay hooks?

1 Like

The 100k gas limit is fixed in the RelayHub so can’t be changed.

The OpenGSN is working on a new version: opengsn/gsn