From 7dec2d601dbd849b11b2b7f1c098537a403895b9 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Mon, 10 Jun 2024 04:00:52 -0400 Subject: [PATCH 01/23] Enhanced `simulateTransaction` Documentation This update attempts to improve the documentation for the `simulateTransaction` endpoint in Soroban RPC, and a deeper look at both the RPC method and SDK methods that implement it. --- .../simulateTransaction-Deep-Dive.mdx | 486 ++++++++++++++++++ 1 file changed, 486 insertions(+) create mode 100644 docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx new file mode 100644 index 000000000..8e8a42f2f --- /dev/null +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -0,0 +1,486 @@ +## simulateTransaction Examples and Tutorials Guide + +### Table of Contents + +- [simulateTransaction Examples and Tutorials Guide](#simulatetransaction-examples-and-tutorials-guide) + - [Table of Contents](#table-of-contents) +- [Overview](#overview) +- [When to Use `simulateTransaction` (whenever you use soroban :D )](#when-to-use-simulatetransaction-whenever-you-use-soroban-d-) +- [How to Call `simulateTransaction`](#how-to-call-simulatetransaction) + - [Using Fetch](#using-fetch) + - [Using the JavaScript SDK](#using-the-javascript-sdk) +- [Understanding the Footprint](#understanding-the-footprint) +- [Assembling a Transaction](#assembling-a-transaction) + - [javascript-sdk-assembleTransaction](#javascript-sdk-assembletransaction) +- [Handling Archived Ledger Entries](#handling-archived-ledger-entries) +- [Fees and Resource Usage](#fees-and-resource-usage) +- [Preflight Error Handling](#preflight-error-handling) + - [Common Preflight Errors](#common-preflight-errors) +- [Backend Code and Workflow](#backend-code-and-workflow) +- [Further Reading](#further-reading) + +## Overview + +The `simulateTransaction` endpoint in Soroban RPC allows you to submit a trial contract invocation to simulate how it would be executed by the Stellar network. This simulation calculates the effective transaction data, required authorizations, and minimal resource fee. It provides a way to test and analyze the potential outcomes of a transaction without actually submitting it to the network. It can be a nice way to get contract data as well sometimes. + +While calling the method on the rpc server is not the ONLY way to simulate a transaction, it will likely be the most common and easiest way. + +Here we will look at the objects involved and their definitions. + +**SimulateTransactionParams** is the argument passed to the rpc endpoint for simulateTransaction + +```typescript +interface SimulateTransactionParams { + transaction: string; // The Stellar transaction to be simulated, serialized as a base64 string. + resourceConfig?: { + instructionLeeway: number; // Allow this many extra instructions when budgeting resources. + }; +} +``` + +**SimulateTransactionResult** is the return result from the call. It includes many useful things! let's take a look. + +```typescript +interface SimulateTransactionResult { + latestLedger: number; // The sequence number of the latest ledger known to Soroban RPC at the time it handled the request. + minResourceFee?: string; // Recommended minimum resource fee to add when submitting the transaction. This fee is to be added on top of the Stellar network fee. + cost?: { + cpuInsns: string; // Total CPU instructions consumed by this transaction. + memBytes: string; // Total memory bytes allocated by this transaction. + }; + results?: { + xdr: string; // Serialized base64 string - return value of the Host Function call. + auth: string[]; // Array of serialized base64 strings - Per-address authorizations recorded when simulating this Host Function call. + }[]; + transactionData?: string; // Serialized base64 string - The recommended Soroban Transaction Data to use when submitting the simulated transaction. + events?: string[]; // Array of serialized base64 strings - The events emitted during the contract invocation. + restorePreamble?: { // There is a restorePreamble if a ledgerkey or contract code is expired, and you can use the transactionData to build a new transaction. + minResourceFee: string; // Recommended minimum resource fee to add when submitting the RestoreFootprint operation. + transactionData: string; // The recommended Soroban Transaction Data to use when submitting the RestoreFootprint operation. + }; + stateChanges?: { + type: number; // Indicates if the entry was created (1), updated (2), or deleted (3). + key: string; // The LedgerKey for this delta. + before: string | null; // LedgerEntry state prior to simulation. + after: string | null; // LedgerEntry state after simulation. + }[]; + error?: string; // Details about why the invoke host function call failed. +} +``` + +## When to Use `simulateTransaction` (whenever you use soroban :D ) + +1. **Preparing `invokeHostFunctionOp` Transactions**: Anytime you need to submit an `invokeHostFunctionOp` transaction to the network. +2. **Footprint Determination**: To determine the ledger footprint, which includes all the data entries the transaction will read or write. +3. **Authorization Identification**: To identify the authorizations required for the transaction. +4. **Error Detection**: To detect potential errors and issues before actual submission, saving time and network resources. +5. **Restoring Archived Ledger Entries or Contract Code**: To prepare and restore archived data before actual transaction submission. +6. **Simulating Contract Getter Calls**: To retrieve certain data from the contract without affecting the ledger state. +7. **Resource Calculation**: To calculate the necessary resources (CPU instructions, memory, etc.) that a transaction will consume. + +## How to Call `simulateTransaction` + +### Using Fetch + +Here's an example of how to call the `simulateTransaction` endpoint directly using `fetch` in JavaScript: + +```javascript +async function simulateTransaction(transactionXDR) { + const requestBody = { + jsonrpc: "2.0", + id: 8675309, + method: "simulateTransaction", + params: { + transaction: transactionXDR, + resourceConfig: { + instructionLeeway: 50000 + } + } + }; + + const response = await fetch('https://soroban-testnet.stellar.org/simulateTransaction', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody), + }); + + const result = await response.json(); + console.log(result); +} + +// Example XDR transaction envelope +const transactionXDR = 'AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA='; // Replace with your actual XDR transaction envelope +simulateTransaction(transactionXDR); +``` + +### Using the JavaScript SDK + +The Stellar SDK provides a convenient method to simulate a transaction: + +```javascript +const StellarSdk = require('stellar-sdk'); + +// Initialize the server +const server = new StellarSdk.Server('https://soroban-testnet.stellar.org'); + +// Define the transaction +const transaction = new StellarSdk.TransactionBuilder(account, { fee: StellarSdk.BASE_FEE }) + .setNetworkPassphrase(StellarSdk.Networks.TESTNET) + .setTimeout(30) + .addOperation(StellarSdk.Operation.invokeHostFunction({ + function: 'increment' + })) + .build(); + +server.simulateTransaction(transaction).then((sim) => { + console.log('cost:', sim.cost); + console.log('result:', sim.result); + console.log('error:', sim.error); + console.log('latestLedger:', sim.latestLedger); +}); +``` + +## Understanding the Footprint + +A footprint is a set of ledger keys that the transaction will read or write. These keys are marked as either read-only or read-write: + +- **Read-Only Keys**: Available for reading only. +- **Read-Write Keys**: Available for reading and writing. + +The footprint ensures that a transaction is aware of all the ledger entries it will interact with, preventing unexpected errors during execution. + +## Assembling a Transaction + +Once you have simulated the transaction and obtained the necessary data, you can assemble the transaction for actual submission. The `assembleTransaction` function in the SDK helps with this process, but you can also call `prepareTransaction` to have it both simulate and assemble the transaction for you. + +### javascript-sdk-assembleTransaction + +Here's how the `assembleTransaction` function in the javascript sdk works to combine the raw transaction with the simulation results: + +```javascript +import { + FeeBumpTransaction, + Operation, + Transaction, + TransactionBuilder +} from '@stellar/stellar-base'; + +import { Api } from './api'; +import { parseRawSimulation } from './parsers'; + +/** + * Combines the given raw transaction alongside the simulation results. + * + * @param raw the initial transaction, w/o simulation applied + * @param simulation the Soroban RPC simulation result (see + * {@link Server.simulateTransaction}) + * + * @returns a new, cloned transaction with the proper auth and resource (fee, + * footprint) simulation data applied + * + * @note if the given transaction already has authorization entries in a host + * function invocation (see {@link Operation.invokeHostFunction}), **the + * simulation entries are ignored**. + * + * @see {Server.simulateTransaction} + * @see {Server.prepareTransaction} + */ +export function assembleTransaction( + raw: Transaction | FeeBumpTransaction, + simulation: + | Api.SimulateTransactionResponse + | Api.RawSimulateTransactionResponse +): TransactionBuilder { + if ('innerTransaction' in raw) { + // TODO: Handle feebump transactions + return assembleTransaction( + raw.innerTransaction, + simulation + ); + } + + if (!isSorobanTransaction(raw)) { + throw new TypeError( + 'unsupported transaction: must contain exactly one ' + + 'invokeHostFunction, extendFootprintTtl, or restoreFootprint ' + + 'operation' + ); + } + + let success = parseRawSimulation(simulation); + if (!Api.isSimulationSuccess(success)) { + throw new Error + +(`simulation incorrect: ${JSON.stringify(success)}`); + } + + const classicFeeNum = parseInt(raw.fee) || 0; + const minResourceFeeNum = parseInt(success.minResourceFee) || 0; + const txnBuilder = TransactionBuilder.cloneFrom(raw, { + // automatically update the tx fee that will be set on the resulting tx to + // the sum of 'classic' fee provided from incoming tx.fee and minResourceFee + // provided by simulation. + // + // 'classic' tx fees are measured as the product of tx.fee * 'number of + // operations', In soroban contract tx, there can only be single operation + // in the tx, so can make simplification of total classic fees for the + // soroban transaction will be equal to incoming tx.fee + minResourceFee. + fee: (classicFeeNum + minResourceFeeNum).toString(), + // apply the pre-built Soroban Tx Data from simulation onto the Tx + sorobanData: success.transactionData.build(), + networkPassphrase: raw.networkPassphrase + }); + + switch (raw.operations[0].type) { + case 'invokeHostFunction': + // In this case, we don't want to clone the operation, so we drop it. + txnBuilder.clearOperations(); + + const invokeOp: Operation.InvokeHostFunction = raw.operations[0]; + const existingAuth = invokeOp.auth ?? []; + txnBuilder.addOperation( + Operation.invokeHostFunction({ + source: invokeOp.source, + func: invokeOp.func, + // if auth entries are already present, we consider this "advanced + // usage" and disregard ALL auth entries from the simulation + // + // the intuition is "if auth exists, this tx has probably been + // simulated before" + auth: existingAuth.length > 0 ? existingAuth : success.result!.auth + }) + ); + break; + } + + return txnBuilder; +} + +function isSorobanTransaction(tx: Transaction): boolean { + if (tx.operations.length !== 1) { + return false; + } + + switch (tx.operations[0].type) { + case 'invokeHostFunction': + case 'extendFootprintTtl': + case 'restoreFootprint': + return true; + + default: + return false; + } +} +``` + +## Handling Archived Ledger Entries + +When a ledger entry is archived, it needs to be restored before the transaction can be submitted. This is indicated in the `restorePreamble` field of the result. + +```typescript +interface RestorePreamble { + minResourceFee: string; // Recommended minimum resource fee to add when submitting the RestoreFootprint operation. + transactionData: string; // The recommended Soroban Transaction Data to use when submitting the RestoreFootprint operation. +} +``` + +Here is an example for handling restoration using the `restorePreamble` to restore archived data: + +```typescript +/** + * Simulates a restoration transaction to determine if restoration is needed. + * This function first checks the ledger entry for the given WASM hash. If the entry is found and has expired, + * it attempts a restoration. If the entry hasn't expired yet but the TTL needs extension, it proceeds with TTL extension. + * @param wasmHash - The hash of the WASM to check. + * @param txParams - The transaction parameters including account and signer. + * @returns A promise that resolves to a simulation response, indicating whether restoration or TTL extension is needed. + */ +export async function simulateRestorationIfNeeded( + wasmHash: Buffer, + txParams: TxParams +): Promise { + try { + const account = await config.rpc.getAccount(txParams.account.accountId()); + const ledgerKey = getLedgerKeyWasmId(wasmHash); + const response = await config.rpc.getLedgerEntries(...[ledgerKey]); + if (response.entries && response.entries.length > 0 && response.entries[0].liveUntilLedgerSeq) { + const expirationLedger = response.entries[0].liveUntilLedgerSeq; + const desiredLedgerSeq = response.latestLedger + 500000; + let extendLedgers = desiredLedgerSeq - expirationLedger; + if (extendLedgers < 10000) { + extendLedgers = 10000; + } + console.log('Expiration:', expirationLedger); + console.log('Desired TTL:', desiredLedgerSeq); + const sorobanData = new SorobanDataBuilder().setReadWrite([ledgerKey]).build(); + const restoreTx = new TransactionBuilder(account, txParams.txBuilderOptions) + .setSorobanData(sorobanData) + .addOperation(Operation.restoreFootprint({})) // The actual restore operation + .build(); + // Simulate a transaction with a restoration operation to check if it's necessary + + const restorationSimulation: SorobanRpc.Api.SimulateTransactionResponse = + await config.rpc.simulateTransaction(restoreTx); + const restoreNeeded = SorobanRpc.Api.isSimulationRestore(restorationSimulation); + const resSimSuccess = SorobanRpc.Api.isSimulationSuccess(restorationSimulation); + console.log(`restoration needed: ${restoreNeeded}\nSimulation Success: ${resSimSuccess}`); + // Check if the simulation indicates a need for restoration + if (restoreNeeded) { + return restorationSimulation as SorobanRpc.Api.SimulateTransactionRestoreResponse; + } else { + console.log('No restoration needed., bumping the ttl.'); + const account1 = await config.rpc.getAccount(txParams.account.accountId()); + + const bumpTTLtx = new TransactionBuilder(account1, txParams.txBuilderOptions) + .setSorobanData(new SorobanDataBuilder().setReadWrite([ledgerKey]).build()) + .addOperation( + Operation.extendFootprintTtl({ + extendTo: desiredLedgerSeq, + }) + ) // The actual TTL extension operation + .build(); + const ttlSimResponse: SorobanRpc.Api.SimulateTransactionResponse = + await config.rpc.simulateTransaction(bumpTTLtx); + const assembledTx = SorobanRpc.assembleTransaction(bumpTTLtx, ttlSimResponse).build(); + const signedTx = new Transaction( + await txParams.signerFunction(assembledTx.toXDR()), + config.passphrase + ); + // submit the assembled and signed transaction to bump it. + try { + const response = await sendTransaction(signedTx, (result) => { + console.log(`bump ttl for contract result: ${result}`); + return result; + }); + return response; + } catch (error) { + console.error('Transaction submission failed with error:', error); + throw error; + } + } + } else { + console.log('No ledger entry found for the given WASM hash.'); + } + } catch (error) { + console.error('Failed to simulate restoration:', error); + throw error; + } + return undefined; +} + +/** + * Handles the restoration of a Soroban contract. + * @param {SorobanRpc.Api.SimulateTransactionRestoreResponse} simResponse - The simulation response containing restoration information. + * @param {TxParams} txParams - The transaction parameters. + * @returns {Promise} A promise that resolves when the restoration transaction has been submitted. + */ +export async function handleRestoration( + simResponse: SorobanRpc.Api.SimulateTransactionRestoreResponse, + txParams: TxParams +): Promise { + const restorePreamble = simResponse.restorePreamble; + console.log('Restoring for account:', txParams.account.accountId()); + const account = await config.rpc.getAccount(txParams.account.accountId()); + // Construct the transaction builder with the necessary parameters + const restoreTx = new TransactionBuilder(account, { + ...txParams.txBuilderOptions, + fee: restorePreamble.minResourceFee, // Update fee based on the restoration requirement + }) + .setSorobanData(restorePreamble.transactionData.build()) // Set Soroban Data from the simulation + .addOperation(Operation.restoreFootprint({})) // Add the RestoreFootprint operation + .build(); // Build the transaction + + const simulation: SorobanRpc.Api.SimulateTransactionResponse = + await config.rpc.simulateTransaction(restoreTx); + const assembledTx = SorobanRpc.assembleTransaction(restoreTx, simulation).build(); + + const signedTx = new Transaction( + await txParams.signerFunction(assembledTx.toXDR()), + config.passphrase + ); + + console.log('Submitting restoration transaction'); + + try { + // Submit the transaction to the network + const response = await config.rpc.sendTransaction(signedTx); + console.log('Restoration transaction submitted successfully:', response.hash); + } catch (error) { + console.error('Failed to submit restoration transaction:', error); + throw new Error('Restoration transaction failed'); + } +} + +import { + Account, + Keypair, + Operation, + SorobanDataBuilder, + SorobanRpc, + TimeoutInfinite, + Transaction, + TransactionBuilder, + scValToNative, + xdr, +} from '@stellar/stellar-sdk'; +``` + +## Fees and Resource Usage + +Soroban smart contracts on Stellar use a multidimensional resource fee model, charging fees for several resource types: + +1. **CPU Instructions**: Number of CPU instructions the transaction uses. +2. **Ledger Entry Accesses**: Reading or writing any single ledger entry. +3. **Ledger I/O**: Number of bytes read from or written to the ledger. +4. **Transaction Size**: Size of the transaction submitted to the network in bytes. +5. **Events & Return Value Size**: Size of the events produced by the contract and the return value of the top-level contract function. +6. **Ledger Space Rent**: Payment for ledger entry TTL extensions and rent payments for increasing ledger entry size. + +Fees are calculated based on the resource consumption declared in the + + transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. + +## Preflight Error Handling + +The preflight mechanism provides an estimation of CPU and memory consumption in a transaction. It helps identify potential errors and resource limitations before actual submission. Errors returned by the host are propagated through RPC and do not cover network errors or errors in RPC itself. + +### Common Preflight Errors + +- **HostError(Budget, LimitExceeded)**: Network-defined resource limit exceeded. Optimize the contract to consume fewer resources. +- **HostError(Storage, MissingValue)**: Trying to access a non-existent ledger entry. Deploy the respective contract or Wasm. +- **HostError(WasmVm, InvalidAction)**: Failure in a Wasm contract, typically a panic. Fix the contract logic or invocation arguments. + +## Backend Code and Workflow + +The `simulateTransaction` endpoint leverages various backend components to simulate the execution of a transaction. Here is a brief explanation of how it works: + +1. **Invocation of Simulation**: + - The simulation is initiated by calling `simulate_invoke_host_function_op` which takes in parameters such as the transaction to be simulated, resource configuration, and other necessary details. + +2. **Snapshot Source and Network Configuration**: + - The simulation utilizes a snapshot source (`MockSnapshotSource`) and network configuration (`NetworkConfig`) to mimic the state of the ledger and network conditions. + +3. **Resource Calculation**: + - The function `simulate_invoke_host_function_op_resources` computes the resources (CPU instructions, memory bytes) required for the transaction by analyzing ledger changes. + +4. **Execution and Result Handling**: + - The core of the execution is handled by `invoke_host_function_in_recording_mode`, which records the transaction's impact on the ledger. + - The results are then processed, including any required authorizations, emitted events, and transaction data. + +5. **Adjustments and Fees**: + - Adjustments to resource usage and fees are made based on predefined configurations (`SimulationAdjustmentConfig`), ensuring accurate fee estimation. + +These functions are defined in the [`rs-soroban-env`](https://github.com/stellar/rs-soroban-env) and also in a [`soroban-simulation`](https://github.com/stellar/rs-soroban-env/tree/main/soroban-simulation) [crate](https://crates.io/crates/soroban-simulation) and handle the core logic for simulating transactions. + + +## Further Reading + +For more information and examples, check out the code and other documentation: + +- [openRpc Documentation](https://developers.stellar.org/network/soroban-rpc/api-reference/methods/simulateTransaction) +- [openRpc json Specification](https://github.com/stellar/stellar-docs/blob/main/static/openrpc.json) +- [preflight.go](https://github.com/stellar/soroban-rpc/blob/release/v21.0.0/cmd/soroban-rpc/internal/preflight/preflight.go) +- [Soroban Example Code](https://github.com/stellar/soroban-examples) +- [Stellar SDK Documentation](https://stellar.github.io/js-stellar-sdk/) From cde33135c5fabf14c9ab1fa075f8c8a916770157 Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Mon, 10 Jun 2024 12:41:17 -0400 Subject: [PATCH 02/23] format mdx --- .../simulateTransaction-Deep-Dive.mdx | 157 +++++++++++------- 1 file changed, 101 insertions(+), 56 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 8e8a42f2f..cb8d3ac99 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -21,7 +21,7 @@ ## Overview -The `simulateTransaction` endpoint in Soroban RPC allows you to submit a trial contract invocation to simulate how it would be executed by the Stellar network. This simulation calculates the effective transaction data, required authorizations, and minimal resource fee. It provides a way to test and analyze the potential outcomes of a transaction without actually submitting it to the network. It can be a nice way to get contract data as well sometimes. +The `simulateTransaction` endpoint in Soroban RPC allows you to submit a trial contract invocation to simulate how it would be executed by the Stellar network. This simulation calculates the effective transaction data, required authorizations, and minimal resource fee. It provides a way to test and analyze the potential outcomes of a transaction without actually submitting it to the network. It can be a nice way to get contract data as well sometimes. While calling the method on the rpc server is not the ONLY way to simulate a transaction, it will likely be the most common and easiest way. @@ -38,7 +38,7 @@ interface SimulateTransactionParams { } ``` -**SimulateTransactionResult** is the return result from the call. It includes many useful things! let's take a look. +**SimulateTransactionResult** is the return result from the call. It includes many useful things! let's take a look. ```typescript interface SimulateTransactionResult { @@ -54,7 +54,8 @@ interface SimulateTransactionResult { }[]; transactionData?: string; // Serialized base64 string - The recommended Soroban Transaction Data to use when submitting the simulated transaction. events?: string[]; // Array of serialized base64 strings - The events emitted during the contract invocation. - restorePreamble?: { // There is a restorePreamble if a ledgerkey or contract code is expired, and you can use the transactionData to build a new transaction. + restorePreamble?: { + // There is a restorePreamble if a ledgerkey or contract code is expired, and you can use the transactionData to build a new transaction. minResourceFee: string; // Recommended minimum resource fee to add when submitting the RestoreFootprint operation. transactionData: string; // The recommended Soroban Transaction Data to use when submitting the RestoreFootprint operation. }; @@ -93,25 +94,29 @@ async function simulateTransaction(transactionXDR) { params: { transaction: transactionXDR, resourceConfig: { - instructionLeeway: 50000 - } - } + instructionLeeway: 50000, + }, + }, }; - const response = await fetch('https://soroban-testnet.stellar.org/simulateTransaction', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + "https://soroban-testnet.stellar.org/simulateTransaction", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(requestBody), }, - body: JSON.stringify(requestBody), - }); + ); const result = await response.json(); console.log(result); } // Example XDR transaction envelope -const transactionXDR = 'AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA='; // Replace with your actual XDR transaction envelope +const transactionXDR = + "AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA="; // Replace with your actual XDR transaction envelope simulateTransaction(transactionXDR); ``` @@ -120,25 +125,29 @@ simulateTransaction(transactionXDR); The Stellar SDK provides a convenient method to simulate a transaction: ```javascript -const StellarSdk = require('stellar-sdk'); +const StellarSdk = require("stellar-sdk"); // Initialize the server -const server = new StellarSdk.Server('https://soroban-testnet.stellar.org'); +const server = new StellarSdk.Server("https://soroban-testnet.stellar.org"); // Define the transaction -const transaction = new StellarSdk.TransactionBuilder(account, { fee: StellarSdk.BASE_FEE }) +const transaction = new StellarSdk.TransactionBuilder(account, { + fee: StellarSdk.BASE_FEE, +}) .setNetworkPassphrase(StellarSdk.Networks.TESTNET) .setTimeout(30) - .addOperation(StellarSdk.Operation.invokeHostFunction({ - function: 'increment' - })) + .addOperation( + StellarSdk.Operation.invokeHostFunction({ + function: "increment", + }), + ) .build(); server.simulateTransaction(transaction).then((sim) => { - console.log('cost:', sim.cost); - console.log('result:', sim.result); - console.log('error:', sim.error); - console.log('latestLedger:', sim.latestLedger); + console.log("cost:", sim.cost); + console.log("result:", sim.result); + console.log("error:", sim.error); + console.log("latestLedger:", sim.latestLedger); }); ``` @@ -299,23 +308,34 @@ Here is an example for handling restoration using the `restorePreamble` to resto */ export async function simulateRestorationIfNeeded( wasmHash: Buffer, - txParams: TxParams -): Promise { + txParams: TxParams, +): Promise< + SorobanRpc.Api.SimulateTransactionRestoreResponse | string | undefined +> { try { const account = await config.rpc.getAccount(txParams.account.accountId()); const ledgerKey = getLedgerKeyWasmId(wasmHash); const response = await config.rpc.getLedgerEntries(...[ledgerKey]); - if (response.entries && response.entries.length > 0 && response.entries[0].liveUntilLedgerSeq) { + if ( + response.entries && + response.entries.length > 0 && + response.entries[0].liveUntilLedgerSeq + ) { const expirationLedger = response.entries[0].liveUntilLedgerSeq; const desiredLedgerSeq = response.latestLedger + 500000; let extendLedgers = desiredLedgerSeq - expirationLedger; if (extendLedgers < 10000) { extendLedgers = 10000; } - console.log('Expiration:', expirationLedger); - console.log('Desired TTL:', desiredLedgerSeq); - const sorobanData = new SorobanDataBuilder().setReadWrite([ledgerKey]).build(); - const restoreTx = new TransactionBuilder(account, txParams.txBuilderOptions) + console.log("Expiration:", expirationLedger); + console.log("Desired TTL:", desiredLedgerSeq); + const sorobanData = new SorobanDataBuilder() + .setReadWrite([ledgerKey]) + .build(); + const restoreTx = new TransactionBuilder( + account, + txParams.txBuilderOptions, + ) .setSorobanData(sorobanData) .addOperation(Operation.restoreFootprint({})) // The actual restore operation .build(); @@ -323,30 +343,46 @@ export async function simulateRestorationIfNeeded( const restorationSimulation: SorobanRpc.Api.SimulateTransactionResponse = await config.rpc.simulateTransaction(restoreTx); - const restoreNeeded = SorobanRpc.Api.isSimulationRestore(restorationSimulation); - const resSimSuccess = SorobanRpc.Api.isSimulationSuccess(restorationSimulation); - console.log(`restoration needed: ${restoreNeeded}\nSimulation Success: ${resSimSuccess}`); + const restoreNeeded = SorobanRpc.Api.isSimulationRestore( + restorationSimulation, + ); + const resSimSuccess = SorobanRpc.Api.isSimulationSuccess( + restorationSimulation, + ); + console.log( + `restoration needed: ${restoreNeeded}\nSimulation Success: ${resSimSuccess}`, + ); // Check if the simulation indicates a need for restoration if (restoreNeeded) { return restorationSimulation as SorobanRpc.Api.SimulateTransactionRestoreResponse; } else { - console.log('No restoration needed., bumping the ttl.'); - const account1 = await config.rpc.getAccount(txParams.account.accountId()); + console.log("No restoration needed., bumping the ttl."); + const account1 = await config.rpc.getAccount( + txParams.account.accountId(), + ); - const bumpTTLtx = new TransactionBuilder(account1, txParams.txBuilderOptions) - .setSorobanData(new SorobanDataBuilder().setReadWrite([ledgerKey]).build()) + const bumpTTLtx = new TransactionBuilder( + account1, + txParams.txBuilderOptions, + ) + .setSorobanData( + new SorobanDataBuilder().setReadWrite([ledgerKey]).build(), + ) .addOperation( Operation.extendFootprintTtl({ extendTo: desiredLedgerSeq, - }) + }), ) // The actual TTL extension operation .build(); const ttlSimResponse: SorobanRpc.Api.SimulateTransactionResponse = await config.rpc.simulateTransaction(bumpTTLtx); - const assembledTx = SorobanRpc.assembleTransaction(bumpTTLtx, ttlSimResponse).build(); + const assembledTx = SorobanRpc.assembleTransaction( + bumpTTLtx, + ttlSimResponse, + ).build(); const signedTx = new Transaction( await txParams.signerFunction(assembledTx.toXDR()), - config.passphrase + config.passphrase, ); // submit the assembled and signed transaction to bump it. try { @@ -356,15 +392,15 @@ export async function simulateRestorationIfNeeded( }); return response; } catch (error) { - console.error('Transaction submission failed with error:', error); + console.error("Transaction submission failed with error:", error); throw error; } } } else { - console.log('No ledger entry found for the given WASM hash.'); + console.log("No ledger entry found for the given WASM hash."); } } catch (error) { - console.error('Failed to simulate restoration:', error); + console.error("Failed to simulate restoration:", error); throw error; } return undefined; @@ -378,10 +414,10 @@ export async function simulateRestorationIfNeeded( */ export async function handleRestoration( simResponse: SorobanRpc.Api.SimulateTransactionRestoreResponse, - txParams: TxParams + txParams: TxParams, ): Promise { const restorePreamble = simResponse.restorePreamble; - console.log('Restoring for account:', txParams.account.accountId()); + console.log("Restoring for account:", txParams.account.accountId()); const account = await config.rpc.getAccount(txParams.account.accountId()); // Construct the transaction builder with the necessary parameters const restoreTx = new TransactionBuilder(account, { @@ -394,22 +430,28 @@ export async function handleRestoration( const simulation: SorobanRpc.Api.SimulateTransactionResponse = await config.rpc.simulateTransaction(restoreTx); - const assembledTx = SorobanRpc.assembleTransaction(restoreTx, simulation).build(); + const assembledTx = SorobanRpc.assembleTransaction( + restoreTx, + simulation, + ).build(); const signedTx = new Transaction( await txParams.signerFunction(assembledTx.toXDR()), - config.passphrase + config.passphrase, ); - console.log('Submitting restoration transaction'); + console.log("Submitting restoration transaction"); try { // Submit the transaction to the network const response = await config.rpc.sendTransaction(signedTx); - console.log('Restoration transaction submitted successfully:', response.hash); + console.log( + "Restoration transaction submitted successfully:", + response.hash, + ); } catch (error) { - console.error('Failed to submit restoration transaction:', error); - throw new Error('Restoration transaction failed'); + console.error("Failed to submit restoration transaction:", error); + throw new Error("Restoration transaction failed"); } } @@ -421,10 +463,10 @@ import { SorobanRpc, TimeoutInfinite, Transaction, - TransactionBuilder, + TransactionBuilder, scValToNative, - xdr, -} from '@stellar/stellar-sdk'; + xdr, +} from "@stellar/stellar-sdk"; ``` ## Fees and Resource Usage @@ -440,7 +482,7 @@ Soroban smart contracts on Stellar use a multidimensional resource fee model, ch Fees are calculated based on the resource consumption declared in the - transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. +transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. ## Preflight Error Handling @@ -457,15 +499,19 @@ The preflight mechanism provides an estimation of CPU and memory consumption in The `simulateTransaction` endpoint leverages various backend components to simulate the execution of a transaction. Here is a brief explanation of how it works: 1. **Invocation of Simulation**: + - The simulation is initiated by calling `simulate_invoke_host_function_op` which takes in parameters such as the transaction to be simulated, resource configuration, and other necessary details. 2. **Snapshot Source and Network Configuration**: + - The simulation utilizes a snapshot source (`MockSnapshotSource`) and network configuration (`NetworkConfig`) to mimic the state of the ledger and network conditions. 3. **Resource Calculation**: + - The function `simulate_invoke_host_function_op_resources` computes the resources (CPU instructions, memory bytes) required for the transaction by analyzing ledger changes. 4. **Execution and Result Handling**: + - The core of the execution is handled by `invoke_host_function_in_recording_mode`, which records the transaction's impact on the ledger. - The results are then processed, including any required authorizations, emitted events, and transaction data. @@ -474,7 +520,6 @@ The `simulateTransaction` endpoint leverages various backend components to simul These functions are defined in the [`rs-soroban-env`](https://github.com/stellar/rs-soroban-env) and also in a [`soroban-simulation`](https://github.com/stellar/rs-soroban-env/tree/main/soroban-simulation) [crate](https://crates.io/crates/soroban-simulation) and handle the core logic for simulating transactions. - ## Further Reading For more information and examples, check out the code and other documentation: From e415d96362b0982525e40a90f442597126f7696f Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:43:17 -0400 Subject: [PATCH 03/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: George --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index cb8d3ac99..e50104b91 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -480,9 +480,7 @@ Soroban smart contracts on Stellar use a multidimensional resource fee model, ch 5. **Events & Return Value Size**: Size of the events produced by the contract and the return value of the top-level contract function. 6. **Ledger Space Rent**: Payment for ledger entry TTL extensions and rent payments for increasing ledger entry size. -Fees are calculated based on the resource consumption declared in the - -transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. +Fees are calculated based on the resource consumption declared in the transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. ## Preflight Error Handling From 288b9534c20c454039e033909bab94938e1ff1c2 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:43:37 -0400 Subject: [PATCH 04/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: George --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index e50104b91..79443dacc 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -488,7 +488,7 @@ The preflight mechanism provides an estimation of CPU and memory consumption in ### Common Preflight Errors -- **HostError(Budget, LimitExceeded)**: Network-defined resource limit exceeded. Optimize the contract to consume fewer resources. +- **HostError(Budget, LimitExceeded)**: A network-defined resource limit was exceeded: optimize the contract to consume fewer resources. - **HostError(Storage, MissingValue)**: Trying to access a non-existent ledger entry. Deploy the respective contract or Wasm. - **HostError(WasmVm, InvalidAction)**: Failure in a Wasm contract, typically a panic. Fix the contract logic or invocation arguments. From d1e3dcc1286a86fa34f0f5d7ad3824d3955fa876 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:43:45 -0400 Subject: [PATCH 05/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: George --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 79443dacc..178a4273f 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -403,7 +403,6 @@ export async function simulateRestorationIfNeeded( console.error("Failed to simulate restoration:", error); throw error; } - return undefined; } /** From edb1154ded3ba6adcea893c1f33b68c7949efc1a Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Tue, 18 Jun 2024 02:03:45 -0400 Subject: [PATCH 06/23] resolve some issues --- .../simulateTransaction-Deep-Dive.mdx | 163 ++---------------- 1 file changed, 10 insertions(+), 153 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 178a4273f..e694cadaf 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -38,38 +38,9 @@ interface SimulateTransactionParams { } ``` -**SimulateTransactionResult** is the return result from the call. It includes many useful things! let's take a look. +**SimulateTransactionResult** is the return result from the call. It includes many useful things! (take a look at the code here!)[https://github.com/stellar/stellar-docs/blob/88eeb4a318778513880e01fe9728c4cbbc73b87c/openrpc/src/methods/simulateTransaction.json#L18]. -```typescript -interface SimulateTransactionResult { - latestLedger: number; // The sequence number of the latest ledger known to Soroban RPC at the time it handled the request. - minResourceFee?: string; // Recommended minimum resource fee to add when submitting the transaction. This fee is to be added on top of the Stellar network fee. - cost?: { - cpuInsns: string; // Total CPU instructions consumed by this transaction. - memBytes: string; // Total memory bytes allocated by this transaction. - }; - results?: { - xdr: string; // Serialized base64 string - return value of the Host Function call. - auth: string[]; // Array of serialized base64 strings - Per-address authorizations recorded when simulating this Host Function call. - }[]; - transactionData?: string; // Serialized base64 string - The recommended Soroban Transaction Data to use when submitting the simulated transaction. - events?: string[]; // Array of serialized base64 strings - The events emitted during the contract invocation. - restorePreamble?: { - // There is a restorePreamble if a ledgerkey or contract code is expired, and you can use the transactionData to build a new transaction. - minResourceFee: string; // Recommended minimum resource fee to add when submitting the RestoreFootprint operation. - transactionData: string; // The recommended Soroban Transaction Data to use when submitting the RestoreFootprint operation. - }; - stateChanges?: { - type: number; // Indicates if the entry was created (1), updated (2), or deleted (3). - key: string; // The LedgerKey for this delta. - before: string | null; // LedgerEntry state prior to simulation. - after: string | null; // LedgerEntry state after simulation. - }[]; - error?: string; // Details about why the invoke host function call failed. -} -``` - -## When to Use `simulateTransaction` (whenever you use soroban :D ) +## When to Use `simulateTransaction` (whenever you use soroban :D) 1. **Preparing `invokeHostFunctionOp` Transactions**: Anytime you need to submit an `invokeHostFunctionOp` transaction to the network. 2. **Footprint Determination**: To determine the ledger footprint, which includes all the data entries the transaction will read or write. @@ -164,125 +135,9 @@ The footprint ensures that a transaction is aware of all the ledger entries it w Once you have simulated the transaction and obtained the necessary data, you can assemble the transaction for actual submission. The `assembleTransaction` function in the SDK helps with this process, but you can also call `prepareTransaction` to have it both simulate and assemble the transaction for you. -### javascript-sdk-assembleTransaction - -Here's how the `assembleTransaction` function in the javascript sdk works to combine the raw transaction with the simulation results: - -```javascript -import { - FeeBumpTransaction, - Operation, - Transaction, - TransactionBuilder -} from '@stellar/stellar-base'; - -import { Api } from './api'; -import { parseRawSimulation } from './parsers'; - -/** - * Combines the given raw transaction alongside the simulation results. - * - * @param raw the initial transaction, w/o simulation applied - * @param simulation the Soroban RPC simulation result (see - * {@link Server.simulateTransaction}) - * - * @returns a new, cloned transaction with the proper auth and resource (fee, - * footprint) simulation data applied - * - * @note if the given transaction already has authorization entries in a host - * function invocation (see {@link Operation.invokeHostFunction}), **the - * simulation entries are ignored**. - * - * @see {Server.simulateTransaction} - * @see {Server.prepareTransaction} - */ -export function assembleTransaction( - raw: Transaction | FeeBumpTransaction, - simulation: - | Api.SimulateTransactionResponse - | Api.RawSimulateTransactionResponse -): TransactionBuilder { - if ('innerTransaction' in raw) { - // TODO: Handle feebump transactions - return assembleTransaction( - raw.innerTransaction, - simulation - ); - } +### js-stellar-sdk `assembleTransaction ` - if (!isSorobanTransaction(raw)) { - throw new TypeError( - 'unsupported transaction: must contain exactly one ' + - 'invokeHostFunction, extendFootprintTtl, or restoreFootprint ' + - 'operation' - ); - } - - let success = parseRawSimulation(simulation); - if (!Api.isSimulationSuccess(success)) { - throw new Error - -(`simulation incorrect: ${JSON.stringify(success)}`); - } - - const classicFeeNum = parseInt(raw.fee) || 0; - const minResourceFeeNum = parseInt(success.minResourceFee) || 0; - const txnBuilder = TransactionBuilder.cloneFrom(raw, { - // automatically update the tx fee that will be set on the resulting tx to - // the sum of 'classic' fee provided from incoming tx.fee and minResourceFee - // provided by simulation. - // - // 'classic' tx fees are measured as the product of tx.fee * 'number of - // operations', In soroban contract tx, there can only be single operation - // in the tx, so can make simplification of total classic fees for the - // soroban transaction will be equal to incoming tx.fee + minResourceFee. - fee: (classicFeeNum + minResourceFeeNum).toString(), - // apply the pre-built Soroban Tx Data from simulation onto the Tx - sorobanData: success.transactionData.build(), - networkPassphrase: raw.networkPassphrase - }); - - switch (raw.operations[0].type) { - case 'invokeHostFunction': - // In this case, we don't want to clone the operation, so we drop it. - txnBuilder.clearOperations(); - - const invokeOp: Operation.InvokeHostFunction = raw.operations[0]; - const existingAuth = invokeOp.auth ?? []; - txnBuilder.addOperation( - Operation.invokeHostFunction({ - source: invokeOp.source, - func: invokeOp.func, - // if auth entries are already present, we consider this "advanced - // usage" and disregard ALL auth entries from the simulation - // - // the intuition is "if auth exists, this tx has probably been - // simulated before" - auth: existingAuth.length > 0 ? existingAuth : success.result!.auth - }) - ); - break; - } - - return txnBuilder; -} - -function isSorobanTransaction(tx: Transaction): boolean { - if (tx.operations.length !== 1) { - return false; - } - - switch (tx.operations[0].type) { - case 'invokeHostFunction': - case 'extendFootprintTtl': - case 'restoreFootprint': - return true; - - default: - return false; - } -} -``` +Using the javascript SDK we can call (`assembleTransaction`)[https://github.com/stellar/js-stellar-sdk/blob/master/src/rpc/transaction.ts#L28] to easily assemble a transaction. ## Handling Archived Ledger Entries @@ -302,19 +157,21 @@ Here is an example for handling restoration using the `restorePreamble` to resto * Simulates a restoration transaction to determine if restoration is needed. * This function first checks the ledger entry for the given WASM hash. If the entry is found and has expired, * it attempts a restoration. If the entry hasn't expired yet but the TTL needs extension, it proceeds with TTL extension. - * @param wasmHash - The hash of the WASM to check. + * @param contract - The address of the contract to check * @param txParams - The transaction parameters including account and signer. * @returns A promise that resolves to a simulation response, indicating whether restoration or TTL extension is needed. */ export async function simulateRestorationIfNeeded( - wasmHash: Buffer, + contract: ContractAddress, txParams: TxParams, ): Promise< SorobanRpc.Api.SimulateTransactionRestoreResponse | string | undefined > { try { const account = await config.rpc.getAccount(txParams.account.accountId()); - const ledgerKey = getLedgerKeyWasmId(wasmHash); + const contract = new Contract(contract); + //const ledgerKey = getLedgerKeyWasmId(wasmHash); + const ledgerKey = contract.getFootprint(); const response = await config.rpc.getLedgerEntries(...[ledgerKey]); if ( response.entries && @@ -479,7 +336,7 @@ Soroban smart contracts on Stellar use a multidimensional resource fee model, ch 5. **Events & Return Value Size**: Size of the events produced by the contract and the return value of the top-level contract function. 6. **Ledger Space Rent**: Payment for ledger entry TTL extensions and rent payments for increasing ledger entry size. -Fees are calculated based on the resource consumption declared in the transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. +Fees are calculated based on the resource consumption declared in the transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. (Check out this document for a more in depth understanding of fees and metering.)[https://developers.stellar.org/docs/learn/fundamentals/fees-resource-limits-metering] ## Preflight Error Handling From e862a9e403382c0bd188a8597441094fe89b336c Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:04:25 -0400 Subject: [PATCH 07/23] resolve issue --- .../transactions/simulateTransaction-Deep-Dive.mdx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index e694cadaf..491128035 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -200,15 +200,12 @@ export async function simulateRestorationIfNeeded( const restorationSimulation: SorobanRpc.Api.SimulateTransactionResponse = await config.rpc.simulateTransaction(restoreTx); + + //check if restore is necessary. this code also checks if the simulation was successful. const restoreNeeded = SorobanRpc.Api.isSimulationRestore( restorationSimulation, ); - const resSimSuccess = SorobanRpc.Api.isSimulationSuccess( - restorationSimulation, - ); - console.log( - `restoration needed: ${restoreNeeded}\nSimulation Success: ${resSimSuccess}`, - ); + console.log(`restoration needed: ${restoreNeeded}`); // Check if the simulation indicates a need for restoration if (restoreNeeded) { return restorationSimulation as SorobanRpc.Api.SimulateTransactionRestoreResponse; From 9b321484fd1d6b167da5a369cdf751e96ab6f078 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:49:12 -0400 Subject: [PATCH 08/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 491128035..f10251735 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -38,7 +38,7 @@ interface SimulateTransactionParams { } ``` -**SimulateTransactionResult** is the return result from the call. It includes many useful things! (take a look at the code here!)[https://github.com/stellar/stellar-docs/blob/88eeb4a318778513880e01fe9728c4cbbc73b87c/openrpc/src/methods/simulateTransaction.json#L18]. +**SimulateTransactionResult** is the return result from the call. It includes many useful things! [take a look at the code here!](https://github.com/stellar/stellar-docs/blob/88eeb4a318778513880e01fe9728c4cbbc73b87c/openrpc/src/methods/simulateTransaction.json#L18). ## When to Use `simulateTransaction` (whenever you use soroban :D) From 3829c78dc2e35279ae778db428c2e5c16db79196 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:49:23 -0400 Subject: [PATCH 09/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index f10251735..0b02f07ee 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -137,7 +137,7 @@ Once you have simulated the transaction and obtained the necessary data, you can ### js-stellar-sdk `assembleTransaction ` -Using the javascript SDK we can call (`assembleTransaction`)[https://github.com/stellar/js-stellar-sdk/blob/master/src/rpc/transaction.ts#L28] to easily assemble a transaction. +Using the javascript SDK we can call [`assembleTransaction`](https://github.com/stellar/js-stellar-sdk/blob/master/src/rpc/transaction.ts#L28) to easily assemble a transaction. ## Handling Archived Ledger Entries From 20b56fc193e7848919ceda64a5fe58658b4c6f13 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:49:34 -0400 Subject: [PATCH 10/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 0b02f07ee..e90b28c17 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -333,7 +333,7 @@ Soroban smart contracts on Stellar use a multidimensional resource fee model, ch 5. **Events & Return Value Size**: Size of the events produced by the contract and the return value of the top-level contract function. 6. **Ledger Space Rent**: Payment for ledger entry TTL extensions and rent payments for increasing ledger entry size. -Fees are calculated based on the resource consumption declared in the transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. (Check out this document for a more in depth understanding of fees and metering.)[https://developers.stellar.org/docs/learn/fundamentals/fees-resource-limits-metering] +Fees are calculated based on the resource consumption declared in the transaction. Refundable fees are charged before execution and refunded based on actual usage, while non-refundable fees are calculated from CPU instructions, read bytes, write bytes, and transaction size. [Check out this document for a more in depth understanding of fees and metering.](https://developers.stellar.org/docs/learn/fundamentals/fees-resource-limits-metering) ## Preflight Error Handling From b4daf4fc817830d2b0c48dbd65219e464f1846ec Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:49:44 -0400 Subject: [PATCH 11/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index e90b28c17..d844549f4 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -71,7 +71,7 @@ async function simulateTransaction(transactionXDR) { }; const response = await fetch( - "https://soroban-testnet.stellar.org/simulateTransaction", + "https://soroban-testnet.stellar.org:443", { method: "POST", headers: { From 452d88d36d8a932e21e675d3656a785e10c99543 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:49:55 -0400 Subject: [PATCH 12/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index d844549f4..671192211 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -86,6 +86,7 @@ async function simulateTransaction(transactionXDR) { } // Example XDR transaction envelope +// Replace the following placeholder with your actual XDR transaction envelope const transactionXDR = "AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA="; // Replace with your actual XDR transaction envelope simulateTransaction(transactionXDR); From 9ab3454700d3329ab343a1a932b9507043a31f2f Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:50:00 -0400 Subject: [PATCH 13/23] Update docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 671192211..fc163137a 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -88,7 +88,7 @@ async function simulateTransaction(transactionXDR) { // Example XDR transaction envelope // Replace the following placeholder with your actual XDR transaction envelope const transactionXDR = - "AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA="; // Replace with your actual XDR transaction envelope + "AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA="; simulateTransaction(transactionXDR); ``` From be66ae7f52158cba4c2a07f058a9855ad2dd594b Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:59:15 -0400 Subject: [PATCH 14/23] add rpc server links and fix js --- .../simulateTransaction-Deep-Dive.mdx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index fc163137a..de19fa5af 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -27,6 +27,20 @@ While calling the method on the rpc server is not the ONLY way to simulate a tra Here we will look at the objects involved and their definitions. +## RPC Servers + +Stellar Development Foundation provides a testnet RPC endpoint at +For Public network providers please refer to the [Ecosystem RPC Providers] list. +At the time of writing this documentation there are two public and free RPC providers, and many more you can subscribe to. + +### Public Network Endpoints: +[Liquify](https://www.liquify.com) +https://stellar-mainnet.liquify.com/api=41EEWAH79Y5OCGI7/mainnet +[Gateway.fm](https://www.gateway.fm) +https://soroban-rpc.mainnet.stellar.gateway.fm +### Testnet Endpoint: +https://soroban-testnet.stellar.org:443 + **SimulateTransactionParams** is the argument passed to the rpc endpoint for simulateTransaction ```typescript @@ -109,7 +123,7 @@ const transaction = new StellarSdk.TransactionBuilder(account, { .setNetworkPassphrase(StellarSdk.Networks.TESTNET) .setTimeout(30) .addOperation( - StellarSdk.Operation.invokeHostFunction({ + StellarSdk.Operation.invokeContractFunction({ function: "increment", }), ) From 3b819472633dffb6a99a138b3af42bf7e8074909 Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Fri, 21 Jun 2024 14:09:16 -0400 Subject: [PATCH 15/23] Fix js example --- .../simulateTransaction-Deep-Dive.mdx | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index de19fa5af..7053a1471 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -29,16 +29,14 @@ Here we will look at the objects involved and their definitions. ## RPC Servers -Stellar Development Foundation provides a testnet RPC endpoint at -For Public network providers please refer to the [Ecosystem RPC Providers] list. -At the time of writing this documentation there are two public and free RPC providers, and many more you can subscribe to. +Stellar Development Foundation provides a testnet RPC endpoint at For Public network providers please refer to the [Ecosystem RPC Providers] list. At the time of writing this documentation there are two public and free RPC providers, and many more you can subscribe to. ### Public Network Endpoints: -[Liquify](https://www.liquify.com) -https://stellar-mainnet.liquify.com/api=41EEWAH79Y5OCGI7/mainnet -[Gateway.fm](https://www.gateway.fm) -https://soroban-rpc.mainnet.stellar.gateway.fm + +[Liquify](https://www.liquify.com) https://stellar-mainnet.liquify.com/api=41EEWAH79Y5OCGI7/mainnet [Gateway.fm](https://www.gateway.fm) https://soroban-rpc.mainnet.stellar.gateway.fm + ### Testnet Endpoint: + https://soroban-testnet.stellar.org:443 **SimulateTransactionParams** is the argument passed to the rpc endpoint for simulateTransaction @@ -84,16 +82,13 @@ async function simulateTransaction(transactionXDR) { }, }; - const response = await fetch( - "https://soroban-testnet.stellar.org:443", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(requestBody), + const response = await fetch("https://soroban-testnet.stellar.org:443", { + method: "POST", + headers: { + "Content-Type": "application/json", }, - ); + body: JSON.stringify(requestBody), + }); const result = await response.json(); console.log(result); @@ -112,9 +107,20 @@ The Stellar SDK provides a convenient method to simulate a transaction: ```javascript const StellarSdk = require("stellar-sdk"); +const { Keypair, SorobanRpc } = StellarSdk; + +const rpc_url = 'https://soroban-testnet.stellar.org:443' + +// Generate a new keypair for transaction authorization. +const keypair = Keypair.random(); +const secret = keypair.secret(); +const public = keypair.publicKey(); + +// Initialize the rpcServer +const rpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true }) -// Initialize the server -const server = new StellarSdk.Server("https://soroban-testnet.stellar.org"); +// Load the account (getting the sequence number for the account and making an account object.) +Const account = rpcServer.getAccount(public) // Define the transaction const transaction = new StellarSdk.TransactionBuilder(account, { @@ -129,7 +135,7 @@ const transaction = new StellarSdk.TransactionBuilder(account, { ) .build(); -server.simulateTransaction(transaction).then((sim) => { +rpcServer.simulateTransaction(transaction).then((sim) => { console.log("cost:", sim.cost); console.log("result:", sim.result); console.log("error:", sim.error); From 3dbde25b9cbe296203e52080c963da6673ada219 Mon Sep 17 00:00:00 2001 From: Silence <35656692+silence48@users.noreply.github.com> Date: Thu, 27 Jun 2024 14:38:33 -0400 Subject: [PATCH 16/23] Apply suggestions from code review Co-authored-by: George Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .../simulateTransaction-Deep-Dive.mdx | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 7053a1471..be42c4add 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -29,7 +29,7 @@ Here we will look at the objects involved and their definitions. ## RPC Servers -Stellar Development Foundation provides a testnet RPC endpoint at For Public network providers please refer to the [Ecosystem RPC Providers] list. At the time of writing this documentation there are two public and free RPC providers, and many more you can subscribe to. +Stellar Development Foundation provides a testnet RPC service at `http://soroban-testnet.stellar.org`. For public network providers please refer to the [Ecosystem RPC Providers] list. At the time of writing this documentation there are two public and free RPC providers, and many more you can subscribe to. ### Public Network Endpoints: @@ -39,7 +39,7 @@ Stellar Development Foundation provides a testnet RPC endpoint at For Public net https://soroban-testnet.stellar.org:443 -**SimulateTransactionParams** is the argument passed to the rpc endpoint for simulateTransaction +**SimulateTransactionParams** is the argument passed to the `simulateTransaction` RPC endpoint: ```typescript interface SimulateTransactionParams { @@ -50,7 +50,7 @@ interface SimulateTransactionParams { } ``` -**SimulateTransactionResult** is the return result from the call. It includes many useful things! [take a look at the code here!](https://github.com/stellar/stellar-docs/blob/88eeb4a318778513880e01fe9728c4cbbc73b87c/openrpc/src/methods/simulateTransaction.json#L18). +**SimulateTransactionResult** is the return result from the call. It includes [many useful things](https://developers.stellar.org/docs/data/rpc/methods/simulateTransaction)! ## When to Use `simulateTransaction` (whenever you use soroban :D) @@ -91,7 +91,7 @@ async function simulateTransaction(transactionXDR) { }); const result = await response.json(); - console.log(result); + console.log(JSON.parse(result)); } // Example XDR transaction envelope @@ -106,8 +106,7 @@ simulateTransaction(transactionXDR); The Stellar SDK provides a convenient method to simulate a transaction: ```javascript -const StellarSdk = require("stellar-sdk"); -const { Keypair, SorobanRpc } = StellarSdk; +import { Keypair, rpc } from "@stellar/stellar-sdk"; const rpc_url = 'https://soroban-testnet.stellar.org:443' @@ -117,19 +116,19 @@ const secret = keypair.secret(); const public = keypair.publicKey(); // Initialize the rpcServer -const rpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true }) +const rpcServer = new rpc.Server(rpc_url) // Load the account (getting the sequence number for the account and making an account object.) -Const account = rpcServer.getAccount(public) +const account = rpcServer.getAccount(public) // Define the transaction -const transaction = new StellarSdk.TransactionBuilder(account, { - fee: StellarSdk.BASE_FEE, +const transaction = new TransactionBuilder(account, { + fee: BASE_FEE, }) - .setNetworkPassphrase(StellarSdk.Networks.TESTNET) + .setNetworkPassphrase(Networks.TESTNET) .setTimeout(30) .addOperation( - StellarSdk.Operation.invokeContractFunction({ + Operation.invokeContractFunction({ function: "increment", }), ) @@ -154,7 +153,7 @@ The footprint ensures that a transaction is aware of all the ledger entries it w ## Assembling a Transaction -Once you have simulated the transaction and obtained the necessary data, you can assemble the transaction for actual submission. The `assembleTransaction` function in the SDK helps with this process, but you can also call `prepareTransaction` to have it both simulate and assemble the transaction for you. +Once you have simulated the transaction and obtained the necessary data, you can assemble the transaction for actual submission. The `assembleTransaction` function in the SDK helps with this process, but you can also call `prepareTransaction` to have it both simulate and assemble the transaction for you in one step. ### js-stellar-sdk `assembleTransaction ` @@ -166,7 +165,7 @@ When a ledger entry is archived, it needs to be restored before the transaction ```typescript interface RestorePreamble { - minResourceFee: string; // Recommended minimum resource fee to add when submitting the RestoreFootprint operation. + minResourceFee: string; // Absolute minimum resource fee to add when submitting the RestoreFootprint operation. transactionData: string; // The recommended Soroban Transaction Data to use when submitting the RestoreFootprint operation. } ``` @@ -193,7 +192,7 @@ export async function simulateRestorationIfNeeded( const contract = new Contract(contract); //const ledgerKey = getLedgerKeyWasmId(wasmHash); const ledgerKey = contract.getFootprint(); - const response = await config.rpc.getLedgerEntries(...[ledgerKey]); + const response = await config.rpc.getLedgerEntries(ledgerKey); if ( response.entries && response.entries.length > 0 && From 64d637687e680c1346a3b099915ab783e63b13bf Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:17:30 -0400 Subject: [PATCH 17/23] resolve review concerns --- .../simulateTransaction-Deep-Dive.mdx | 84 ++++++++++--------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index be42c4add..aac5a1899 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -50,16 +50,16 @@ interface SimulateTransactionParams { } ``` -**SimulateTransactionResult** is the return result from the call. It includes [many useful things](https://developers.stellar.org/docs/data/rpc/methods/simulateTransaction)! +**SimulateTransactionResult** is the return result from the call. It includes [many useful things](https://developers.stellar.org/docs/data/rpc/api-reference/methods/simulateTransaction)! -## When to Use `simulateTransaction` (whenever you use soroban :D) +## Things `simulateTransaction` is used for: 1. **Preparing `invokeHostFunctionOp` Transactions**: Anytime you need to submit an `invokeHostFunctionOp` transaction to the network. 2. **Footprint Determination**: To determine the ledger footprint, which includes all the data entries the transaction will read or write. 3. **Authorization Identification**: To identify the authorizations required for the transaction. 4. **Error Detection**: To detect potential errors and issues before actual submission, saving time and network resources. 5. **Restoring Archived Ledger Entries or Contract Code**: To prepare and restore archived data before actual transaction submission. -6. **Simulating Contract Getter Calls**: To retrieve certain data from the contract without affecting the ledger state. +6. **Simulating Contract Getter Calls**: To retrieve certain data from the contract without affecting the ledger state. (It's worth noting you could also retrieve certain contract data direct from the ledgerkeys without simulation if it doesn't require any manipulation within the contract logic.) 7. **Resource Calculation**: To calculate the necessary resources (CPU instructions, memory, etc.) that a transaction will consume. ## How to Call `simulateTransaction` @@ -98,6 +98,7 @@ async function simulateTransaction(transactionXDR) { // Replace the following placeholder with your actual XDR transaction envelope const transactionXDR = "AAAAAgAAAAAg4dbAxsGAGICfBG3iT2cKGYQ6hK4sJWzZ6or1C5v6GAAAAGQAJsOiAAAAEQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABzAP+dP0PsNzYvFF1pv7a8RQXwH5eg3uZBbbWjE9PwAsAAAAJaW5jcmVtZW50AAAAAAAAAgAAABIAAAAAAAAAACDh1sDGwYAYgJ8EbeJPZwoZhDqEriwlbNnqivULm/oYAAAAAwAAAAMAAAAAAAAAAAAAAAA="; +// An example of where to get the XDR is from TransactionBuilder class from the sdk as shown in the next example. simulateTransaction(transactionXDR); ``` @@ -108,7 +109,7 @@ The Stellar SDK provides a convenient method to simulate a transaction: ```javascript import { Keypair, rpc } from "@stellar/stellar-sdk"; -const rpc_url = 'https://soroban-testnet.stellar.org:443' +const rpc_url = "https://soroban-testnet.stellar.org:443"; // Generate a new keypair for transaction authorization. const keypair = Keypair.random(); @@ -116,10 +117,10 @@ const secret = keypair.secret(); const public = keypair.publicKey(); // Initialize the rpcServer -const rpcServer = new rpc.Server(rpc_url) +const rpcServer = new rpc.Server(rpc_url); // Load the account (getting the sequence number for the account and making an account object.) -const account = rpcServer.getAccount(public) +const account = rpcServer.getAccount(public); // Define the transaction const transaction = new TransactionBuilder(account, { @@ -133,6 +134,7 @@ const transaction = new TransactionBuilder(account, { }), ) .build(); +// If you want to get this as an XDR string directly, you would use `transaction.toXDR('base64')` rpcServer.simulateTransaction(transaction).then((sim) => { console.log("cost:", sim.cost); @@ -153,11 +155,7 @@ The footprint ensures that a transaction is aware of all the ledger entries it w ## Assembling a Transaction -Once you have simulated the transaction and obtained the necessary data, you can assemble the transaction for actual submission. The `assembleTransaction` function in the SDK helps with this process, but you can also call `prepareTransaction` to have it both simulate and assemble the transaction for you in one step. - -### js-stellar-sdk `assembleTransaction ` - -Using the javascript SDK we can call [`assembleTransaction`](https://github.com/stellar/js-stellar-sdk/blob/master/src/rpc/transaction.ts#L28) to easily assemble a transaction. +Once you have simulated the transaction and obtained the necessary data, you can assemble the transaction for actual submission. The `assembleTransaction` function in the SDK helps with this process, but you can also call `prepareTransaction` to have it both simulate and assemble the transaction for you in one step. Using the javascript SDK we can call [`assembleTransaction`](https://stellar.github.io/js-stellar-sdk/global.html#assembleTransaction) to easily assemble a transaction. ## Handling Archived Ledger Entries @@ -173,6 +171,20 @@ interface RestorePreamble { Here is an example for handling restoration using the `restorePreamble` to restore archived data: ```typescript +// Make sure to add the necessary imports: +import { Contract } from "@stellar/stellar-sdk/contract"; +import { + Account, + Keypair, + Operation, + SorobanDataBuilder, + SorobanRpc, + TimeoutInfinite, + Transaction, + TransactionBuilder, + scValToNative, + xdr, +} from "@stellar/stellar-sdk"; /** * Simulates a restoration transaction to determine if restoration is needed. * This function first checks the ledger entry for the given WASM hash. If the entry is found and has expired, @@ -188,11 +200,15 @@ export async function simulateRestorationIfNeeded( SorobanRpc.Api.SimulateTransactionRestoreResponse | string | undefined > { try { - const account = await config.rpc.getAccount(txParams.account.accountId()); + const RpcServer = new SorobanRpc.Server( + "https://soroban-testnet.stellar.org", + { allowHttp: true }, + ); + const account = await RpcServer.getAccount(txParams.account.accountId()); const contract = new Contract(contract); - //const ledgerKey = getLedgerKeyWasmId(wasmHash); const ledgerKey = contract.getFootprint(); - const response = await config.rpc.getLedgerEntries(ledgerKey); + const response = await RpcServer.getLedgerEntries(ledgerKey); + // Here we parse the response to make sure we got a response and that the liveUntilLedgerSeq parameter is there to make sure it's the response we want before continuing. if ( response.entries && response.entries.length > 0 && @@ -200,6 +216,7 @@ export async function simulateRestorationIfNeeded( ) { const expirationLedger = response.entries[0].liveUntilLedgerSeq; const desiredLedgerSeq = response.latestLedger + 500000; + // Be very aware of how many ledgers you want to extend it by. It could quickly become extremely pricey in fees. let extendLedgers = desiredLedgerSeq - expirationLedger; if (extendLedgers < 10000) { extendLedgers = 10000; @@ -219,7 +236,7 @@ export async function simulateRestorationIfNeeded( // Simulate a transaction with a restoration operation to check if it's necessary const restorationSimulation: SorobanRpc.Api.SimulateTransactionResponse = - await config.rpc.simulateTransaction(restoreTx); + await RpcServer.simulateTransaction(restoreTx); //check if restore is necessary. this code also checks if the simulation was successful. const restoreNeeded = SorobanRpc.Api.isSimulationRestore( @@ -231,7 +248,7 @@ export async function simulateRestorationIfNeeded( return restorationSimulation as SorobanRpc.Api.SimulateTransactionRestoreResponse; } else { console.log("No restoration needed., bumping the ttl."); - const account1 = await config.rpc.getAccount( + const account1 = await RpcServer.getAccount( txParams.account.accountId(), ); @@ -249,14 +266,14 @@ export async function simulateRestorationIfNeeded( ) // The actual TTL extension operation .build(); const ttlSimResponse: SorobanRpc.Api.SimulateTransactionResponse = - await config.rpc.simulateTransaction(bumpTTLtx); + await RpcServer.simulateTransaction(bumpTTLtx); const assembledTx = SorobanRpc.assembleTransaction( bumpTTLtx, ttlSimResponse, ).build(); const signedTx = new Transaction( await txParams.signerFunction(assembledTx.toXDR()), - config.passphrase, + Networks.TESTNET, ); // submit the assembled and signed transaction to bump it. try { @@ -289,9 +306,13 @@ export async function handleRestoration( simResponse: SorobanRpc.Api.SimulateTransactionRestoreResponse, txParams: TxParams, ): Promise { + const RpcServer = new SorobanRpc.Server( + "https://soroban-testnet.stellar.org", + { allowHttp: true }, + ); const restorePreamble = simResponse.restorePreamble; console.log("Restoring for account:", txParams.account.accountId()); - const account = await config.rpc.getAccount(txParams.account.accountId()); + const account = await RpcServer.getAccount(txParams.account.accountId()); // Construct the transaction builder with the necessary parameters const restoreTx = new TransactionBuilder(account, { ...txParams.txBuilderOptions, @@ -302,7 +323,7 @@ export async function handleRestoration( .build(); // Build the transaction const simulation: SorobanRpc.Api.SimulateTransactionResponse = - await config.rpc.simulateTransaction(restoreTx); + await RpcServer.simulateTransaction(restoreTx); const assembledTx = SorobanRpc.assembleTransaction( restoreTx, simulation, @@ -310,14 +331,14 @@ export async function handleRestoration( const signedTx = new Transaction( await txParams.signerFunction(assembledTx.toXDR()), - config.passphrase, + Networks.TESTNET, ); console.log("Submitting restoration transaction"); try { // Submit the transaction to the network - const response = await config.rpc.sendTransaction(signedTx); + const response = await RpcServer.sendTransaction(signedTx); console.log( "Restoration transaction submitted successfully:", response.hash, @@ -327,19 +348,6 @@ export async function handleRestoration( throw new Error("Restoration transaction failed"); } } - -import { - Account, - Keypair, - Operation, - SorobanDataBuilder, - SorobanRpc, - TimeoutInfinite, - Transaction, - TransactionBuilder, - scValToNative, - xdr, -} from "@stellar/stellar-sdk"; ``` ## Fees and Resource Usage @@ -359,11 +367,7 @@ Fees are calculated based on the resource consumption declared in the transactio The preflight mechanism provides an estimation of CPU and memory consumption in a transaction. It helps identify potential errors and resource limitations before actual submission. Errors returned by the host are propagated through RPC and do not cover network errors or errors in RPC itself. -### Common Preflight Errors - -- **HostError(Budget, LimitExceeded)**: A network-defined resource limit was exceeded: optimize the contract to consume fewer resources. -- **HostError(Storage, MissingValue)**: Trying to access a non-existent ledger entry. Deploy the respective contract or Wasm. -- **HostError(WasmVm, InvalidAction)**: Failure in a Wasm contract, typically a panic. Fix the contract logic or invocation arguments. +[Common Preflight Errors, and more information can be found here.](https://developers.stellar.org/docs/learn/encyclopedia/errors-and-debugging/debugging-errors#1-preflight) ## Backend Code and Workflow From b06ac6ad9c98f74ac646cac3c6f8a73fd0903a54 Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:24:19 -0400 Subject: [PATCH 18/23] SorobanRpc not rpc --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index aac5a1899..e63bbdd1b 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -107,7 +107,7 @@ simulateTransaction(transactionXDR); The Stellar SDK provides a convenient method to simulate a transaction: ```javascript -import { Keypair, rpc } from "@stellar/stellar-sdk"; +import { Keypair, SorobanRpc, scValToNative } from "@stellar/stellar-sdk"; const rpc_url = "https://soroban-testnet.stellar.org:443"; @@ -117,7 +117,7 @@ const secret = keypair.secret(); const public = keypair.publicKey(); // Initialize the rpcServer -const rpcServer = new rpc.Server(rpc_url); + const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true }, ); // Load the account (getting the sequence number for the account and making an account object.) const account = rpcServer.getAccount(public); @@ -139,6 +139,8 @@ const transaction = new TransactionBuilder(account, { rpcServer.simulateTransaction(transaction).then((sim) => { console.log("cost:", sim.cost); console.log("result:", sim.result); + // the result is a ScVal and so we can parse that to human readable output using the sdk's `scValToNative` function: + console.log("humanReadable Result:", scValToNative(sim.result?.retval as xdr.ScVal);) console.log("error:", sim.error); console.log("latestLedger:", sim.latestLedger); }); From a419fc8d477a0133721d228f6f707a65040c3b02 Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Sat, 29 Jun 2024 15:08:37 -0400 Subject: [PATCH 19/23] fix js --- .../simulateTransaction-Deep-Dive.mdx | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index e63bbdd1b..cb69e6d6e 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -107,20 +107,28 @@ simulateTransaction(transactionXDR); The Stellar SDK provides a convenient method to simulate a transaction: ```javascript -import { Keypair, SorobanRpc, scValToNative } from "@stellar/stellar-sdk"; +import { Keypair, SorobanRpc, scValToNative, TransactionBuilder, BASE_FEE, Networks, Operation } from "@stellar/stellar-sdk"; + +const FRIENDBOT_URL = "https://friendbot-testnet.stellar.org/" const rpc_url = "https://soroban-testnet.stellar.org:443"; // Generate a new keypair for transaction authorization. const keypair = Keypair.random(); const secret = keypair.secret(); -const public = keypair.publicKey(); +const publicKey = keypair.publicKey(); +console.log("publicKey:", publicKey); +// you need to fund the account. +await fetch(`https://friendbot-testnet.stellar.org/?addr=${publicKey}`).then((res) => { + console.log(`funded account: ${publicKey}`); +}); + // Initialize the rpcServer - const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true }, ); +const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true },); // Load the account (getting the sequence number for the account and making an account object.) -const account = rpcServer.getAccount(public); +const account = await RpcServer.getAccount(publicKey); // Define the transaction const transaction = new TransactionBuilder(account, { @@ -130,17 +138,20 @@ const transaction = new TransactionBuilder(account, { .setTimeout(30) .addOperation( Operation.invokeContractFunction({ - function: "increment", + function: "symbol", + // the contract function and address need to be set by you. + contract: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", + args: [] }), ) .build(); // If you want to get this as an XDR string directly, you would use `transaction.toXDR('base64')` -rpcServer.simulateTransaction(transaction).then((sim) => { +RpcServer.simulateTransaction(transaction).then((sim) => { console.log("cost:", sim.cost); console.log("result:", sim.result); // the result is a ScVal and so we can parse that to human readable output using the sdk's `scValToNative` function: - console.log("humanReadable Result:", scValToNative(sim.result?.retval as xdr.ScVal);) + console.log("humanReadable Result:", scValToNative(sim.result?.retval)) console.log("error:", sim.error); console.log("latestLedger:", sim.latestLedger); }); From 33ce5af0525dbc26fe88c21a75d5faf1a2fca131 Mon Sep 17 00:00:00 2001 From: Julian Martinez Date: Fri, 5 Jul 2024 14:58:22 -0700 Subject: [PATCH 20/23] formatting --- .../simulateTransaction-Deep-Dive.mdx | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index cb69e6d6e..3adff275f 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -107,9 +107,17 @@ simulateTransaction(transactionXDR); The Stellar SDK provides a convenient method to simulate a transaction: ```javascript -import { Keypair, SorobanRpc, scValToNative, TransactionBuilder, BASE_FEE, Networks, Operation } from "@stellar/stellar-sdk"; +import { + Keypair, + SorobanRpc, + scValToNative, + TransactionBuilder, + BASE_FEE, + Networks, + Operation, +} from "@stellar/stellar-sdk"; -const FRIENDBOT_URL = "https://friendbot-testnet.stellar.org/" +const FRIENDBOT_URL = "https://friendbot-testnet.stellar.org/"; const rpc_url = "https://soroban-testnet.stellar.org:443"; @@ -119,13 +127,14 @@ const secret = keypair.secret(); const publicKey = keypair.publicKey(); console.log("publicKey:", publicKey); // you need to fund the account. -await fetch(`https://friendbot-testnet.stellar.org/?addr=${publicKey}`).then((res) => { - console.log(`funded account: ${publicKey}`); -}); - +await fetch(`https://friendbot-testnet.stellar.org/?addr=${publicKey}`).then( + (res) => { + console.log(`funded account: ${publicKey}`); + }, +); // Initialize the rpcServer -const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true },); +const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true }); // Load the account (getting the sequence number for the account and making an account object.) const account = await RpcServer.getAccount(publicKey); @@ -141,7 +150,7 @@ const transaction = new TransactionBuilder(account, { function: "symbol", // the contract function and address need to be set by you. contract: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", - args: [] + args: [], }), ) .build(); @@ -151,7 +160,7 @@ RpcServer.simulateTransaction(transaction).then((sim) => { console.log("cost:", sim.cost); console.log("result:", sim.result); // the result is a ScVal and so we can parse that to human readable output using the sdk's `scValToNative` function: - console.log("humanReadable Result:", scValToNative(sim.result?.retval)) + console.log("humanReadable Result:", scValToNative(sim.result?.retval)); console.log("error:", sim.error); console.log("latestLedger:", sim.latestLedger); }); From 1a19f286a91f0282101554aabf5ba888b7785b80 Mon Sep 17 00:00:00 2001 From: Julian Martinez Date: Fri, 5 Jul 2024 15:12:57 -0700 Subject: [PATCH 21/23] nit: link formatting --- .../guides/transactions/simulateTransaction-Deep-Dive.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index 3adff275f..b0961f0f0 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -33,7 +33,9 @@ Stellar Development Foundation provides a testnet RPC service at `http://soroban ### Public Network Endpoints: -[Liquify](https://www.liquify.com) https://stellar-mainnet.liquify.com/api=41EEWAH79Y5OCGI7/mainnet [Gateway.fm](https://www.gateway.fm) https://soroban-rpc.mainnet.stellar.gateway.fm +[Liquify](https://www.liquify.com): https://stellar-mainnet.liquify.com/api=41EEWAH79Y5OCGI7/mainnet + +[Gateway.fm](https://www.gateway.fm): https://soroban-rpc.mainnet.stellar.gateway.fm ### Testnet Endpoint: From d1e4ebb9a76105cb2026b607521ef620e74acda8 Mon Sep 17 00:00:00 2001 From: silence <35656692+silence48@users.noreply.github.com> Date: Fri, 5 Jul 2024 19:30:59 -0400 Subject: [PATCH 22/23] add instructions for example --- .../simulateTransaction-Deep-Dive.mdx | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index cb69e6d6e..69ae17d27 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -107,9 +107,17 @@ simulateTransaction(transactionXDR); The Stellar SDK provides a convenient method to simulate a transaction: ```javascript -import { Keypair, SorobanRpc, scValToNative, TransactionBuilder, BASE_FEE, Networks, Operation } from "@stellar/stellar-sdk"; +import { + Keypair, + SorobanRpc, + scValToNative, + TransactionBuilder, + BASE_FEE, + Networks, + Operation, +} from "@stellar/stellar-sdk"; -const FRIENDBOT_URL = "https://friendbot-testnet.stellar.org/" +const FRIENDBOT_URL = "https://friendbot-testnet.stellar.org/"; const rpc_url = "https://soroban-testnet.stellar.org:443"; @@ -119,13 +127,14 @@ const secret = keypair.secret(); const publicKey = keypair.publicKey(); console.log("publicKey:", publicKey); // you need to fund the account. -await fetch(`https://friendbot-testnet.stellar.org/?addr=${publicKey}`).then((res) => { - console.log(`funded account: ${publicKey}`); -}); - +await fetch(`https://friendbot-testnet.stellar.org/?addr=${publicKey}`).then( + (res) => { + console.log(`funded account: ${publicKey}`); + }, +); // Initialize the rpcServer -const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true },); +const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true }); // Load the account (getting the sequence number for the account and making an account object.) const account = await RpcServer.getAccount(publicKey); @@ -141,7 +150,7 @@ const transaction = new TransactionBuilder(account, { function: "symbol", // the contract function and address need to be set by you. contract: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", - args: [] + args: [], }), ) .build(); @@ -151,12 +160,22 @@ RpcServer.simulateTransaction(transaction).then((sim) => { console.log("cost:", sim.cost); console.log("result:", sim.result); // the result is a ScVal and so we can parse that to human readable output using the sdk's `scValToNative` function: - console.log("humanReadable Result:", scValToNative(sim.result?.retval)) + console.log("humanReadable Result:", scValToNative(sim.result?.retval)); console.log("error:", sim.error); console.log("latestLedger:", sim.latestLedger); }); ``` +#### Running the example + +To run the above code, you will need to install the Stellar SDK into your project. You can do this by running the following command in your project directory: + +`npm install @stellar/stellar-sdk` + +Once your project is set up, you can create a new mjs file and paste the code above. You can then run the file using Node.js by running: + +`node .mjs` + ## Understanding the Footprint A footprint is a set of ledger keys that the transaction will read or write. These keys are marked as either read-only or read-write: From f8665a01a2b51c68de0505b02d5aa45f41eab872 Mon Sep 17 00:00:00 2001 From: Bri <92327786+briwylde08@users.noreply.github.com> Date: Mon, 8 Jul 2024 08:31:33 -0600 Subject: [PATCH 23/23] Add title --- .../simulateTransaction-Deep-Dive.mdx | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx index cb69e6d6e..317115492 100644 --- a/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx +++ b/docs/smart-contracts/guides/transactions/simulateTransaction-Deep-Dive.mdx @@ -1,3 +1,8 @@ +--- +title: simulateTransaction RPC method guide +hide_table_of_contents: true +--- + ## simulateTransaction Examples and Tutorials Guide ### Table of Contents @@ -107,9 +112,17 @@ simulateTransaction(transactionXDR); The Stellar SDK provides a convenient method to simulate a transaction: ```javascript -import { Keypair, SorobanRpc, scValToNative, TransactionBuilder, BASE_FEE, Networks, Operation } from "@stellar/stellar-sdk"; +import { + Keypair, + SorobanRpc, + scValToNative, + TransactionBuilder, + BASE_FEE, + Networks, + Operation, +} from "@stellar/stellar-sdk"; -const FRIENDBOT_URL = "https://friendbot-testnet.stellar.org/" +const FRIENDBOT_URL = "https://friendbot-testnet.stellar.org/"; const rpc_url = "https://soroban-testnet.stellar.org:443"; @@ -119,13 +132,14 @@ const secret = keypair.secret(); const publicKey = keypair.publicKey(); console.log("publicKey:", publicKey); // you need to fund the account. -await fetch(`https://friendbot-testnet.stellar.org/?addr=${publicKey}`).then((res) => { - console.log(`funded account: ${publicKey}`); -}); - +await fetch(`https://friendbot-testnet.stellar.org/?addr=${publicKey}`).then( + (res) => { + console.log(`funded account: ${publicKey}`); + }, +); // Initialize the rpcServer -const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true },); +const RpcServer = new SorobanRpc.Server(rpc_url, { allowHttp: true }); // Load the account (getting the sequence number for the account and making an account object.) const account = await RpcServer.getAccount(publicKey); @@ -141,7 +155,7 @@ const transaction = new TransactionBuilder(account, { function: "symbol", // the contract function and address need to be set by you. contract: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", - args: [] + args: [], }), ) .build(); @@ -151,7 +165,7 @@ RpcServer.simulateTransaction(transaction).then((sim) => { console.log("cost:", sim.cost); console.log("result:", sim.result); // the result is a ScVal and so we can parse that to human readable output using the sdk's `scValToNative` function: - console.log("humanReadable Result:", scValToNative(sim.result?.retval)) + console.log("humanReadable Result:", scValToNative(sim.result?.retval)); console.log("error:", sim.error); console.log("latestLedger:", sim.latestLedger); });