Skip to content

Commit

Permalink
Rename Ethers.send/2 to Ethers.send_transaction/2 (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
alisinabh authored Jan 1, 2025
1 parent a2a5d33 commit b4911b5
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 72 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Removed auto-gas estimation from send_transaction calls
- `tx_type` option in transaction overrides has been replaced with `type`, now requiring explicit struct modules (e.g. `Ethers.Transaction.Eip1559`, `Ethers.Transaction.Legacy`)
- Moved `Ethers.Transaction.calculate_y_parity_or_v/1` to `Ethers.Transaction.Signed` module
- Deprecate `Ethers.send/2` in favor of `Ethers.send_transaction/2` for clarity and prevent collision with `Kernel.send/2`.

### New features

Expand Down
6 changes: 3 additions & 3 deletions guides/typed-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ defmodule Overloaded do
end

Overloaded.transfer(Ethers.Types.typed({:uint, 256}, 100))
|> Ethers.send!(...)
|> Ethers.send_transaction!(...)
```

This way we have explicitly told Ethers to use the `uint256` type for the first argument.
Expand All @@ -52,8 +52,8 @@ Ethers supports all generic data types from EVM. Here is a list of them.
| `:address` | `address` | Ethereum wallet address |
| `:bool` | `bool` | Boolean value |
| `:string` | `string` | Dynamic length string |
| `:bytes` | `bytes` | Dynamic length byte array [^1] |
| `{:bytes, size}` | `bytes{size}` | Fixed length byte array [^1] |
| `:bytes` | `bytes` | Dynamic length byte array [^1] |
| `{:bytes, size}` | `bytes{size}` | Fixed length byte array [^1] |
| `{:uint, bitsize}` | `uint{bitsize}` | Unsigned integer [^2] |
| `{:int, bitsize}` | `int{bitsize}` | Signed integer [^2] |
| `{:array, type}` | `T[]` | Dynamic length array of type |
Expand Down
53 changes: 32 additions & 21 deletions lib/ethers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ defmodule Ethers do
- `action_name_atom`: This only works with requests which do not require any additional data.
e.g. `:current_gas_price` or `:net_version`.
- `{action_name_atom, data}`: This works with all other actions which accept input data.
e.g. `:call`, `:send` or `:get_logs`.
e.g. `:call`, `:send_transaction` or `:get_logs`.
- `{action_name_atom, data, overrides_keyword_list}`: Use this to override or add attributes
to the action data. This is only accepted for these actions and will through error on others.
- `:call`: data should be a Ethers.TxData struct and overrides are accepted.
- `:estimate_gas`: data should be a Ethers.TxData struct or a map and overrides are accepted.
- `:get_logs`: data should be a Ethers.EventFilter struct and overrides are accepted.
- `:send`: data should be a Ethers.TxData struct and overrides are accepted.
- `:send_transaction`: data should be a Ethers.TxData struct and overrides are accepted.
### Example
Expand All @@ -47,7 +47,7 @@ defmodule Ethers do
:current_block_number,
:current_gas_price,
{:call, Ethers.Contracts.ERC20.name(), to: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"},
{:send, MyContract.ping(), from: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},
{:send_transaction, MyContract.ping(), from: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},
{:get_logs, Ethers.Contracts.ERC20.EventFilters.approval(nil, nil)} # <- can have add overrides
])
{:ok, [
Expand Down Expand Up @@ -90,8 +90,11 @@ defmodule Ethers do
get_transaction_count: :eth_get_transaction_count,
get_transaction: :eth_get_transaction_by_hash,
max_priority_fee_per_gas: :eth_max_priority_fee_per_gas,
send_transaction: :eth_send_transaction,
# Deprecated, kept for backward compatibility
send: :eth_send_transaction
}
@send_transaction_actions [:send_transaction, :send]

@type t_batch_request :: atom() | {atom, term()} | {atom, term(), Keyword.t()}

Expand Down Expand Up @@ -223,7 +226,7 @@ defmodule Ethers do
- overrides: A keyword list containing options and overrides.
- `:encoded_constructor`: Hex encoded value for constructor parameters. (See `constructor`
function of the contract module)
- All other options from `Ethers.send/2`
- All other options from `Ethers.send_transaction/2`
"""
@spec deploy(atom() | binary(), Keyword.t()) ::
{:ok, Types.t_hash()} | {:error, term()}
Expand Down Expand Up @@ -355,38 +358,44 @@ defmodule Ethers do
## Examples
```elixir
Ethers.Contract.ERC20.transfer("0xff0...ea2", 1000) |> Ethers.send(to: "0xa0b...ef6")
Ethers.Contract.ERC20.transfer("0xff0...ea2", 1000) |> Ethers.send_transaction(to: "0xa0b...ef6")
{:ok, _tx_hash}
```
"""
@spec send(map() | TxData.t(), Keyword.t()) :: {:ok, String.t()} | {:error, term()}
def send(tx_data, overrides \\ []) do
@spec send_transaction(map() | TxData.t(), Keyword.t()) :: {:ok, String.t()} | {:error, term()}
def send_transaction(tx_data, overrides \\ []) do
{opts, overrides} = Keyword.split(overrides, @option_keys)

{rpc_client, rpc_opts} = get_rpc_client(opts)

with {:ok, tx_params, action} <- pre_process(tx_data, overrides, :send, opts) do
with {:ok, tx_params, action} <- pre_process(tx_data, overrides, :send_transaction, opts) do
apply(rpc_client, action, [tx_params, rpc_opts])
|> post_process(tx_data, :send)
|> post_process(tx_data, :send_transaction)
end
end

@deprecated "Use `Ethers.send_transaction/2` instead"
def send(tx_data, overrides \\ []), do: send_transaction(tx_data, overrides)

@doc """
Same as `Ethers.send/2` but raises on error.
Same as `Ethers.send_transaction/2` but raises on error.
"""
@spec send!(map() | TxData.t(), Keyword.t()) :: String.t() | no_return()
def send!(tx_data, overrides \\ []) do
case __MODULE__.send(tx_data, overrides) do
@spec send_transaction!(map() | TxData.t(), Keyword.t()) :: String.t() | no_return()
def send_transaction!(tx_data, overrides \\ []) do
case __MODULE__.send_transaction(tx_data, overrides) do
{:ok, tx_hash} -> tx_hash
{:error, reason} -> raise ExecutionError, reason
end
end

@deprecated "Use `Ethers.send_transaction!/2` instead"
def send!(tx_data, overrides \\ []), do: send_transaction!(tx_data, overrides)

@doc """
Signs a transaction and returns the encoded signed transaction hex.
## Parameters
Accepts same parameters as `Ethers.send/2`.
Accepts same parameters as `Ethers.send_transaction/2`.
"""
@spec sign_transaction(map(), Keyword.t()) :: {:ok, binary()} | {:error, term()}
def sign_transaction(tx_data, overrides \\ []) do
Expand Down Expand Up @@ -521,7 +530,7 @@ defmodule Ethers do
Ethers.batch([
{:call, WETH.name()},
{:call, WETH.symbol(), to: "[WETH ADDRESS]"},
{:send, WETH.transfer("[RECEIVER]", 1000), from: "[SENDER]"},
{:send_transaction, WETH.transfer("[RECEIVER]", 1000), from: "[SENDER]"},
:current_block_number
])
{:ok, [ok: "Weapped Ethereum", ok: "WETH", ok: "0xhash...", ok: 182394532]}
Expand Down Expand Up @@ -623,11 +632,12 @@ defmodule Ethers do
maybe_use_signer(tx_params, opts)
end

defp pre_process("0x" <> _ = signed_tx, _overrides, :send, _opts) do
defp pre_process("0x" <> _ = signed_tx, _overrides, action, _opts)
when action in @send_transaction_actions do
{:ok, signed_tx, :eth_send_raw_transaction}
end

defp pre_process(tx_data, overrides, :send = action, opts) do
defp pre_process(tx_data, overrides, action, opts) when action in @send_transaction_actions do
tx_params = TxData.to_map(tx_data, overrides)

with :ok <- check_params(tx_params, action) do
Expand Down Expand Up @@ -679,8 +689,9 @@ defmodule Ethers do
{:ok, resp}
end

defp post_process({:ok, tx_hash}, _tx_data, _action = :send) when valid_result(tx_hash),
do: {:ok, tx_hash}
defp post_process({:ok, tx_hash}, _tx_data, action)
when valid_result(tx_hash) and action in @send_transaction_actions,
do: {:ok, tx_hash}

defp post_process({:ok, tx_hash}, _tx_params, _action = :deploy) when valid_result(tx_hash),
do: {:ok, tx_hash}
Expand Down Expand Up @@ -846,15 +857,15 @@ defmodule Ethers do
defp check_to_address(%{to: to_address}, _action) when is_binary(to_address), do: :ok

defp check_to_address(%{to: nil}, action)
when action in [:send, :sign_transaction, :estimate_gas],
when action in [:send, :send_transaction, :sign_transaction, :estimate_gas],
do: :ok

defp check_to_address(_params, _action), do: {:error, :no_to_address}

defp check_from_address(%{from: from}, _action) when not is_nil(from), do: :ok

defp check_from_address(_tx_params, action)
when action in [:send, :sign_transaction],
when action in [:send, :send_transaction, :sign_transaction],
do: {:error, :no_from_address}

defp check_from_address(_tx_params, _action), do: :ok
Expand Down
6 changes: 3 additions & 3 deletions lib/ethers/contract_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ defmodule Ethers.ContractHelpers do

:non_payable ->
"""
This function can be used for a transaction or additionally called for results (Use `Ethers.send/2`).
This function can be used for a transaction or additionally called for results (Use `Ethers.send_transaction/2`).
No amount of Ether can be sent with this function.
"""

:payable ->
"""
This function can be used for a transaction or additionally called for results (Use `Ethers.send/2`).
This function can be used for a transaction or additionally called for results (Use `Ethers.send_transaction/2`).
It also supports receiving ether from the transaction origin.
"""
end
Expand All @@ -81,7 +81,7 @@ defmodule Ethers.ContractHelpers do
defp do_document_help_message(state_mutabilities) do
"""
This function has multiple state mutabilities based on the overload that you use.
You may use the correct function (`Ethers.call/2` or `Ethers.send/2`) to interact with this function
You may use the correct function (`Ethers.call/2` or `Ethers.send_transaction/2`) to interact with this function
based on the overload you choose.
State mutabilities: #{document_state_mutabilities(state_mutabilities)}
Expand Down
2 changes: 1 addition & 1 deletion lib/ethers/multicall.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Ethers.Multicall do
The primary function of this module is to aggregate multiple Ethereum contract calls
into a single operation. This aggregated call can be subsequently submitted using `Ethers.call/2`
or `Ethers.send/2` (If you know what you are doing!).
or `Ethers.send_transaction/2` (If you know what you are doing!).
Upon receiving the response, it can be decoded using `Ethers.Multicall.decode/2` to interpret the
results returned by the `Multicall3` contract.
Expand Down
2 changes: 1 addition & 1 deletion lib/ethers/tx_data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule Ethers.TxData do
@typedoc """
Holds transaction data, the function selector and the default `to` address.
Can be passed in to `Ethers.call/2` or `Ethers.send/2` to execute.
Can be passed in to `Ethers.call/2` or `Ethers.send_transaction/2` to execute.
"""
@type t :: %__MODULE__{
data: binary() | [binary()],
Expand Down
26 changes: 13 additions & 13 deletions test/ethers/counter_contract_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ defmodule Ethers.CounterContractTest do
end

test "sending transaction with state mutating functions", %{address: address} do
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send(from: @from, to: address)
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send_transaction(from: @from, to: address)
wait_for_transaction!(tx_hash)

{:ok, 101} = CounterContract.get() |> Ethers.call(to: address)
Expand All @@ -151,7 +151,7 @@ defmodule Ethers.CounterContractTest do
test "sending transaction with state mutating functions using bang functions", %{
address: address
} do
tx_hash = CounterContract.set(101) |> Ethers.send!(from: @from, to: address)
tx_hash = CounterContract.set(101) |> Ethers.send_transaction!(from: @from, to: address)

wait_for_transaction!(tx_hash)

Expand All @@ -160,12 +160,12 @@ defmodule Ethers.CounterContractTest do

test "returns error if to address is not given" do
assert {:error, :no_to_address} = CounterContract.get() |> Ethers.call()
assert {:error, :no_to_address} = CounterContract.set(101) |> Ethers.send(from: @from)
assert {:error, :no_to_address} = CounterContract.set(101) |> Ethers.send_transaction(from: @from)

assert {:error, :no_to_address} =
CounterContract.set(101) |> Ethers.send(from: @from, gas: 100)
CounterContract.set(101) |> Ethers.send_transaction(from: @from, gas: 100)

assert {:error, :no_to_address} = CounterContract.set(101) |> Ethers.send()
assert {:error, :no_to_address} = CounterContract.set(101) |> Ethers.send_transaction()

assert {:error, :no_to_address} =
CounterContract.set(101) |> Ethers.estimate_gas(from: @from, gas: 100)
Expand All @@ -177,11 +177,11 @@ defmodule Ethers.CounterContractTest do
end

assert_raise Ethers.ExecutionError, "Unexpected error: no_to_address", fn ->
CounterContract.set(101) |> Ethers.send!(from: @from)
CounterContract.set(101) |> Ethers.send_transaction!(from: @from)
end

assert_raise Ethers.ExecutionError, "Unexpected error: no_to_address", fn ->
CounterContract.set(101) |> Ethers.send!(from: @from, gas: 100)
CounterContract.set(101) |> Ethers.send_transaction!(from: @from, gas: 100)
end

assert_raise Ethers.ExecutionError, "Unexpected error: no_to_address", fn ->
Expand Down Expand Up @@ -223,7 +223,7 @@ defmodule Ethers.CounterContractTest do
setup :deploy_counter_contract

test "can get the emitted event with the correct filter", %{address: address} do
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send(from: @from, to: address)
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send_transaction(from: @from, to: address)

wait_for_transaction!(tx_hash)

Expand All @@ -245,7 +245,7 @@ defmodule Ethers.CounterContractTest do
end

test "cat get the emitted events with get_logs! function", %{address: address} do
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send(from: @from, to: address)
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send_transaction(from: @from, to: address)

wait_for_transaction!(tx_hash)

Expand Down Expand Up @@ -275,7 +275,7 @@ defmodule Ethers.CounterContractTest do
end

test "can filter logs with from_block and to_block options", %{address: address} do
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send(from: @from, to: address)
{:ok, tx_hash} = CounterContract.set(101) |> Ethers.send_transaction(from: @from, to: address)

wait_for_transaction!(tx_hash)

Expand Down Expand Up @@ -317,21 +317,21 @@ defmodule Ethers.CounterContractTest do

test "can call a view function on a previous block", %{address: address} do
CounterContract.set(101)
|> Ethers.send!(from: @from, to: address)
|> Ethers.send_transaction!(from: @from, to: address)
|> wait_for_transaction!()

{:ok, block_1} = Ethers.current_block_number()

CounterContract.set(102)
|> Ethers.send!(from: @from, to: address)
|> Ethers.send_transaction!(from: @from, to: address)
|> wait_for_transaction!()

{:ok, block_2} = Ethers.current_block_number()

assert is_integer(block_2)

CounterContract.set(103)
|> Ethers.send!(from: @from, to: address)
|> Ethers.send_transaction!(from: @from, to: address)
|> wait_for_transaction!()

assert CounterContract.get() |> Ethers.call!(to: address, block: "latest") == 103
Expand Down
2 changes: 1 addition & 1 deletion test/ethers/event_mixed_index_contract_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ defmodule Ethers.EventMixedIndexContractTest do
assert {:ok, address} = Ethers.deployed_address(tx_hash)

EventMixedIndexContract.transfer(100, @from, true, @from)
|> Ethers.send!(to: address, from: @from)
|> Ethers.send_transaction!(to: address, from: @from)
|> wait_for_transaction!()

filter = EventMixedIndexContract.EventFilters.transfer(@from, @from)
Expand Down
10 changes: 5 additions & 5 deletions test/ethers/multi_clause_contract_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ defmodule Ethers.MultiClauseContractTest do
describe "multi clause events" do
test "listens on the right event", %{address: address} do
MultiClauseContract.emit_event(typed({:uint, 256}, 10))
|> Ethers.send!(to: address, from: @from)
|> Ethers.send_transaction!(to: address, from: @from)
|> wait_for_transaction!()

uint_filter = MultiClauseContract.EventFilters.multi_event(typed({:uint, 256}, 10))
Expand All @@ -63,7 +63,7 @@ defmodule Ethers.MultiClauseContractTest do
Ethers.get_logs(uint_filter, address: address)

MultiClauseContract.emit_event(typed({:int, 256}, -20))
|> Ethers.send!(to: address, from: @from)
|> Ethers.send_transaction!(to: address, from: @from)
|> wait_for_transaction!()

int_filter = MultiClauseContract.EventFilters.multi_event(typed({:int, 256}, -20))
Expand All @@ -72,7 +72,7 @@ defmodule Ethers.MultiClauseContractTest do
Ethers.get_logs(int_filter, address: address)

MultiClauseContract.emit_event("Hello")
|> Ethers.send!(to: address, from: @from)
|> Ethers.send_transaction!(to: address, from: @from)
|> wait_for_transaction!()

string_filter = MultiClauseContract.EventFilters.multi_event(typed(:string, "Hello"))
Expand All @@ -87,7 +87,7 @@ defmodule Ethers.MultiClauseContractTest do

test "listens on the right event with nil values", %{address: address} do
MultiClauseContract.emit_event(typed({:uint, 256}, 10))
|> Ethers.send!(to: address, from: @from)
|> Ethers.send_transaction!(to: address, from: @from)
|> wait_for_transaction!()

uint_filter = MultiClauseContract.EventFilters.multi_event(typed({:uint, 256}, nil))
Expand All @@ -96,7 +96,7 @@ defmodule Ethers.MultiClauseContractTest do
Ethers.get_logs(uint_filter, address: address)

MultiClauseContract.emit_event(typed({:int, 256}, -20))
|> Ethers.send!(to: address, from: @from)
|> Ethers.send_transaction!(to: address, from: @from)
|> wait_for_transaction!()

int_filter = MultiClauseContract.EventFilters.multi_event(typed({:int, 256}, nil))
Expand Down
Loading

0 comments on commit b4911b5

Please sign in to comment.