paint-brush
EIP-712 を使用的したイーサリアムのガスレス メタトランザクション に@thebojda
1,802 測定値
1,802 測定値

EIP-712 を使用したイーサリアムのガスレス メタトランザクション

Laszlo Fazekas12m2023/10/17
Read on Terminal Reader

長すぎる; 読むには

メタトランザクションの場合、ユーザーはトランザクションを記述する構造を作成し、秘密キーを使用してそれにデジタル署名します。それは誰かに小切手を書くのと似ています。デジタル署名されたトランザクションは中継ノードに送信され、中継ノードがそれをスマート コントラクトに送信します。コントラクトは署名を検証し、署名が有効であればトランザクションを実行します。中継ノードは契約の実行に対して支払いを行います。
featured image - EIP-712 を使用したイーサリアムのガスレス メタトランザクション
Laszlo Fazekas HackerNoon profile picture
0-item


私は最近、独自の ERC-20 トークンに基づく代替通貨システムであるKarma Moneyについての記事を書きました。私はカルマ マネーを、ユーザーが取引手数料もカルマで支払うことができるクローズド システムとして構想しました。独自のブロックチェーンを構築することはこれを実現する方法の 1 つですが、それは困難な作業です。ブロックチェーンのセキュリティと信頼性を確保するには、必要なインフラストラクチャと十分な規模のコミュニティを確立する必要があります。既存のブロックチェーンを使用する方がはるかに簡単です。 やなどのチェーンがあり、イーサリアムと完全に互換性があり、取引手数料が非常に低くなります。これらのチェーンでの ERC20 取引の手数料は通常 1 セント未満です。問題は、この料金をチェーン独自の暗号通貨で支払わなければならないため、ユーザーにとってチェーンの使用が複雑になる可能性があることです。幸いなことに、 メタル トランザクションというブリッジ ソリューションがあります。


メタトランザクションの場合、ユーザーはトランザクションを記述する構造を制成し、秘蜜キーを运用してそれにデジタル注明します。それは誰かに小切手を書くのと似ています。デジタル注明されたトランザクションは中継ノードに送信され、中継ノードがそれをスマート コントラクトに送信します。コントラクトは注明を検証し、注明が有効であればトランザクションを実行します。中継ノードは契約の実行に対して支払いを行います。


たとえば、カルマ トランザクションでは、ユーザーはトランザクションの金額 (たとえば、10 カルマ ドル)、その金額を送信するイーサリアム アドレス、および提示する意思のある取引手数料 (カルマ ドル) を提供します。取引のために。この構造はデジタル署名され、中継ノードに送信されます。ノードが取引手数料を許容できると判断した場合、デジタル署名された構造をカルマ コントラクトに送信し、カルマ コントラクトが署名を検証してトランザクションを実行します。取引手数料は中継ノードによってブロックチェーンのネイティブ通貨で支払われるため、ユーザーには、独自のブロックチェーンを必要とせずに取引に対してカルマドルを使って支払っているように見えます。


理論の次は実践を見てみましょう。


EIP-712 標準は、標準化された最简单的做法で構造化データ パッケージに摘要する最简单的做法を定義します。 MetaMask は、これらの構造化データをユーザーが読み取り或者な组织形式で表达します。 MetaMask に示されている EIP-712 準拠の構造 () は次のようになります。


EIP-712準拠の構造


