問題一覧に戻る
上級高度なパターン
問題94: メタトランザクション
Solidityのメタトランザクションを学習 - EIP-2771実装によるガスレストランザクション。メタトランザクションはユーザーがガス用ETHを保有せずにコントラクトと相互作用でき、ユーザー体験を向上。リレイヤーがガス料金を支払い、ユーザーはオフチェーンでトランザクションデータに署名。EIP-712はセキュリティのためドメイン分離を持つ構造化データ署名を提供。このパターンは主流採用、ウォレットレスオンボーディング、ガス複雑性が抽象化されたユーザーフレンドリーDeFiアプリ作成に不可欠です。
pragma solidity ^0.8.0;
contract MetaTransaction {
mapping(address => uint256) public nonces;
// EIP712ドメインセパレーターハッシュ
bytes32 private constant = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
// メタトランザクション型ハッシュ
bytes32 private constant = keccak256(
"MetaTx(address from,address to,uint256 value,uint256 nonce)"
);
struct MetaTx {
address from;
address to;
uint256 value;
uint256 nonce;
}
function executeMetaTransaction(
MetaTx memory metaTx,
bytes memory signature
) public {
// 署名の真正性を検証
address signer = ();
require(signer == metaTx.from, "Invalid signature");
// nonceをチェックして増加
require(nonces[metaTx.from] == metaTx.nonce, "Invalid nonce");
[metaTx.from]++;
// トランザクションを実行
(bool success, ) = metaTx.to.call{value: metaTx.value}("");
require(success, "Transaction failed");
}
function verifySignature(
MetaTx memory metaTx,
bytes memory signature
) internal view returns (address) {
// EIP712ハッシュを作成
bytes32 digest = keccak256(abi.encodePacked(
"\x19\x01",
(),
));
// 署名者アドレスを復元
return );
}
function hashMetaTx(MetaTx memory metaTx) internal pure returns (bytes32) {
// メタトランザクションデータをエンコード
return keccak256(abi.encode(
,
metaTx.from,
metaTx.to,
metaTx.value,
metaTx.nonce
));
}
function domainSeparator() internal view returns (bytes32) {
// ドメインセパレーターを生成
return keccak256(abi.encode(
,
keccak256("MetaTransaction"),
keccak256("1"),
block.chainid,
address(this)
));
}
}