Here's some working code using ethereumjs-tx:
const EthereumTx = require('ethereumjs-tx');.Transaction;
const raw = '0xf9010806808407fffd2894e80ab11db5543603cd620a7185fff71c98f54d3b80b8a4b93fa138000000000000000000000000000000009f6f0c2d68a7489c4ec7916fd2c51d88000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020dd11395091aa1bd2f8cc16768b286d992faf78a24ec9fa904bc44167e7680bbb8218aea08dfeee407aecbbeb816e3bb3a3957baa78c135b7d9ce66094554184bc80245a6a07a1f9dd58e96a80f5fcca28b819922467e23dab86a3159893b7ae2d09c7ef799';
console.log(new EthereumTx(raw).getSenderAddress().toString('hex'));
If you want to understand how this is done, the ethereumjs-tx
source code is a good read. In short:
- The raw transaction is the RLP encoding of a bunch of fields, including
r
,s
, andv
. r
ands
constitute a signature, andv
is a "recovery parameter," which is needed to recover the public key that created the signature.- To recover the public key, you need the message that was signed. In the case of transactions, this is the hash of the RLP encoding of the transaction, but with the
v
parameter replaced with the chain ID and ther
ands
values replaced with zeros. - Then you do elliptic curve stuff to retrieve the public key, which I couldn't explain here even if I wanted to. :-)
- An address is Ethereum is the last 20 bytes of the keccak256 hash of the public key.