|
36 | 36 | - Для чего необходимо реализовать контракт ```Paymaster```? |
37 | 37 | - Можно ли использовать [контракты из библиотеки OpenZeppelin](https://docs.openzeppelin.com/contracts/4.x/api/metatx) для организации метатранзакций? |
38 | 38 | - Какие еще есть сервисы, которые можно использовать для организации метатранзакций? |
39 | | -5. Творческий вопрос. Как ты считаешь, на сколько важны метатранзакции? Есть ли у них будущее? Нарушают ли они какие-нибудь законы децентрализации? |
| 39 | +5. Можно ли реализовать метатранзакции нативно? |
| 40 | + - Как работает следующий пример кода? |
| 41 | + ```solidity |
| 42 | + // SPDX-License-Identifier: UNLICENSED |
| 43 | + pragma solidity ^0.8.19; |
| 44 | +
|
| 45 | + import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; |
| 46 | +
|
| 47 | + contract Token is ERC20 { |
| 48 | + bytes32 public constant META_TRANSACTION_TYPEHASH = |
| 49 | + keccak256("MetaTransaction(uint256 nonce,address signer,bytes functionSignature)"); |
| 50 | +
|
| 51 | + mapping(address signer => uint256 nonce) private _nonces; |
| 52 | +
|
| 53 | + struct MetaTransaction { |
| 54 | + uint256 nonce; |
| 55 | + address signer; |
| 56 | + bytes functionSignature; |
| 57 | + } |
| 58 | +
|
| 59 | + event MetaTransactionExecuted( |
| 60 | + address signer, |
| 61 | + address relayer, |
| 62 | + bytes functionSignature |
| 63 | + ); |
| 64 | +
|
| 65 | + error ZeroAddress(); |
| 66 | + error InvalidSignature(); |
| 67 | + error InvalidCall(); |
| 68 | +
|
| 69 | + constructor() ERC20("Token", "MTT") {} |
| 70 | +
|
| 71 | + function DOMAIN_SEPARATOR() public view returns (bytes32) { |
| 72 | + return keccak256( |
| 73 | + abi.encode( |
| 74 | + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), |
| 75 | + keccak256("EIP712"), |
| 76 | + keccak256("1"), |
| 77 | + block.chainid, |
| 78 | + address(this) |
| 79 | + ) |
| 80 | + ); |
| 81 | + } |
| 82 | +
|
| 83 | + function executeMetaTransaction( |
| 84 | + address signer, |
| 85 | + bytes memory functionSignature, |
| 86 | + uint8 v, |
| 87 | + bytes32 r, |
| 88 | + bytes32 s |
| 89 | + ) external payable returns (bytes memory result) { |
| 90 | + MetaTransaction memory _tx = MetaTransaction({ |
| 91 | + nonce: _nonces[signer], |
| 92 | + signer: signer, |
| 93 | + functionSignature: functionSignature |
| 94 | + }); |
| 95 | +
|
| 96 | + bool isVerify = _verify(signer, _tx, v, r, s); |
| 97 | + if (!isVerify) { |
| 98 | + revert InvalidSignature(); |
| 99 | + } |
| 100 | +
|
| 101 | + _nonces[signer] += 1; |
| 102 | +
|
| 103 | + (bool success, bytes memory data) = address(this).call( |
| 104 | + abi.encodePacked(functionSignature, signer) |
| 105 | + ); |
| 106 | +
|
| 107 | + if (!success) { |
| 108 | + revert InvalidCall(); |
| 109 | + } |
| 110 | +
|
| 111 | + emit MetaTransactionExecuted(signer, msg.sender, functionSignature); |
| 112 | +
|
| 113 | + return data; |
| 114 | + } |
| 115 | +
|
| 116 | + function getNonce(address account) external view returns (uint256) { |
| 117 | + return _nonces[account]; |
| 118 | + } |
| 119 | +
|
| 120 | + function _msgSender() internal view override returns (address sender) { |
| 121 | + if (msg.sender == address(this)) { |
| 122 | + assembly { |
| 123 | + sender := shr(96, calldataload(sub(calldatasize(), 20))) |
| 124 | + } |
| 125 | + } |
| 126 | + else { |
| 127 | + return super._msgSender(); |
| 128 | + } |
| 129 | + } |
| 130 | +
|
| 131 | + function _verify( |
| 132 | + address signer, |
| 133 | + MetaTransaction memory _tx, |
| 134 | + uint8 v, |
| 135 | + bytes32 r, |
| 136 | + bytes32 s |
| 137 | + ) private view returns (bool) { |
| 138 | + if (signer == address(0)) { |
| 139 | + revert ZeroAddress(); |
| 140 | + } |
| 141 | +
|
| 142 | + return signer == ecrecover(_getDigest(_tx), v, r, s); |
| 143 | + } |
| 144 | +
|
| 145 | + function _getDigest(MetaTransaction memory _tx) private view returns (bytes32) { |
| 146 | + return keccak256( |
| 147 | + abi.encodePacked( |
| 148 | + "\x19\x01", |
| 149 | + DOMAIN_SEPARATOR(), |
| 150 | + keccak256( |
| 151 | + abi.encode( |
| 152 | + META_TRANSACTION_TYPEHASH, |
| 153 | + _tx.nonce, |
| 154 | + _tx.signer, |
| 155 | + keccak256(_tx.functionSignature) |
| 156 | + ) |
| 157 | + ) |
| 158 | + ) |
| 159 | + ); |
| 160 | + } |
| 161 | + } |
| 162 | + ``` |
| 163 | +6. Творческий вопрос. Как ты считаешь, на сколько важны метатранзакции? Есть ли у них будущее? Нарушают ли они какие-нибудь законы децентрализации? |
40 | 164 |
|
41 | 165 | - [Gas-free transactions: Meta Transactions explained](https://medium.com/coinmonks/gas-free-transactions-meta-transactions-explained-f829509a462d) |
42 | 166 | - [ERC-2771](https://eips.ethereum.org/EIPS/eip-2771) |
43 | 167 | - [Gas Station Network](https://docs.opengsn.org/) |
| 168 | +- [Native Meta Transactions](https://medium.com/gitcoin/native-meta-transactions-e509d91a8482) |
44 | 169 |
|
45 | 170 | ## Oracles |
46 | 171 |
|
|
0 commit comments