英文:
how to confirm ethers off-chain signatures on-chain
问题
以下是代码的翻译部分:
"It's fairly easy to get ethers to get a metamask signature of a given piece of text, but how to confirm the signer onchain seems to be a bigger challenge than I thought. On a client side app with metamask installed I can call:
let provider = new ethers.providers.Web3Provider(window.ethereum);
let signer = provider.getSigner();
let signature = await signer.signMessage("Please confirm this: 12.315")
Metamask will pop the signing verification dialog with the message , and return a signature after the user approves.
You can pretty easily validate the address that produced the signature off-chain:
let signerAddress = ethers.utils.verifyMessage('Please confirm this: 12.315', sig);
But if you want to send the signature to a smart contract, and confirm the address that produced the signature, its not so easy.
The ECDSA package from OpenZeppelin has a recover() function but it only takes a hash as the "message", not a string. You can hash the string, but that doesn't return the right account:
function getSigner(string memory message, bytes sig) public view returns(address) {
bytes32 messageHash = keccak256(abi.encodePacked(message));
address signer = ECDSA.recover(messageHash, sig);
return signer;
}
Nor does
address signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(message, signature));
So how can validate you validate on-chain that the signature of a message produced off-chain by ethers is in fact the expected signer address?"
英文:
It's fairly easy to get ethers to get a metamask signature of a given piece of text, but how to confirm the signer onchain seems to be a bigger challenge than I thought. On a client side app with metamask installed I can call:
let provider = new ethers.providers.Web3Provider(window.ethereum);
let signer = provider.getSigner();
let signature = await signer.signMessage("Please confirm this: 12.315")
Metamask will pop the signing verification dialog with the message , and return a signature after the user approves.
You can pretty easily validate the address that produced the signature off-chain:
let signerAddress = ethers.utils.verifyMessage(ethers.utils.verifyMessage('Please confirm this: 12.315', sig);
But if you want to send the signature to a smart contract, and confirm the address that produced the signature, its not so easy.
The ECDSA package from OpenZeppelin has a recover() function but it only takes a hash as the "message', not a string. You can hash the string, but that doesn't return the right account:
function getSigner(string memory message, bytes sig) public view returns(address) {
bytes32 messageHash = keccak256(abi.encodePacked(message);
address signer = ECDSA.recover(messageHash, sig);
return signer;
}
Nor does
address signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(message, signature);
So how can validate you validate on-chain that the signature of a message produced off-chain by ethers is in fact the expected signer address?
答案1
得分: 1
代码部分不要翻译,以下是翻译好的内容:
"After poking around for a while in various posts and videos, I was able to figure out that metamask adds a prefix to the string being signed before the message signature is generated. The prefix added to the message is `\x19Ethereum Signed Message:\n$'' + the length of the message.
So the message used by metamask to produce the signature is actually:
let signedMessage = \x19Ethereum Signed Message:\n${signedMessage.length}${message}
;
So if your on chain function looks like:
function getSigner(string memory message, bytes memory sig) public view returns(address) {
bytes32 messageHash = keccak256(abi.encodePacked(message));
address signer = ECDSA.recover(messageHash, sig);
return signer;
}
then you should call it like this:
let prefixedMessage = \x19Ethereum Signed Message:\n${message.length}${message}
address = await mycontract.getSigner(prefixedMessage, signature);
Perhaps this will be helpful to somebody."
英文:
After poking around for a while in various posts and videos, I was able to figure out that metamask adds a prefix to the string being signed before the message signature is generated. The prefix added to the message is `\x19Ethereum Signed Message:\n$' + the length of the message.
So the message used by metamask to produce the signature is actually:
let signedMessage = `\x19Ethereum Signed Message:\n${signedMessage.length}${message}`;
So if your on chain function looks like:
function getSigner(string memory message, bytes memory sig) public view returns(address) {
bytes32 messageHash = keccak256(abi.encodePacked(message));
address signer = ECDSA.recover(messageHash, sig);
return signer;
}
then you should call it like this:
let prefixedMessage = `\x19Ethereum Signed Message:\n${message.length}${message}`
address = await mycontract.getSigner(prefixedMessage, signature);
Perhaps this will be helpful to somebody
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论