From 92c8cb0e51f623ac1c5c1e7c887706319c05810a Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Mon, 3 Jun 2024 18:39:55 +0800 Subject: [PATCH 1/3] Add examples of calling contracts using Python SDK and Java SDK --- .../transactions/invoke-contract-tx-js.mdx | 255 +++++++++++++++++- 1 file changed, 250 insertions(+), 5 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/invoke-contract-tx-js.mdx b/docs/smart-contracts/guides/transactions/invoke-contract-tx-js.mdx index 0823000e0..40c004cd1 100644 --- a/docs/smart-contracts/guides/transactions/invoke-contract-tx-js.mdx +++ b/docs/smart-contracts/guides/transactions/invoke-contract-tx-js.mdx @@ -1,9 +1,21 @@ --- -title: Invoke a contract function in a Stellar transaction using JavaScript +title: Invoke a contract function in a Stellar transaction using SDKs hide_table_of_contents: true --- -This is a simple example using the `@stellar/stellar-sdk` JavaScript library to create, simulate, and then assemble a Stellar transaction which invokes an `increment` function of the [auth example contract](../../example-contracts/auth.mdx). +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +This is a simple example using the Stellar SDK to create, simulate, and then assemble a Stellar transaction which invokes an `increment` function of the [auth example contract](../../example-contracts/auth.mdx). + + + + +:::tip + +Please go to [the project homepage](https://github.com/stellar/js-stellar-sdk) of JavaScript SDK to learn how to install it. + +::: ```javascript (async () => { @@ -14,6 +26,8 @@ This is a simple example using the `@stellar/stellar-sdk` JavaScript library to TransactionBuilder, Networks, BASE_FEE, + nativeToScVal, + Address, } = require("@stellar/stellar-sdk"); // The source account will be used to sign and send the transaction. @@ -44,9 +58,18 @@ This is a simple example using the `@stellar/stellar-sdk` JavaScript library to networkPassphrase: Networks.FUTURENET, }) // The invocation of the `increment` function of our contract is added - // to the transaction. Note: `increment` doesn't require any parameters, - // but many contract functions do. You would need to provide those here. - .addOperation(contract.call("increment")) + // to the transaction. + .addOperation( + contract.call( + "increment", + nativeToScVal( + Address.fromString( + "GCWY3M4VRW4NXJRI7IVAU3CC7XOPN6PRBG6I5M7TAOQNKZXLT3KAH362", + ), + ), + nativeToScVal(5, { type: "u32" }), + ), + ) // This transaction will be valid for the next 30 seconds .setTimeout(30) .build(); @@ -111,3 +134,225 @@ This is a simple example using the `@stellar/stellar-sdk` JavaScript library to } })(); ``` + + + + + +:::tip + +Please go to [the project homepage](https://github.com/StellarCN/py-stellar-base) of Python SDK to learn how to install it. + +In addition, Python provides a lot of example code, which you can find [here](https://github.com/StellarCN/py-stellar-base/tree/main/examples). + +::: + +```py +import time + +from stellar_sdk import Keypair, Network, SorobanServer, TransactionBuilder, scval +from stellar_sdk import xdr as stellar_xdr +from stellar_sdk.exceptions import PrepareTransactionException +from stellar_sdk.soroban_rpc import GetTransactionStatus, SendTransactionStatus + +secret = "SAAPYAPTTRZMCUZFPG3G66V4ZMHTK4TWA6NS7U4F7Z3IMUD52EK4DDEV" +rpc_server_url = "https://soroban-testnet.stellar.org:443" +network_passphrase = Network.TESTNET_NETWORK_PASSPHRASE + +# Here we will use a deployed instance of the `increment` example contract. +contract_id = "CDOGJBJMRVVXW5K3UJ5BGVJ5RSQXQB4UFVQYVFOIARC2UYXSEPF4YAVR" +# The source account will be used to sign and send the transaction. +source_keypair = Keypair.from_secret(secret) +# Configure SorobanClient to use the `soroban-rpc` instance of your choosing. +soroban_server = SorobanServer(rpc_server_url) +# Transactions require a valid sequence number (which varies from one account to another). +# We fetch this sequence number from the RPC server. +source = soroban_server.load_account(source_keypair.public_key) + +tx = ( + # The transaction begins as pretty standard. The source account, minimum fee, + # and network passphrase are provided. + TransactionBuilder(source, network_passphrase, base_fee=100) + # This transaction will be valid for the next 30 seconds + .set_timeout(30) + # The invocation of the `increment` function of our contract is added to the transaction. + .append_invoke_contract_function_op( + contract_id=contract_id, + function_name="increment", + parameters=[scval.to_address(source_keypair.public_key), scval.to_uint32(5)], + ).build() +) + +print(f"builtTransaction: {tx.to_xdr()}") + +try: + # We use the RPC server to "prepare" the transaction. This simulating the + # transaction, discovering the soroban data, and updating the + # transaction to include that soroban data. If you know the soroban data ahead of + # time, you could manually use `set_soroban_data` and skip this step. + tx = soroban_server.prepare_transaction(tx) +except PrepareTransactionException as e: + print(f"Prepare Transaction Failed: {e.simulate_transaction_response}") + raise e + +# Sign the transaction with the source account's keypair. +tx.sign(source_keypair) + +# Let's see the base64-encoded XDR of the transaction we just built. +print(f"Signed prepared transaction XDR: {tx.to_xdr()}") + +# Submit the transaction to the Soroban-RPC server. The RPC server will +# then submit the transaction into the network for us. Then we will have to +# wait, polling `get_transaction` until the transaction completes. +send_transaction_data = soroban_server.send_transaction(tx) +print(f"Sent transaction: {send_transaction_data}") +if send_transaction_data.status != SendTransactionStatus.PENDING: + print(send_transaction_data.error_result_xdr) + raise Exception("Send transaction failed") + +while True: + print("Waiting for transaction to be confirmed...") + # Poll `get_transaction` until the status is not "NOT_FOUND" + get_transaction_data = soroban_server.get_transaction(send_transaction_data.hash) + if get_transaction_data.status != GetTransactionStatus.NOT_FOUND: + break + time.sleep(3) + +print(f"getTransaction response: {get_transaction_data}") + +if get_transaction_data.status == GetTransactionStatus.SUCCESS: + # The transaction was successful, so we can extract the `result_meta_xdr` + transaction_meta = stellar_xdr.TransactionMeta.from_xdr( + get_transaction_data.result_meta_xdr + ) + result = transaction_meta.v3.soroban_meta.return_value + # Find the return value from the contract and return it + print(f"Transaction result: {scval.from_uint32(result)}") +else: + # The transaction failed, so we can extract the `result_xdr` + print(f"Transaction failed: {get_transaction_data.result_xdr}") + raise Exception("Transaction failed") +``` + + + + + +:::tip + +Please go to [the project homepage](https://github.com/lightsail-network/java-stellar-sdk) of Java SDK to learn how to install it. + +::: + +```java +import org.stellar.sdk.AccountNotFoundException; +import org.stellar.sdk.InvokeHostFunctionOperation; +import org.stellar.sdk.KeyPair; +import org.stellar.sdk.Network; +import org.stellar.sdk.PrepareTransactionException; +import org.stellar.sdk.SorobanServer; +import org.stellar.sdk.Transaction; +import org.stellar.sdk.TransactionBuilder; +import org.stellar.sdk.TransactionBuilderAccount; +import org.stellar.sdk.requests.sorobanrpc.SorobanRpcErrorResponse; +import org.stellar.sdk.responses.sorobanrpc.GetTransactionResponse; +import org.stellar.sdk.responses.sorobanrpc.SendTransactionResponse; +import org.stellar.sdk.scval.Scv; +import org.stellar.sdk.xdr.SCVal; +import org.stellar.sdk.xdr.TransactionMeta; + +import java.io.IOException; +import java.util.List; + +public class Example { + public static void main(String[] args) throws SorobanRpcErrorResponse, IOException, InterruptedException { + // The source account will be used to sign and send the transaction. + KeyPair sourceKeypair = KeyPair.fromSecretSeed("SAAPYAPTTRZMCUZFPG3G66V4ZMHTK4TWA6NS7U4F7Z3IMUD52EK4DDEV"); + + // Configure SorobanClient to use the `soroban-rpc` instance of your choosing. + SorobanServer sorobanServer = new SorobanServer("https://soroban-testnet.stellar.org"); + + // Here we will use a deployed instance of the `increment` example contract. + String contractAddress = "CDOGJBJMRVVXW5K3UJ5BGVJ5RSQXQB4UFVQYVFOIARC2UYXSEPF4YAVR"; + + // Transactions require a valid sequence number (which varies from one account to + // another). We fetch this sequence number from the RPC server. + TransactionBuilderAccount sourceAccount = null; + try { + sourceAccount = sorobanServer.getAccount(sourceKeypair.getAccountId()); + } catch (AccountNotFoundException e) { + throw new RuntimeException("Account not found, please activate it first"); + } + + // The invocation of the `increment` function. + InvokeHostFunctionOperation operation = InvokeHostFunctionOperation.invokeContractFunctionOperationBuilder(contractAddress, "increment", + List.of( + Scv.toAddress(sourceAccount.getAccountId()), + Scv.toUint32(5) + ) + ).build(); + + // Create a transaction with the source account and the operation we want to invoke. + Transaction transaction = new TransactionBuilder(sourceAccount, Network.TESTNET) + .addOperation(operation) // The invocation of the `increment` function of our contract is added to the transaction. + .setTimeout(30) // This transaction will be valid for the next 30 seconds + .setBaseFee(100) // The base fee is 100 stroops (0.00001 XLM) + .build(); + + // We use the RPC server to "prepare" the transaction. This simulating the + // transaction, discovering the soroban data, and updating the + // transaction to include that soroban data. If you know the soroban data ahead of + // time, you could manually use `setSorobanData` and skip this step. + try { + transaction = sorobanServer.prepareTransaction(transaction); + } catch (PrepareTransactionException e) { + // You should handle the error here + System.out.println("Prepare Transaction Failed: " + e.getMessage()); + throw new RuntimeException(e); + } + + // Sign the transaction with the source account's keypair. + transaction.sign(sourceKeypair); + + // Let's see the base64-encoded XDR of the transaction we just built. + System.out.println("Signed prepared transaction XDR: " + transaction.toEnvelopeXdrBase64()); + + // Submit the transaction to the Soroban-RPC server. The RPC server will then + // submit the transaction into the network for us. Then we will have to wait, + // polling `getTransaction` until the transaction completes. + SendTransactionResponse response = sorobanServer.sendTransaction(transaction); + if (!SendTransactionResponse.SendTransactionStatus.PENDING.equals(response.getStatus())) { + throw new RuntimeException("Sending transaction failed"); + } + + // Poll `getTransaction` until the status is not "NOT_FOUND" + GetTransactionResponse getTransactionResponse; + while (true) { + System.out.println("Waiting for transaction confirmation..."); + // See if the transaction is complete + getTransactionResponse = sorobanServer.getTransaction(response.getHash()); + if (!GetTransactionResponse.GetTransactionStatus.NOT_FOUND.equals(getTransactionResponse.getStatus())) { + break; + } + // Wait one second + Thread.sleep(1000); + } + + System.out.println("Get transaction response: " + getTransactionResponse); + + if (GetTransactionResponse.GetTransactionStatus.SUCCESS.equals(getTransactionResponse.getStatus())) { + // The transaction was successful, so we can extract the `resultMetaXdr` + TransactionMeta transactionMeta = TransactionMeta.fromXdrBase64(getTransactionResponse.getResultMetaXdr()); + SCVal result = transactionMeta.getV3().getSorobanMeta().getReturnValue(); + long parsedResult = Scv.fromUint32(result); + System.out.println("Transaction result: " + parsedResult); + } else { + // The transaction failed, so we can extract the `resultXdr` + System.out.println("Transaction failed: " + getTransactionResponse.getResultXdr()); + } + } +} +``` + + + From ded775b78bee1654ba9fa4165e35bda548dfbf70 Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Mon, 3 Jun 2024 18:55:45 +0800 Subject: [PATCH 2/3] rename file --- .../{invoke-contract-tx-js.mdx => invoke-contract-tx-sdk.mdx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/smart-contracts/guides/transactions/{invoke-contract-tx-js.mdx => invoke-contract-tx-sdk.mdx} (100%) diff --git a/docs/smart-contracts/guides/transactions/invoke-contract-tx-js.mdx b/docs/smart-contracts/guides/transactions/invoke-contract-tx-sdk.mdx similarity index 100% rename from docs/smart-contracts/guides/transactions/invoke-contract-tx-js.mdx rename to docs/smart-contracts/guides/transactions/invoke-contract-tx-sdk.mdx From 29adde247491783dfadbd5f797eaced64f22972b Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Thu, 13 Jun 2024 07:13:26 +0800 Subject: [PATCH 3/3] fix js example --- .../guides/transactions/invoke-contract-tx-sdk.mdx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/smart-contracts/guides/transactions/invoke-contract-tx-sdk.mdx b/docs/smart-contracts/guides/transactions/invoke-contract-tx-sdk.mdx index 40c004cd1..bce5308ae 100644 --- a/docs/smart-contracts/guides/transactions/invoke-contract-tx-sdk.mdx +++ b/docs/smart-contracts/guides/transactions/invoke-contract-tx-sdk.mdx @@ -55,18 +55,14 @@ Please go to [the project homepage](https://github.com/stellar/js-stellar-sdk) o // fee, and network passphrase are provided. let builtTransaction = new TransactionBuilder(sourceAccount, { fee: BASE_FEE, - networkPassphrase: Networks.FUTURENET, + networkPassphrase: Networks.TESTNET, }) // The invocation of the `increment` function of our contract is added // to the transaction. .addOperation( contract.call( "increment", - nativeToScVal( - Address.fromString( - "GCWY3M4VRW4NXJRI7IVAU3CC7XOPN6PRBG6I5M7TAOQNKZXLT3KAH362", - ), - ), + nativeToScVal(Address.fromString(sourceKeypair.publicKey())), nativeToScVal(5, { type: "u32" }), ), )