Invoking and Creating Contracts with Stellar Transactions
Stellar supports invoking and deploying contracts with a new Operation named InvokeHostFunctionOp
. The soroban-cli
abstracts these details away from the user, but SDKs do not yet and if you're building a dapp you'll probably find yourself building the XDR transaction to submit to the network.
The InvokeHostFunctionOp
can be used to perform the following Soroban operations:
- Invoke contract functions.
- Install WASM of the new contracts.
- Deploy new contracts using the installed WASM or built-in implementations (this currently includes only the token contract).
InvokeHostFunctionOp
The XDR of HostFunction
and InvokeHostFunctionOp
below can be found
here.
union HostFunction switch (HostFunctionType type)
{
case HOST_FUNCTION_TYPE_INVOKE_CONTRACT:
SCVec invokeArgs;
case HOST_FUNCTION_TYPE_CREATE_CONTRACT:
CreateContractArgs createContractArgs;
case HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE:
InstallContractCodeArgs installContractCodeArgs;
};
struct InvokeHostFunctionOp
{
// The host function to invoke
HostFunction function;
// The footprint for this invocation
LedgerFootprint footprint;
// Per-address authorizations for this host fn
// Currently only supported for INVOKE_CONTRACT function
ContractAuth auth<>;
};
Function
The function
in InvokeHostFunctionOp
will be executed by the Soroban host environment. The function arguments are passed as function-dependent XDR. The options are:
HOST_FUNCTION_TYPE_INVOKE_CONTRACT
- This will call the
call_n
host function, invoking a contract function. invokeArgs
is expected to contain the contract id, contract function name, and the parameters to the contract function being invoked.
- This will call the
HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE
- This will install the contract WASM using the provided
code
blob:
struct InstallContractCodeArgs
{
opaque code<SCVAL_LIMIT>;
};- This will install the contract WASM using the provided
HOST_FUNCTION_TYPE_CREATE_CONTRACT
- This will create a contract instance in the network using the specified
source
and build a 32-byte contract identifer based oncontractID
value.
struct CreateContractArgs
{
ContractID contractID;
SCContractCode source;
};source
can be either a reference to the hash of the installed WASM (to be more precise, a SHA-256 hash of theInstallContractCodeArgs
from the operation above) or just specify that a built-in contract has to be used:union SCContractCode switch (SCContractCodeType type)
{
case SCCONTRACT_CODE_WASM_REF:
Hash wasm_id;
case SCCONTRACT_CODE_TOKEN:
void;
};
- This will create a contract instance in the network using the specified
contractID
is defined as following:union ContractID switch (ContractIDType type)
{
case CONTRACT_ID_FROM_SOURCE_ACCOUNT:
uint256 salt;
case CONTRACT_ID_FROM_ED25519_PUBLIC_KEY:
struct
{
uint256 key;
Signature signature;
uint256 salt;
} fromEd25519PublicKey;
case CONTRACT_ID_FROM_ASSET:
Asset asset;
};- The parameters of this value define which the hash preimage that is then hashed with SHA-256 to get the ID of the created contract.
CONTRACT_ID_FROM_SOURCE_ACCOUNT
specifies that the contract ID will be created using the Stellar source account and the provided salt. The contract ID preimage used isENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT
.CONTRACT_ID_FROM_ASSET
specifies that the contract will be created using the Stellar asset. This is only supported whensource == SCCONTRACT_CODE_TOKEN
. Note, that the asset doesn't need to exist when this is applied, however the issuer of the asset will be the initial token administrator. The contract ID preimage used isENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET
.CONTRACT_ID_FROM_ED25519_PUBLIC_KEY
specified that the contract will be created using a public ED25519 key. Since this operation is not tied to any on-chain entity, this also has to contain an ED25519 signature of SHA256 hash ofENVELOPE_TYPE_CREATE_CONTRACT_ARGS
XDR preimage. The contract ID preimage used isENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519
.
Footprint
The footprint must contain the LedgerKeys
that will be read and/or written. More information about the footprint can be found in the advanced section of interacting with contracts.
Authorization Data
This is currently only supported for HOST_FUNCTION_TYPE_INVOKE_CONTRACT
.
Soroban authorization framework provides a
standardized way for passing authorization data to the contract invocations via
ContractAuth
structures.
struct AddressWithNonce
{
SCAddress address;
uint64 nonce;
};
struct ContractAuth
{
AddressWithNonce* addressWithNonce; // not present for invoker
AuthorizedInvocation rootInvocation;
SCVec signatureArgs;
};
ContractAuth
contains a tree of invocations authorized by an Address
and
the corresponding signature (in Address
-dependent format).
In order to build a ContractAuth
the following is required:
Address
that authorizes the invocations and the correspondingnonce
.- When
addressWithNonce
is missing, then it means that the transaction source account (or operation source when present) authorizes these invocations.signatureArgs
have to be skipped as well in this case. nonce
has to correspond to thecontractID
of therootInvocation
. It is stored in the ledger entry withCONTRACT_DATA
key withcontractID
fromrootInvocation
andSCVal
key
with the following value:ScVal::Object(Some(ScObject::NonceKey(address)))
(when not present, nonce is equal to0
).
- When
rootInvocation
structure corresponding to the authorized invocation treesignatureArgs
- signature (or multiple signatures) that sign the 32-byte payload that is a SHA-256 hash ofENVELOPE_TYPE_CONTRACT_AUTH
preimage (XDR). The signature structure is defined by theAddress
(see below for the Stellar account signatures). This should be empty ifaddressWithNonce
is not present (as transaction/operation signature is used instead).
AuthorizedInvocation
defines a node in the authorized invocation tree:
struct AuthorizedInvocation
{
Hash contractID;
SCSymbol functionName;
SCVec args;
AuthorizedInvocation subInvocations<>;
};
AuthorizedInvocation
needs to include a contract, contract function, arguments
of require_auth
/require_auth_for_args
call and all the authorized
sub-contract invocations originating from the current node. Building
AuthorizedInvocation
trees may be simplified by using the recording auth mode
in Soroban preflight (see the docs for more details).
Stellar Account Signatures
signatureArgs
format is user-defined for the custom accounts, but it is
protocol-defined for the Stellar accounts.
The signatures for the Stellar account are a vector of the following Soroban structures in the Soroban SDK format:
#[contracttype]
pub struct AccountEd25519Signature {
pub public_key: BytesN<32>,
pub signature: BytesN<64>,
}