私は最近、独自の ERC-20 トークンに基づく代替通貨システムであるKarma Moneyについての記事を書きました。私はカルマ マネーを、ユーザーが取引手数料もカルマで支払うことができるクローズド システムとして構想しました。独自のブロックチェーンを構築することはこれを実現する方法の 1 つですが、それは困難な作業です。ブロックチェーンのセキュリティと信頼性を確保するには、必要なインフラストラクチャと十分な規模のコミュニティを確立する必要があります。既存のブロックチェーンを使用する方がはるかに簡単です。 やなどのチェーンがあり、イーサリアムと完全に互換性があり、取引手数料が非常に低くなります。これらのチェーンでの ERC20 取引の手数料は通常 1 セント未満です。問題は、この料金をチェーン独自の暗号通貨で支払わなければならないため、ユーザーにとってチェーンの使用が複雑になる可能性があることです。幸いなことに、 メタル トランザクションというブリッジ ソリューションがあります。
たとえば、カルマ トランザクションでは、ユーザーはトランザクションの金額 (たとえば、10 カルマ ドル)、その金額を送信するイーサリアム アドレス、および提示する意思のある取引手数料 (カルマ ドル) を提供します。取引のために。この構造はデジタル署名され、中継ノードに送信されます。ノードが取引手数料を許容できると判断した場合、デジタル署名された構造をカルマ コントラクトに送信し、カルマ コントラクトが署名を検証してトランザクションを実行します。取引手数料は中継ノードによってブロックチェーンのネイティブ通貨で支払われるため、ユーザーには、独自のブロックチェーンを必要とせずに取引に対してカルマドルを使って支払っているように見えます。
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; }
EIP-712 は署名構造の一般標準であり、メタトランザクションを実装するための多くの用途の 1 つにすぎません。署名はスマート コントラクトだけでなく検証できるため、ブロックチェーン以外のアプリケーションでも非常に役立ちます。たとえば、ユーザーが秘密キーで自分自身を識別するサーバー側の認証に使用できます。このようなシステムは、通常は暗号通貨に関連する高レベルのセキュリティを提供することができ、ハードウェア キーのみを使用して Web アプリケーションを使用できるようになります。さらに、MetaMask を使用して個々の API 呼び出しに署名することもできます。