Skip to content

Commit acd38af

Browse files
authored
Allow skipping checksum address in Utils.public_key_to_address (#116)
* Make it possible to opt-out of checksum address * Update CHANGELOG.md
1 parent 78c0d09 commit acd38af

File tree

3 files changed

+62
-13
lines changed

3 files changed

+62
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

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

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

lib/ethers/utils.ex

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ defmodule Ethers.Utils do
246246
def to_checksum_address("0x" <> address), do: to_checksum_address(address)
247247
def to_checksum_address("0X" <> address), do: to_checksum_address(address)
248248

249+
def to_checksum_address(<<address_bin::binary-20>>),
250+
do: hex_encode(address_bin) |> to_checksum_address()
251+
249252
def to_checksum_address(address) do
250253
address = String.downcase(address)
251254

@@ -295,33 +298,43 @@ defmodule Ethers.Utils do
295298
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
296299
"""
297300
@spec public_key_to_address(Ethers.Types.t_pub_key()) :: Ethers.Types.t_address()
298-
def public_key_to_address(<<public_key::binary-64>>) do
299-
Ethers.keccak_module().hash_256(public_key)
300-
|> :binary.part(32 - 20, 20)
301-
|> hex_encode()
302-
|> to_checksum_address()
301+
def public_key_to_address(public_key, use_checksum_address \\ true)
302+
303+
def public_key_to_address(<<public_key::binary-64>>, use_checksum_address) do
304+
address =
305+
Ethers.keccak_module().hash_256(public_key)
306+
|> :binary.part(32 - 20, 20)
307+
|> hex_encode()
308+
309+
if use_checksum_address do
310+
to_checksum_address(address)
311+
else
312+
address
313+
end
303314
end
304315

305-
def public_key_to_address(<<4, public_key::binary-64>>) do
306-
public_key_to_address(public_key)
316+
def public_key_to_address(<<4, public_key::binary-64>>, use_checksum_address) do
317+
public_key_to_address(public_key, use_checksum_address)
307318
end
308319

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

314-
def public_key_to_address(<<pre, _::binary-32>> = compressed) when pre in [2, 3] do
326+
def public_key_to_address(<<pre, _::binary-32>> = compressed, use_checksum_address)
327+
when pre in [2, 3] do
315328
case Ethers.secp256k1_module().public_key_decompress(compressed) do
316-
{:ok, public_key} -> public_key_to_address(public_key)
329+
{:ok, public_key} -> public_key_to_address(public_key, use_checksum_address)
317330
error -> raise ArgumentError, "Invalid compressed public key #{inspect(error)}"
318331
end
319332
end
320333

321-
def public_key_to_address("0x" <> _ = key) do
334+
def public_key_to_address("0x" <> _ = key, use_checksum_address) do
322335
key
323336
|> hex_decode!()
324-
|> public_key_to_address()
337+
|> public_key_to_address(use_checksum_address)
325338
end
326339

327340
@doc """

test/ethers/utils_test.exs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,39 @@ defmodule Ethers.UtilsTest do
8383
fn -> Ethers.Utils.hex_decode!("0xrubbish") end
8484
end
8585
end
86+
87+
describe "to_checksum_address/1" do
88+
test "converts address to checksum form" do
89+
assert Ethers.Utils.to_checksum_address("0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1") ==
90+
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
91+
92+
assert Ethers.Utils.to_checksum_address("0x90F8BF6A479F320EAD074411A4B0E7944EA8C9C1") ==
93+
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
94+
end
95+
96+
test "works with binary addresses" do
97+
bin_address = Ethers.Utils.hex_decode!("0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1")
98+
99+
assert Ethers.Utils.to_checksum_address(bin_address) ==
100+
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
101+
end
102+
end
103+
104+
describe "public_key_to_address/2" do
105+
@public_key "0x04e68acfc0253a10620dff706b0a1b1f1f5833ea3beb3bde2250d5f271f3563606672ebc45e0b7ea2e816ecb70ca03137b1c9476eec63d4632e990020b7b6fba39"
106+
test "converts public_key to address" do
107+
assert Ethers.Utils.public_key_to_address(@public_key) ==
108+
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
109+
110+
assert Ethers.Utils.public_key_to_address(@public_key, false) ==
111+
"0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1"
112+
end
113+
114+
test "works with binary public_key" do
115+
bin_public_key = Ethers.Utils.hex_decode!(@public_key)
116+
117+
assert Ethers.Utils.public_key_to_address(bin_public_key) ==
118+
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
119+
end
120+
end
86121
end

0 commit comments

Comments
 (0)