Skip to content

Commit

Permalink
Allow skipping checksum address in Utils.public_key_to_address (#116)
Browse files Browse the repository at this point in the history
* Make it possible to opt-out of checksum address

* Update CHANGELOG.md
  • Loading branch information
alisinabh authored Apr 12, 2024
1 parent 78c0d09 commit acd38af
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Add ERC-165 contract and behaviour
- Add `skip_docs` option for contract module doc and typespec generation
- Allow skipping checksum address in `Ethers.Utils.public_key_to_address/2`

## v0.4.3 (2024-04-05)

Expand Down
39 changes: 26 additions & 13 deletions lib/ethers/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ defmodule Ethers.Utils do
def to_checksum_address("0x" <> address), do: to_checksum_address(address)
def to_checksum_address("0X" <> address), do: to_checksum_address(address)

def to_checksum_address(<<address_bin::binary-20>>),
do: hex_encode(address_bin) |> to_checksum_address()

def to_checksum_address(address) do
address = String.downcase(address)

Expand Down Expand Up @@ -295,33 +298,43 @@ defmodule Ethers.Utils do
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
"""
@spec public_key_to_address(Ethers.Types.t_pub_key()) :: Ethers.Types.t_address()
def public_key_to_address(<<public_key::binary-64>>) do
Ethers.keccak_module().hash_256(public_key)
|> :binary.part(32 - 20, 20)
|> hex_encode()
|> to_checksum_address()
def public_key_to_address(public_key, use_checksum_address \\ true)

def public_key_to_address(<<public_key::binary-64>>, use_checksum_address) do
address =
Ethers.keccak_module().hash_256(public_key)
|> :binary.part(32 - 20, 20)
|> hex_encode()

if use_checksum_address do
to_checksum_address(address)
else
address
end
end

def public_key_to_address(<<4, public_key::binary-64>>) do
public_key_to_address(public_key)
def public_key_to_address(<<4, public_key::binary-64>>, use_checksum_address) do
public_key_to_address(public_key, use_checksum_address)
end

unless Code.ensure_loaded?(Ethers.secp256k1_module()) do
def public_key_to_address(<<pre, _::binary-32>> = compressed) when pre in [2, 3],
do: raise("secp256k1 module not loaded")
def public_key_to_address(<<pre, _::binary-32>> = compressed, _use_checksum_address)
when pre in [2, 3],
do: raise("secp256k1 module not loaded")
end

def public_key_to_address(<<pre, _::binary-32>> = compressed) when pre in [2, 3] do
def public_key_to_address(<<pre, _::binary-32>> = compressed, use_checksum_address)
when pre in [2, 3] do
case Ethers.secp256k1_module().public_key_decompress(compressed) do
{:ok, public_key} -> public_key_to_address(public_key)
{:ok, public_key} -> public_key_to_address(public_key, use_checksum_address)
error -> raise ArgumentError, "Invalid compressed public key #{inspect(error)}"
end
end

def public_key_to_address("0x" <> _ = key) do
def public_key_to_address("0x" <> _ = key, use_checksum_address) do
key
|> hex_decode!()
|> public_key_to_address()
|> public_key_to_address(use_checksum_address)
end

@doc """
Expand Down
35 changes: 35 additions & 0 deletions test/ethers/utils_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,39 @@ defmodule Ethers.UtilsTest do
fn -> Ethers.Utils.hex_decode!("0xrubbish") end
end
end

describe "to_checksum_address/1" do
test "converts address to checksum form" do
assert Ethers.Utils.to_checksum_address("0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1") ==
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"

assert Ethers.Utils.to_checksum_address("0x90F8BF6A479F320EAD074411A4B0E7944EA8C9C1") ==
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
end

test "works with binary addresses" do
bin_address = Ethers.Utils.hex_decode!("0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1")

assert Ethers.Utils.to_checksum_address(bin_address) ==
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
end
end

describe "public_key_to_address/2" do
@public_key "0x04e68acfc0253a10620dff706b0a1b1f1f5833ea3beb3bde2250d5f271f3563606672ebc45e0b7ea2e816ecb70ca03137b1c9476eec63d4632e990020b7b6fba39"
test "converts public_key to address" do
assert Ethers.Utils.public_key_to_address(@public_key) ==
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"

assert Ethers.Utils.public_key_to_address(@public_key, false) ==
"0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1"
end

test "works with binary public_key" do
bin_public_key = Ethers.Utils.hex_decode!(@public_key)

assert Ethers.Utils.public_key_to_address(bin_public_key) ==
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
end
end
end

0 comments on commit acd38af

Please sign in to comment.