lib/tx_build/sc_contract_executable.ex

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

  @behaviour Stellar.TxBuild.XDR

  alias StellarBase.XDR.{Hash, SCContractExecutable, SCContractExecutableType, Void}

  @type type :: :wasm_ref | :token
  @type value :: binary() | :token
  @type validation :: {:ok, value()} | {:error, atom()}
  @type t :: %__MODULE__{
          type: type(),
          value: value()
        }

  defstruct [:type, :value]

  @impl true
  def new(args, opts \\ nil)

  def new(:token, _opts), do: %__MODULE__{type: :token, value: nil}

  def new([{:wasm_ref, value}], _opts) do
    with {:ok, _value} <- validate_sc_contract_executable({:wasm_ref, value}) do
      %__MODULE__{
        type: :wasm_ref,
        value: value
      }
    end
  end

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

  @impl true
  def to_xdr(%__MODULE__{type: :wasm_ref, value: value}) do
    type = SCContractExecutableType.new(:SCCONTRACT_EXECUTABLE_WASM_REF)

    value
    |> Hash.new()
    |> SCContractExecutable.new(type)
  end

  def to_xdr(%__MODULE__{type: :token, value: nil}) do
    type = SCContractExecutableType.new(:SCCONTRACT_EXECUTABLE_TOKEN)
    void = Void.new()

    SCContractExecutable.new(void, type)
  end

  def to_xdr(_error), do: {:error, :invalid_sc_contract_executable}

  @spec validate_sc_contract_executable(tuple()) :: validation()
  defp validate_sc_contract_executable({:wasm_ref, value}) when is_binary(value), do: {:ok, value}

  defp validate_sc_contract_executable({:wasm_ref, _value}), do: {:error, :invalid_contract_hash}
end