defmodule ExW3.Rpc do
import ExW3.Client
@type invalid_hex_string_error :: ExW3.Utils.invalid_hex_string_error()
@type request_error :: Ethereumex.Client.Behaviour.error()
@type opts :: {:url, String.t()}
@type hex_block_number :: String.t()
@type latest :: String.t()
@type earliest :: String.t()
@type pending :: String.t()
@doc "returns all available accounts"
@spec accounts() :: list()
@spec accounts([opts]) :: list()
def accounts(opts \\ []) do
case call_client(:eth_accounts, [opts]) do
{:ok, accounts} -> accounts
err -> err
end
end
@doc "Returns the current block number"
@spec block_number() :: {:ok, non_neg_integer} | {:error, ExW3.Utils.invalid_hex_string()}
@spec block_number([opts]) :: {:ok, non_neg_integer} | {:error, ExW3.Utils.invalid_hex_string()}
def block_number(opts \\ []) do
case call_client(:eth_block_number, [opts]) do
{:ok, hex_block_number} -> ExW3.Utils.hex_to_integer(hex_block_number)
err -> err
end
end
@doc "Returns current balance of account"
@spec balance(binary()) :: integer() | {:error, any()}
@spec balance(binary(), [opts]) :: integer() | {:error, any()}
def balance(account, opts \\ []) do
case call_client(:eth_get_balance, [account, "latest", opts]) do
{:ok, hex_balance} ->
{:ok, balance} = ExW3.Utils.hex_to_integer(hex_balance)
balance
err ->
err
end
end
@doc "Returns transaction receipt for specified transaction hash(id)"
@spec tx_receipt(binary()) :: {:ok, map()} | {:error, any()}
def tx_receipt(tx_hash) do
case call_client(:eth_get_transaction_receipt, [tx_hash]) do
{:ok, nil} ->
{:error, :not_mined}
{:ok, receipt} ->
normalized_receipt =
ExW3.Normalize.transform_to_integer(receipt, ~w(blockNumber cumulativeGasUsed gasUsed))
{:ok, Map.merge(receipt, normalized_receipt)}
err ->
{:error, err}
end
end
@doc "Returns block data for specified block number"
@spec block(integer()) :: any() | {:error, any()}
def block(block_number) do
case call_client(:eth_get_block_by_number, [block_number, true]) do
{:ok, block} -> block
err -> err
end
end
@doc "Creates a new filter, returns filter id. For more sophisticated use, prefer ExW3.Contract.filter."
@spec new_filter(map()) :: binary() | {:error, any()}
def new_filter(map) do
case call_client(:eth_new_filter, [map]) do
{:ok, filter_id} -> filter_id
err -> err
end
end
@doc "Gets event changes (logs) by filter. Unlike ExW3.Contract.get_filter_changes it does not return the data in a formatted way"
@spec get_filter_changes(binary()) :: any()
def get_filter_changes(filter_id) do
case call_client(:eth_get_filter_changes, [filter_id]) do
{:ok, changes} -> changes
err -> err
end
end
@type log_filter :: %{
optional(:address) => String.t(),
optional(:fromBlock) => hex_block_number | latest | earliest | pending,
optional(:toBlock) => hex_block_number | latest | earliest | pending,
optional(:topics) => [String.t()],
optional(:blockhash) => String.t()
}
@spec get_logs(log_filter, [opts]) :: {:ok, list} | {:error, term} | request_error
def get_logs(filter, opts \\ []) do
with {:ok, _} = result <- call_client(:eth_get_logs, [filter, opts]) do
result
else
err -> err
end
end
@doc "Uninstalls filter from the ethereum node"
@spec uninstall_filter(binary()) :: boolean() | {:error, any()}
def uninstall_filter(filter_id) do
case call_client(:eth_uninstall_filter, [filter_id]) do
{:ok, result} -> result
err -> err
end
end
@doc "Mines number of blocks specified. Default is 1"
@spec mine(integer()) :: any() | {:error, any()}
def mine(num_blocks \\ 1) do
for _ <- 0..(num_blocks - 1) do
call_client(:request, ["evm_mine", [], []])
end
end
@doc "Using the personal api, returns list of accounts."
@spec personal_list_accounts(list()) :: {:ok, list()} | {:error, any()}
def personal_list_accounts(opts \\ []) do
call_client(:request, ["personal_listAccounts", [], opts])
end
@doc "Using the personal api, this method creates a new account with the passphrase, and returns new account address."
@spec personal_new_account(binary(), list()) :: {:ok, binary()} | {:error, any()}
def personal_new_account(password, opts \\ []) do
call_client(:request, ["personal_newAccount", [password], opts])
end
@doc "Using the personal api, this method unlocks account using the passphrase provided, and returns a boolean."
@spec personal_unlock_account(binary(), list()) :: {:ok, boolean()} | {:error, any()}
### E.g. ExW3.personal_unlock_account(["0x1234","Password",30], [])
def personal_unlock_account(params, opts \\ []) do
call_client(:request, ["personal_unlockAccount", params, opts])
end
@doc "Using the personal api, this method sends a transaction and signs it in one call, and returns a transaction id hash."
@spec personal_send_transaction(map(), binary(), list()) :: {:ok, binary()} | {:error, any()}
def personal_send_transaction(param_map, passphrase, opts \\ []) do
call_client(:request, ["personal_sendTransaction", [param_map, passphrase], opts])
end
@doc "Using the personal api, this method signs a transaction, and returns the signed transaction."
@spec personal_sign_transaction(map(), binary(), list()) :: {:ok, map()} | {:error, any()}
def personal_sign_transaction(param_map, passphrase, opts \\ []) do
call_client(:request, ["personal_signTransaction", [param_map, passphrase], opts])
end
@doc "Using the personal api, this method calculates an Ethereum specific signature, and returns that signature."
@spec personal_sign(binary(), binary(), binary(), list()) :: {:ok, binary()} | {:error, any()}
def personal_sign(data, address, passphrase, opts \\ []) do
call_client(:request, ["personal_sign", [data, address, passphrase], opts])
end
@doc "Using the personal api, this method returns the address associated with the private key that was used to calculate the signature with personal_sign."
@spec personal_ec_recover(binary(), binary(), []) :: {:ok, binary()} | {:error, any()}
def personal_ec_recover(data0, data1, opts \\ []) do
call_client(:request, ["personal_ecRecover", [data0, data1], opts])
end
@doc "Calculates an Ethereum specific signature and signs the data provided, using the accounts private key"
@spec eth_sign(binary(), binary(), list()) :: {:ok, binary()} | {:error, any()}
def eth_sign(data0, data1, opts \\ []) do
call_client(:request, ["eth_sign", [data0, data1], opts])
end
@doc "Simple eth_call to client. Recommended to use ExW3.Contract.call instead."
@spec eth_call(list()) :: any()
def eth_call(arguments) do
call_client(:eth_call, arguments)
end
@doc "Simple eth_send_transaction. Recommended to use ExW3.Contract.send instead."
@spec eth_send(list()) :: any()
def eth_send(arguments) do
call_client(:eth_send_transaction, arguments)
end
end