defmodule Soroban.Contract.DeployContract do
@moduledoc """
`DeployContract` implementation to deploy contract from a wasm file.
"""
alias Soroban.RPC
alias Soroban.RPC.{SendTransactionResponse, Server}
alias Stellar.TxBuild.{
Account,
ContractExecutable,
ContractIDPreimage,
ContractIDPreimageFromAddress,
CreateContractArgs,
HostFunction,
InvokeHostFunction,
SCAddress,
SequenceNumber,
Signature
}
alias Soroban.Contract.RPCCalls
@type server :: Server.t()
@type network_passphrase :: String.t()
@type envelope_xdr :: String.t()
@type public_key :: String.t()
@type wasm_id :: binary()
@type invoke_host_function :: InvokeHostFunction.t()
@type send_response :: {:ok, SendTransactionResponse.t()}
@type addl_resources :: keyword()
@spec deploy(
server :: server(),
network_passphrase :: network_passphrase(),
wasm_id :: wasm_id(),
secret_key :: binary(),
addl_resources :: addl_resources()
) ::
send_response()
def deploy(%Server{} = server, network_passphrase, wasm_id, secret_key, addl_resources \\ []) do
with {public_key, _secret} = keypair <- Stellar.KeyPair.from_secret_seed(secret_key),
%Account{} = source_account <- Account.new(public_key),
{:ok, seq_num} <- RPC.fetch_next_sequence_number(server, public_key),
%SequenceNumber{} = sequence_number <- SequenceNumber.new(seq_num),
%Signature{} = signature <- Signature.new(keypair),
%InvokeHostFunction{} = invoke_host_function_op <-
create_host_function_deploy_op(wasm_id, public_key) do
invoke_host_function_op
|> RPCCalls.simulate(
server,
network_passphrase,
source_account,
sequence_number,
addl_resources
)
|> RPCCalls.send_transaction(
server,
network_passphrase,
source_account,
sequence_number,
signature,
invoke_host_function_op
)
end
end
@spec retrieve_unsigned_xdr_to_deploy(
server :: server(),
network_passphrase :: network_passphrase(),
wasm_id :: wasm_id(),
source_public_key :: binary(),
addl_resources :: addl_resources()
) :: envelope_xdr()
def retrieve_unsigned_xdr_to_deploy(
%Server{} = server,
network_passphrase,
wasm_id,
source_public_key,
addl_resources \\ []
) do
with {:ok, seq_num} <- RPC.fetch_next_sequence_number(server, source_public_key),
%Account{} = source_account <- Account.new(source_public_key),
%SequenceNumber{} = sequence_number <- SequenceNumber.new(seq_num),
%InvokeHostFunction{} = invoke_host_function_op <-
create_host_function_deploy_op(wasm_id, source_public_key) do
invoke_host_function_op
|> RPCCalls.simulate(
server,
network_passphrase,
source_account,
sequence_number,
addl_resources
)
|> RPCCalls.retrieve_unsigned_xdr(
server,
network_passphrase,
source_account,
sequence_number,
invoke_host_function_op
)
end
end
@spec create_host_function_deploy_op(wasm_id :: wasm_id(), public_key :: public_key()) ::
invoke_host_function()
defp create_host_function_deploy_op(wasm_id, public_key) do
address = SCAddress.new(public_key)
salt = :crypto.strong_rand_bytes(32)
address_preimage = ContractIDPreimageFromAddress.new(address: address, salt: salt)
contract_id_preimage = ContractIDPreimage.new(from_address: address_preimage)
contract_executable = ContractExecutable.new(wasm_ref: wasm_id)
create_contract_args =
CreateContractArgs.new(
contract_id_preimage: contract_id_preimage,
contract_executable: contract_executable
)
host_function = HostFunction.new(create_contract: create_contract_args)
InvokeHostFunction.new(host_function: host_function)
end
end