Stellar PHP SDK API Documentation

AssembledTransaction

High-level transaction builder for Soroban smart contract interactions

This class wraps a transaction-under-construction and provides convenient methods for the most common Soroban workflows: simulating transactions, signing them, and sending them to the network. It handles resource fees, footprint management, authorization entries, and automatic retries for transactions that require state restoration.

Most of the time, you will not construct an AssembledTransaction directly, but instead receive one as the return value of a SorobanClient method.

Tags
see
SorobanClient

For the high-level contract client that creates these transactions

see
https://developers.stellar.org/docs/smart-contracts

Soroban Smart Contracts Documentation

since
1.0.0

Let's look at examples of how to use AssembledTransaction for a variety of use-cases:

1. Simple read call

Since these only require simulation, you can get the result of the call right after constructing your AssembledTransaction:


$clientOptions = new ClientOptions(
     sourceAccountKeyPair: $sourceAccountKeyPair,
     contractId: 'C123…',
     network: Network::testnet(),
     rpcUrl: 'https://…',
);

$txOptions = new AssembledTransactionOptions(
                 clientOptions: $clientOptions,
                 methodOptions: new MethodOptions(),
                 method: 'myReadMethod',
                 arguments: $args);

$tx = AssembledTransaction::build($options);
$result = $tx->getSimulationData()->returnedValue;

While that looks pretty complicated, most of the time you will use this in conjunction with , which simplifies it to:

$result = $client->invokeMethod(name: 'myReadMethod', args: $args);

2. Simple write call

For write calls that will be simulated and then sent to the network without further manipulation, only one more step is needed:

$tx = AssembledTransaction::build($options);
$response = $tx->signAndSend();

if ($response->getStatus() === GetTransactionResponse::STATUS_SUCCESS) {

    $result = $response->getResultValue();
}

If you are using it in conjunction with :

 $result = $client->invokeMethod(name: 'myWriteMethod', args: $args);

3. More fine-grained control over transaction construction

If you need more control over the transaction before simulating it, you can set various when constructing your AssembledTransaction. With a , this can be passed as an argument when calling invokeMethod or buildInvokeMethodTx :

$methodOptions = new MethodOptions(
         fee: 10000,
         timeoutInSeconds: 20,
         simulate: false,
);

$tx = $client->buildInvokeMethodTx(name: 'myWriteMethod', args: $args, methodOptions: $methodOptions);

Since we've skipped simulation, we can now edit the raw transaction builder and then manually call simulate:

 $tx->raw->addMemo(Memo::text("Hello!"));
 $tx->simulate();

If you need to inspect the simulation later, you can access it with $tx->getSimulationData().

4. Multi-auth workflows

Soroban, and Stellar in general, allows multiple parties to sign a transaction.

Let's consider an Atomic Swap contract. Alice wants to give some of her Token A tokens to Bob for some of his Token B tokens.

$swapMethodName = "swap";

$amountA = XdrSCVal::forI128(new XdrInt128Parts(0,1000));
$minBForA = XdrSCVal::forI128(new XdrInt128Parts(0,4500));

$amountB = XdrSCVal::forI128(new XdrInt128Parts(0,5000));
$minAForB = XdrSCVal::forI128(new XdrInt128Parts(0,950));

$args = [
     Address::fromAccountId($aliceAccountId)->toXdrSCVal(),
     Address::fromAccountId($bobAccountId)->toXdrSCVal(),
     Address::fromContractId($tokenAContractId)->toXdrSCVal(),
     Address::fromContractId($tokenBContractId)->toXdrSCVal(),
     $amountA,
     $minBForA,
     $amountB,
     $minAForB
];

Let's say Alice is also going to be the one signing the final transaction envelope, meaning she is the invoker. So your app, she simulates the swap call:

 $tx = $atomicSwapClient->buildInvokeMethodTx(name: $swapMethodName, args: $args);

But your app can't signAndSend this right away, because Bob needs to sign it first. You can check this:

 $whoElseNeedsToSign = tx->needsNonInvokerSigningBy()

You can verify that $whoElseNeedsToSign is an array of length 1, containing only Bob's public key.

If you have Bob's secret key, you can sign it right away with:

