diff --git a/docs/soroban-internals/contract-interactions/stellar-transaction.mdx b/docs/soroban-internals/contract-interactions/stellar-transaction.mdx index 284e5005..c3b98800 100644 --- a/docs/soroban-internals/contract-interactions/stellar-transaction.mdx +++ b/docs/soroban-internals/contract-interactions/stellar-transaction.mdx @@ -255,6 +255,126 @@ else: print(f"Transaction failed: {get_response.result_xdr}") ``` + + + +:::tip + +[java-stellar-sdk](https://github.com/stellar/java-stellar-sdk) provides support for Soroban, please visit the project homepage for more information. + +::: + +```java +import java.io.IOException; +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.TransactionMeta; + +public class SorobanExample { + 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("SCQN3XGRO65BHNSWLSHYIR4B65AHLDUQ7YLHGIWQ4677AZFRS77TCZRB"); + + // 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 = "CBEOJUP5FU6KKOEZ7RMTSKZ7YLBS5D6LVATIGCESOGXSZEQ2UWQFKZW6"; + + // 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 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. + InvokeHostFunctionOperation operation = + InvokeHostFunctionOperation.invokeContractFunctionOperationBuilder( + contractAddress, "increment", null) + .build(); + + // Create a transaction with the source account and the operation we want to invoke. + Transaction transaction = + new TransactionBuilder(sourceAccount, Network.TESTNET) + .addOperation(operation) + .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 storage footprint, and updating the transaction + // to include that footprint. If you know the footprint ahead of time, you could + // manually use `addFootprint` and skip this step. + try { + transaction = sorobanServer.prepareTransaction(transaction); + } catch (PrepareTransactionException e) { + // You should handle the error here + 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())) { + // Find the return value from the contract and return it + TransactionMeta transactionMeta = + TransactionMeta.fromXdrBase64(getTransactionResponse.getResultMetaXdr()); + long returnValue = Scv.fromUint32(transactionMeta.getV3().getSorobanMeta().getReturnValue()); + System.out.println("Transaction result: " + returnValue); + } else { + System.out.println("Transaction failed: " + getTransactionResponse.getResultXdr()); + } + } +} +``` +