Contracts cannot access the public key of the sender, since the raw transaction data is not visible to contracts. However, given the public key, you can verify that it does in fact match the address of the sender by re-deriving the address from the public key.
In Solidity it would look something like this:
function checkPubKey(bytes pubkey) constant returns (bool){
return (uint(keccak256(pubkey)) & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) == uint(msg.sender);
}
The easiest solution is to use ethereumjs-tx
module.
If you use web3@0.20
:
const Transaction = require('ethereumjs-tx')
const tx = web3.eth.getTransaction(txHash) // insert txhash here
const pubkey = new Transaction({
nonce: tx.nonce,
gasPrice: `0x${tx.gasPrice.toString(16)}`,
gasLimit: tx.gas,
to: tx.to,
value: `0x${tx.value.toString(16)}`,
data: tx.input,
chainId: 1, // mainnet network ID is 1. or use web3.version.network to find out
r: tx.r,
s: tx.s,
v: tx.v,
}).getSenderPublicKey()
console.log(pubkey.toString('hex'))
If you use web3 1.0 beta (and you use ethereumjs-util
), you need to convert some values to 0x prefixed hex strings
new Transaction({
nonce: tx.nonce,
gasPrice: ethJsUtil.bufferToHex(new ethJsUtil.BN(tx.gasPrice)),
gasLimit: tx.gas,
to: tx.to,
value: ethJsUtil.bufferToHex(new ethJsUtil.BN(tx.value)),
data: tx.input,
chainId: 1,
r: tx.r,
s: tx.s,
v: tx.v,
});
To verify if the pub key can be derived to the same sender address you can either use publicToAddress(pubkey)
from ethereumjs-util
, or use tx.getSenderAddress()
from ethereumjs-tx
Best Answer
As far as I know, Web3.js doesn't expose such functionalities directly. You could however do it by relying on one of its dependencies (@ethereumjs/tx).
Here is an example code heavily inspired by the recoverTransaction implementation :