开源项目 metatx-standard
使用教程
1. 项目的目录结构及介绍
metatx-standard/
├── src/
│ ├── contracts/
│ │ ├── EIP712MetaTransaction.sol
│ │ └── ...
│ └── ...
├── test/
│ └── ...
├── package.json
├── README.md
└── ...
src/
:包含项目的源代码,主要为智能合约文件。contracts/
:存放智能合约文件,如EIP712MetaTransaction.sol
。
test/
:包含项目的测试文件。package.json
:项目的依赖管理文件。README.md
:项目的说明文档。
2. 项目的启动文件介绍
项目的启动文件主要是智能合约文件 EIP712MetaTransaction.sol
,该文件定义了元交易的标准接口和实现。
// EIP712MetaTransaction.sol
pragma solidity ^0.8.0;
import "./EIP712Base.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.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;
}
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 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 successful");
nonces[userAddress] = nonces[userAddress].add(1);
emit MetaTransactionExecuted(userAddress, msg.sender, functionSignature);
return returnData;
}
function hashMetaTransaction(MetaTransaction memory metaTx) internal pure returns (bytes32) {
return keccak256(abi.encode(
META_TRANSACTION_TYPEHASH,
metaTx.nonce,
metaTx.from,
keccak256(metaTx.functionSignature)
));
}
function getNonce(address user) public view returns(uint256) {
return nonces[user];
}
function verify(address user, MetaTransaction memory metaTx, bytes32 sigR, bytes32 sigS, uint8 sigV) internal view returns (bool) {
address signer = ecrecover(toTypedMessageHash(hashMetaTransaction(metaTx)), sigV, sigR, sigS);
require(signer != address(0), "Invalid signature");
return signer == user;
}
}
3. 项目的配置文件介绍
项目的配置文件主要是 package.json
,该文件定义了项目的依赖和其他配置信息。
{
"name": "metatx-standard",
"version": "1.0.0",
"description": "Generalized meta transaction standard",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository