Skip to content

Instantly share code, notes, and snippets.

@probablyangg
Last active February 24, 2020 13:28
Show Gist options
  • Save probablyangg/171b5236028c3250f4bccc90683627d2 to your computer and use it in GitHub Desktop.
Save probablyangg/171b5236028c3250f4bccc90683627d2 to your computer and use it in GitHub Desktop.
import { ChildERC20 } from './ChildERC20'
// other ERC20 contract imports ...
contract ERC20Meta is ERC20 {
mapping (address => uint256) public replayNonce;
ChildERC20 childErc20;
constructor (address _childErc20) {
childErc20 = ChildERC20(_childErc20);
}
function metaTransfer(
bytes calldata signature,
address to,
uint256 value,
uint256 nonce
) external returns (bool) {
bytes32 metaHash = metaTransferHash(to, value, nonce);
address signer = _getSigner(metaHash, signature);
require(signer != address(0), "metaTransfer: invalid signer address");
require(nonce == replayNonce[signer], "metaTransfer: invalid nonce");
replayNonce[signer]++;
// _transfer(signer, to, value);
childErc20.transfer(signer, to, value);
}
function metaTransferHash(
address to,
uint256 value,
uint256 nonce
) public view returns (bytes32) {
return keccak256(abi.encodePacked(address(this), "metaTransfer", to, value, nonce));
}
function getUserReplayNonce(
address user
) public view returns (uint256) {
return replayNonce[user];
}
function _getSigner(
bytes32 _hash,
bytes memory _signature
) internal pure returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
if (_signature.length != 65) {
return address(0);
}
assembly {
r := mload(add(_signature, 32))
s := mload(add(_signature, 64))
v := byte(0, mload(add(_signature, 96)))
}
if (v < 27) {
v += 27;
}
if (v != 27 && v != 28) {
return address(0);
} else {
return ecrecover(keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)
), v, r, s);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment