can someone help me to find out what is wrong with my solidity code? (I'm trying to implement usage of the signatures and EIP712)
(ECDSA and _hashTypedDataV4 are from OpenZeppelin: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.7/contracts/utils/cryptography/ECDSA.sol and https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.7/contracts/utils/cryptography/draft-EIP712.sol)
string public constant AUTHORIZER_SIGNATURE = "Authorizer(string websiteDomain,uint256 currentBlock,bytes32 uniqueToken)";
bytes32 private constant _AUTHORIZER_SIGNATURE_TYPEHASH = keccak256(abi.encodePacked(keccak256(bytes(AUTHORIZER_SIGNATURE))));
function _getDigest(string memory websiteDomain, uint256 signCurrentBlock, bytes32 uniqueToken) private view returns (bytes32) {
return _hashTypedDataV4(
_getStructHashFromPayloadMsg(websiteDomain, signCurrentBlock, uniqueToken)
);
}
function _getStructHashFromPayloadMsg(string memory websiteDomain, uint256 signCurrentBlock, bytes32 uniqueToken) private pure returns (bytes32) {
return keccak256(
abi.encode(
_AUTHORIZER_SIGNATURE_TYPEHASH, // "message(string websiteDomain,uint256 currentBlock,bytes32 uniqueToken)"
keccak256(bytes(websiteDomain)),
signCurrentBlock,
uniqueToken
)
);
}
function DEBUG_recover(string memory websiteDomain, uint256 signCurrentBlock, bytes32 uniqueToken, bytes memory signature) external view returns (address) {
return ECDSA.recover(_getDigest(websiteDomain, signCurrentBlock, uniqueToken), signature);
}
On the node side, I write something like:
web3.currentProvider.send(
{
method: 'eth_signTypedData_v4',
params: ["0xb2AF24e5249479C3160b10b15eDc1192dc1171C8",{domain:{chainId:11155111,name:"my-domain",verifyingContract:"my-deployed-contract",version:"1"},message:{websiteDomain:"a-domain",currentBlock:1,uniqueToken:"0x31323334353637383930313233343536373839"},types:{EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}],Authorizer:[{name:"websiteDomain",type:"string"},{name:"currentBlock",type:"uint256"},{name:"uniqueToken",type:"bytes32"}]},primaryType:"Authorizer"}];,
from: '0xb2AF24e5249479C3160b10b15eDc1192dc1171C8',
},
(err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
}
);
await instance.DEBUG_recover('a-domain', 1, '0x31323334353637383930313233343536373839', '0x6b10a4e4010eec912205e604dafcff30a4204dd50f158ffd24d3f95a5b85dd2a2db3af256aac3a04a06c4e45eb606bfc3f3b7a4e0be24b796794a675f75c11411b');
So basically, I expect DEBUG_recover to return me: 0xb2AF24e5249479C3160b10b15eDc1192dc1171C8
(a testnet wallet address), but I receive another address instead…
(first I was using Ganache, but it seems to mess with the chainId… So I try with Sepolia instead, but it doesn't work either…)
Could this be related to my attribute "uniqueToken" being of type bytes32?
(I got it's "0x31323334353637383930313233343536373839" value with a command like web3.utils.asciiToHex("<another-value>")
Best Answer
Ok, so actually the problem was that I used an incorrect signature first, then when I try with string and bytes instead of bytes32 for the uniqueToken, I got another problem due to the dynamic types I guess...
I solved by problems just using correctly a bytes32 (correctly generated), so no more than 1 dynamic types value and it's now working as I expected.