上記のトランザクションは、次の単純なコードを食用して合成されました。


 async function main() { if (!window.ethereum || !window.ethereum.isMetaMask) { console.log("Please install MetaMask") return } const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); const chainId = await window.ethereum.request({ method: 'eth_chainId' }); const eip712domain_type_definition = { "EIP712Domain": [ { "name": "name", "type": "string" }, { "name": "version", "type": "string" }, { "name": "chainId", "type": "uint256" }, { "name": "verifyingContract", "type": "address" } ] } const karma_request_domain = { "name": "Karma Request", "version": "1", "chainId": chainId, "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" } document.getElementById('transfer_request')?.addEventListener("click", async function () { const transfer_request = { "types": { ...eip712domain_type_definition, "TransferRequest": [ { "name": "to", "type": "address" }, { "name": "amount", "type": "uint256" } ] }, "primaryType": "TransferRequest", "domain": karma_request_domain, "message": { "to": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", "amount": 1234 } } let signature = await window.ethereum.request({ "method": "eth_signTypedData_v4", "params": [ accounts[0], transfer_request ] }) alert("Signature: " + signature) }) } main()


eip712domain_type_definition は、メタデータを含む一般的な構造の説明です。 name フィールドは構造の名前、version フィールドは構造の定義バージョン、chainId フィールドと verifyingContract フィールドはメッセージの対象となるコントラクトを決定します。実行コントラクトは、署名されたトランザクションがターゲット コントラクトでのみ実行されることを保証するために、このメタデータを検証します。


karma_request_domain には、 EIP712Domain 構造によって定義されたメタデータの特定の値が含まれています。


署名のために MetaMask に送信する実際の構造は、 transfer_request変数に含まれています。 type ブロックには型定義が含まれます。ここで、最初の要素は必須の EIP712Domain 定義であり、メタデータを記述します。これに実際の構造定義が続きます。この場合は TransferRequest です。これは、ユーザーの MetaMask に表示される構造です。ドメイン ブロックにはメタデータの特定の値が含まれ、メッセージにはユーザーと署名する特定の構造が含まれます。


カルマ マネーに関して言えば、メタトランザクションがどのようにまとめられてスマート コントラクトに送信されるかの例は次のようになります。


 const types = { "TransferRequest": [ { "name": "from", "type": "address" }, { "name": "to", "type": "address" }, { "name": "amount", "type": "uint256" }, { "name": "fee", "type": "uint256" }, { "name": "nonce", "type": "uint256" } ] } let nonce = await contract.connect(MINER).getNonce(ALICE.address) const message = { "from": ALICE.address, "to": JOHN.address, "amount": 10, "fee": 1, "nonce": nonce } const signature = await ALICE.signTypedData(karma_request_domain, types, message) await contract.connect(MINER).metaTransfer(ALICE.address, JOHN.address, 10, 1, nonce, signature) assert.equal(await contract.balanceOf(ALICE.address), ethers.toBigInt(11))


types変数はトランザクションの構造を定義します。 「from」は送信者のアドレス、「to」は受信者のアドレスです。金額は、転送されるトークンの量を表します。料金は、トランザクションを実行し、チェーンのネイティブ通貨でコストをカバーする代わりに、中継ノードに提供するトークンの「量」です。 「ノンス」は、トランザクションの一意性を保証するためのカウンターとして機能します。このフィールドがないと、トランザクションが複数回実行される可能性があります。ただし、nonce のおかげで、署名されたトランザクションは 1 回しか実行できません。


が提供するsignTypedData関数を使用すると、EIP-712 構造に簡単に署名できます。これは前に示したコードと同じことを行いますが、使用方法はより簡単です。


メタトランスファーは、メタトランザクションを実行するためのカルマコントラクトのメソッドです。それがどのように機能するかを見てみましょう:


 function metaTransfer( address from, address to, uint256 amount, uint256 fee, uint256 nonce, bytes calldata signature ) public virtual returns (bool) { uint256 currentNonce = _useNonce(from, nonce); (address recoveredAddress, ECDSA.RecoverError err) = ECDSA.tryRecover( _hashTypedDataV4( keccak256( abi.encode( TRANSFER_REQUEST_TYPEHASH, from, to, amount, fee, currentNonce ) ) ), signature ); require( err == ECDSA.RecoverError.NoError && recoveredAddress == from, "Signature error" ); _transfer(recoveredAddress, to, amount); _transfer(recoveredAddress, msg.sender, fee); return true; }


落款を検証するには、まず構造体のハッシュを形成する必要的があります。これを行うための正確な手順は、と含むで詳しく説明されています。


要約すると、本質は、abi.encode を用して TYPEHASH (構造記述のハッシュ) と構造のフィールドを組み合わせるということです。次に、keccak256 ハッシュを提取します。ハッシュは、Karma コントラクト内の EIP712 OpenZeppelin コントラクトから継承された _hashTypedDataV4 メソッドに渡されます。この関数はメタデータを構造に追加し、最終的なハッシュを提取するため、構造の検証が极其にシンプルかつ透過的になります。最も外側の関数は ECDSA.tryRecover で、ハッシュと签字から签字者のアドレスを復元しようとします。 「from」パラメータのアドレスと一致性する場合、签字は有効です。コードの最後で、実際のトランザクションが実行され、トランザクションを実行する中継ノードが料金を受け取ります。


EIP-712 は署名構造の一般標準であり、メタトランザクションを実装するための多くの用途の 1 つにすぎません。署名はスマート コントラクトだけでなく検証できるため、ブロックチェーン以外のアプリケーションでも非常に役立ちます。たとえば、ユーザーが秘密キーで自分自身を識別するサーバー側の認証に使用できます。このようなシステムは、通常は暗号通貨に関連する高レベルのセキュリティを提供することができ、ハードウェア キーのみを使用して Web アプリケーションを使用できるようになります。さらに、MetaMask を使用して個々の API 呼び出しに署名することもできます。


EIP-712 標準のこの内容梗概が多くの人にとってインスピレーションとなり、ブロックチェーン ベースのプロジェクトと非ブロックチェーン プロジェクトの両方で EIP-712 標準を活用できることを願っています。


すべてのコードは、 で着手できます。
바카라사이트 바카라사이트 온라인바카라