I'm currently trying to get the public key of the user that deploys a contract. Unfortunately I can't make it work.
I am trying to achieve this solely by using ethers.js as I don't want to bloat my React build with other packages. I can easily get the public key from a given signature using the following code taken from this issue.
let msg = "This is a normal string.";
let sig = await signer.signMessage(msg);
const msgHash = ethers.utils.hashMessage(msg);
const msgHashBytes = ethers.utils.arrayify(msgHash);
const recoveredPubKey = ethers.utils.recoverPublicKey(msgHashBytes, sig);
const recoveredAddress = ethers.utils.recoverAddress(msgHashBytes, sig);
When deploying a contract I should be able to do the same thing by simply stitching together the r
, s
and v
values taken from the deployTransaction
. The example in the documentation is similar. Here's my code:
const deployTx = contract.deployTransaction;
const msgHash = ethers.utils.hashMessage(deployTx.raw);
const dataBytes = ethers.utils.arrayify(msgHash);
const expanded = {
r: deployTx.r,
s: deployTx.s,
recoveryParam: 0,
v: deployTx.v
};
const signature = ethers.utils.joinSignature(expanded);
// now the signature should be correctly formatted
const recoveredPubKey = ethers.utils.recoverPublicKey(dataBytes, signature);
const recoveredAddress = ethers.utils.recoverAddress(dataBytes, signature);
This approach does not work. As far as I know the data that was signed during the deployment is in deployTransaction.raw
. So this should work. But I tested it with deployTransaction.data
as well.
To me it looks like the signature might be wrong. The joinSignature
automatically converts the v
value to either 27 or 28. According to EIP155 this doesn't make any sense?
Edit: To clarify, I think all I need is the true signing hash. How can I generate it? It's apparently not the hash of the raw deployment transaction.
Edit 2: After some research in the ethereum book I found this:
In Ethereum’s implementation of ECDSA, the "message" being signed is the transaction, or more accurately, the Keccak-256 hash of the RLP-encoded data from the transaction. The signing key is the EOA’s private key.
So I changed my code to the following:
const deployTx = contract.deployTransaction;
const msg = ethers.utils.RLP.encode(deployTx.data);
const msgHash = ethers.utils.keccak256(msg);
const msgBytes = ethers.utils.arrayify(msgHash);
const expanded = {
r: deployTx.r,
s: deployTx.s,
recoveryParam: 0,
v: deployTx.v
};
const signature = ethers.utils.joinSignature(expanded);
const recoveredPubKey = ethers.utils.recoverPublicKey(
msgBytes,
signature
);
const recoveredAddress = ethers.utils.recoverAddress(msgBytes, signature);
This still does not work unfortunately.
tx.hash(false)
).