defmodule Stellar.TxBuild.AuthorizedInvocation do
@moduledoc """
`AuthorizedInvocation` struct definition.
"""
import Stellar.TxBuild.Validations,
only: [
validate_sc_vals: 1,
validate_contract_id: 1,
validate_string: 1,
is_struct?: 2
]
alias StellarBase.XDR.{AuthorizedInvocation, AuthorizedInvocationList, Hash, SCSymbol, SCVec}
alias Stellar.TxBuild.SCVal
@type error :: Keyword.t() | atom()
@type validation :: {:ok, any()} | {:error, error()}
@type authorized_invocation_list :: AuthorizedInvocationList.t()
@type t :: %__MODULE__{
contract_id: binary(),
function_name: String.t(),
args: list(SCVal.t()),
sub_invocations: list(t())
}
@behaviour Stellar.TxBuild.XDR
defstruct [:contract_id, :function_name, :args, :sub_invocations]
@impl true
def new(args, opts \\ nil)
def new(args, _opts) when is_list(args) do
contract_id = Keyword.get(args, :contract_id)
function_name = Keyword.get(args, :function_name)
sub_invocations = Keyword.get(args, :sub_invocations)
args = Keyword.get(args, :args)
with {:ok, contract_id} <- validate_contract_id({:contract_id, contract_id}),
{:ok, function_name} <- validate_string({:function_name, function_name}),
{:ok, args} <- validate_sc_vals({:args, args}),
{:ok, sub_invocations} <- validate_sub_invocations({:sub_invocations, sub_invocations}) do
%__MODULE__{
contract_id: contract_id,
function_name: function_name,
args: args,
sub_invocations: sub_invocations
}
end
end
def new(_args, _opts), do: {:error, :invalid_authorized_invocation}
@impl true
def to_xdr(%__MODULE__{
contract_id: contract_id,
function_name: function_name,
args: args,
sub_invocations: sub_invocations
}) do
contract_id =
contract_id
|> Base.decode16!(case: :lower)
|> Hash.new()
function_name = SCSymbol.new(function_name)
args = args |> Enum.map(&SCVal.to_xdr/1) |> SCVec.new()
sub_invocations = sub_invocations |> Enum.map(&to_xdr/1) |> AuthorizedInvocationList.new()
AuthorizedInvocation.new(contract_id, function_name, args, sub_invocations)
end
def to_xdr(_error), do: {:error, :invalid_struct_authorized_invocation}
@spec validate_sub_invocations(tuple :: tuple()) :: validation()
defp validate_sub_invocations({field, args}) when is_list(args) do
if Enum.all?(args, &is_struct?(&1, __MODULE__)),
do: {:ok, args},
else: {:error, :"invalid_#{field}"}
end
defp validate_sub_invocations({field, _args}), do: {:error, :"invalid_#{field}"}
end