Packages
stellar_sdk
0.11.3
0.23.0
0.22.0
0.21.2
0.21.1
0.21.0
0.20.0
0.19.0
0.18.1
0.18.0
0.17.1
0.17.0
0.16.1
0.16.0
0.15.1
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Elixir SDK for the Stellar network.
Current section
Files
Jump to
Current section
Files
lib/tx_build/preconditions.ex
defmodule Stellar.TxBuild.Preconditions do
@moduledoc """
`Preconditions` struct definition.
"""
alias Stellar.TxBuild.{
TimeBounds,
LedgerBounds,
SequenceNumber,
SignerKey,
OptionalSequenceNumber
}
alias StellarBase.XDR.TimeBounds, as: TimeBoundsXDR
alias StellarBase.XDR.{
Preconditions,
PreconditionsV2,
PreconditionType,
Duration,
SignerKeyList,
TimePoint,
UInt32,
Void
}
@behaviour Stellar.TxBuild.XDR
@type precond_v2 :: [
time_bounds: TimeBounds.t(),
ledger_bounds: LedgerBounds.t(),
min_seq_num: OptionalSequenceNumber.t(),
min_seq_age: non_neg_integer(),
min_seq_ledger_gap: non_neg_integer(),
extra_signers: list(SignerKey.t())
]
@type valid :: non_neg_integer() | struct() | list(struct())
@type validation :: {:ok, valid()} | {:error, atom()}
@type type :: :precond_v2 | :precond_time | :none
@type preconditions :: precond_v2() | TimeBounds.t() | nil
@type t :: %__MODULE__{type: type(), preconditions: preconditions()}
defstruct [:type, :preconditions]
@impl true
def new(preconditions \\ [], opts \\ [])
def new([], _opts) do
%__MODULE__{type: :none, preconditions: nil}
end
def new([time_bounds: %TimeBounds{} = time_bounds], _opts) do
%__MODULE__{type: :precond_time, preconditions: time_bounds}
end
def new(preconditions, _opts) do
time_bounds = Keyword.get(preconditions, :time_bounds)
ledger_bounds = Keyword.get(preconditions, :ledger_bounds)
min_seq_num = Keyword.get(preconditions, :min_seq_num)
min_seq_age = Keyword.get(preconditions, :min_seq_age, 0)
min_seq_ledger_gap = Keyword.get(preconditions, :min_seq_ledger_gap, 0)
extra_signers = Keyword.get(preconditions, :extra_signers, [])
with {:ok, time_bounds} <- validate_time_bounds(time_bounds),
{:ok, ledger_bounds} <- validate_ledger_bounds(ledger_bounds),
{:ok, min_seq_num} <- validate_optional_min_seq_num(min_seq_num),
{:ok, min_seq_age} <- validate_min_seq_age(min_seq_age),
{:ok, min_seq_ledger_gap} <- validate_min_seq_ledger_gap(min_seq_ledger_gap),
{:ok, extra_signers} <- validate_extra_signers([], extra_signers) do
%__MODULE__{
type: :precond_v2,
preconditions: [
time_bounds: time_bounds,
ledger_bounds: ledger_bounds,
min_seq_num: min_seq_num,
min_seq_age: min_seq_age,
min_seq_ledger_gap: min_seq_ledger_gap,
extra_signers: extra_signers
]
}
end
end
@impl true
def to_xdr(%__MODULE__{type: :none, preconditions: nil}) do
preconditions_type = PreconditionType.new(:PRECOND_NONE)
Preconditions.new(Void.new(), preconditions_type)
end
def to_xdr(%__MODULE__{
type: :precond_time,
preconditions: %TimeBounds{min_time: min_time, max_time: max_time}
}) do
preconditions_type = PreconditionType.new(:PRECOND_TIME)
min_time = TimePoint.new(min_time)
max_time = TimePoint.new(max_time)
min_time
|> TimeBoundsXDR.new(max_time)
|> Preconditions.new(preconditions_type)
end
def to_xdr(%__MODULE__{
type: :precond_v2,
preconditions: [
time_bounds: time_bounds,
ledger_bounds: ledger_bounds,
min_seq_num: min_seq_num,
min_seq_age: min_seq_age,
min_seq_ledger_gap: min_seq_ledger_gap,
extra_signers: extra_signers
]
}) do
preconditions_type = PreconditionType.new(:PRECOND_V2)
time_bounds = TimeBounds.to_xdr(time_bounds)
ledger_bounds = LedgerBounds.to_xdr(ledger_bounds)
min_seq_num = OptionalSequenceNumber.to_xdr(min_seq_num)
min_seq_age = Duration.new(min_seq_age)
min_seq_ledger_gap = UInt32.new(min_seq_ledger_gap)
extra_signers_list = get_extra_signers_list(extra_signers)
time_bounds
|> PreconditionsV2.new(
ledger_bounds,
min_seq_num,
min_seq_age,
min_seq_ledger_gap,
extra_signers_list
)
|> Preconditions.new(preconditions_type)
end
@spec get_extra_signers_list(extra_signers :: list(SignerKey.t())) :: SignerKeyList.t()
defp get_extra_signers_list(extra_signers) do
extra_signers
|> Enum.map(&SignerKey.to_xdr(&1))
|> SignerKeyList.new()
end
@spec validate_time_bounds(time_bounds :: TimeBounds.t()) :: validation()
defp validate_time_bounds(%TimeBounds{} = time_bounds), do: {:ok, time_bounds}
defp validate_time_bounds(_time_bounds), do: {:error, :invalid_time_bounds}
@spec validate_ledger_bounds(ledger_bounds :: LedgerBounds.t()) :: validation()
defp validate_ledger_bounds(%LedgerBounds{} = ledger_bounds),
do: {:ok, ledger_bounds}
defp validate_ledger_bounds(_ledger_bounds), do: {:error, :invalid_ledger_bounds}
@spec validate_optional_min_seq_num(min_seq_num :: SequenceNumber.t() | nil) :: validation()
defp validate_optional_min_seq_num(nil),
do: {:ok, OptionalSequenceNumber.new()}
defp validate_optional_min_seq_num(%SequenceNumber{} = min_seq_num),
do:
min_seq_num
|> OptionalSequenceNumber.new()
|> (&{:ok, &1}).()
defp validate_optional_min_seq_num(_min_seq_num), do: {:error, :invalid_min_seq_num}
@spec validate_min_seq_age(min_seq_age :: non_neg_integer()) :: validation()
defp validate_min_seq_age(min_seq_age)
when is_integer(min_seq_age) and min_seq_age >= 0,
do: {:ok, min_seq_age}
defp validate_min_seq_age(_min_seq_age), do: {:error, :invalid_min_seq_age}
@spec validate_min_seq_ledger_gap(min_seq_ledger_gap :: non_neg_integer()) :: validation()
defp validate_min_seq_ledger_gap(min_seq_ledger_gap)
when is_integer(min_seq_ledger_gap) and min_seq_ledger_gap >= 0,
do: {:ok, min_seq_ledger_gap}
defp validate_min_seq_ledger_gap(_min_seq_ledger_gap), do: {:error, :invalid_min_seq_ledger_gap}
@spec validate_extra_signers(
response :: list(String.t()),
extra_signers :: list(String.t())
) :: validation()
def validate_extra_signers(response, []), do: {:ok, response}
def validate_extra_signers(response, [h | t]) do
case SignerKey.new(h) do
%SignerKey{} = signer_key -> validate_extra_signers(response ++ [signer_key], t)
_error -> {:error, :invalid_extra_signers}
end
end
def validate_extra_signers(_response, _extra_signers),
do: {:error, :invalid_extra_signers}
end