$bobsKeyPair = KeyPair::fromSeed('S...')
$tx->signAuthEntries(signerKeyPair: $bobsKeyPair);

But if you don't have Bob's private key, and e.g. need to send it to another server for signing, you can provide a callback function for signing the auth entry:

$bobsPublicKeyKeyPair = KeyPair::fromAccountId($bobsAccountId);
$tx->signAuthEntries(signerKeyPair: $bobPublicKeyKeyPair,
                    authorizeEntryCallback: function (SorobanAuthorizationEntry $entry,
                                                      Network $network) : SorobanAuthorizationEntry  {

            // You can send it to some other server for signing by encoding it as a base64xdr string
            $base64Entry = $entry->toBase64Xdr();
            // send for signing ...
            // and on the other server you can decode it:
            $entryToSign = SorobanAuthorizationEntry::fromBase64Xdr($base64Entry);
            // sign it
            $entryToSign->sign($bobsSecretKeyPair, $network);
            // encode as a base64xdr string and send it back
            $signedBase64Entry = $entryToSign->toBase64Xdr();
            // here you can now decode it and return it
            return SorobanAuthorizationEntry::fromBase64Xdr($signedBase64Entry);
     },
);

To see an even more complicated example, where Alice swaps with Bob but the transaction is invoked by yet another party, check out in the SorobanClientTest.testAtomicSwap()

Table of Contents

Properties

$options  : AssembledTransactionOptions
$raw  : TransactionBuilder|null
$signed  : Transaction|null
$simulationResponse  : SimulateTransactionResponse|null
The response of the transaction simulation. This is set after the first call to `simulate`.
$tx  : Transaction|null
The Transaction as it was built with `$raw->build()` right before simulation. Once this is set, modifying `$raw` will have no effect unless you call `$tx->simulate()` again.

Methods

build()  : AssembledTransaction
Constructs a new AssembledTransaction for invoking a contract method
buildWithOp()  : AssembledTransaction
Constructs an AssembledTransaction with a custom host function operation
getSimulationData()  : SimulateHostFunctionResult
Retrieves the simulation results from the transaction
isReadCall()  : bool
Determines if this is a read-only transaction
needsNonInvokerSigningBy()  : array<string|int, string>
Get a list of accounts, other than the invoker of the simulation, that need to sign auth entries in this transaction.
restoreFootprint()  : GetTransactionResponse
Restores expired ledger entries required by the transaction
send()  : GetTransactionResponse
Sends the signed transaction to the network and waits for completion
sign()  : void
Signs the transaction with the source account's private key
signAndSend()  : GetTransactionResponse
Signs the transaction and sends it to the network, waiting for completion
signAuthEntries()  : void
Signs and updates the auth entries related to the public key of the $signerKeyPair provided.
simulate()  : void
Simulates the transaction and updates it with the simulation results

Properties

$raw

public TransactionBuilder|null $raw = null

The TransactionBuilder as constructed in AssembledTransaction::build Feel free set simulate: false in the method options to modify this object before calling tx->simulate() manually. Example:

 $methodOptions = new MethodOptions(
          simulate: false,
 );

 $tx = $client->buildInvokeMethodTx(name: 'myWriteMethod', args: $args, methodOptions: $methodOptions);
 $tx->raw->addMemo(Memo::text("Hello!"));
 $tx->simulate();

$tx

The Transaction as it was built with `$raw->build()` right before simulation. Once this is set, modifying `$raw` will have no effect unless you call `$tx->simulate()` again.

public Transaction|null $tx = null

Methods

build()

Constructs a new AssembledTransaction for invoking a contract method

public static build(AssembledTransactionOptions $options) : AssembledTransaction

This is the main factory method for creating AssembledTransactions. It fetches the source account from the network to get the current sequence number, builds a transaction with an InvokeContractHostFunction operation, and optionally simulates it to get resource fees.

If you need to use a different host function type (e.g., CreateContractWithConstructorHostFunction), use AssembledTransaction::buildWithOp instead.

Parameters
$options : AssembledTransactionOptions

Configuration including contract id, method name, and arguments

Tags
throws
GuzzleException

If fetching the account or simulation fails

throws
Exception

If transaction construction fails

