Created
August 13, 2020 14:16
-
-
Save arefaslani/2cf18a162c32da2cd8497782370714a3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.6.0; | |
pragma experimental ABIEncoderV2; | |
import "@openzeppelin/contracts/math/SafeMath.sol"; | |
import "./EIP712Base.sol"; | |
contract EIP712MetaTransaction is EIP712Base { | |
using SafeMath for uint256; | |
bytes32 private constant META_TRANSACTION_TYPEHASH = keccak256( | |
bytes( | |
"MetaTransaction(uint256 nonce,address from,bytes functionSignature)" | |
) | |
); | |
event MetaTransactionExecuted( | |
address userAddress, | |
address payable relayerAddress, | |
bytes functionSignature | |
); | |
mapping(address => uint256) nonces; | |
/* | |
* Meta transaction structure. | |
* No point of including value field here as if user is doing value transfer then he has the funds to pay for gas | |
* He should call the desired function directly in that case. | |
*/ | |
struct MetaTransaction { | |
uint256 nonce; | |
address from; | |
bytes functionSignature; | |
} | |
constructor(string memory name, string memory version) | |
public | |
EIP712Base(name, version) | |
{} | |
function executeMetaTransaction( | |
address userAddress, | |
bytes memory functionSignature, | |
bytes32 sigR, | |
bytes32 sigS, | |
uint8 sigV | |
) public payable returns (bytes memory) { | |
MetaTransaction memory metaTx = MetaTransaction({ | |
nonce: nonces[userAddress], | |
from: userAddress, | |
functionSignature: functionSignature | |
}); | |
require( | |
verify(userAddress, metaTx, sigR, sigS, sigV), | |
"Signer and signature do not match" | |
); | |
// Append userAddress and relayer address at the end to extract it from calling context | |
(bool success, bytes memory returnData) = address(this).call( | |
abi.encodePacked(functionSignature, userAddress) | |
); | |
require(success, "Function call not successfull"); | |
nonces[userAddress] = nonces[userAddress].add(1); | |
emit MetaTransactionExecuted( | |
userAddress, | |
msg.sender, | |
functionSignature | |
); | |
return returnData; | |
} | |
function hashMetaTransaction(MetaTransaction memory metaTx) | |
internal | |
view | |
returns (bytes32) | |
{ | |
return | |
keccak256( | |
abi.encode( | |
META_TRANSACTION_TYPEHASH, | |
metaTx.nonce, | |
metaTx.from, | |
keccak256(metaTx.functionSignature) | |
) | |
); | |
} | |
function getNonce(address user) public view returns (uint256 nonce) { | |
nonce = nonces[user]; | |
} | |
function verify( | |
address signer, | |
MetaTransaction memory metaTx, | |
bytes32 sigR, | |
bytes32 sigS, | |
uint8 sigV | |
) internal view returns (bool) { | |
return | |
signer == | |
ecrecover( | |
toTypedMessageHash(hashMetaTransaction(metaTx)), | |
sigV, | |
sigR, | |
sigS | |
); | |
} | |
function _msgSender() internal view returns (address sender) { | |
if (msg.sender == address(this)) { | |
bytes memory array = msg.data; | |
uint256 index = msg.data.length; | |
assembly { | |
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those. | |
sender := and( | |
mload(add(array, index)), | |
0xffffffffffffffffffffffffffffffffffffffff | |
) | |
} | |
} else { | |
sender = msg.sender; | |
} | |
return sender; | |
} | |
// To recieve ether in contract | |
receive() external payable {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment