lib/tx_build/signer.ex

defmodule Stellar.TxBuild.Signer do
  @moduledoc """
  `Signer` struct definition.
  """
  alias Stellar.TxBuild.{Weight, SignerKey}
  alias StellarBase.XDR.Signer

  @behaviour Stellar.TxBuild.XDR

  @type validation :: {:ok, any()} | {:error, atom()}

  @type t :: %__MODULE__{signer_key: SignerKey.t(), weight: Weight.t()}

  defstruct [:signer_key, :weight]

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

  def new([{signer_type, signer_key}, {:weight, weight}], _opts) do
    with {:ok, signer_key} <- validate_signer_key({signer_type, signer_key}),
         {:ok, weight} <- validate_signer_weight(weight) do
      %__MODULE__{signer_key: signer_key, weight: weight}
    end
  end

  def new(_args, _opts), do: {:error, :invalid_signer}

  @impl true
  def to_xdr(%__MODULE__{signer_key: signer_key, weight: weight}) do
    weight_xdr = Weight.to_xdr(weight)

    signer_key
    |> SignerKey.to_xdr()
    |> Signer.new(weight_xdr)
  end

  @spec validate_signer_weight(weight :: non_neg_integer()) :: validation()
  defp validate_signer_weight(weight) do
    case Weight.new(weight) do
      %Weight{} = weight -> {:ok, weight}
      {:error, _reason} -> {:error, :invalid_signer_weight}
    end
  end

  @spec validate_signer_key(signer_key :: tuple()) :: validation()
  defp validate_signer_key(signer_key) do
    case SignerKey.new(signer_key) do
      %SignerKey{} = signer_key -> {:ok, signer_key}
      _error -> {:error, :invalid_signer_key}
    end
  end
end