defmodule Stellar.TxBuild.Memo do
@moduledoc """
`Memo` struct definition.
"""
alias StellarBase.XDR.{UInt64, Hash, String28, MemoType, Memo}
@behaviour Stellar.TxBuild.XDR
@type memo_value :: String.t() | integer() | binary() | nil
@type xdr_memo_value :: String28.t() | UInt64.t() | Hash.t() | nil
@type t :: %__MODULE__{type: atom(), value: memo_value()}
defstruct [:type, :value]
@impl true
def new(type \\ :none, opts \\ [])
def new(:none, _value) do
%__MODULE__{type: :MEMO_NONE, value: nil}
end
def new([text: value], _opts) when is_bitstring(value) and byte_size(value) < 28 do
%__MODULE__{type: :MEMO_TEXT, value: value}
end
def new([id: value], _opts) when is_integer(value) do
%__MODULE__{type: :MEMO_ID, value: value}
end
def new([hash: value], _opts) when is_bitstring(value) and byte_size(value) == 64 do
%__MODULE__{type: :MEMO_HASH, value: value}
end
def new([return: value], _opts) when is_bitstring(value) and byte_size(value) == 64 do
%__MODULE__{type: :MEMO_RETURN, value: value}
end
def new(_type, _value), do: {:error, :invalid_memo}
@impl true
def to_xdr(%__MODULE__{type: type, value: value}) do
memo_type = MemoType.new(type)
value
|> memo_xdr_value(type)
|> Memo.new(memo_type)
end
@spec memo_xdr_value(value :: memo_value(), type :: atom()) :: xdr_memo_value()
defp memo_xdr_value(value, memo_type) when memo_type in [:MEMO_HASH, :MEMO_RETURN] do
value
|> String.upcase()
|> Base.decode16!()
|> Hash.new()
end
defp memo_xdr_value(_value, :MEMO_NONE), do: nil
defp memo_xdr_value(value, :MEMO_TEXT), do: String28.new(value)
defp memo_xdr_value(value, :MEMO_ID), do: UInt64.new(value)
end