上述数据由 EIP-191 字节、哈希域分隔符、哈希后的 Transaction 类型和 Transaction 输入组成。该数据会再经过一次哈希计算,并进行签署。然后,我们可以使用 ecrecover 来验证智能合约中的签名: function verify (address signer, Transaction calldata transaction, bytes32 r, bytes32 s, uint8 v) public returns (bool) {return signer == ecrecover(hashTransaction(transaction), v, r, s);} 在下一节中,我们将详细解释 ecrecover。如果你想找一个简单的 JavaScript 或 TypeScript 代码库来来实现 EIP 712,请查看这个库: https://github.com/Mrtenz/eip-712 如果你想详细了解如何在智能合约中实现 EIP 712,我建议你阅读 MetaMask 的这篇文章。遗憾的是,EIP 712 规范目前还是草案,还没有得到很多应用的支持。目前,Ledger 和 Trezor 都还没支持 EIP 712,可能会阻碍该规范的广泛采用。不过,Ledger 表示他们即将发布的更新版会支持 EIP 712。 通过智能合约来验证签名 消息签名更有趣的地方在于,我们可以使用智能合约来验证 ECDSA 签名。Solidity 有一个内置函数叫做 ecrecover(这实际上是地址 0x1 上的预编译合约),可以恢复用来签署消息的私钥的地址。一个(非常)基本的合约实现如下所示: // SPDX-License-Identifier: MITpragma solidity 0.7.0;contract SignatureVerifier {/*** @notice Recovers the address for an ECDSA signature and message hash, note that the hash is automatically prefixed with "\x19Ethereum Signed Message:\n32"* @return address The address that was used to sign the message*/function recoverAddress (bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure returns (address) {bytes memory prefix = "\x19Ethereum Signed Message:\n32";bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, hash));return ecrecover(prefixedHash, v, r, s);}/*** @notice Checks if the recovered address from an ECDSA signature is equal to the address `signer` provided.* @return valid Whether the provided address matches with the signature*/function isValid (address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s) external pure returns (bool) {return recoverAddress(hash, v, r, s) == signer;}} 该合约仅用于验证签名,本身没有任何用处,因为签名验证也可以在没有智能合约的情况下完成。 这种方式的用处在于,用户可以通过免信任方式向智能合约发送某些指令,而无需发送交易。例如,用户可以签署一条消息:“请从我的地址向该地址发送 1 个以太币。” 智能合约可以使用 EIP-712 和/或 EIP-1077 标准来验证签名者并执行该指令。智能合约中的签名验证可用于以下应用:
|