defmodule Stellar.TxBuild.HostFunction do
@moduledoc """
`HostFunction` struct definition.
"""
alias Stellar.TxBuild.{CreateContractArgs, InvokeContractArgs}
alias StellarBase.XDR.{HostFunction, HostFunctionType, VariableOpaque}
@behaviour Stellar.TxBuild.XDR
@type value :: CreateContractArgs.t() | InvokeContractArgs.t() | binary()
@type error :: {:error, atom()}
@type validation :: {:ok, any()} | error()
@type type ::
:invoke_contract
| :create_contract
| :upload_contract_wasm
@type t :: %__MODULE__{
type: type(),
value: value()
}
defstruct [:type, :value]
@allowed_types ~w(invoke_contract create_contract upload_contract_wasm)a
@impl true
def new(args, opts \\ [])
def new([{type, value}], _opts) when type in @allowed_types do
with {:ok, _value} <- validate_host_function({type, value}) do
%__MODULE__{
type: type,
value: value
}
end
end
def new(_args, _opts), do: {:error, :invalid_operation_attributes}
@impl true
def to_xdr(%__MODULE__{
type: :invoke_contract,
value: value
}) do
type = HostFunctionType.new(:HOST_FUNCTION_TYPE_INVOKE_CONTRACT)
value
|> InvokeContractArgs.to_xdr()
|> HostFunction.new(type)
end
def to_xdr(%__MODULE__{
type: :create_contract,
value: value
}) do
type = HostFunctionType.new(:HOST_FUNCTION_TYPE_CREATE_CONTRACT)
value
|> CreateContractArgs.to_xdr()
|> HostFunction.new(type)
end
def to_xdr(%__MODULE__{
type: :upload_contract_wasm,
value: value
}) do
type = HostFunctionType.new(:HOST_FUNCTION_TYPE_UPLOAD_CONTRACT_WASM)
value
|> VariableOpaque.new()
|> HostFunction.new(type)
end
@spec validate_host_function({type :: atom(), value :: value()}) :: validation()
defp validate_host_function({:invoke_contract, %InvokeContractArgs{} = value}), do: {:ok, value}
defp validate_host_function({:create_contract, %CreateContractArgs{} = value}), do: {:ok, value}
defp validate_host_function({:upload_contract_wasm, value}) when is_binary(value),
do: {:ok, value}
defp validate_host_function({type, _value}), do: {:error, :"invalid_#{type}"}
end