lib/tx_build/soroban_authorized_contract_function.ex

defmodule Stellar.TxBuild.SorobanAuthorizedContractFunction do
  @moduledoc """
  `SorobanAuthorizedContractFunction` struct definition.
  """

  import Stellar.TxBuild.Validations,
    only: [validate_vec: 1, validate_address: 1]

  alias StellarBase.XDR.{SorobanAuthorizedContractFunction, SCSymbol}
  alias Stellar.TxBuild.{SCAddress, SCVec}

  @behaviour Stellar.TxBuild.XDR

  @type error :: {:error, atom()}
  @type validation :: {:ok, any()} | error()
  @type contract_address :: SCAddress.t()
  @type function_name :: String.t()
  @type args :: SCVec.t()

  @type t :: %__MODULE__{
          contract_address: contract_address(),
          function_name: function_name(),
          args: args()
        }

  defstruct [:contract_address, :function_name, :args]

  @impl true
  def new(args, opts \\ [])

  def new(args, _opts) when is_list(args) do
    contract_address = Keyword.get(args, :contract_address)
    function_name = Keyword.get(args, :function_name)
    function_args = Keyword.get(args, :args)

    with {:ok, contract_address} <- validate_address(contract_address),
         {:ok, function_name} <- validate_function_name(function_name),
         {:ok, function_args} <- validate_vec(function_args) do
      %__MODULE__{
        contract_address: contract_address,
        function_name: function_name,
        args: function_args
      }
    end
  end

  def new(_value, _opts), do: {:error, :invalid_soroban_auth_contract_function_args}

  @impl true
  def to_xdr(%__MODULE__{
        contract_address: contract_address,
        function_name: function_name,
        args: args
      }) do
    function_name = SCSymbol.new(function_name)
    args = SCVec.to_xdr(args)

    contract_address
    |> SCAddress.to_xdr()
    |> SorobanAuthorizedContractFunction.new(function_name, args)
  end

  def to_xdr(_struct), do: {:error, :invalid_struct}

  @spec validate_function_name(function_name :: function_name()) :: validation()
  defp validate_function_name(function_name) when is_binary(function_name),
    do: {:ok, function_name}

  defp validate_function_name(_function_name), do: {:error, :invalid_function_name}
end