From 4c45959597eb27fb515e1565b6c4d90fbb40bb1a Mon Sep 17 00:00:00 2001 From: Alisina Bahadori Date: Thu, 4 Apr 2024 14:03:20 -0400 Subject: [PATCH] Add `Ethers.get_transaction_count/2` (#110) --- CHANGELOG.md | 6 ++++++ lib/ethers.ex | 29 +++++++++++++++++++++++++++-- lib/ethers/transaction.ex | 6 +++++- test/ethers_test.exs | 20 ++++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2b3e69..4df3649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Enhancements + +- Add `Ethers.get_transaction_count/2` + ## v0.4.2 (2024-04-04) ### Enhancements diff --git a/lib/ethers.ex b/lib/ethers.ex index 3f79d3d..ea2634c 100644 --- a/lib/ethers.ex +++ b/lib/ethers.ex @@ -70,10 +70,11 @@ defmodule Ethers do @option_keys [:rpc_client, :rpc_opts, :signer, :signer_opts, :tx_type] @hex_decode_post_process [ - :current_gas_price, :current_block_number, + :current_gas_price, :estimate_gas, :get_balance, + :get_transaction_count, :max_priority_fee_per_gas ] @rpc_actions_map %{ @@ -139,6 +140,29 @@ defmodule Ethers do end end + @doc """ + Returns the transaction count of an address. + + ## Parameters + - account: Account which the transaction count is queried for. + - overrides: + - block: The block you want to query the transaction count in (defaults to latest). + - rpc_client: The RPC module to use for this request (overrides default). + - rpc_opts: Specific RPC options to specify for this request. + """ + @spec get_transaction_count(Types.t_address(), Keyword.t()) :: + {:ok, non_neg_integer()} | {:error, term()} + def get_transaction_count(account, overrides \\ []) do + {opts, overrides} = Keyword.split(overrides, @option_keys) + + {rpc_client, rpc_opts} = get_rpc_client(opts) + + with {:ok, account, block} <- pre_process(account, overrides, :get_transaction_count, opts) do + rpc_client.eth_get_transaction_count(account, block, rpc_opts) + |> post_process(nil, :get_transaction_count) + end + end + @doc """ Returns the native transaction (ETH) by transaction hash. @@ -571,7 +595,8 @@ defmodule Ethers do end end - defp pre_process(account, overrides, :get_balance = _action, _opts) do + defp pre_process(account, overrides, action, _opts) + when action in [:get_balance, :get_transaction_count] do block = case Keyword.get(overrides, :block, "latest") do number when is_integer(number) -> Utils.integer_to_hex(number) diff --git a/lib/ethers/transaction.ex b/lib/ethers/transaction.ex index 4225f4c..030cda5 100644 --- a/lib/ethers/transaction.ex +++ b/lib/ethers/transaction.ex @@ -229,7 +229,7 @@ defmodule Ethers.Transaction do end defp fill_action(:chain_id, _tx), do: :chain_id - defp fill_action(:nonce, tx), do: {:get_transaction_count, [tx.from, "latest"]} + defp fill_action(:nonce, tx), do: {:get_transaction_count, tx.from, block: "latest"} defp fill_action(:max_fee_per_gas, _tx), do: :gas_price defp fill_action(:max_priority_fee_per_gas, _tx), do: :max_priority_fee_per_gas defp fill_action(:gas_price, _tx), do: :gas_price @@ -257,6 +257,10 @@ defmodule Ethers.Transaction do {:ok, {:max_priority_fee_per_gas, Utils.integer_to_hex(v_int)}} end + defp do_post_process(:nonce, {:ok, nonce}) when is_integer(nonce) do + {:ok, {:nonce, Utils.integer_to_hex(nonce)}} + end + defp do_post_process(key, {:ok, v_hex}) do {:ok, {key, v_hex}} end diff --git a/test/ethers_test.exs b/test/ethers_test.exs index 92e04df..3254f3d 100644 --- a/test/ethers_test.exs +++ b/test/ethers_test.exs @@ -67,6 +67,26 @@ defmodule EthersTest do end end + describe "get_transaction_count" do + test "returns the correct transaction count" do + assert {:ok, c} = + Ethers.get_transaction_count("0xACa94ef8bD5ffEE41947b4585a84BdA5a3d3DA6E") + + assert is_integer(c) + assert c >= 0 + + {:ok, _} = + Ethers.send(%{ + from: "0xACa94ef8bD5ffEE41947b4585a84BdA5a3d3DA6E", + to: "0xaadA6BF26964aF9D7eEd9e03E53415D37aA96045", + value: 1000 + }) + + assert {:ok, c + 1} == + Ethers.get_transaction_count("0xACa94ef8bD5ffEE41947b4585a84BdA5a3d3DA6E") + end + end + describe "get_transaction" do test "returns correct transaction by tx_hash" do {:ok, tx_hash} =