MinimalForwarder Smart Contract Module in Bunzz

This is a simple minimal meta transactions forwarder to be used together with an ERC2771 compatible contract.

This MinimalForwarder module is mainly meant for testing, as there are some features missing to be a good production-ready forwarder. So this contract does not intend to have all the properties that are needed for a sound forwarding system, as that would require more complexity such as the GSN project.

You can access this Module and the code here:

How to Use

In order to use the MinimalFowarder module, we have to implement ERC2771Context in the Recipient contract.

  • This contract has in memory a flag object that is initially white and with no owner.
  • Any user can call the setFlagOwner method of the contract and claim the flag ownership and paint the flag with the color he prefers.
  • The recipient contract must be able to deal with both direct and forwarded transactions. The difference between them is the msg.sender value.
  • In forwarded transactions, the msg.sender is the address of the Forwarder contract. So, in this situation, the recipient contract must retrieve the actual msg.sender from the payload of the transaction.

This is targeted by extending the “@openzeppelin/contracts/metatx/ERC2771Context.sol” contract.

  • Contract Recipient is ERC2771Context In addition, the contract has to be deployed indicating a trusted Forwarder (the only one enabled to forward transactions to it):

Constructor(address trustedForwarder) ERC2771Context(trustedForwarder) {} and, in the contract code, msg.sender has to be replaced by the _msgSender() method.

  • The function setFlagOwner(string memory _color) external { address previousHolder = currentHolder; currentHolder = _msgSender(); color = _color; emit FlagCaptured(previousHolder, currentHolder, color); } 

In the code below, how the _msgSender() method is able to retrieve the intended message sender for both direct and forwarded transactions.

function _msgSender() internal view virtual override returns (address sender) { if (isTrustedForwarder(msg.sender)) { assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } } else { return msg.sender; } } 

Similar approaches that should be investigated are used in exchange protocols like:

A running example is available on Vercel at:

A web interface is available to users who want to call the setFlagOwner method without paying the gas fee. The only requirement is to have the metamask plugin installed on the browser, for signing messages, but someone has still to pay for gas fees and we agreed that this is the Relayer job. But don’t worry, the gas fees (of course of a testnet) will be paid by a demo Relayer server.



  • transferOwnership
  • execute
  • renounceOwnership


  • verify
  • owner
  • getNonce

You can access this Module and the code here:

If you still haven’t signed up to Bunzz, what are you waiting for?

Sign up here and get your smart contracts deployed in 5 minutes through our great GUI.

Share this article: