Mix.install([:ethers, :ex_secp256k1])
raw_transaction =
"0xf86b35850861c4680082520894dec50599773e005112663e4e35528460319c5507875f53e91d066f0b8025a07bbf52ea4ee9b12ca3f1e5d63e93eee550d111225457e0b59d7698324b04993aa06ab577a1f38941cc08d7345d8aee9fc62024bca37da2115d8420baa7e3fcc300"
"0xf86b35850861c4680082520894dec50599773e005112663e4e35528460319c5507875f53e91d066f0b8025a07bbf52ea4ee9b12ca3f1e5d63e93eee550d111225457e0b59d7698324b04993aa06ab577a1f38941cc08d7345d8aee9fc62024bca37da2115d8420baa7e3fcc300"
decoded_raw_transaction = Ethers.Utils.hex_decode!(raw_transaction)
<<248, 107, 53, 133, 8, 97, 196, 104, 0, 130, 82, 8, 148, 222, 197, 5, 153, 119, 62, 0, 81, 18, 102,
62, 78, 53, 82, 132, 96, 49, 156, 85, 7, 135, 95, 83, 233, 29, 6, 111, 11, 128, 37, 160, 123, 191,
82, 234, 78, 233, ...>>
This is the structure of legacy ethereum transactions.
[nonce, gas_price, gas, to, value, data, v, r, s] = ExRLP.decode(decoded_raw_transaction)
[
"5",
<<8, 97, 196, 104, 0>>,
"R\b",
<<222, 197, 5, 153, 119, 62, 0, 81, 18, 102, 62, 78, 53, 82, 132, 96, 49, 156, 85, 7>>,
<<95, 83, 233, 29, 6, 111, 11>>,
"",
"%",
<<123, 191, 82, 234, 78, 233, 177, 44, 163, 241, 229, 214, 62, 147, 238, 229, 80, 209, 17, 34, 84,
87, 224, 181, 157, 118, 152, 50, 75, 4, 153, 58>>,
<<106, 181, 119, 161, 243, 137, 65, 204, 8, 215, 52, 93, 138, 238, 159, 198, 32, 36, 188, 163,
125, 162, 17, 93, 132, 32, 186, 167, 227, 252, 195, 0>>
]
Re-construct transaction body and calculate recovery_id based on EIP-155
v_int = :binary.decode_unsigned(v)
{tx_body, parity} =
if v_int > 27 do
m = v_int - 35
parity = rem(m, 2)
chain_id = div(m - parity, 2)
{[nonce, gas_price, gas, to, value, data, chain_id, 0, 0], parity}
else
{[nonce, gas_price, gas, to, value, data], v_int - 27}
end
{[
"5",
<<8, 97, 196, 104, 0>>,
"R\b",
<<222, 197, 5, 153, 119, 62, 0, 81, 18, 102, 62, 78, 53, 82, 132, 96, 49, 156, 85, 7>>,
<<95, 83, 233, 29, 6, 111, 11>>,
"",
1,
0,
0
], 0}
RLP encode and Hash the body
tx_body_hash = ExRLP.encode(tx_body) |> ExKeccak.hash_256()
<<152, 121, 142, 245, 217, 136, 37, 192, 238, 92, 189, 151, 145, 126, 37, 43, 195, 38, 80, 60, 92,
47, 60, 44, 197, 2, 131, 195, 179, 173, 212, 165>>
Recover public key
{:ok, pub_key} = ExSecp256k1.recover(tx_body_hash, r, s, parity)
{:ok,
<<4, 151, 206, 146, 242, 45, 215, 166, 141, 181, 30, 205, 84, 73, 151, 234, 173, 231, 63, 182, 120,
35, 117, 51, 226, 227, 195, 92, 141, 221, 98, 121, 152, 231, 183, 11, 129, 58, 154, 14, 48, 102,
215, 221, 133, 5, 87, 44, ...>>}
Calculate address of a public key
Ethers.Utils.public_key_to_address(pub_key)
"0xb412E9D7c64638bDD554EcaDf2520633147Eaa44"
i think the if should be
> 28
as i just hit that case in testing with atype:0
transaction signed in ethers.js .>27
produces a -7 in that case..could likely be more like
>=35
as there's no case we want a signed int thereuuugh. these fkn magic number holders from btc.. silly.. anyway since we also subtract 27 should likely put this in a cond where if v >= 35 do w/chain_id etc.. if >=27 do w/o and :else throw maybe? or just return with the v_int being whatever it is...
i'll likely assign some const-type things like
@155_magic_number 35
and@legacy_magic_number 27
@alisinabh