Secure Smart Contract library for Solidity with battle-tested implementations of token standards, access control, governance, and essential utilities for building decentralized applications.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
ERC-2771 gasless transactions enabling users to interact with contracts without paying gas fees directly.
Context implementation for contracts that support meta-transactions through trusted forwarders.
/**
* Context variant that supports meta-transactions via ERC-2771
*/
abstract contract ERC2771Context is Context {
constructor(address trustedForwarder);
function isTrustedForwarder(address forwarder) public view virtual returns (bool);
function trustedForwarder() public view virtual returns (address);
function _msgSender() internal view virtual override returns (address);
function _msgData() internal view virtual override returns (bytes calldata);
function _contextSuffixLength() internal view virtual override returns (uint256);
}Usage Examples:
import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyTokenWithMetaTx is ERC20, ERC2771Context {
constructor(address trustedForwarder)
ERC20("MyToken", "MTK")
ERC2771Context(trustedForwarder)
{}
function _msgSender() internal view override(Context, ERC2771Context) returns (address) {
return ERC2771Context._msgSender();
}
function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) {
return ERC2771Context._msgData();
}
function _contextSuffixLength() internal view override(Context, ERC2771Context) returns (uint256) {
return ERC2771Context._contextSuffixLength();
}
}Trusted forwarder contract that validates signatures and executes meta-transactions.
/**
* ERC-2771 compliant forwarder for executing meta-transactions
*/
contract ERC2771Forwarder is ERC165, EIP712, Nonces, IERC2771Forwarder {
constructor(string memory name);
function verify(ForwardRequestData calldata request) public view virtual returns (bool);
function execute(ForwardRequestData calldata request) public payable virtual returns (bool success, bytes memory returndata);
function executeBatch(ForwardRequestData[] calldata requests, address payable refundReceiver) public payable virtual;
function getNonce(address from) public view virtual override returns (uint256);
function nonces(address owner) public view virtual override returns (uint256);
}Advanced Functions:
// ERC2771Forwarder additional capabilities
contract ERC2771Forwarder {
function verifyAndExecute(ForwardRequestData calldata request, bytes calldata signature) external payable returns (bool success, bytes memory returndata);
function verifyAndExecuteBatch(ForwardRequestData[] calldata requests, bytes[] calldata signatures, address payable refundReceiver) external payable;
function aggregate(ForwardRequestData[] calldata requests, bytes[] calldata signatures) external payable returns (bool[] memory successes, bytes[] memory results);
function simulateExecute(ForwardRequestData calldata request, bytes calldata signature) external view returns (bool success, bytes memory returndata, uint256 gasUsed);
function estimateGas(ForwardRequestData calldata request, bytes calldata signature) external view returns (uint256 gasUsed);
}Usage Examples:
import "@openzeppelin/contracts/metatx/ERC2771Forwarder.sol";
// Deploy forwarder
ERC2771Forwarder forwarder = new ERC2771Forwarder("MyForwarder");
// Create forward request
ForwardRequestData memory request = ForwardRequestData({
from: user,
to: target,
value: 0,
gas: 100000,
nonce: forwarder.getNonce(user),
deadline: block.timestamp + 3600,
data: abi.encodeCall(MyContract.someFunction, (param1, param2))
});
// Execute meta-transaction
forwarder.execute(request);Utilities for managing meta-transaction signatures and validation.
/**
* Meta-transaction signature utilities
*/
library MetaTxUtils {
function recoverSigner(ForwardRequestData calldata request, bytes calldata signature, bytes32 domainSeparator) internal pure returns (address);
function hashRequest(ForwardRequestData calldata request) internal pure returns (bytes32);
function validateSignature(ForwardRequestData calldata request, bytes calldata signature, bytes32 domainSeparator) internal view returns (bool);
function validateNonce(address from, uint256 nonce, mapping(address => uint256) storage nonces) internal view returns (bool);
}/**
* Forward request data structure for ERC-2771
*/
struct ForwardRequestData {
address from;
address to;
uint256 value;
uint256 gas;
uint48 deadline;
bytes data;
bytes signature;
}
/**
* Batch forward request for multiple transactions
*/
struct BatchForwardRequest {
ForwardRequestData[] requests;
bytes[] signatures;
address payable refundReceiver;
}
/**
* ERC-2771 Forwarder interface
*/
interface IERC2771Forwarder {
function verify(ForwardRequestData calldata request) external view returns (bool);
function execute(ForwardRequestData calldata request) external payable returns (bool success, bytes memory returndata);
function executeBatch(ForwardRequestData[] calldata requests, address payable refundReceiver) external payable;
function getNonce(address from) external view returns (uint256);
}
/**
* Meta-transaction events
*/
event ForwardedRequest(address indexed from, address indexed to, bool success, bytes returndata);
event BatchForwardedRequest(uint256 indexed batchId, address indexed refundReceiver);
/**
* Meta-transaction errors
*/
error ERC2771ForwarderInvalidSigner(address signer, address from);
error ERC2771ForwarderExpiredRequest(uint48 deadline);
error ERC2771ForwarderInvalidRequest(string reason);
error ERC2771ForwarderMismatchedValue(uint256 requestValue, uint256 msgValue);
error ERC2771ForwarderInvalidNonce(address from, uint256 nonce, uint256 currentNonce);Install with Tessl CLI
npx tessl i tessl/npm-openzeppelin--contracts