Packages
stellar_sdk
0.16.0
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/invoke_host_function.ex
defmodule Stellar.TxBuild.InvokeHostFunction do
@moduledoc """
Performs the following operations:
- Invokes contract host_functions.
- Upload WASM of the new contracts.
- Deploys new contracts using the uploaded WASM or built-in implementations.
"""
import Stellar.TxBuild.Validations, only: [validate_optional_account: 1]
alias Stellar.TxBuild.{HostFunction, SorobanAuthorizationEntry, OptionalAccount}
alias StellarBase.XDR.Operations.InvokeHostFunction
alias StellarBase.XDR.{
OperationBody,
OperationType,
SorobanAuthorizationEntryList
}
alias StellarBase.XDR.SorobanAuthorizationEntry, as: SorobanAuthorizationEntryXDR
@behaviour Stellar.TxBuild.XDR
@type auths :: list(SorobanAuthorizationEntry.t()) | list(String.t())
@type error :: {:error, atom()}
@type host_function :: HostFunction.t()
@type soroban_auth_xdr :: SorobanAuthorizationEntryXDR.t()
@type validation :: {:ok, any()} | {:error, atom()}
@type t :: %__MODULE__{
host_function: host_function(),
auths: auths(),
source_account: OptionalAccount.t()
}
defstruct [:host_function, :auths, :source_account]
@impl true
def new(host_function, opts \\ [])
def new(args, _opts) when is_list(args) do
host_function = Keyword.get(args, :host_function)
auths = Keyword.get(args, :auths, [])
source_account = Keyword.get(args, :source_account)
with {:ok, host_function} <- validate_host_host_function(host_function),
{:ok, auths} <- validate_soroban_auth_entries(auths),
{:ok, source_account} <- validate_optional_account({:source_account, source_account}) do
%__MODULE__{
host_function: host_function,
auths: auths,
source_account: source_account
}
end
end
def new(_args, _opts), do: {:error, :invalid_operation_attributes}
@impl true
def to_xdr(%__MODULE__{
host_function: host_function,
auths: [%SorobanAuthorizationEntry{} | _] = auths
}) do
op_type = OperationType.new(:INVOKE_HOST_FUNCTION)
SCEC_INTERNAL_ERROR
auth =
auths
|> Enum.map(&SorobanAuthorizationEntry.to_xdr/1)
|> SorobanAuthorizationEntryList.new()
host_function
|> HostFunction.to_xdr()
|> InvokeHostFunction.new(auth)
|> OperationBody.new(op_type)
end
def to_xdr(%__MODULE__{
host_function: host_function,
auths: auths
})
when is_list(auths) do
op_type = OperationType.new(:INVOKE_HOST_FUNCTION)
auth =
auths
|> Enum.map(&decode_soroban_auth/1)
|> SorobanAuthorizationEntryList.new()
host_function
|> HostFunction.to_xdr()
|> InvokeHostFunction.new(auth)
|> OperationBody.new(op_type)
end
@spec set_auth(module :: t(), auths :: auths()) :: t() | error()
def set_auth(%__MODULE__{} = module, auths) when is_list(auths) do
with {:ok, auths} <- validate_auth_strings(auths) do
%{module | auths: auths}
end
end
def set_auth(_module, _auths), do: {:error, :invalid_auth}
defp validate_auth_strings(auth) do
if Enum.all?(auth, &validate_xdr_string/1),
do: {:ok, auth},
else: {:error, :invalid_auth}
end
@spec validate_xdr_string(xdr :: String.t() | nil) :: boolean()
defp validate_xdr_string(nil), do: true
defp validate_xdr_string(xdr) when is_binary(xdr) do
case Base.decode64(xdr) do
{:ok, _} -> true
:error -> false
end
end
@spec validate_host_host_function(host_function :: host_function()) :: validation()
defp validate_host_host_function(%HostFunction{} = host_function), do: {:ok, host_function}
defp validate_host_host_function(_host_function), do: {:error, :invalid_host_host_function}
defp validate_soroban_auth_entries(auths) when is_list(auths) do
if Enum.all?(auths, &is_soroban_auth_entry?/1),
do: {:ok, auths},
else: {:error, :invalid_soroban_auth_entries}
end
defp validate_soroban_auth_entries(_auths), do: {:error, :invalid_soroban_auth_entries}
defp is_soroban_auth_entry?(%SorobanAuthorizationEntry{}), do: true
defp is_soroban_auth_entry?(_auth), do: false
@spec decode_soroban_auth(auth :: String.t()) :: soroban_auth_xdr()
defp decode_soroban_auth(auth) do
{contract_auth, ""} =
auth
|> Base.decode64!()
|> SorobanAuthorizationEntryXDR.decode_xdr!()
contract_auth
end
end