defmodule Forge.Wallet do @moduledoc """ Wallet client """ alias Forge.{AccountState, Crypto, Rpc, Server, Tx.TransferTransaction} @typedoc """ Ethereum-compatible wallet. It contains keys as folows: * `:private_key`: Base16 encoded private key. * `:public_key`: Base16 encoded public key. * `:address`: wallet address. """ @type t :: %{ private_key: String.t(), public_key: String.t(), address: String.t() } @doc """ Create a new eth-like wallet """ @spec new() :: t() def new do private_key = Crypto.create_private_key() public_key = Crypto.create_public_key(private_key) address = Crypto.create_wallet_address(public_key) %{ private_key: Base.encode16(private_key), public_key: Base.encode16(public_key), address: address } end @doc """ Transfer token from one address to another """ @spec transfer(t(), String.t(), non_neg_integer()) :: :ok | {:error, any} def transfer(%{address: from, public_key: public_key, private_key: private_key}, to, total) do nonce = nonce(from) from |> TransferTransaction.create(to, nonce, total, public_key, private_key) |> Rpc.send() end @doc """ Retrieve the current balance of the address """ @spec balance(String.t()) :: non_neg_integer() def balance(address) do apply(Server, :account_balance, [address]) end @doc """ Retrieve the current nonce of the address """ @spec nonce(String.t()) :: non_neg_integer() def nonce(address) do apply(Server, :account_nonce, [address]) end @doc """ Retrieve the account info of the address """ @spec info(String.t(), String.t()) :: AccountState.t() | nil def info(address, app_hash \\ "") do apply(Server, :account_info, [address, app_hash]) end @doc """ Retrieve the chain info """ @spec chain_info :: map() def chain_info do apply(Server, :chain_info, []) end end