Return values
AssembledTransaction

The assembled and optionally simulated transaction

buildWithOp()

Constructs an AssembledTransaction with a custom host function operation

public static buildWithOp(InvokeHostFunctionOperation $operation, AssembledTransactionOptions $options) : AssembledTransaction

Use this factory method when you need to use a host function other than InvokeContractHostFunction, such as CreateContractWithConstructorHostFunction for deploying contracts or UploadContractWasmHostFunction for installing contract code.

Parameters
$operation : InvokeHostFunctionOperation

The host function operation to include in the transaction

$options : AssembledTransactionOptions

Configuration for the transaction

Tags
throws
GuzzleException

If fetching the account or simulation fails

throws
Exception

If transaction construction fails

Return values
AssembledTransaction

The assembled and optionally simulated transaction

getSimulationData()

Retrieves the simulation results from the transaction

public getSimulationData() : SimulateHostFunctionResult

Returns the parsed simulation data including the returned value, transaction data, and authorization entries. This method caches the result after first call.

Tags
throws
Exception

If the transaction has not been simulated or simulation failed

Return values
SimulateHostFunctionResult

The simulation result with return value and transaction data

isReadCall()

Determines if this is a read-only transaction

public isReadCall() : bool

Read-only transactions have no authorization entries and an empty read-write footprint, meaning they don't modify any ledger state. These transactions only need simulation and don't require signing or submission to the network.

Tags
throws
Exception

If the transaction has not been simulated

Return values
bool

True if the transaction is read-only, false if it modifies state

needsNonInvokerSigningBy()

Get a list of accounts, other than the invoker of the simulation, that need to sign auth entries in this transaction.

public needsNonInvokerSigningBy([bool $includeAlreadySigned = false ]) : array<string|int, string>

Soroban allows multiple people to sign a transaction. Someone needs to sign the final transaction envelope; this person/account is called the invoker, or source. Other accounts might need to sign individual auth entries in the transaction, if they're not also the invoker.

This function returns a list of accounts that need to sign auth entries, assuming that the same invoker/source account will sign the final transaction envelope as signed the initial simulation.

Parameters
$includeAlreadySigned : bool = false

if the list should include the needed signers that already signed their auth entries.

Tags
throws
Exception
Return values
array<string|int, string>

the list of account ids of the accounts that need to sign auth entries.

restoreFootprint()

Restores expired ledger entries required by the transaction

public restoreFootprint(RestorePreamble $restorePreamble) : GetTransactionResponse

When contract state entries have been archived, they must be restored before the contract can be invoked. This method builds, signs, and sends a RestoreFootprint transaction to restore the necessary ledger entries back to the active state.

The restore preamble is typically received from a simulation response when archived entries are detected. The method requires a source account with private key to sign the restore transaction.

Parameters
$restorePreamble : RestorePreamble

The restore data from simulation including footprint and fees

Tags
throws
GuzzleException

If the RPC request fails

throws
Exception

If the source account has no private key or the restore fails

Return values
GetTransactionResponse

The result of the restore transaction

send()

Sends the signed transaction to the network and waits for completion

public send() : GetTransactionResponse

Submits the transaction via the sendTransaction RPC method and polls getTransaction until the transaction reaches a terminal state (SUCCESS, FAILED, or timeout).

Tags
throws
Exception

If the transaction has not been signed, sending fails, or timeout is exceeded

throws
GuzzleException

If the RPC request fails

Return values
GetTransactionResponse

The transaction result after completion

sign()

Signs the transaction with the source account's private key

public sign([KeyPair|null $sourceAccountKeyPair = null ][, bool $force = false ]) : void

Signs the transaction envelope with the invoker's keypair. This does not submit the transaction. The original transaction object is cloned before signing to preserve the unsigned version. Read-only calls will throw an exception unless force is set to true. Multi-signature transactions should use signAuthEntries for additional signers.

Parameters
$sourceAccountKeyPair : KeyPair|null = null

The keypair with private key to sign with (overrides options)

$force : bool = false

Force signing even if it is a read-only call (default: false)

Tags
security

