feat: Enhance UI components and implement Soroban contract invocation#670
feat: Enhance UI components and implement Soroban contract invocation#670Abdullahi130 wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughThese changes update the visual styling of wallet connection and status UI components with gradients, glows, and shadows, and refactor the Soroban contract invocation logic to use stellar-sdk with transaction simulation and explicit error handling. Changes
Sequence Diagram(s)sequenceDiagram
actor Client
participant stellar as stellar-sdk
participant RPC as Soroban RPC
participant Freighter
Client->>stellar: Build transaction with contractId, functionName, args
Client->>RPC: Simulate transaction
alt Simulation Succeeds
RPC-->>Client: Return transactionData & metadata
Client->>stellar: Assemble transaction with simulation output
Client->>Freighter: Sign transaction XDR
Freighter-->>Client: Return signed XDR
Client->>RPC: Submit signed transaction
alt Submit Succeeds
RPC-->>Client: Return result
else Submit Fails
RPC-->>Client: ERROR response
Client-->>Client: Throw error
end
else Simulation Fails
RPC-->>Client: Simulation error
Client-->>Client: Throw error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
frontend/context/walletContext.tsx (3)
229-247:⚠️ Potential issue | 🟠 Major
signedEnvelopeXDR as unknown as Transactionwon't work as a fallback.
Horizon.Server#submitTransactionexpects aTransaction/FeeBumpTransactioninstance, not a raw XDR string. Casting the string throughunknownsilences TypeScript but will fail at runtime (Horizon calls.toEnvelope()/.signatureson the argument). If the first branch succeeded at parsing the XDR viaTransactionBuilder.fromXDR, there is no realistic case where the same XDR would then need to be submitted as a string — remove the fallback and let the original error propagate with context.🔧 Proposed simplification
- try { - const txObj = TransactionBuilder.fromXDR(signedEnvelopeXDR, NETWORK_PASSPHRASE); - const res = await server.submitTransaction(txObj); - return res; - } catch (err) { - try { - const res = await server.submitTransaction(signedEnvelopeXDR as unknown as Transaction); - return res; - } catch (e) { - console.error("submitTransaction failed", e); - throw e; - } - } + const txObj = TransactionBuilder.fromXDR(signedEnvelopeXDR, NETWORK_PASSPHRASE); + try { + return await server.submitTransaction(txObj); + } catch (err) { + console.error("submitTransaction failed", err); + throw err; + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/context/walletContext.tsx` around lines 229 - 247, Remove the unsafe fallback that casts signedEnvelopeXDR to a Transaction and instead let the original parsing/submission error surface: in the block after obtaining signedEnvelopeXDR from signWithFreighter, keep the try that builds txObj via TransactionBuilder.fromXDR and calls server.submitTransaction(txObj), but delete the inner catch which attempts server.submitTransaction(signedEnvelopeXDR as unknown as Transaction); rethrow or throw a new error with context from the original catch so failures from TransactionBuilder.fromXDR / server.submitTransaction are not masked (refer to signWithFreighter, signedEnvelopeXDR, TransactionBuilder.fromXDR, and server.submitTransaction).
152-175:⚠️ Potential issue | 🔴 CriticalReplace ad-hoc window probing with
@stellar/freighter-apipackage for stable, reliable Freighter integration.The current code relies on unsafe
window.freighter*detection (lines 152–155, 163) which fails silently on browser/version combinations where Freighter doesn't inject globals. The official@stellar/freighter-apipackage provides a stable, typed API (isConnected,requestAccess,getAddress,signTransaction, etc.) and is the recommended integration path.Additionally, line 165 contains a logic error: the ternary condition
freighter.getPublicKey ? freighter.getPublicKey() : freighter.getPublicKey()invokes the same call in both branches, so the guard has no effect. Any version without that method will throwTypeError: freighter.getPublicKey is not a function.🔧 Suggested direction
-import React, { createContext, useContext, useEffect, useState } from "react"; +import React, { createContext, useContext, useEffect, useState } from "react"; +import { + isConnected, + requestAccess, + getAddress, + signTransaction, +} from "@stellar/freighter-api"; ... - const connectWallet = async () => { - setStatus("connecting"); - try { - if (!isFreighterAvailable()) throw new Error("Freighter not found. Please install Freighter."); - const freighter = (window as any).freighterApi || (window as any).freighter; - const publicKey = await (freighter.getPublicKey ? freighter.getPublicKey() : freighter.getPublicKey()); - if (!publicKey) throw new Error("Unable to read public key from Freighter"); + const connectWallet = async () => { + setStatus("connecting"); + try { + const { isConnected: installed } = await isConnected(); + if (!installed) throw new Error("Freighter not found. Please install Freighter."); + await requestAccess(); + const { address: publicKey, error } = await getAddress(); + if (error || !publicKey) throw new Error(error ?? "Unable to read public key from Freighter");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/context/walletContext.tsx` around lines 152 - 175, Replace the ad-hoc window probing in isFreighterAvailable and connectWallet with the official `@stellar/freighter-api` usage: import and use the package's client (e.g., call its isConnected()/requestAccess() then getAddress() or getPublicKey() methods) instead of checking window.freighter*/freighterApi; update connectWallet to call requestAccess if not connected, then await getAddress()/getPublicKey(), setAddress/localStorage and setStatus("connected"), and properly catch and log errors; also remove the meaningless ternary that calls freighter.getPublicKey() in both branches and guard calls against missing methods by using the freighter-api methods only.
183-211:⚠️ Potential issue | 🟠 MajorFix Freighter API calls: incorrect argument format and non-existent fallback methods.
The
signTransactioncall at line 192 passesNETWORK_PASSPHRASEas a positional string argument, but@stellar/freighter-apiexpects an options object:signTransaction(xdr, { networkPassphrase }). Additionally, the code checks forres.signed_envelope_xdr(lines 194, 199, 204) but the API returns{ signedTxXdr, signerAddress }— the property name issignedTxXdr, notsigned_envelope_xdr.The fallback methods at lines 197–204 (
.sign()and.requestSignTransaction()) are not part of the official Freighter API and should be removed. Use only the documented@stellar/freighter-apisignTransactionmethod with the correct signature.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/context/walletContext.tsx` around lines 183 - 211, In signWithFreighter, fix the Freighter API usage: call the documented signTransaction signature (e.g., freighter.signTransaction(txXDR, { networkPassphrase: NETWORK_PASSPHRASE }) or freighterApi.signTransaction with the same options), check for the correct response property signedTxXdr (or a string) instead of signed_envelope_xdr, and remove the non-official fallback branches that check freighter.sign and freighter.requestSignTransaction; ensure the function returns the signedTxXdr or string when present and throws the existing error if the interface is unsupported.
🧹 Nitpick comments (2)
frontend/context/walletContext.tsx (2)
135-136: Tighten the context types — dropany.
Promise<any>andargs?: any[]erase safety at the public API boundary. For Soroban calls specifically, the arg type should bexdr.ScVal[](see companion comment on Line 249), and the return type should beSorobanRpc.Api.SendTransactionResponse(orHorizon.HorizonApi.SubmitTransactionResponseforsendXLM).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/context/walletContext.tsx` around lines 135 - 136, Change the loose any types on the Wallet context API to concrete Stellar/Soroban types: update sendXLM to return Promise<Horizon.HorizonApi.SubmitTransactionResponse> and update invokeSorobanContract to accept args?: xdr.ScVal[] and return Promise<SorobanRpc.Api.SendTransactionResponse>; update the Context interface entries for sendXLM and invokeSorobanContract accordingly and add the required imports for xdr, SorobanRpc and Horizon types from the appropriate Stellar/Soroban SDK modules so the public API boundary is strongly typed.
1-118: Remove the ~118-line commented-out legacy block.Dead, commented-out code adds review noise and can mislead future maintainers into thinking it's still relevant. Git history already preserves the prior implementation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/context/walletContext.tsx` around lines 1 - 118, Remove the entire commented-out legacy block in frontend/context/walletContext.tsx (the ~118-line comment that contains the old AppProvider, AppContext, useAppContext, and related imports and code). Keep the file clean by deleting that commented section so only the current implementation remains; ensure references to AppProvider, AppContext, and useAppContext still compile after removal and run tests/build to confirm nothing else depends on the commented code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/context/walletContext.tsx`:
- Around line 249-281: invokeSorobanContract has three issues: contract.call is
being passed raw JS values — change the args type to xdr.ScVal[] and require
callers to convert values (use nativeToScVal/xdr.ScVal helpers) so each
parameter is an xdr.ScVal when calling contract.call(method, ...args);
simulatedTx error checking should use the SDK helper
SorobanRpc.Api.isSimulationError(simulatedTx) instead of manual property checks;
and assembling the final tx must call SorobanRpc.assembleTransaction(tx,
simulatedTx).build() (not TransactionBuilder.assembleTransaction with a
networkPassphrase arg). Also update imports to bring in SorobanRpc, xdr,
nativeToScVal (and ensure you construct the RPC client with new
SorobanRpc.Server(SOROBAN_RPC, { allowHttp: true })) so the corrected symbols
are available.
---
Outside diff comments:
In `@frontend/context/walletContext.tsx`:
- Around line 229-247: Remove the unsafe fallback that casts signedEnvelopeXDR
to a Transaction and instead let the original parsing/submission error surface:
in the block after obtaining signedEnvelopeXDR from signWithFreighter, keep the
try that builds txObj via TransactionBuilder.fromXDR and calls
server.submitTransaction(txObj), but delete the inner catch which attempts
server.submitTransaction(signedEnvelopeXDR as unknown as Transaction); rethrow
or throw a new error with context from the original catch so failures from
TransactionBuilder.fromXDR / server.submitTransaction are not masked (refer to
signWithFreighter, signedEnvelopeXDR, TransactionBuilder.fromXDR, and
server.submitTransaction).
- Around line 152-175: Replace the ad-hoc window probing in isFreighterAvailable
and connectWallet with the official `@stellar/freighter-api` usage: import and use
the package's client (e.g., call its isConnected()/requestAccess() then
getAddress() or getPublicKey() methods) instead of checking
window.freighter*/freighterApi; update connectWallet to call requestAccess if
not connected, then await getAddress()/getPublicKey(), setAddress/localStorage
and setStatus("connected"), and properly catch and log errors; also remove the
meaningless ternary that calls freighter.getPublicKey() in both branches and
guard calls against missing methods by using the freighter-api methods only.
- Around line 183-211: In signWithFreighter, fix the Freighter API usage: call
the documented signTransaction signature (e.g., freighter.signTransaction(txXDR,
{ networkPassphrase: NETWORK_PASSPHRASE }) or freighterApi.signTransaction with
the same options), check for the correct response property signedTxXdr (or a
string) instead of signed_envelope_xdr, and remove the non-official fallback
branches that check freighter.sign and freighter.requestSignTransaction; ensure
the function returns the signedTxXdr or string when present and throws the
existing error if the interface is unsupported.
---
Nitpick comments:
In `@frontend/context/walletContext.tsx`:
- Around line 135-136: Change the loose any types on the Wallet context API to
concrete Stellar/Soroban types: update sendXLM to return
Promise<Horizon.HorizonApi.SubmitTransactionResponse> and update
invokeSorobanContract to accept args?: xdr.ScVal[] and return
Promise<SorobanRpc.Api.SendTransactionResponse>; update the Context interface
entries for sendXLM and invokeSorobanContract accordingly and add the required
imports for xdr, SorobanRpc and Horizon types from the appropriate
Stellar/Soroban SDK modules so the public API boundary is strongly typed.
- Around line 1-118: Remove the entire commented-out legacy block in
frontend/context/walletContext.tsx (the ~118-line comment that contains the old
AppProvider, AppContext, useAppContext, and related imports and code). Keep the
file clean by deleting that commented section so only the current implementation
remains; ensure references to AppProvider, AppContext, and useAppContext still
compile after removal and run tests/build to confirm nothing else depends on the
commented code.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2d714fc4-2f70-40b4-9e24-a95ef446f96a
📒 Files selected for processing (3)
frontend/components/WalletConnectModal.tsxfrontend/components/Web3StatusBar.tsxfrontend/context/walletContext.tsx
| const invokeSorobanContract = async (contractId: string, functionName: string, args: any[] = []) => { | ||
| if (!address) throw new Error("No wallet connected"); | ||
| // Best-effort Soroban invocation using `soroban-client` if present. This is a helper that | ||
| // will build a transaction targeting the Soroban network and request Freighter to sign it. | ||
| // Actual invocation details (host function, footprints, etc.) depend on the contract ABI. | ||
| try { | ||
| // dynamic import to avoid build-time hard dependency when not used | ||
| const sc = await import("soroban-client"); | ||
| const SorobanClient = sc.default; | ||
| // Modern Soroban SDK usage | ||
| const rpc = new SorobanClient(SOROBAN_RPC); | ||
| // TODO: Implement full hostfunction builder for specific contract/ABI | ||
| // Example: await rpc.getContractData(contractId); | ||
| // TODO: Implement full hostfunction builder for specific contract/ABI | ||
| throw new Error("invokeSorobanContract: implement contract-specific invocation (ABI required)"); | ||
| // Dynamic import to avoid build-time issues | ||
| const { Contract, TimeoutInfinite } = await import("stellar-sdk"); | ||
|
|
||
| // Use the Soroban RPC | ||
| const rpcServer = new Server(SOROBAN_RPC, { allowHttp: true }); | ||
| const acct = await rpcServer.getAccount(address); | ||
| const contract = new Contract(contractId); | ||
|
|
||
| // Build the initial transaction | ||
| let tx = new TransactionBuilder(acct, { | ||
| fee: "10000", | ||
| networkPassphrase: NETWORK_PASSPHRASE, | ||
| }) | ||
| .addOperation(contract.call(functionName, ...args)) | ||
| .setTimeout(TimeoutInfinite) | ||
| .build(); | ||
|
|
||
| // Simulate transaction to get correct footprints & fee | ||
| const simulatedTx = await rpcServer.simulateTransaction(tx); | ||
|
|
||
| if ("error" in simulatedTx && simulatedTx.error) { | ||
| throw new Error(`Simulation failed: ${simulatedTx.error}`); | ||
| } | ||
|
|
||
| // Assemble transaction with simulation data | ||
| if (!simulatedTx.transactionData) { | ||
| throw new Error("Simulation failed: missing transactionData"); | ||
| } | ||
|
|
||
| tx = TransactionBuilder.assembleTransaction(tx, NETWORK_PASSPHRASE, simulatedTx as any).build(); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
fd -t f 'package.json' --exclude node_modules | xargs rg -n '"(`@stellar/`)?stellar-sdk"\s*:\s*"[^"]+"'Repository: NOVUS-X/XLMate
Length of output: 111
🏁 Script executed:
cat -n frontend/context/walletContext.tsx | sed -n '240,290p'Repository: NOVUS-X/XLMate
Length of output: 2324
🏁 Script executed:
rg -n "import.*stellar-sdk|from.*stellar-sdk" frontend/context/walletContext.tsxRepository: NOVUS-X/XLMate
Length of output: 271
🏁 Script executed:
rg -n "invokeSorobanContract" frontend/context/walletContext.tsx -A 40Repository: NOVUS-X/XLMate
Length of output: 4378
🏁 Script executed:
cat frontend/package.json | grep -A 20 -B 5 "stellar-sdk"Repository: NOVUS-X/XLMate
Length of output: 719
🌐 Web query:
stellar-sdk 10.4.0 contract.call xdr.ScVal parameters
💡 Result:
In stellar-sdk version 10.4.0 (specifically @stellar/stellar-sdk), the Contract.call method is used to invoke a Soroban smart contract function and returns an xdr.Operation for InvokeHostFunctionOp. Method signature: contract.call(method: string, ...params: xdr.ScVal[]): xdr.Operation Parameters: - method: string - Name of the contract method to call. - ...params: xdr.ScVal[] - Variable number of xdr.ScVal arguments to pass to the function. Each parameter must be a properly constructed xdr.ScVal instance matching the contract function's expected input types. Usage example: const contract = new Contract("CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE"); const op = contract.call("increment", xdr.ScVal.scvU32(5)); The SDK provides nativeToScVal and related utilities (via Contract.Spec) to convert JavaScript native values (numbers, strings, objects, arrays, etc.) to xdr.ScVal instances. For example: - Numbers: nativeToScVal(123, {type: 'u32'}) → xdr.ScVal.scvU32(123) - Addresses: Address.fromString("G...").toScVal - Strings: nativeToScVal("hello") → xdr.ScVal.scvString("hello") - Maps/Vecs: Automatically converted from objects/arrays with optional type hints. This API has remained stable across versions including 10.4.0, as confirmed by the official documentation and changelog. For full conversion details, see the scval.js source which handles type inference and validation.
Citations:
- 1: https://stellar.github.io/js-stellar-sdk/Contract.html
- 2: https://developers.stellar.org/docs/build/guides/transactions/invoke-contract-tx-sdk
- 3: http://stellar.github.io/js-stellar-sdk/module-contract.Spec.html
- 4: https://stellar.github.io/js-stellar-sdk/js-stellar-base_src_scval.js.html
- 5: https://raw.githubusercontent.com/stellar/js-stellar-sdk/master/CHANGELOG.md
- 6: https://registry.npmjs.org/%40stellar%2Fstellar-sdk
- 7: http://stellar.github.io/js-stellar-sdk/Contract.html
🌐 Web query:
stellar-sdk 10.4.0 TransactionBuilder.assembleTransaction signature networkPassphrase
💡 Result:
In @stellar/stellar-sdk version 10.4.0, TransactionBuilder does not have a direct method called assembleTransaction. The assembleTransaction function is a static utility in the rpc module that takes a raw Transaction or FeeBumpTransaction and a simulation response (Api.SimulateTransactionResponse or Api.RawSimulateTransactionResponse), returning a new TransactionBuilder with applied Soroban auth, resources, and adjusted fee. The networkPassphrase is preserved from the input raw transaction via TransactionBuilder.cloneFrom(raw, {..., networkPassphrase: raw.networkPassphrase}). Signature: assembleTransaction(raw: Transaction | FeeBumpTransaction, simulation: Api.SimulateTransactionResponse | Api.RawSimulateTransactionResponse): TransactionBuilder Usage example from source: const txnBuilder = TransactionBuilder.cloneFrom(raw, { fee: classicFeeNum.toString, sorobanData: success.transactionData.build, networkPassphrase: raw.networkPassphrase }); This is used in Soroban transaction preparation after simulateTransaction, typically via SorobanServer.prepareTransaction which internally calls it. The networkPassphrase ensures signatures are valid for the correct network (e.g., "Public Global Stellar Network ; September 2015" for mainnet).
Citations:
- 1: https://stellar.github.io/js-stellar-sdk/module-rpc.html
- 2: https://stellar.github.io/js-stellar-sdk/lib_rpc_transaction.js.html
- 3: https://stellar.github.io/js-stellar-sdk/TransactionBuilder.html
- 4: https://github.com/stellar/js-stellar-base/blob/master/CHANGELOG.md
🌐 Web query:
stellar-sdk 10.4.0 SorobanRpc.Api.isSimulationError
💡 Result:
SorobanRpc.Api.isSimulationError is a static method in the @stellar/stellar-sdk JavaScript library (available in version 10.4.0 and later) that checks if a Soroban RPC simulateTransaction response indicates an error. It returns true if the simulation failed (e.g., the response has an 'error' field), and false otherwise. This method is used in typical Soroban transaction workflows to validate simulation results before assembling and submitting transactions. For example: if (SorobanRpc.Api.isSimulationError(sim)) { throw sim.error; // or handle the error } It pairs with related methods like SorobanRpc.Api.isSimulationSuccess (checks for successful simulation) and SorobanRpc.Api.isSimulationRestore (checks if footprint restoration is needed). The method is part of the rpc.Api namespace, imported as: import { SorobanRpc } from '@stellar/stellar-sdk'; Note: In newer SDK versions (post-v12), the import path may be '@stellar/stellar-sdk/rpc' for the Api, but the functionality remains the same. Version 10.4.0 specifically includes Soroban RPC support via updates to stellar-base.
Citations:
- 1: http://stellar.github.io/js-stellar-sdk/module-rpc.html
- 2: https://stellar.github.io/js-stellar-sdk/lib_rpc_transaction.js.html
- 3:
error: invalid version byte. expected 48, got 16trying toauthorizeEntrystellar/js-stellar-sdk#1020 - 4: https://github.com/stellar/js-stellar-sdk
- 5: https://registry.npmjs.org/%40stellar%2Fstellar-sdk
🌐 Web query:
stellar-sdk 10.4.0 SorobanRpc namespace import rpc module
💡 Result:
In stellar-sdk version 10.4.0, the Soroban RPC functionality is accessed via the SorobanRpc namespace. To import the rpc module (which provides the Soroban RPC Server, API types, and helpers like assembleTransaction), use: import { SorobanRpc } from 'stellar-sdk'; Then destructure as needed: const { Server, Api, assembleTransaction } = SorobanRpc; Example usage: const server = new SorobanRpc.Server('https://soroban-testnet.stellar.org'); This structure was established around v11.0.0 but was present in v10.4.0 per the changelog mentioning v10.4.0 and migration guides referencing SorobanRpc. In later versions (post-v11), SorobanRpc was deprecated in favor of a top-level rpc export: import { rpc } from '@stellar/stellar-sdk'; Note: The package transitioned to @stellar/stellar-sdk scoped name starting around v11+, but v10.4.0 uses the unscoped stellar-sdk. Always check your bundler for tree-shaking with named imports.
Citations:
- 1: https://gist.github.com/Shaptic/5ce4f16d9cce7118f391fbde398c2f30
- 2: https://github.com/stellar/js-stellar-sdk
- 3: https://github.com/stellar/js-stellar-sdk/blob/master/CHANGELOG.md
- 4: http://stellar.github.io/js-stellar-sdk/module-rpc.Server.html
🌐 Web query:
stellar-sdk 10.4.0 "new Server" SOROBAN_RPC vs SorobanRpc.Server
💡 Result:
In the stellar-sdk JavaScript/TypeScript library (likely @stellar/stellar-sdk, as the legacy 'stellar-sdk' package reached v13.x), the primary way to create a Soroban RPC client (now Stellar RPC) is via new Server(url, options), where Server is from the rpc module. SorobanRpc.Server refers to the Server class in the SorobanRpc namespace, used in older or specific contexts like the deprecated js-soroban-client library. Example: new SorobanRpc.Server('http://localhost:8000/soroban/rpc'). "SOROBAN_RPC" likely refers to the Soroban RPC protocol or environment variable/constant, while new Server is the constructor call for the client. No specific changes or differences are noted in version 10.4.0 (which exists in the old stellar-sdk package per changelogs), as RPC client usage has remained consistent: const server = new StellarSdk.rpc.Server(rpcUrl); or similar import. Official docs confirm new Server(serverURL) for RPC connections, with options like {allowHttp: true} for local dev. Soroban RPC was renamed to Stellar RPC in late 2024, but SDK classes retained naming. Usage example: import * as StellarSdk from '@stellar/stellar-sdk'; const server = new StellarSdk.rpc.Server('https://soroban-testnet.stellar.org'); No evidence of breaking changes to this API in recent versions; it's the standard constructor.
Citations:
- 1: https://www.npmjs.com/package/@stellar/stellar-sdk
- 2: https://github.com/stellar/js-stellar-sdk/blob/master/CHANGELOG.md
- 3: https://github.com/stellar/js-stellar-sdk/releases/tag/v14.4.0
- 4: https://stellar.github.io/js-soroban-client/Server.html
- 5: https://github.com/stellar/js-soroban-client
- 6: http://stellar.github.io/js-stellar-sdk/module-rpc.Server.html
- 7: https://cdn.jsdelivr.net/npm/soroban-client@1.0.1/lib/server.d.ts
- 8: https://github.com/stellar/js-stellar-sdk
Fix critical API breakage in Soroban transaction flow.
-
contract.call()requiresxdr.ScVal[]arguments (Line 265): Currently passingany[]directly. The method signature iscontract.call(method: string, ...params: xdr.ScVal[]). Each argument must be a properly constructedxdr.ScValinstance (e.g.,xdr.ScVal.scvU32(5)for numbers). Raw JS values will fail simulation. Change parameter type fromany[]toxdr.ScVal[]and require callers to pre-convert using SDK utilities likenativeToScVal. -
assembleTransaction()call is broken (Line 281): The method is in therpcmodule, notTransactionBuilder. Correct signature isSorobanRpc.assembleTransaction(tx, simulatedTx)(two arguments only;networkPassphraseis implicitly preserved from the transaction). The current three-argument call will throw at runtime. ReplaceTransactionBuilder.assembleTransaction(tx, NETWORK_PASSPHRASE, simulatedTx as any).build()withSorobanRpc.assembleTransaction(tx, simulatedTx).build(). -
Use
SorobanRpc.Api.isSimulationError()for error checking (Line 272): Replace the manual check with the SDK's discriminated union helper:if (SorobanRpc.Api.isSimulationError(simulatedTx)).
Also update imports to use SorobanRpc namespace: import { SorobanRpc, ... } from "stellar-sdk" and use new SorobanRpc.Server(SOROBAN_RPC, { allowHttp: true }) instead of plain new Server().
🔧 Proposed fix
const invokeSorobanContract = async (
contractId: string,
functionName: string,
- args: any[] = [],
+ args: xdr.ScVal[] = [],
) => {
if (!address) throw new Error("No wallet connected");
try {
- // Dynamic import to avoid build-time issues
- const { Contract, TimeoutInfinite } = await import("stellar-sdk");
-
- // Use the Soroban RPC
- const rpcServer = new Server(SOROBAN_RPC, { allowHttp: true });
+ const rpcServer = new SorobanRpc.Server(SOROBAN_RPC, { allowHttp: true });
const acct = await rpcServer.getAccount(address);
const contract = new Contract(contractId);
let tx = new TransactionBuilder(acct, {
fee: "10000",
networkPassphrase: NETWORK_PASSPHRASE,
})
.addOperation(contract.call(functionName, ...args))
.setTimeout(TimeoutInfinite)
.build();
const simulatedTx = await rpcServer.simulateTransaction(tx);
- if ("error" in simulatedTx && simulatedTx.error) {
+ if (SorobanRpc.Api.isSimulationError(simulatedTx)) {
throw new Error(`Simulation failed: ${simulatedTx.error}`);
}
- // Assemble transaction with simulation data
- if (!simulatedTx.transactionData) {
- throw new Error("Simulation failed: missing transactionData");
- }
-
- tx = TransactionBuilder.assembleTransaction(tx, NETWORK_PASSPHRASE, simulatedTx as any).build();
+ tx = SorobanRpc.assembleTransaction(tx, simulatedTx).build();Also update imports (top of file):
-import { Server, TransactionBuilder, Networks, Operation, Asset } from "stellar-sdk";
+import { SorobanRpc, TransactionBuilder, Networks, Operation, Asset } from "stellar-sdk";And import Contract and TimeoutInfinite statically or ensure they come from the right namespace.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@frontend/context/walletContext.tsx` around lines 249 - 281,
invokeSorobanContract has three issues: contract.call is being passed raw JS
values — change the args type to xdr.ScVal[] and require callers to convert
values (use nativeToScVal/xdr.ScVal helpers) so each parameter is an xdr.ScVal
when calling contract.call(method, ...args); simulatedTx error checking should
use the SDK helper SorobanRpc.Api.isSimulationError(simulatedTx) instead of
manual property checks; and assembling the final tx must call
SorobanRpc.assembleTransaction(tx, simulatedTx).build() (not
TransactionBuilder.assembleTransaction with a networkPassphrase arg). Also
update imports to bring in SorobanRpc, xdr, nativeToScVal (and ensure you
construct the RPC client with new SorobanRpc.Server(SOROBAN_RPC, { allowHttp:
true })) so the corrected symbols are available.
I have successfully finished the Frontend: Sound FX engine for captures and checks.
I look forward to working with you next time.]
Thank you.
Closes #581