lib/aptos/rpc.ex

defmodule Web3MoveEx.Aptos.RPC do
    @moduledoc """
      Copy From: https://github.com/myastrallabs/stormstout
    """

    defstruct [:endpoint, :client, :chain_id]

    # @endpoint "https://fullnode.devnet.aptoslabs.com/v1"
    @endpoint "https://testnet.aptoslabs.com/v1"

    @doc """
      {:ok, client} = AptosRPC.connect()
      {:ok, result} = Aptos.RPC.get_token_data(
          client,
          "0xdc4e806913a006d86da8327a079d794435e2e3117fd418062ddf43943d663490",
          "DummyDog",
          "DummyDog 1"
        )
    """
    def get_token_data(client, creator, collection_name, token_name) do
      with {:ok, result} <- get_account_resource(client, creator, "0x3::token::Collections") do
        %{handle: handle} = result.data.token_data

        token_data_id = %{
          creator: creator,
          collection: collection_name,
          name: token_name
        }

        table_key = %{
          key_type: "0x3::token::TokenDataId",
          value_type: "0x3::token::TokenData",
          key: token_data_id
        }

        get_table_item(client, handle, table_key)
      end
    end

        @doc """
      {:ok, client} = AptosRPC.connect()
      {:ok, res} =  Aptos.RPC.get_collection_data(
        client,
        "0xdc4e806913a006d86da8327a079d794435e2e3117fd418062ddf43943d663490",
        "DummyDog"
      )
    """
    def get_collection_data(client, account, collection_name) do
      with {:ok, result} <- get_account_resource(client, account, "0x3::token::Collections") do
        %{handle: handle} = result.data.collection_data

        table_key = %{
          key_type: "0x1::string::String",
          value_type: "0x3::token::CollectionData",
          key: collection_name
        }

        {:ok, result} = get_table_item(client, handle, table_key)

        case result do
          %{error_code: _} -> {:error, result}
          _ -> {:ok, result}
        end
      else
        _ -> {:error, "Token data not found"}
      end
    end



    def connect(endpoint \\ @endpoint) do
      client =
        Tesla.client([
          # TODO: convert input/output type
          {Tesla.Middleware.BaseUrl, endpoint},
          # {Tesla.Middleware.Headers, [{"content-type", "application/json"}]},
          {Tesla.Middleware.JSON, engine_opts: [keys: :atoms]}
        ])

      rpc = %__MODULE__{client: client, endpoint: endpoint}

      with {:ok, %{chain_id: chain_id}} <- ledger_information(rpc) do
        {:ok, %{rpc | endpoint: endpoint, chain_id: chain_id}}
      end
    end

    defp get(%{client: client}, path, options \\ []) do
      with {:ok, %{status: 200, body: resp_body}} <- Tesla.get(client, path, options) do
        {:ok, resp_body}
      else
        {:ok, %{body: resp_body}} -> {:error, resp_body}
        {:error, error} -> {:error, error}
      end
    end

    defp post(%{client: client}, path, body, options \\ []) do
      with {:ok, %{body: resp_body}} <- Tesla.post(client, path, body, options) do
        case resp_body do
          %{code: _, message: message} -> {:error, message}
          _ -> {:ok, resp_body}
        end
      else
        {:error, error} -> {:error, error}
      end
    end

    # Chain
    def ledger_information(client) do
      get(client, "/")
    end

    # Accounts
    def get_account(client, address) do
      get(client, "/accounts/#{address}")
    end

    def get_account_resources(client, address, query \\ []) do
      get(client, "/accounts/#{address}/resources", query: query)
    end

    def get_account_resource(client, address, resource_type, query \\ []) do
      get(client, "/accounts/#{address}/resource/#{resource_type}", query: query)
    end

    # Transactions
    def get_transaction_by_hash(client, hash) do
      get(client, "/transactions/by_hash/#{hash}")
    end

    def check_transaction_by_hash(client, hash, times \\ 3) do
      case get_transaction_by_hash(client, hash) do
        {:ok, result} ->
          result.success

        {:error, _} ->
          if times > 0 do
            Process.sleep(1000)
            check_transaction_by_hash(client, hash, times - 1)
          else
            false
          end
      end
    end

    # Events
    def get_events(client, event_key) do
      case get(client, "/events/#{event_key}") do
        {:ok, event_list} -> {:ok, event_list}
        {:error, %{error_code: "resource_not_found"}} -> {:ok, []}
      end
    end

    def get_events(client, address, event_handle, field, query \\ [limit: 10]) do
      case get(client, "/accounts/#{address}/events/#{event_handle}/#{field}", query: query) do
        {:ok, event_list} -> {:ok, event_list}
        {:error, %{error_code: "resource_not_found"}} -> {:ok, []}
      end
    end

    # Table
    def get_table_item(client, table_handle, table_key) do
      post(client, "/tables/#{table_handle}/item", table_key)
    end

  end