defmodule Soroban.Contract.RPCCalls do
@moduledoc """
Exposes the functions to execute the simulate and send_transaction endpoints
"""
alias Soroban.RPC
alias Soroban.RPC.{SendTransactionResponse, SimulateTransactionResponse}
alias Stellar.TxBuild
alias Stellar.TxBuild.{
Account,
ContractAuth,
InvokeHostFunction,
SequenceNumber,
Signature
}
@type account :: Account.t()
@type auth :: String.t() | nil
@type auth_account :: String.t() | nil
@type invoke_host_function :: InvokeHostFunction.t()
@type simulate_response :: {:ok, SimulateTransactionResponse.t()}
@type send_response :: {:ok, SendTransactionResponse.t()}
@type signature :: Signature.t()
@type sequence_number :: SequenceNumber.t()
@spec simulate(
invoke_host_function_op :: invoke_host_function(),
source_account :: account(),
sequence_number :: sequence_number()
) :: simulate_response()
def simulate(
invoke_host_function_op,
source_account,
sequence_number
) do
{:ok, envelop_xdr} =
source_account
|> TxBuild.new(sequence_number: sequence_number)
|> TxBuild.add_operation(invoke_host_function_op)
|> TxBuild.envelope()
RPC.simulate_transaction(envelop_xdr)
end
@spec send_transaction(
simulate_response :: simulate_response(),
source_account :: account(),
sequence_number :: sequence_number(),
signature :: signature(),
invoke_host_function_op :: invoke_host_function()
) :: send_response() | simulate_response()
def send_transaction(
_simulate_transaction,
_source_account,
_sequence_number,
_signature,
_invoke_host_function_op,
auth_account \\ nil
)
def send_transaction(
{:ok, %SimulateTransactionResponse{results: [%{footprint: footprint, auth: auth}]}},
source_account,
sequence_number,
signature,
invoke_host_function_op,
auth_account
) do
invoke_host_function_op =
set_invoke_host_function_params(invoke_host_function_op, footprint, auth, auth_account)
{:ok, envelope_xdr} =
source_account
|> TxBuild.new(sequence_number: sequence_number)
|> TxBuild.add_operation(invoke_host_function_op)
|> TxBuild.sign(signature)
|> TxBuild.envelope()
RPC.send_transaction(envelope_xdr)
end
def send_transaction(
{:ok, %SimulateTransactionResponse{}} = response,
_source_account,
_sequence_number,
_signature,
_invoke_host_function_op,
_auth_account
),
do: response
@spec set_invoke_host_function_params(
invoke_host_function :: invoke_host_function(),
footprint :: String.t(),
auth :: auth(),
auth_account :: auth_account()
) :: invoke_host_function() | {:error, :required_auth}
defp set_invoke_host_function_params(invoke_host_function_op, footprint, [auth], nil) do
invoke_host_function_op
|> InvokeHostFunction.set_footprint(footprint)
|> InvokeHostFunction.set_contract_auth(auth)
end
defp set_invoke_host_function_params(invoke_host_function_op, footprint, [auth], auth_account) do
authorization = ContractAuth.sign_xdr(auth, auth_account)
invoke_host_function_op
|> InvokeHostFunction.set_footprint(footprint)
|> InvokeHostFunction.set_contract_auth(authorization)
end
defp set_invoke_host_function_params(invoke_host_function_op, footprint, nil, _auth_account),
do: InvokeHostFunction.set_footprint(invoke_host_function_op, footprint)
end