Solidity
無法使用 ethers.js 驗證經過身份驗證的消息
我需要能夠從契約中檢索文件,讓使用者錢包對其進行簽名,然後將其發送回契約並驗證簽名。
這是我讓 address0 在客戶端簽名的方法:
let message : string = "check this message signed by account0"; let messageHash = keccak256(utils.toUtf8Bytes(message)); let signature = await address0.signMessage(messageHash); await hm.connect(address0).verifyMessage(message, signature);
這是我契約中的驗證器:
function verifyMessage(string memory message, bytes memory signature) public view returns(bool) { //hash the plain text message bytes32 messagehash = keccak256(bytes(message)); //hash the prefix and messagehash together bytes32 messagehash2 = keccak256(abi.encodePacked("x19Ethereum Signed Messsage:\\n32", messagehash)); //extract the signing contract address address signeraddress = ECDSA.recover( messagehash2, signature); if (msg.sender==signeraddress) { //The message is authentic return true; } else { //msg.sender didnt sign this message. return false; } }
遺憾的是,ECDSA.recover 為 signeraddress 返回的值不是 account0 的地址,儘管經過大量實驗,我仍無法得出消息發送者的正確地址。
將不勝感激任何指針。
我能夠從 Openzeppelin 上的人們那裡得到答案。
萬一任何其他機構遇到這種情況,一個問題是計算雜湊和在客戶端計算簽名的方式
代替
let messageHash = keccak256(utils.toUtf8Bytes(message));
採用
let messageHash = ethers.utils.solidityKeccak256(['string'], [message]);
而不是
let signature = await address0.signMessage(messageHash);
採用
let signature = await address0.signMessage(ethers.utils.arrayify(messageHash));
在伺服器端,可以使用 `ECDSA.toEthSignedMessageHash() 更簡單地添加前綴,如下面的解決方案所示:
using ECDSA for bytes32; function verifyMessage(string memory message, bytes memory signature) public view returns(address, bool) { //hash the plain text message bytes32 messagehash = keccak256(bytes(message)); address signeraddress = messagehash.toEthSignedMessageHash().recover(signature); if (msg.sender==signeraddress) { //The message is authentic return (signeraddress, true); } else { //msg.sender didnt sign this message. return (signeraddress, false); } }