From 641721dbdc2aba62b41221c017fc4eb184422c46 Mon Sep 17 00:00:00 2001 From: Alisina Bahadori Date: Thu, 16 Oct 2025 22:56:17 -0400 Subject: [PATCH 1/4] Fix input and signature issue --- CHANGELOG.md | 7 ++ lib/ethers/transaction.ex | 7 +- test/ethers/transaction_test.exs | 141 +++++++++++++++++++++++++++++++ test/ethers_test.exs | 13 ++- 4 files changed, 162 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c563064..8670dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +### Bug Fixes + +- Fix decoding of `input` values from RPC results +- Handle the case when RPC result does not have signature of transaction + ## 0.6.8 (2025-10-13) ### Enhancements diff --git a/lib/ethers/transaction.ex b/lib/ethers/transaction.ex index 3b29be5..8fc7418 100644 --- a/lib/ethers/transaction.ex +++ b/lib/ethers/transaction.ex @@ -96,13 +96,16 @@ defmodule Ethers.Transaction do end end - defp maybe_wrap_signed({:ok, transaction}, params) do + defp maybe_wrap_signed({:ok, transaction}, params) when not is_nil(transaction) do case Map.fetch(params, :signature_r) do {:ok, sig_r} when not is_nil(sig_r) -> params |> Map.put(:payload, transaction) |> Signed.new() + {:ok, nil} -> + {:ok, transaction} + :error -> {:ok, transaction} end @@ -265,7 +268,7 @@ defmodule Ethers.Transaction do block_hash: from_map_value(tx, :blockHash), block_number: from_map_value_int(tx, :blockNumber), chain_id: from_map_value_int(tx, :chainId), - input: from_map_value(tx, :input) || from_map_value(tx, :data), + input: from_map_value_bin(tx, :input) || from_map_value_bin(tx, :data) || "", from: from_map_value(tx, :from), gas: from_map_value_int(tx, :gas), gas_price: from_map_value_int(tx, :gasPrice), diff --git a/test/ethers/transaction_test.exs b/test/ethers/transaction_test.exs index 0fda947..3ec9d50 100644 --- a/test/ethers/transaction_test.exs +++ b/test/ethers/transaction_test.exs @@ -272,4 +272,145 @@ defmodule Ethers.TransactionTest do assert Transaction.Protocol.type_envelope(signed_tx) == type.type_envelope() end end + + describe "from_rpc_map/1" do + test "handles transaction with input field" do + tx_map = %{ + "type" => "0x2", + "chainId" => "0x1", + "nonce" => "0x0", + "to" => "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + "value" => "0x0", + "input" => "0x1234567890", + "gas" => "0x5208", + "maxFeePerGas" => "0x3b9aca00", + "maxPriorityFeePerGas" => "0x0" + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == Utils.hex_decode!("0x1234567890") + end + + test "handles transaction with data field instead of input" do + tx_map = %{ + "type" => "0x2", + "chainId" => "0x1", + "nonce" => "0x0", + "to" => "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + "value" => "0x0", + "data" => "0xabcdef", + "gas" => "0x5208", + "maxFeePerGas" => "0x3b9aca00", + "maxPriorityFeePerGas" => "0x0" + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == Utils.hex_decode!("0xabcdef") + end + + test "handles transaction with both input and data fields (input takes precedence)" do + tx_map = %{ + "type" => "0x2", + "chainId" => "0x1", + "nonce" => "0x0", + "to" => "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + "value" => "0x0", + "input" => "0x1234", + "data" => "0x5678", + "gas" => "0x5208", + "maxFeePerGas" => "0x3b9aca00", + "maxPriorityFeePerGas" => "0x0" + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == Utils.hex_decode!("0x1234") + end + + test "handles transaction with neither input nor data field (defaults to empty string)" do + tx_map = %{ + "type" => "0x2", + "chainId" => "0x1", + "nonce" => "0x0", + "to" => "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + "value" => "0x0", + "gas" => "0x5208", + "maxFeePerGas" => "0x3b9aca00", + "maxPriorityFeePerGas" => "0x0" + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == "" + end + + test "handles transaction with nil input and data fields" do + tx_map = %{ + "type" => "0x2", + "chainId" => "0x1", + "nonce" => "0x0", + "to" => "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + "value" => "0x0", + "input" => nil, + "data" => nil, + "gas" => "0x5208", + "maxFeePerGas" => "0x3b9aca00", + "maxPriorityFeePerGas" => "0x0" + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == "" + end + + test "handles transaction with atom keys" do + tx_map = %{ + type: "0x2", + chainId: "0x1", + nonce: "0x0", + to: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + value: "0x0", + input: "0xdeadbeef", + gas: "0x5208", + maxFeePerGas: "0x3b9aca00", + maxPriorityFeePerGas: "0x0" + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == Utils.hex_decode!("0xdeadbeef") + assert %Transaction.Eip1559{} = transaction + end + + test "handles legacy transaction type" do + tx_map = %{ + "type" => "0x0", + "chainId" => "0x1", + "nonce" => "0x0", + "to" => "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + "value" => "0x0", + "data" => "0xaabbcc", + "gas" => "0x5208", + "gasPrice" => "0x3b9aca00" + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == Utils.hex_decode!("0xaabbcc") + assert %Transaction.Legacy{} = transaction + end + + test "handles EIP-2930 transaction type" do + tx_map = %{ + "type" => "0x1", + "chainId" => "0x1", + "nonce" => "0x0", + "to" => "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5", + "value" => "0x0", + "input" => "0x112233", + "gas" => "0x5208", + "gasPrice" => "0x3b9aca00", + "accessList" => [] + } + + assert {:ok, transaction} = Transaction.from_rpc_map(tx_map) + assert transaction.input == Utils.hex_decode!("0x112233") + assert %Transaction.Eip2930{} = transaction + end + end end diff --git a/test/ethers_test.exs b/test/ethers_test.exs index 861d49e..bf641e9 100644 --- a/test/ethers_test.exs +++ b/test/ethers_test.exs @@ -16,6 +16,7 @@ defmodule EthersTest do import Ethers.TestHelpers + alias Ethers.Transaction alias Ethers.Utils alias Ethers.Contract.Test.HelloWorldContract @@ -122,9 +123,10 @@ defmodule EthersTest do describe "get_transaction" do test "returns correct transaction by tx_hash" do + %{data: input} = call = HelloWorldContract.set_hello("hello local signer") + {:ok, tx_hash} = - HelloWorldContract.set_hello("hello local signer") - |> Ethers.send_transaction( + Ethers.send_transaction(call, from: @from, to: @to, signer: Ethers.Signer.Local, @@ -140,14 +142,17 @@ defmodule EthersTest do assert {:ok, %Ethers.Transaction.Signed{ payload: %Ethers.Transaction.Eip1559{ - to: ^checksum_to_addr + to: ^checksum_to_addr, + input: ^input }, metadata: %Ethers.Transaction.Metadata{ block_hash: "0x" <> _, block_number: block_number, transaction_index: 0 } - }} = Ethers.get_transaction(tx_hash) + } = transaction} = Ethers.get_transaction(tx_hash) + + assert Transaction.transaction_hash(transaction) == tx_hash assert is_integer(block_number) and block_number >= 0 end From da0bb4ef787d2605716573dc4896a2f817290fab Mon Sep 17 00:00:00 2001 From: Alisina Bahadori Date: Thu, 16 Oct 2025 23:01:17 -0400 Subject: [PATCH 2/4] Update lib/ethers/transaction.ex Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- lib/ethers/transaction.ex | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/ethers/transaction.ex b/lib/ethers/transaction.ex index 8fc7418..bcb71dc 100644 --- a/lib/ethers/transaction.ex +++ b/lib/ethers/transaction.ex @@ -97,17 +97,13 @@ defmodule Ethers.Transaction do end defp maybe_wrap_signed({:ok, transaction}, params) when not is_nil(transaction) do - case Map.fetch(params, :signature_r) do - {:ok, sig_r} when not is_nil(sig_r) -> + case Map.get(params, :signature_r) do + nil -> + {:ok, transaction} + _sig_r -> params |> Map.put(:payload, transaction) |> Signed.new() - - {:ok, nil} -> - {:ok, transaction} - - :error -> - {:ok, transaction} end end From 93b99967c98a7bcd9e1dfa5417a556457c0a8574 Mon Sep 17 00:00:00 2001 From: Alisina Bahadori Date: Thu, 16 Oct 2025 23:01:30 -0400 Subject: [PATCH 3/4] Update CHANGELOG.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8670dd7..fcf9201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Bug Fixes - Fix decoding of `input` values from RPC results -- Handle the case when RPC result does not have signature of transaction +- Handle the case when the RPC result does not have a transaction signature ## 0.6.8 (2025-10-13) From 24bb53d9d617d982a5520a295aee3c6284a70877 Mon Sep 17 00:00:00 2001 From: Alisina Bahadori Date: Thu, 16 Oct 2025 23:02:14 -0400 Subject: [PATCH 4/4] Fix formatting --- lib/ethers/transaction.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ethers/transaction.ex b/lib/ethers/transaction.ex index bcb71dc..e078cdb 100644 --- a/lib/ethers/transaction.ex +++ b/lib/ethers/transaction.ex @@ -100,6 +100,7 @@ defmodule Ethers.Transaction do case Map.get(params, :signature_r) do nil -> {:ok, transaction} + _sig_r -> params |> Map.put(:payload, transaction)