Modify Respective Function

Make a method which supports native meta transactions

Now using all the information from previous sections, let's make a new method that sets the quote from the user but this time we do it with native meta transaction support.

Create a new function to include the following params

  • userAddress

  • newQuote

  • sigR

  • sigS

  • sigV

function setQuoteMeta(address userAddress,string memory newQuote, bytes32 sigR, bytes32 sigS, uint8 sigV) public {
}

Add an instance of the struct

// Make an instance of the predefined struct
MetaTransaction memory metaTx = MetaTransaction({
nonce: nonces[userAddress],
from: userAddress
});

Hash message in EIP712 compatible form

// Hash the mandatory fields of EIP712
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(META_TRANSACTION_TYPEHASH, metaTx.nonce, metaTx.from))
)
);

"\x19" makes the encoding deterministic

"\x01" is the version byte to make it compatible to EIP-191

Verify the Signatures On Chain

// Verify the userAddress is not address zero
require(userAddress != address(0), "invalid-address-0");
​
// Verify the userAddress with the address recovered from the signatures
require(userAddress == ecrecover(digest, v, r, s), "invalid-signatures");

ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address) recover the address associated with the public key from elliptic curve signature

Add the Necessary Logic

quote = newQuote;
owner = userAddress;

Increment Nonce for Replay Protection

nonces[userAddress]++;

Complete Code Snippet

function setQuoteMeta(address userAddress,string memory newQuote, bytes32 r, bytes32 s, uint8 v) public {
MetaTransaction memory metaTx = MetaTransaction({
nonce: nonces[userAddress],
from: userAddress
});
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(META_TRANSACTION_TYPEHASH, metaTx.nonce, metaTx.from))
)
);
​
require(userAddress != address(0), "invalid-address-0");
require(userAddress == ecrecover(digest, v, r, s), "invalid-signatures");
quote = newQuote;
owner = userAddress;
nonces[userAddress]++;
}

Checkout the full working code here https://github.com/bcnmy/dapp-demo​

Congratulations! You have successfully integrated meta transactions in your Smart Contracts

In the next section, Let's see what changes we need to do on the Client side.