Current section

Files

Jump to
signet lib signet erc_20.ex
Raw

lib/signet/erc_20.ex

defmodule Signet.Erc20 do
@moduledoc """
A wrapper for an [ERC-20 contract](https://eips.ethereum.org/EIPS/eip-20),
allowing the code to interact by pulling data from the contract, or sending
transaction to it.
"""
@type call_opts() :: nil
@type exec_opts() :: {:signer, atom()} | call_opts()
@errors []
@doc ~S"""
Returns a list of known error codes (ABI signatures), which can be used
when parsing error messages from contract calls.
"""
@spec errors() :: [String.t()]
def errors(), do: @errors
@spec exec_trx(Signet.contract(), binary(), [exec_opts()]) :: term()
def exec_trx(token, call_data, exec_opts) do
Signet.RPC.execute_trx(
Signet.get_contract_address(token),
call_data,
Keyword.put_new(exec_opts, :errors, errors())
)
end
@spec call_trx(Signet.contract(), binary(), [call_opts()]) :: term()
def call_trx(token, call_data, call_opts) do
Signet.Transaction.build_trx(Signet.get_contract_address(token), 0, call_data, 0, nil, 0)
|> Signet.RPC.call_trx(Keyword.put_new(call_opts, :errors, errors()))
end
defmodule CallData do
@moduledoc """
Module to encode `calldata` for given adaptor operations.
"""
@doc ~S"""
Encodes the call data for a `balanceOf` operation.
## Examples
iex> Signet.Erc20.CallData.balance_of(<<0xDD>>) |> Signet.Util.encode_hex()
"0x"
"""
@spec balance_of(Signet.address()) :: binary()
def balance_of(address) do
ABI.encode("balanceOf(address)", [address])
end
@doc ~S"""
Encodes the call data for a `transfer` operation.
## Examples
iex> Signet.Erc20.CallData.transfer(<<0xDD>>, 100_000)
...> |> Signet.Util.encode_hex()
"0x8035F0CE"
"""
@spec transfer(Signet.address(), non_neg_integer()) :: binary()
def transfer(destination, amount_wei) do
ABI.encode("transfer(address,uint256)", [destination, amount_wei])
end
end
defmodule Call do
@moduledoc """
Module to call operations and receive return value, without sending a transaction.
"""
@doc ~S"""
Calls the `balanceOf` operation, returning the result of the Ethereum function call.
## Examples
iex> Signet.Erc20.Call.balance_of(<<0xCC>>, <<0xDD>>)
{:ok, <<>>}
"""
@spec balance_of(Signet.contract(), Signet.address(), [Signet.Erc20.call_opts()]) ::
{:ok, number()} | {:error, term()}
def balance_of(token, address, call_opts \\ []) do
call_opts = Keyword.put(call_opts, :decode, :hex_unsigned)
Signet.Erc20.call_trx(token, CallData.balance_of(address), call_opts)
end
@doc ~S"""
Calls the `transfer` operation, returning the result of the Ethereum function call.
## Examples
iex> Signet.Erc20.Call.transfer(<<0xCC>>, <<0xDD>>, 100_000)
{:ok, <<>>}
"""
@spec transfer(Signet.contract(), Signet.address(), non_neg_integer(), [
Signet.Erc20.call_opts()
]) :: binary()
def transfer(token, destination, amount_wei, call_opts \\ []) do
call_opts = Keyword.put(call_opts, :decode, :hex)
Signet.Erc20.call_trx(token, CallData.transfer(destination, amount_wei), call_opts)
end
end
@doc ~S"""
Executes a `transfer` transaction.
Arguments:
- `destination`: The destination address
- `amount_wei`: The amount, in token wei, to transfer.
- `exec_opts`: Execution options, such as the gas price for the transaction.
## Examples
iex> {:ok, _trx_id} = Signet.Erc20.transfer(<<0xCC>>, <<0xDD>>, 100_000)
"""
@spec transfer(Signet.contract(), Signet.address(), non_neg_integer(), [exec_opts()]) ::
{:ok, binary()} | {:error, term()}
def transfer(token, destination, amount_wei, exec_opts \\ []) do
exec_trx(token, CallData.transfer(destination, amount_wei), exec_opts)
end
end