Hello,
I am trying to create a signature and send it to a smart contract but can't seem to get it working.
This is how the signature is created on the backend.
const ganacheUserWallet = "0xF4F9E9eE0F4cB3EB3445FC3074A5b45e86a7D862";
const ganachePrivateKey = "0xa90a794905a9e223471e2818ccc5b66df413f99534463a52e82e5595d49ef17a";
let wallet = new ethers.Wallet(ganachePrivateKey);
let to = ganacheUserWallet;
let amount = ethers.utils.parseUnits("100", "wei");
let nonce = Date.now();
let contractAddress = "0x6C862c458e77028e85274dcaD6cB30E11b939081";
let message = ethers.utils.solidityKeccak256(
["address", "uint256", "uint256"],
[to, ethers.utils.hexlify(amount), nonce, contractAddress]
);
let prefix = "\x19Ethereum Signed Message:\n32";
let prefixedMessage = ethers.utils.solidityKeccak256(
["string", "bytes32"],
[prefix, message]
);
// Sign the message
let signature = await wallet.signMessage(ethers.utils.arrayify(prefixedMessage));
return res.status(200).send({ signature, nonce, to, amount });
The client/frontend receives the response and calls a contract function
if (signatureRequest.status === 200) {
const { signature, nonce, to, amount } = signatureRequest.data;
console.log(
signature,
nonce,
to,
amount,
"signature, nonce, to, amount"
);
const logResult = await contract.recoverSignerAndLog(
to,
ethers.BigNumber.from(amount),
nonce,
signature
);
console.log(logResult, "logResult");
} else {
setTxError("Server responded with status: " + signatureRequest.status);
}
And this is the contract. I tried using ECDSA.recover(message, sig)
to recover the address since the other functions didn't work. The ECDSA is not working either. Any ideas of examples of a working contract with signature decoding would be greatly appreciated.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract UrbsToken {
address owner = msg.sender;
event LogData(address recoveredAddress, address owner);
event LogString(string message);
event LogMessage(bytes32 message);
mapping(uint256 => bool) usedNonces;
constructor() payable {}
function recoverSignerAndLog(
address to,
uint256 amount,
uint256 nonce,
bytes memory sig
) public {
bytes32 message = prefixed(
keccak256(abi.encodePacked(to, amount, nonce, this))
);
emit LogMessage(message);
address recoveredAddress = recoverSigner(message, sig);
emit LogData(recoveredAddress, owner);
}
// function splitSignature(
// bytes memory sig
// ) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
// require(sig.length == 65, "Invalid signature length");
// assembly {
// r := mload(add(sig, 32))
// s := mload(add(sig, 64))
// v := byte(0, mload(add(sig, 96)))
// }
// return (v, r, s);
// }
function recoverSigner(
bytes32 message,
bytes memory sig
) internal pure returns (address) {
return ECDSA.recover(message, sig);
}
// function recoverSigner(
// bytes32 message,
// bytes memory sig
// ) internal pure returns (address) {
// uint8 v;
// bytes32 r;
// bytes32 s;
// (v, r, s) = splitSignature(sig);
// return ecrecover(message, v, r, s);
// }
function prefixed(bytes32 hash) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
);
}
}
Code to reproduce
Environment
I am running a blockchain locally using Ganache and Truffle.