0
# Meta-transactions
1
2
ERC-2771 gasless transactions enabling users to interact with contracts without paying gas fees directly.
3
4
## Capabilities
5
6
### ERC2771 Context
7
8
Context implementation for contracts that support meta-transactions through trusted forwarders.
9
10
```solidity { .api }
11
/**
12
* Context variant that supports meta-transactions via ERC-2771
13
*/
14
abstract contract ERC2771Context is Context {
15
constructor(address trustedForwarder);
16
function isTrustedForwarder(address forwarder) public view virtual returns (bool);
17
function trustedForwarder() public view virtual returns (address);
18
function _msgSender() internal view virtual override returns (address);
19
function _msgData() internal view virtual override returns (bytes calldata);
20
function _contextSuffixLength() internal view virtual override returns (uint256);
21
}
22
```
23
24
**Usage Examples:**
25
26
```solidity
27
import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
28
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
29
30
contract MyTokenWithMetaTx is ERC20, ERC2771Context {
31
constructor(address trustedForwarder)
32
ERC20("MyToken", "MTK")
33
ERC2771Context(trustedForwarder)
34
{}
35
36
function _msgSender() internal view override(Context, ERC2771Context) returns (address) {
37
return ERC2771Context._msgSender();
38
}
39
40
function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) {
41
return ERC2771Context._msgData();
42
}
43
44
function _contextSuffixLength() internal view override(Context, ERC2771Context) returns (uint256) {
45
return ERC2771Context._contextSuffixLength();
46
}
47
}
48
```
49
50
### ERC2771 Forwarder
51
52
Trusted forwarder contract that validates signatures and executes meta-transactions.
53
54
```solidity { .api }
55
/**
56
* ERC-2771 compliant forwarder for executing meta-transactions
57
*/
58
contract ERC2771Forwarder is ERC165, EIP712, Nonces, IERC2771Forwarder {
59
constructor(string memory name);
60
function verify(ForwardRequestData calldata request) public view virtual returns (bool);
61
function execute(ForwardRequestData calldata request) public payable virtual returns (bool success, bytes memory returndata);
62
function executeBatch(ForwardRequestData[] calldata requests, address payable refundReceiver) public payable virtual;
63
function getNonce(address from) public view virtual override returns (uint256);
64
function nonces(address owner) public view virtual override returns (uint256);
65
}
66
```
67
68
**Advanced Functions:**
69
70
```solidity { .api }
71
// ERC2771Forwarder additional capabilities
72
contract ERC2771Forwarder {
73
function verifyAndExecute(ForwardRequestData calldata request, bytes calldata signature) external payable returns (bool success, bytes memory returndata);
74
function verifyAndExecuteBatch(ForwardRequestData[] calldata requests, bytes[] calldata signatures, address payable refundReceiver) external payable;
75
function aggregate(ForwardRequestData[] calldata requests, bytes[] calldata signatures) external payable returns (bool[] memory successes, bytes[] memory results);
76
function simulateExecute(ForwardRequestData calldata request, bytes calldata signature) external view returns (bool success, bytes memory returndata, uint256 gasUsed);
77
function estimateGas(ForwardRequestData calldata request, bytes calldata signature) external view returns (uint256 gasUsed);
78
}
79
```
80
81
**Usage Examples:**
82
83
```solidity
84
import "@openzeppelin/contracts/metatx/ERC2771Forwarder.sol";
85
86
// Deploy forwarder
87
ERC2771Forwarder forwarder = new ERC2771Forwarder("MyForwarder");
88
89
// Create forward request
90
ForwardRequestData memory request = ForwardRequestData({
91
from: user,
92
to: target,
93
value: 0,
94
gas: 100000,
95
nonce: forwarder.getNonce(user),
96
deadline: block.timestamp + 3600,
97
data: abi.encodeCall(MyContract.someFunction, (param1, param2))
98
});
99
100
// Execute meta-transaction
101
forwarder.execute(request);
102
```
103
104
### Meta-transaction Utilities
105
106
Utilities for managing meta-transaction signatures and validation.
107
108
```solidity { .api }
109
/**
110
* Meta-transaction signature utilities
111
*/
112
library MetaTxUtils {
113
function recoverSigner(ForwardRequestData calldata request, bytes calldata signature, bytes32 domainSeparator) internal pure returns (address);
114
function hashRequest(ForwardRequestData calldata request) internal pure returns (bytes32);
115
function validateSignature(ForwardRequestData calldata request, bytes calldata signature, bytes32 domainSeparator) internal view returns (bool);
116
function validateNonce(address from, uint256 nonce, mapping(address => uint256) storage nonces) internal view returns (bool);
117
}
118
```
119
120
## Types
121
122
```solidity { .api }
123
/**
124
* Forward request data structure for ERC-2771
125
*/
126
struct ForwardRequestData {
127
address from;
128
address to;
129
uint256 value;
130
uint256 gas;
131
uint48 deadline;
132
bytes data;
133
bytes signature;
134
}
135
136
/**
137
* Batch forward request for multiple transactions
138
*/
139
struct BatchForwardRequest {
140
ForwardRequestData[] requests;
141
bytes[] signatures;
142
address payable refundReceiver;
143
}
144
145
/**
146
* ERC-2771 Forwarder interface
147
*/
148
interface IERC2771Forwarder {
149
function verify(ForwardRequestData calldata request) external view returns (bool);
150
function execute(ForwardRequestData calldata request) external payable returns (bool success, bytes memory returndata);
151
function executeBatch(ForwardRequestData[] calldata requests, address payable refundReceiver) external payable;
152
function getNonce(address from) external view returns (uint256);
153
}
154
155
/**
156
* Meta-transaction events
157
*/
158
event ForwardedRequest(address indexed from, address indexed to, bool success, bytes returndata);
159
event BatchForwardedRequest(uint256 indexed batchId, address indexed refundReceiver);
160
161
/**
162
* Meta-transaction errors
163
*/
164
error ERC2771ForwarderInvalidSigner(address signer, address from);
165
error ERC2771ForwarderExpiredRequest(uint48 deadline);
166
error ERC2771ForwarderInvalidRequest(string reason);
167
error ERC2771ForwarderMismatchedValue(uint256 requestValue, uint256 msgValue);
168
error ERC2771ForwarderInvalidNonce(address from, uint256 nonce, uint256 currentNonce);
169
```