WARNING: This method requires access to private keys. Never expose private keys in client-side code, logs, or error messages. Use secure key storage such as hardware wallets or key management systems. Never send private keys over unencrypted connections. For production applications, implement signing on secure backend servers with proper key management infrastructure.

throws
Exception

If the private key is missing, transaction requires multiple signers, or is read-only without force

see
signAuthEntries()

For signing authorization entries in multi-signature workflows

see
signAndSend()

For signing and sending in a single operation

Return values
void

Sets the $signed property to the signed transaction clone

signAndSend()

Signs the transaction and sends it to the network, waiting for completion

public signAndSend([KeyPair|null $sourceAccountKeyPair = null ][, bool $force = false ]) : GetTransactionResponse

Signs the transaction with the source account's private key, submits it to the network, and polls for transaction completion up to the configured timeout. Read-only calls will throw an exception unless force is set to true.

Parameters
$sourceAccountKeyPair : KeyPair|null = null

The keypair with private key to sign with (overrides options)

$force : bool = false

Force signing and sending even if it is a read-only call (default: false)

Tags
throws
Exception

If signing fails, transaction is read-only without force, or timeout is exceeded

throws
GuzzleException

If the RPC request fails

see
sign()

For signing without sending

see
send()

For sending an already-signed transaction

Return values
GetTransactionResponse

The transaction result with status. Possible status values:

  • STATUS_SUCCESS: Transaction completed successfully
  • STATUS_FAILED: Transaction failed with error
  • STATUS_NOT_FOUND: Transaction timeout (throws exception before returning this)

signAuthEntries()

Signs and updates the auth entries related to the public key of the $signerKeyPair provided.

public signAuthEntries(KeyPair $signerKeyPair[, callable|null $authorizeEntryCallback = null ][, int|null $validUntilLedgerSeq = null ]) : void
Parameters
$signerKeyPair : KeyPair

The keypair of the signer for the auth entry. By default, this function will sign all auth entries that are connected to the signerKeyPair public key by using SorobanAuthorizationEntry->sign(). The signerKeyPair must contain the private key for signing for this default case. If you don't have the signer's private key, provide the signers KeyPair containing only the public key and provide a callback function for signing by using the $authorizeEntryCallback parameter.

$authorizeEntryCallback : callable|null = null

an optional callback used to sign the auth entry. By default, the function will use SorobanAuthorizationEntry->sign(). If you need to sign on another server or if you have a pro use-case and need to use your own function rather than the default SorobanAuthorizationEntry->sign() function you can do that by providing a callback function here! Your function needs to take following arguments: (SorobanAuthorizationEntry $entry, Network $network) and it must return the signed SorobanAuthorizationEntry.

$validUntilLedgerSeq : int|null = null

When to set each auth entry to expire. Could be any number of blocks in the future. Default: current sequence + 100 blocks (about 8.3 minutes from now).

Tags
security

WARNING: This method handles sensitive authorization entries and private keys. When using a custom authorization callback, ensure the callback securely handles sensitive data and validates the authorization entry before signing. Never send unencrypted private keys over the network. Implement proper key management and consider using hardware security modules for production environments. If transmitting entries for remote signing, use secure channels and validate all returned data.

throws
GuzzleException

If the RPC request fails

throws
Exception

If no auth entries need signing, signer address not found, or transaction not simulated

see
sign()

For signing the main transaction envelope

see
needsNonInvokerSigningBy()

For determining which accounts need to sign

simulate()

Simulates the transaction and updates it with the simulation results

public simulate([bool|null $restore = null ]) : void

Calls the Soroban RPC simulateTransaction method to get resource fees and footprint data. The simulation results are applied to the transaction, including soroban transaction data, resource fees, and authorization entries. If restore is enabled and a restore preamble is returned, it will automatically restore the footprint and re-simulate.

Parameters
$restore : bool|null = null

Whether to automatically restore expired ledger entries. If null, uses the restore setting from method options. If true, automatically handles archived entries by building and executing a RestoreFootprint transaction before re-simulating. Requires source account keypair with private key. Default: null (uses method options)

Tags
throws
Exception

If simulation fails or automatic restore is unsuccessful

throws
GuzzleException

If the RPC request fails

see
getSimulationData()

For accessing the simulation results


        
On this page

Search results