defmodule Stellar.TxBuild.Claimants do end # ClaimPredicate # ---- # Stellar.TxBuild.Claimant.new(destination: "ABC", predicate: :unconditional) # Stellar.TxBuild.Claimant.new(destination: "ABC", predicate: conditional: [time: {:relative, 123}]) # defmodule Stellar.TxBuild.UnconditionalPredicate do @moduledoc """ """ @behaviour Stellar.TxBuild.XDR end defmodule Stellar.TxBuild.ConditionalPredicate do @moduledoc """ """ @behaviour Stellar.TxBuild.XDR end defmodule Stellar.TxBuild.Predicate do @moduledoc """ `Predicate` struct definition. """ @type predicate :: :conditional | :unconditional @type type :: :time | :and | :or | :not @type t :: %__MODULE__{predicate: predicate(), type: type(), value: any()} defstruct [:predicate, :type, :value] def new(:unconditional), do: %__MODULE__{type: :unconditional} def new(conditional: predicate) do with {:ok, {type, value}} <- validate_predicate(predicate) do %__MODULE__{type: :time, value: value} end end def new(_predicate), do: {:error, :invalid_predicate} defp validate_predicate(time: {type, value}) when type in ~w(relative absolute)a and is_integer(value) do {:ok, {:time, {type, value}}} end defp validate_predicate(and: {cond1, cond2}) do with {:ok, predicate1} <- new(cond1), {:ok, predicate2} <- new(cond2) do {:ok, {:and, {predicate1, predicate2}}} end end defp validate_predicate(or: {cond1, cond2}) do with {:ok, predicate1} <- new(cond1), {:ok, predicate2} <- new(cond2) do {:ok, {:or, {predicate1, predicate2}}} end end defp validate_predicate(not: conditional) do {:ok, {:and, new(conditional)}} end end defmodule Stellar.TxBuild.Claimant do @moduledoc """ """ @behaviour Stellar.TxBuild.XDR alias Stellar.TxBuild.{AccountID, Predicate} @type account_id :: String.t() @type validation :: {:ok, any()} | {:error, atom()} @type t :: %__MODULE__{destination: account_id(), predicate: Predicate.t()} defstruct [:destination, :predicate] def new(args, opts \\ []) def new(args, _opts) do destination = Keyword.get(args, :destination) predicate = Keyword.get(args, :predicate) with {:ok, destination} <- validate_destionation(destination), {:ok, predicate} <- validate_predicate(predicate) do %__MODULE__{destination: destination, predicate: predicate} end end @spec validate_destionation(account_id :: account_id()) :: validation() defp validate_destionation(account_id) do case AccountID.new(account_id) do %AccountID{} = account_id -> {:ok, account_id} _error -> {:error, :invalid_destination} end end @spec validate_predicate(predicate :: any()) :: validation() defp validate_predicate(predicate) do case Predicate.new(predicate) do %Predicate{} = predicate -> {:ok, predicate} _error -> {:error, :invalid_predicate} end end # defp validate_predicate({:unconditional, _predicate}), do: validate_predicate(:unconditional) # defp validate_predicate(:unconditional), do: :unconditional # defp validate_predicate(_predicate), do: {:error, :invalid_predicate} end