I was curious to know what the gas overhead is for Dapps using the GSN . Im not considering the cost to the developer, only the EVM costs when a given function is called in both non-GSN and GSN enabled contract. I deployed two instances of a SimpleStorage contract that stores an integer on the Ganache test chain:
instance 1: simple storage contract with no OZ library:
Set function Gas usage: 26684
instance 2: same contract with OZ libs (GSNRecipient.sol" Initializable.sol";):
Set function Gas usage: 29364 or 10.043% more
I think for now that it is a reasonable overhead when one considers the benefits of GSN. Did anyone get similar results and or do such tests?
I ran a simple test to call the increase function of the Counter contract. No GSN strategies were used (all relayed calls were accepted).
This is a simple function call, so would consider the overhead more of a fixed amount rather than a percentage.
Direct transaction
Calling increase via the CLI
$ npx oz send-tx
? Pick a network rinkeby
? Pick an instance Counter at 0x9839516a22b383267c4d31DCFD66b4794Df94527
? Select which function increase()
✓ Transaction successful. Transaction hash: 0x620e598d4a40b3a5bdd61e269b2e34e46ec8d62472c54ae890d8bc8af75043ed
The direct transaction was a single call directly to the increase function.
The GSN transaction was via a Relayer and the cost shown by Etherscan to call the increase function via the GSN.
I suggest trying it yourself on a public testnet using the Building a GSN-powered DApp guide. You can then modify the contract to experiment with different options.
The increase function is very basic, so I would expect more complex functions to be a greater part of the gas cost of a GSN transaction.
Counter.sol
// contracts/Counter.sol
pragma solidity ^0.5.0;
import "@openzeppelin/contracts-ethereum-package/contracts/GSN/GSNRecipient.sol";
contract Counter is GSNRecipient {
uint256 public value;
function increase() public {
value += 1;
}
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();
}
// We won't do any pre or post processing, so leave _preRelayedCall and _postRelayedCall empty
function _preRelayedCall(bytes memory context) internal returns (bytes32) {
}
function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal {
}
}