之前在的文章 Solidity 智能合約 - EIP-712 類型結構化資料雜湊和簽名,說明了智能合約如何檢驗 EIP-712 的簽章。這篇文章將說明如何使用 Ethers.js 來進行 EIP-712 簽章。本篇文章使用 Ethers.js 6.7.1 版本。
簽章
signer.signTypedData
Ethers.js 使用下面函式進行簽署,參考之前的文章使用 Ethers.js 簽章與檢驗取得 Signer。
1
| signer.signTypedData(domain, types, value): Promise<string>
|
- domain: 合約中 eip712Domain 的資料。
- types: 類別定義。
- value: 訊息內容,直接參考下面範例說明。
- 回傳值: 為 Promise 物件,內容為簽章。
使用之前的範例合約來說明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
contract Example is EIP712 { struct Mail { address from; address to; string contents; }
bytes32 private constant MAIL_TYPEHASH = keccak256( "Mail(address from,address to,string contents)" );
constructor() EIP712("Example", "1") { }
function hashStruct(Mail memory mail) public pure returns (bytes32) { return keccak256( abi.encode( MAIL_TYPEHASH, mail.from, mail.to, keccak256(abi.encodePacked(mail.contents)) ) ); }
function recover(Mail memory mail, uint8 v, bytes32 r, bytes32 s) public view returns (address) { bytes32 structHash = hashStruct(mail); bytes32 hash = _hashTypedDataV4(structHash); return ecrecover(hash , v, r, s); } }
|
對應的 Ethers.js 用法如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| const chainId = 1;
const verifyingContract = '0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8';
const domain = { chainId, verifyingContract, name: 'Example', version: '1' };
const types = { Mail: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'contents', type: 'string' } ] };
const value = { from: '0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8', to: '0xDA9dfA130Df4dE4673b89022EE50ff26f6EA73Cf', contents: 'Hello' };
const signature = await signer.signTypedData(domain, types, value);
|
最後會得到沒有切開的簽章,可以參考之前的文章使用 Ethers.js 簽章與檢驗 來處理。
其他範例
之前的結構陣列範例為例
1 2 3 4 5 6 7 8 9 10
| struct Mail { Person from; Person[] to; string contents; }
struct Person { address wallet; string name; }
|
types 和資料內容修改如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const types = { Mail: [ { name: 'from', type: 'Person' }, { name: 'to', type: 'Person[]' }, { name: 'contents', type: 'string' } ], Person: [ { name: 'wallet', type: 'address' }, { name: 'name', type: 'string' } ] };
const value = { from: { wallet: '0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8', name: 'Binance 7' }, to: [ { wallet: '0xDA9dfA130Df4dE4673b89022EE50ff26f6EA73Cf', name: 'Kraken 13' } ], contents: 'Hello' };
|
檢驗簽章
如果想在後端程式檢驗簽章,作為登入之類的用途,可以使用下面函式:
1
| verifyTypedData(domain, types, value, signature: SignatureLike): string
|
- domain: 合約中 eip712Domain 的資料。
- types: 類別定義。
- value: 訊息內容,直接參考下面範例說明。
- signature: 簽章,可以是為切開的字串,或者是包含 vrs 的物件。
- 回傳值: 簽署人地址。
範例如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { verifyTypedData } from "ethers";
const signature = '0x78c03866a5efa253157e62596194631b4c9757d38b3556994d6b879d79d713e666f9c0a3e21e48fd061c5cf5217fd7e3c3ced521aa39650fda179ce61e6763b11c';
const address = verifyTypedData(domain, types, value, signature);
|
延伸閱讀
Solidity 智能合約 - EIP-712 類型結構化資料雜湊和簽名
使用 Web3.js 進行 EIP-712 類型結構化資料簽名與檢驗
Solidity 智能合約 - ecrecover 簽章檢驗
使用 Ethers.js 簽章與檢驗