defmodule Stellar.TxBuild.Transaction do
@moduledoc """
`Transaction` struct definition.
"""
alias Stellar.TxBuild.{
Account,
BaseFee,
Operations,
SequenceNumber,
Memo,
Preconditions
}
alias StellarBase.XDR.{Ext, Transaction}
@behaviour Stellar.TxBuild.XDR
@type validation :: {:ok, struct()} | {:error, atom()}
@type t :: %__MODULE__{
source_account: Account.t(),
sequence_number: SequenceNumber.t(),
base_fee: BaseFee.t(),
memo: Memo.t(),
preconditions: Preconditions.t(),
operations: Operations.t()
}
defstruct [:source_account, :sequence_number, :base_fee, :memo, :preconditions, :operations]
@impl true
def new(args, opts \\ [])
def new(args, _opts) do
source_account = Keyword.get(args, :source_account)
sequence_number = Keyword.get(args, :sequence_number)
base_fee = Keyword.get(args, :base_fee)
preconditions = Keyword.get(args, :preconditions)
memo = Keyword.get(args, :memo)
operations = Keyword.get(args, :operations)
with {:ok, source_account} <- validate_source_account(source_account),
{:ok, sequence_number} <- validate_sequence_number(sequence_number),
{:ok, base_fee} <- validate_base_fee(base_fee),
{:ok, preconditions} <- validate_preconditions(preconditions),
{:ok, memo} <- validate_memo(memo),
{:ok, operations} <- validate_operations(operations) do
%__MODULE__{
source_account: source_account,
sequence_number: sequence_number,
base_fee: base_fee,
preconditions: preconditions,
memo: memo,
operations: operations
}
end
end
@impl true
def to_xdr(%__MODULE__{
source_account: source_account,
sequence_number: sequence_number,
base_fee: base_fee,
preconditions: preconditions,
memo: memo,
operations: operations
}) do
Transaction.new(
Account.to_xdr(source_account),
BaseFee.to_xdr(base_fee),
SequenceNumber.to_xdr(sequence_number),
Preconditions.to_xdr(preconditions),
Memo.to_xdr(memo),
Operations.to_xdr(operations),
Ext.new()
)
end
@spec validate_source_account(source_account :: Account.t()) :: validation()
defp validate_source_account(%Account{} = source_account), do: {:ok, source_account}
defp validate_source_account(_source_account), do: {:error, :invalid_source_account}
@spec validate_sequence_number(sequence_number :: SequenceNumber.t()) :: validation()
defp validate_sequence_number(%SequenceNumber{} = sequence_number), do: {:ok, sequence_number}
defp validate_sequence_number(_sequence_number), do: {:error, :invalid_sequence_number}
@spec validate_base_fee(base_fee :: BaseFee.t()) :: validation()
defp validate_base_fee(%BaseFee{} = base_fee), do: {:ok, base_fee}
defp validate_base_fee(_base_fee), do: {:error, :invalid_base_fee}
@spec validate_operations(preconditions :: Preconditions.t()) :: validation()
defp validate_preconditions(%Preconditions{} = preconditions), do: {:ok, preconditions}
defp validate_preconditions(_preconditions), do: {:error, :invalid_preconditions}
@spec validate_memo(memo :: Memo.t()) :: validation()
defp validate_memo(%Memo{} = memo), do: {:ok, memo}
defp validate_memo(_memo), do: {:error, :invalid_memo}
@spec validate_operations(operations :: Operations.t()) :: validation()
defp validate_operations(%Operations{} = operations), do: {:ok, operations}
defp validate_operations(_operations), do: {:error, :invalid_operations}
end