I have a simple contract which recover the signature signer


const signer = new Wallet(process.env.PRIVATE_KEY)
const encoded = abiCoder.encode([ "uint" ], [ 1234 ]);
const signature = await signer.signMessage(arrayify(encoded));
const { r, s, v } = splitSignature(signature)


recover signer:

function recover(uint256 amount, uint8 v, bytes32 r, bytes32 s) view external returns(address signer){

        bytes32 hash =  keccak256(abi.encodePacked(amount));
        bytes32 signedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",hash));
        signer = ecrecover(signedHash, v, r, s);


but somehow I cannot recover the actual signer.

1 Answer 1


You are not signing / verifying the same data on both sides.

On the JavaScript you are signing (Prefix is hidden in signMessage):

  • keccak256("\x19Ethereum Signed Message:\n32" || abi.encode(uint(1234)))

But on the Solidity side you are veryfying for

  • keccak256("\x19Ethereum Signed Message:\n32" || keccak256(abi.encode(uint(1234)))

Assuming that you want to use the solidity code as a reference since you hardcoded the 32 bytes length, you want to sign a hashed encoding of amount on the JavaScript side.

To do so, change this line :

const encoded = abiCoder.encode([ "uint" ], [ 1234 ]);

For :

const encoded = ethers.utils.keccak256(abiCoder.encode(["uint"], [1234]));

And the recovered address matches the signer's address.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.