Skip to content

feat: implement Stellar contract interaction methods in StellarService#429

Merged
ryzen-xp merged 3 commits into
Alien-Protocol:devfrom
Mmesolove:feat/backend-stellar-service-methods
May 2, 2026
Merged

feat: implement Stellar contract interaction methods in StellarService#429
ryzen-xp merged 3 commits into
Alien-Protocol:devfrom
Mmesolove:feat/backend-stellar-service-methods

Conversation

@Mmesolove
Copy link
Copy Markdown
Contributor

@Mmesolove Mmesolove commented Apr 25, 2026

Closes #398


  • Add typed methods for all stable contract calls (getOwner, resolveUsername, getChainAddress, etc.)
  • Implement comprehensive error handling with StellarRpcException
  • Add complete TypeScript interfaces for all return types in stellar.types.ts
  • Create comprehensive test suite with mocked RPC responses
  • Fix package.json and tsconfig.json configuration issues
  • Ensure no any types used throughout implementation

Resolves contract interaction requirements for backend integration

Summary by CodeRabbit

  • Improvements
    • Enhanced error handling for Stellar RPC operations with detailed error messaging and context information.
    • Introduced standardized type definitions for Stellar contract interactions to ensure consistent data handling across the system.

- Add typed methods for all stable contract calls (getOwner, resolveUsername, getChainAddress, etc.)
- Implement comprehensive error handling with StellarRpcException
- Add complete TypeScript interfaces for all return types in stellar.types.ts
- Create comprehensive test suite with mocked RPC responses
- Fix package.json and tsconfig.json configuration issues
- Ensure no any types used throughout implementation

Resolves contract interaction requirements for backend integration
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f0ea38d4-a877-4225-b042-7a2ca434815b

📥 Commits

Reviewing files that changed from the base of the PR and between 7933e20 and f32cb8a.

📒 Files selected for processing (1)
  • backend/src/stellar/stellar.service.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/src/stellar/stellar.service.ts

📝 Walkthrough

Walkthrough

This pull request introduces foundational infrastructure for Stellar contract interactions by adding a dedicated StellarRpcException class for RPC error handling, expanding service imports, and establishing comprehensive TypeScript type definitions for contract method return values and configuration objects.

Changes

Cohort / File(s) Summary
Stellar Exception Handling
backend/src/stellar/stellar.exceptions.ts
New StellarRpcException class extending NestJS HttpException with HTTP status BAD_GATEWAY. Packages error responses with message, label, original error details, and optional context fields (contractId, method).
Stellar Type Definitions
backend/src/stellar/stellar.types.ts
New module exporting enums (ChainType, PrivacyMode), interfaces for vault configuration and state (VaultConfig, VaultState, ScheduledPayment, ResolveData), and typed aliases for contract method return values (GetOwnerResult, ResolveStellarResult, GetChainAddressResult, GetVaultBalanceResult, GetScheduledPaymentResult, IsVaultActiveResult, GetCreatedAtResult).
Stellar Service Imports
backend/src/stellar/stellar.service.ts
Expanded imports to include Address and xdr from @stellar/stellar-sdk, plus StellarRpcException and typed result definitions from stellar.types.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Suggested labels

Approved

Suggested reviewers

  • ryzen-xp

Poem

🐰✨ Fresh types and errors, neat and clean,
Building blocks for Stellar's stellar scene,
RPC exceptions handled with grace,
Foundation set for this blockchain space!
Hop along, the contract calls await! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR changes are incomplete. Required method implementations are missing from stellar.service.ts; only types and exceptions are added, not the actual service methods [#398]. Implement all seven required methods (getOwner, resolveUsername, getChainAddress, getVaultBalance, getScheduledPayment, isVaultActive, getCreatedAt) in stellar.service.ts with proper error handling [#398].
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change—implementing Stellar contract interaction methods in StellarService.
Out of Scope Changes check ✅ Passed All changes are scoped to Stellar contract infrastructure: exception handling, type definitions, and service imports directly support the stated objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@Mmesolove
Copy link
Copy Markdown
Contributor Author

please review.

@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented Apr 25, 2026

@Mmesolove Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/src/stellar/stellar.service.ts (1)

32-32: ⚠️ Potential issue | 🟡 Minor

error.message access on implicit any in catch handlers.

In tsconfig strict mode, catch (error) makes error: unknown, and error.message won't compile. The repeated pattern ${error.message} (Lines 32, 83, 116, 155, 193, 243, 280, 317) relies on any typing. Narrow with error instanceof Error ? error.message : String(error) or a small helper to stay aligned with the PR's "no any" goal.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.service.ts` at line 32, The catch blocks in
StellarService that call this.logger.error with `${error.message}` use an
implicit any; update those logger calls (the ones inside the StellarService
class where you currently do this.logger.error(`Failed to connect to Stellar
RPC: ${error.message}`)` and the similar error logs repeated elsewhere) to first
narrow the caught value to a string safely—either inline with `error instanceof
Error ? error.message : String(error)` or by adding a small helper like
`formatError(error)` that returns `Error` messages or stringifies otherwise—and
use that result in the log message so compilation under strict mode succeeds and
no any is introduced.
🧹 Nitpick comments (3)
backend/src/stellar/stellar.service.ts (3)

56-325: Significant duplication across the seven RPC read methods — extract a helper.

Each method follows the same skeleton: get contract → simulate → check result.error → check retval → parse XDR → check scvVoid → decode → wrap errors as StellarRpcException. The transaction-wrapping fix (see earlier comment) and the scvVoid comparison fix would both benefit from being centralized. Suggest extracting:

private async callContract<T>(
  contract: Contract,
  method: string,
  args: xdr.ScVal[],
  decode: (val: xdr.ScVal) => T,
  errorContext: { contractId: string; logPrefix: string },
): Promise<T | null> { ... }

This roughly halves the file size, makes the seven methods one-liners, and means future fixes (e.g., switching to scValToNative) happen in one place.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.service.ts` around lines 56 - 325, Extract a
common helper (e.g., private async callContract<T>(contract: Contract, method:
string, args: any[], decode: (val: xdr.ScVal)=>T, errorContext:
{contractId:string; logPrefix:string}): Promise<T|null>) to centralize the
repeated pattern used by getOwner, resolveUsername, getChainAddress,
getVaultBalance, getScheduledPayment, isVaultActive and getCreatedAt: call
this.getCoreContract()/getEscrowContract, invoke
this.server.simulateTransaction(contract.call(method, ...args)), check
result.error and result.result?.retval, parse with xdr.ScVal.fromXDR, detect
scvVoid correctly, then run the supplied decode() to produce T (or return null),
and on catch log with errorContext.logPrefix and rethrow a StellarRpcException
constructed with errorContext.contractId and the method name; replace each RPC
method body with a single call to callContract passing the appropriate contract,
method string, args, decode lambda and errorContext.

77-79: parsed.switch() === xdr.ScValType.scvVoid() relies on enum-singleton identity — prefer comparing .value or .name.

In js-xdr (used by @stellar/stellar-sdk), enum members are typically singletons, so reference equality usually works. However, this isn't part of any documented contract; it's safer and more obviously correct to compare the underlying numeric tag. The same pattern is repeated at Lines 147, 186, 224, 274, and 311.

-      if (parsed.switch() === xdr.ScValType.scvVoid()) {
+      if (parsed.switch().value === xdr.ScValType.scvVoid().value) {
         return null;
       }

Or use scValToNative(parsed) from @stellar/stellar-sdk and check for undefined/null, which avoids manual switch-case parsing entirely and handles all the type conversions (i128 → bigint, u64 → bigint, address → string, etc.) below.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.service.ts` around lines 77 - 79, The checks like
parsed.switch() === xdr.ScValType.scvVoid() in stellar.service.ts are relying on
enum-singleton identity; change them to compare the underlying tag (e.g.,
parsed.switch().value === xdr.ScValType.scvVoid().value or .name) or —
preferably — replace the manual switch/parsing logic and use
scValToNative(parsed) from `@stellar/stellar-sdk` and test for undefined/null to
handle all types safely; update all occurrences (the parsed.switch() checks at
the places noted and the surrounding conversion logic) to use the tag comparison
or scValToNative to avoid fragile reference-equality checks.

96-124: resolveUsername lacks a timeout/cancellation safeguard.

This is a blocking external RPC call from a request thread. If simulateTransaction hangs (network partition, slow RPC), the NestJS request will hang with it. Given the BAD_GATEWAY mapping in StellarRpcException already implies upstream-failure semantics, consider wrapping simulateTransaction calls with AbortController / a Promise.race timeout, or configure rpc.Server with HTTP timeouts. Same applies to all seven methods.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.service.ts` around lines 96 - 124, The
resolveUsername method calls this.server.simulateTransaction (in
resolveUsername) without any timeout/cancellation, so a hung RPC will block the
request thread; wrap the simulateTransaction call with a cancellable timeout
(e.g., use AbortController if the rpc.Server supports AbortSignal or implement a
Promise.race with a configurable timeout) and ensure you abort/cleanup the
controller on completion; surface a clear timeout error into the existing catch
so StellarRpcException still contains context (coreContractId,
'resolve_stellar'), and apply the same pattern to the other six methods that
call this.server.simulateTransaction to ensure all RPC calls have consistent
timeout/cancellation handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/package.json`:
- Line 21: The "test:unit" npm script currently filters tests with
--testPathPattern=keeper which omits the new Stellar tests; update package.json
by either removing the --testPathPattern to run the full test suite, or change
it to a broader pattern such as --testPathPattern="keeper|stellar" (or include
'src/stellar') so backend/src/stellar/stellar.service.spec.ts is executed, or
alternatively delete the "test:unit" script and rely on the existing
"test"/"test:cov" targets.

In `@backend/src/stellar/stellar.exceptions.ts`:
- Around line 13-22: The current Stellar RPC exception passes originalError and
contractId into the response body (the object passed to super), which can leak
internal details; change the payload sent to super to contain only a sanitized
message and generic error code (e.g., message: 'Upstream service error', error:
'Stellar RPC Error'), and move the raw originalError and contractId onto the
exception instance for logging only (store them in properties like
this.originalError and this.contractId or similar) so they are not serialized in
the HTTP response; update the class in stellar.exceptions.ts where super(...) is
called to implement this separation and ensure logging routines read the
internal fields instead of the response payload.
- Around line 9-23: Change the public constructor parameter originalError?: any
to originalError?: unknown in the Stellar exception class (the constructor that
assigns originalError and passes originalError?.message into the super payload)
and update any places that read error.message in stellar.service.ts catch blocks
to first narrow the unknown (e.g., check typeof error === 'object' && error !==
null && 'message' in error) before accessing message; keep the payload behavior
the same by extracting the message when present and otherwise using the error
value.

In `@backend/src/stellar/stellar.service.spec.ts`:
- Around line 91-198: Tests currently allow any value to be passed into
mockServer.simulateTransaction, hiding the real bug where
Contract.prototype.call returns an Operation but simulateTransaction expects a
built Transaction/FeeBumpTransaction; update the tests (those exercising
getOwner, resolveUsername, getChainAddress) to assert the simulated RPC receives
a Transaction instance by checking mockServer.simulateTransaction was called
with expect.any(Transaction) or by capturing the argument and asserting it is an
instance of Transaction or FeeBumpTransaction (referencing mockContract.call and
mockServer.simulateTransaction and the service methods
getOwner/resolveUsername/getChainAddress) so the test suite will fail if
contract.call() is not wrapped into a real Transaction before
simulateTransaction is invoked.
- Around line 55-57: Tests currently call jest.spyOn on xdr.ScVal.fromXDR,
xdr.ScValType.scvVoid, and Address.fromScVal but only use jest.clearAllMocks()
in afterEach, which leaves spy implementations in place; change the cleanup to
call jest.restoreAllMocks() in the afterEach (or add jest.restoreAllMocks()
alongside clearAllMocks) so all jest.spyOn mocks are restored between tests and
no mock implementations leak across tests.

In `@backend/src/stellar/stellar.service.ts`:
- Line 237: The code coerces u64 Hyper values to Number (see release_at
assignment and getCreatedAt) which will silently lose precision for values >
Number.MAX_SAFE_INTEGER; update these sites to preserve full precision by
returning a bigint or string instead of Number, adjust the return
types/interfaces and any callers that consume release_at/getCreatedAt to accept
bigint|string, and/or add a clear comment/docstring stating the timestamp is a
Unix seconds value and that Number truncation is acceptable if you decide to
keep it.
- Around line 228-241: The current decoding in getScheduledPayment uses
parsed.instance().instanceValue().map() and positional indexing which is
incorrect for a Soroban struct return; instead use parsed.map() to get the
xdr.ScMapEntry[] and extract fields by their string keys (e.g.
"from","to","token","amount","release_at","executed") rather than by index so
decoding is alphabetical-order independent, then convert values with the same
helpers you already use (Address.fromScVal, .i128(), .u64(), .b(),
Buffer.from(...).toString('hex')); alternatively replace the manual decode with
scValToNative(parsed) and then map that native object into the ScheduledPayment
shape.
- Line 67: The throw currently uses new Error(result.error) which stringifies
structured SimulateTransactionResponse.error to "[object Object]"; replace it
with new Error(typeof result.error === 'string' ? result.error :
JSON.stringify(result.error)) wherever you construct an Error from result.error
(e.g., in the simulate/submit handling blocks that reference result and
SimulateTransactionResponse), and apply the same change to the other occurrences
that build an Error from result.error so the full structured error is preserved
in the thrown message.
- Line 63: The contract.call(...) invocations (get_owner, resolve_stellar,
get_chain_address, get_balance, get_scheduled_payment, is_vault_active,
get_created_at) are passing raw JS values; convert arguments to ScVal instances:
for hex 32-byte values (commitment, usernameHash) do Buffer.from(hex, 'hex')
then wrap with StellarSdk.xdr.ScVal.scvBytes(...); for paymentId use
StellarSdk.xdr.ScVal.scvU32(paymentId); for chain use the ScVal representation
the contract expects (e.g., scvU32(enumIndex) or scvSymbol(enumName) depending
on the contract ABI); update each contract.call(...) call site to pass these
ScVal-wrapped args (follow the pattern used in soroban.service.ts: convert hex →
Buffer → scvBytes, numbers → scvU32, enums → appropriate ScVal) so on-chain
types match.
- Around line 151-153: The current code decodes parsed.bytes() as UTF-8 which
corrupts non-text addresses; update the address conversion in the function that
handles parsed.bytes() (in stellar.service.ts) to branch on the provided chain:
ChainType parameter and use chain-specific encodings — for EVM return '0x' +
Buffer.from(bytes).toString('hex'), for Bitcoin use base58 encoding, for Cosmos
use bech32 encoding (and other chains as required); replace the existing
Buffer.from(bytes).toString('utf8') path with this branching logic and ensure
the function name handling parsed.bytes() uses the ChainType argument to choose
the correct encoder.
- Around line 62-64: The current calls pass an xdr.Operation to
this.server.simulateTransaction but simulateTransaction expects a built
Transaction; create a helper method (e.g., simulateContractCall(operation:
xdr.Operation)) that: imports TransactionBuilder, BASE_FEE and Account from
'@stellar/stellar-sdk', constructs a throwaway source Account with sequence '0',
builds a TransactionBuilder using the service's ConfigService.networkPassphrase
and BASE_FEE, .addOperation(operation).setTimeout(30).build(), and then calls
this.server.simulateTransaction(tx); replace direct
simulateTransaction(contract.call(...)) calls in getOwner, resolveUsername,
getChainAddress, getVaultBalance, getScheduledPayment, isVaultActive, and
getCreatedAt to use this new helper so all operations are wrapped into a proper
Transaction before simulation.

In `@backend/src/stellar/stellar.types.ts`:
- Around line 5-15: Change the string-valued enums ChainType and PrivacyMode to
numeric (C-like) enums so they emit integer discriminants matching the Rust
contract; update the definitions of ChainType and PrivacyMode (the enum
declarations) to assign explicit numeric values (0,1,2,3 for ChainType and 0,1
for PrivacyMode) instead of string literals so the values sent to the contract
are u32 discriminants rather than strings.

---

Outside diff comments:
In `@backend/src/stellar/stellar.service.ts`:
- Line 32: The catch blocks in StellarService that call this.logger.error with
`${error.message}` use an implicit any; update those logger calls (the ones
inside the StellarService class where you currently do this.logger.error(`Failed
to connect to Stellar RPC: ${error.message}`)` and the similar error logs
repeated elsewhere) to first narrow the caught value to a string safely—either
inline with `error instanceof Error ? error.message : String(error)` or by
adding a small helper like `formatError(error)` that returns `Error` messages or
stringifies otherwise—and use that result in the log message so compilation
under strict mode succeeds and no any is introduced.

---

Nitpick comments:
In `@backend/src/stellar/stellar.service.ts`:
- Around line 56-325: Extract a common helper (e.g., private async
callContract<T>(contract: Contract, method: string, args: any[], decode: (val:
xdr.ScVal)=>T, errorContext: {contractId:string; logPrefix:string}):
Promise<T|null>) to centralize the repeated pattern used by getOwner,
resolveUsername, getChainAddress, getVaultBalance, getScheduledPayment,
isVaultActive and getCreatedAt: call this.getCoreContract()/getEscrowContract,
invoke this.server.simulateTransaction(contract.call(method, ...args)), check
result.error and result.result?.retval, parse with xdr.ScVal.fromXDR, detect
scvVoid correctly, then run the supplied decode() to produce T (or return null),
and on catch log with errorContext.logPrefix and rethrow a StellarRpcException
constructed with errorContext.contractId and the method name; replace each RPC
method body with a single call to callContract passing the appropriate contract,
method string, args, decode lambda and errorContext.
- Around line 77-79: The checks like parsed.switch() === xdr.ScValType.scvVoid()
in stellar.service.ts are relying on enum-singleton identity; change them to
compare the underlying tag (e.g., parsed.switch().value ===
xdr.ScValType.scvVoid().value or .name) or — preferably — replace the manual
switch/parsing logic and use scValToNative(parsed) from `@stellar/stellar-sdk` and
test for undefined/null to handle all types safely; update all occurrences (the
parsed.switch() checks at the places noted and the surrounding conversion logic)
to use the tag comparison or scValToNative to avoid fragile reference-equality
checks.
- Around line 96-124: The resolveUsername method calls
this.server.simulateTransaction (in resolveUsername) without any
timeout/cancellation, so a hung RPC will block the request thread; wrap the
simulateTransaction call with a cancellable timeout (e.g., use AbortController
if the rpc.Server supports AbortSignal or implement a Promise.race with a
configurable timeout) and ensure you abort/cleanup the controller on completion;
surface a clear timeout error into the existing catch so StellarRpcException
still contains context (coreContractId, 'resolve_stellar'), and apply the same
pattern to the other six methods that call this.server.simulateTransaction to
ensure all RPC calls have consistent timeout/cancellation handling.
🪄 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: 98ea4b3b-e438-43ee-876b-0a86f74d3771

📥 Commits

Reviewing files that changed from the base of the PR and between ceb40c7 and 7933e20.

📒 Files selected for processing (6)
  • backend/package.json
  • backend/src/stellar/stellar.exceptions.ts
  • backend/src/stellar/stellar.service.spec.ts
  • backend/src/stellar/stellar.service.ts
  • backend/src/stellar/stellar.types.ts
  • backend/tsconfig.json
💤 Files with no reviewable changes (1)
  • backend/tsconfig.json

Comment thread backend/package.json Outdated
Comment thread backend/src/stellar/stellar.exceptions.ts
Comment thread backend/src/stellar/stellar.exceptions.ts
Comment thread backend/src/stellar/stellar.service.spec.ts Outdated
Comment thread backend/src/stellar/stellar.service.spec.ts Outdated
Comment thread backend/src/stellar/stellar.service.ts Outdated
);

if (result.error) {
throw new Error(result.error);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

@stellar/stellar-sdk 11 SimulateTransactionResponse error field type

💡 Result:

In @stellar/stellar-sdk version 11 (and later versions), the SimulateTransactionResponse interface includes an optional 'error' field that captures simulation failure details when present. This field is only populated if the transaction simulation failed; successful simulations omit it and provide fields like transactionData, minResourceFee, results, etc. instead. The exact TypeScript type of the 'error' field is a structured object containing details about the failure reason, as defined in the Soroban RPC specification. Official docs describe it as: "(optional) - This field will include details about why the invoke host function call failed. Only present if the transaction simulation failed." (Stellar Developers documentation). In SDK code examples, it is accessed as sim.error, and utility functions like isSimulationSuccess check if error is absent to determine success. The SDK parses raw RPC responses into this typed interface via parseRawSimulation, ensuring XDR fields are decoded. For version-specific details in v11, the structure aligns with Soroban RPC spec, where error provides diagnostic info (e.g., contract errors, resource limits) even with partial context like events.

Citations:


🏁 Script executed:

cat -n backend/src/stellar/stellar.service.ts | head -80

Repository: Alien-Protocol/Alien-Protocol

Length of output: 2908


🏁 Script executed:

# Search for SimulateTransactionResponse type definition
rg "SimulateTransactionResponse" --type ts -A 5 -B 2

Repository: Alien-Protocol/Alien-Protocol

Length of output: 55


🏁 Script executed:

# Check imports and type definitions in stellar.service.ts
head -50 backend/src/stellar/stellar.service.ts

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1576


🏁 Script executed:

# Check all lines mentioned in the review
rg "throw new Error\(result\.error\)" --type ts -B 2 -A 2

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1981


🏁 Script executed:

# Look at the entire file to find all instances
wc -l backend/src/stellar/stellar.service.ts

Repository: Alien-Protocol/Alien-Protocol

Length of output: 116


🏁 Script executed:

# Get the specific lines mentioned
sed -n '60,70p' backend/src/stellar/stellar.service.ts
sed -n '100,110p' backend/src/stellar/stellar.service.ts
sed -n '133,143p' backend/src/stellar/stellar.service.ts

Repository: Alien-Protocol/Alien-Protocol

Length of output: 912


🏁 Script executed:

# Search for package.json to determine SDK version
cat -n backend/package.json | grep -A 5 -B 5 "stellar-sdk"

Repository: Alien-Protocol/Alien-Protocol

Length of output: 512


🏁 Script executed:

# Check for type definition files or stellar SDK imports
find node_modules/@stellar/stellar-sdk -name "*.d.ts" -type f 2>/dev/null | head -20

Repository: Alien-Protocol/Alien-Protocol

Length of output: 55


🏁 Script executed:

# Search in the codebase for how error is accessed/used from result
rg "result\.error" --type ts -B 2 -A 2

Repository: Alien-Protocol/Alien-Protocol

Length of output: 2317


🏁 Script executed:

# Check if there are TypeScript definitions we can inspect
ls -la node_modules/@stellar/stellar-sdk/ 2>/dev/null | head -20

Repository: Alien-Protocol/Alien-Protocol

Length of output: 55


🏁 Script executed:

# Check if there's any TypeScript interface definition in comments or types
rg "SimulateTransactionResponse|type.*error" --type ts -B 3 -A 3

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1231


🏁 Script executed:

# Look at the stellar SDK source to understand the error type
# Since node_modules may not have the source, let's check what we can infer from usage
cat -n backend/src/stellar/stellar.service.ts | sed -n '50,330p'

Repository: Alien-Protocol/Alien-Protocol

Length of output: 10017


Improve error message by stringifying result.error objects.

The error field in SimulateTransactionResponse is a structured object, not a string. Passing it directly to new Error() results in Error: [object Object], losing error details. Use new Error(typeof result.error === 'string' ? result.error : JSON.stringify(result.error)) instead. This pattern is repeated at lines 104, 137, 176, 214, 264, 301.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.service.ts` at line 67, The throw currently uses
new Error(result.error) which stringifies structured
SimulateTransactionResponse.error to "[object Object]"; replace it with new
Error(typeof result.error === 'string' ? result.error :
JSON.stringify(result.error)) wherever you construct an Error from result.error
(e.g., in the simulate/submit handling blocks that reference result and
SimulateTransactionResponse), and apply the same change to the other occurrences
that build an Error from result.error so the full structured error is preserved
in the thrown message.

Comment thread backend/src/stellar/stellar.service.ts Outdated
Comment on lines +151 to +153
// Convert bytes to string
const bytes = parsed.bytes();
return Buffer.from(bytes).toString('utf8');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

soroban username service get_chain_address EVM bytes representation hex

💡 Result:

No official or widely documented "Soroban Username Service" or specific function "get_chain_address" was found in authoritative sources like Stellar/Soroban documentation. Soroban Name Service (SNS) exists as community projects, such as the one by developer tosinshada (GitHub discussion from 2023, result 19), with contracts in sns-registry, sns-registrar, and sns-resolver folders. These allow registering names associated with Soroban addresses (Stellar account or contract IDs, 32-byte XDR-serialized, often represented as 56/64-char hex strings prefixed "C" for contracts). Soroban addresses are opaque 32-byte identifiers. Their "bytes representation" is the raw 32 bytes. In hex, typically the full XDR AccountContractId (discriminant + 32 bytes), e.g., contract addresses are 64 hex chars. EVM addresses are 20-byte hex (40 chars, "0x" prefixed). No evidence of built-in "get_chain_address" returning EVM-specific bytes/hex in Soroban name services. If it exists in a custom contract, it likely retrieves a stored chain address (e.g., EVM) as BytesN<20> or Bytes, output as base64 or hex via SDK/RPC. To invoke: Use soroban-contract-sdk to call the function on the resolver contract ID, passing username as Symbol or String. Example Rust client: use soroban_client::rpc::Server; use soroban_client::Address; let server = Server::new(&rpc_url, &network); let contract = Address::from_string(&contract_id)?; // SNS resolver contract ID let username = Symbol::new(&env, "example"); // or String let invoke = soroban_client::InvokeBuilder::new(&server, &contract, "get_chain_address", (&username,)); let response = invoke.call?; The response would be SCVal::Bytes(bytes), convertible to hex: hex::encode(bytes.to_vec). No exact function signature or EVM-specific handling confirmed; likely custom to store/retrieve cross-chain addresses. Check specific SNS contract source for details (e.g., tosinshada's repo).

Citations:


🏁 Script executed:

# First, let's examine the file structure and find the specific file
fd -t f "stellar.service.ts" backend/

Repository: Alien-Protocol/Alien-Protocol

Length of output: 112


🏁 Script executed:

# Now let's look at the specific lines and surrounding context
head -160 backend/src/stellar/stellar.service.ts | tail -30

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1024


🏁 Script executed:

# Let's search for ChainType enum definition
rg "enum ChainType" -A 10

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1865


🏁 Script executed:

# Search for the unit test mentioned in the comment
fd -t f "stellar.service.spec.ts" -o "stellar.test.ts" -o "*.spec.ts" backend/ | head -5

Repository: Alien-Protocol/Alien-Protocol

Length of output: 223


🏁 Script executed:

# Look for test files that might test this functionality
fd -t f "*.spec.ts" backend/ | rg -i stellar

Repository: Alien-Protocol/Alien-Protocol

Length of output: 362


🏁 Script executed:

# Find test files properly
find backend -name "*.spec.ts" -type f

Repository: Alien-Protocol/Alien-Protocol

Length of output: 245


🏁 Script executed:

# Get more context around the problematic code - the full function
sed -n '130,170p' backend/src/stellar/stellar.service.ts

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1260


🏁 Script executed:

# Search for how this function is called and if chain is available
rg "get_chain_address" -B 5 -A 15 backend/src/stellar/stellar.service.ts

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1363


🏁 Script executed:

# Look at the stellar service spec file
cat backend/src/stellar/stellar.service.spec.ts

Repository: Alien-Protocol/Alien-Protocol

Length of output: 14915


🏁 Script executed:

# Also check what GetChainAddressResult type is
rg "GetChainAddressResult" -A 5 backend/

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1430


🏁 Script executed:

# Look for the actual Soroban contract code to understand what it returns
find onchain -name "*.rs" -type f | xargs rg "get_chain_address" -A 10 2>/dev/null | head -50

Repository: Alien-Protocol/Alien-Protocol

Length of output: 3826


Replace UTF-8 decoding with chain-specific address encoding.

EVM addresses are 20 raw bytes; Bitcoin and Cosmos addresses are also binary data, not UTF-8 text. Decoding raw bytes as UTF-8 will corrupt addresses with high bytes (≥ 0x80). The unit test passes only because it mocks an ASCII hex string rather than binary data.

For EVM, use hex encoding: '0x' + Buffer.from(bytes).toString('hex'). Other chains require different encodings (base58, bech32). Branch on the available chain: ChainType parameter:

Suggested fix
-      // Convert bytes to string
-      const bytes = parsed.bytes();
-      return Buffer.from(bytes).toString('utf8');
+      const bytes = Buffer.from(parsed.bytes());
+      switch (chain) {
+        case ChainType.Evm:
+          return '0x' + bytes.toString('hex');
+        // TODO: confirm representation for Bitcoin/Solana/Cosmos
+        default:
+          return bytes.toString('hex');
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Convert bytes to string
const bytes = parsed.bytes();
return Buffer.from(bytes).toString('utf8');
const bytes = Buffer.from(parsed.bytes());
switch (chain) {
case ChainType.Evm:
return '0x' + bytes.toString('hex');
// TODO: confirm representation for Bitcoin/Solana/Cosmos
default:
return bytes.toString('hex');
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.service.ts` around lines 151 - 153, The current
code decodes parsed.bytes() as UTF-8 which corrupts non-text addresses; update
the address conversion in the function that handles parsed.bytes() (in
stellar.service.ts) to branch on the provided chain: ChainType parameter and use
chain-specific encodings — for EVM return '0x' +
Buffer.from(bytes).toString('hex'), for Bitcoin use base58 encoding, for Cosmos
use bech32 encoding (and other chains as required); replace the existing
Buffer.from(bytes).toString('utf8') path with this branching logic and ensure
the function name handling parsed.bytes() uses the ChainType argument to choose
the correct encoder.

Comment thread backend/src/stellar/stellar.service.ts Outdated
Comment on lines +228 to +241
// Parse the ScheduledPayment struct
const instance = parsed.instance();
const fields = instance.instanceValue().map();

const payment: ScheduledPayment = {
from: Buffer.from(fields[0].val().bytes()).toString('hex'),
to: Buffer.from(fields[1].val().bytes()).toString('hex'),
token: Address.fromScVal(fields[2].val()).toString(),
amount: fields[3].val().i128().toString(),
release_at: Number(fields[4].val().u64()),
executed: fields[5].val().b(),
};

return payment;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Two correctness bugs in getScheduledPayment: wrong XDR API and order-dependent field indexing.

  1. parsed.instance().instanceValue().map() (Line 229-230) is the API for ScContractInstance (the storage map of a deployed contract), not for a struct return value. A Soroban struct return is encoded as ScValType.scvMap, so the correct accessor is parsed.map(), which returns an array of xdr.ScMapEntry { key, val }.

  2. Indexing the resulting entries by position (fields[0] … fields[5]) assumes the contract emits fields in the declared Rust order (from, to, token, amount, release_at, executed). Soroban canonicalizes struct maps with alphabetically sorted keys, so on the wire you'll receive: amount, executed, from, release_at, to, token. Index-based access will silently mis-bind every field — from will be parsed as the i128 amount, etc. The added unit test mocks the array in declaration order, so it doesn't catch this.

Recommended fix is to look up by key Symbol so the code is order-independent:

🛠️ Suggested fix
-      // Parse the ScheduledPayment struct
-      const instance = parsed.instance();
-      const fields = instance.instanceValue().map();
-
-      const payment: ScheduledPayment = {
-        from: Buffer.from(fields[0].val().bytes()).toString('hex'),
-        to: Buffer.from(fields[1].val().bytes()).toString('hex'),
-        token: Address.fromScVal(fields[2].val()).toString(),
-        amount: fields[3].val().i128().toString(),
-        release_at: Number(fields[4].val().u64()),
-        executed: fields[5].val().b(),
-      };
+      // Parse the ScheduledPayment struct (ScMap of ScSymbol -> ScVal)
+      const entries = parsed.map() ?? [];
+      const byKey = new Map<string, xdr.ScVal>(
+        entries.map((e) => [e.key().sym().toString(), e.val()]),
+      );
+      const need = (k: string): xdr.ScVal => {
+        const v = byKey.get(k);
+        if (!v) throw new Error(`ScheduledPayment missing field "${k}"`);
+        return v;
+      };
+
+      const payment: ScheduledPayment = {
+        from: Buffer.from(need('from').bytes()).toString('hex'),
+        to: Buffer.from(need('to').bytes()).toString('hex'),
+        token: Address.fromScVal(need('token')).toString(),
+        amount: need('amount').i128().toString(),
+        release_at: Number(need('release_at').u64()),
+        executed: need('executed').b(),
+      };

Or, much simpler, drop the manual decoding in favor of scValToNative(parsed) and shape the result into ScheduledPayment.

soroban struct scvMap key sort canonical encoding alphabetical
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.service.ts` around lines 228 - 241, The current
decoding in getScheduledPayment uses parsed.instance().instanceValue().map() and
positional indexing which is incorrect for a Soroban struct return; instead use
parsed.map() to get the xdr.ScMapEntry[] and extract fields by their string keys
(e.g. "from","to","token","amount","release_at","executed") rather than by index
so decoding is alphabetical-order independent, then convert values with the same
helpers you already use (Address.fromScVal, .i128(), .u64(), .b(),
Buffer.from(...).toString('hex')); alternatively replace the manual decode with
scValToNative(parsed) and then map that native object into the ScheduledPayment
shape.

Comment thread backend/src/stellar/stellar.service.ts Outdated
Comment on lines +5 to +15
export enum ChainType {
Evm = 'Evm',
Bitcoin = 'Bitcoin',
Solana = 'Solana',
Cosmos = 'Cosmos',
}

export enum PrivacyMode {
Normal = 'Normal',
Shielded = 'Shielded',
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Soroban contract enum string variant ScVal encoding js-stellar-sdk Contract.call argument

💡 Result:

In Soroban contracts, enums defined as user-defined types (UDT) via #[contracttype] are encoded as ScVal values for contract function arguments. There are two main kinds: 1. C-like integer enums (SC_SPEC_ENTRY_UDT_ENUM_V0): Encoded as a simple SCV_U32 containing the integer value corresponding to the variant (e.g., Red=1, Green=2). 2. Named/tuple variants (unnamed enums or unions): Encoded as a SCV_VEC where the first element is an SCV_SYMBOL with the variant name (string), followed by any tuple fields as additional ScVal elements. For js-stellar-sdk Contract.call(method, ...args), pass native JS values (strings for symbols, numbers, arrays for vecs, objects for maps). The SDK's nativeToScVal (or spec-aware conversion if using contract specs) automatically converts: - For integer enum: pass the number directly, e.g., contract.call("func", 1) - For named variant without fields: pass ["variant_name"] (array with string), converts to vec[symbol] - With fields: pass ["variant_name", field1, field2, ...] Example for enum Color { Red, Green(u64) }: - Red: contract.call("set_color", ["Red"]) - Green(42): contract.call("set_color", ["Green", 42n]) // 42n as bigint for u64 Strings in symbols/variants must use valid Soroban symbol chars ([0-9a-zA-Z_], <=10 chars for small symbols). Sources confirm via SEP-0048 (result 5, first search), Rust SDK examples (result 29), JS SDK Contract.call docs (result 10), nativeToScVal handling arrays as vec (result 22), and contract_spec handling enums/unions as vec[symbol,...] (result 30, result 27).

Citations:


🏁 Script executed:

# Search for usage of ChainType and PrivacyMode in the codebase
rg "ChainType|PrivacyMode" --type ts --type js -B 2 -A 2

Repository: Alien-Protocol/Alien-Protocol

Length of output: 2179


🏁 Script executed:

# Look for contract.call invocations and how arguments are passed
rg "contract\.call" --type ts --type js -A 5

Repository: Alien-Protocol/Alien-Protocol

Length of output: 3596


🏁 Script executed:

# Search for Soroban contract specifications or contract type definitions
fd -e "spec" -e "contract" -e "abi" | head -20

Repository: Alien-Protocol/Alien-Protocol

Length of output: 55


🏁 Script executed:

# Check stellar.service.ts specifically for how enums are used
find . -name "stellar.service.ts" -o -name "stellar.service.js" | xargs cat

Repository: Alien-Protocol/Alien-Protocol

Length of output: 12081


🏁 Script executed:

# Search for Soroban contract files
find . -type f \( -name "*.rs" -o -name "*contract*spec*" -o -name "*.abi" \) | grep -v node_modules | head -20

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1092


🏁 Script executed:

# Look for any Rust contract code
find . -type d -name "contracts" -o -name "soroban"

Repository: Alien-Protocol/Alien-Protocol

Length of output: 93


🏁 Script executed:

# Search for contract specifications in JSON or similar
rg "get_chain_address|ChainType" -t json -t rust --max-count 5

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1822


🏁 Script executed:

# Check if there's a contracts directory with actual source
git ls-files | grep -E "(contract|soroban)" | grep -v node_modules | head -20

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1009


🏁 Script executed:

# Read the Rust contract types definition
cat -n onchain/contracts/core_contract/src/types.rs | head -100

Repository: Alien-Protocol/Alien-Protocol

Length of output: 1517


🏁 Script executed:

# Search for the complete ChainType enum definition in Rust
rg "enum ChainType" -A 10 onchain/contracts/core_contract/src/types.rs

Repository: Alien-Protocol/Alien-Protocol

Length of output: 233


🏁 Script executed:

# Check PrivacyMode as well
rg "enum PrivacyMode" -A 10 onchain/contracts/core_contract/src/types.rs

Repository: Alien-Protocol/Alien-Protocol

Length of output: 268


🏁 Script executed:

# Verify by looking at how the Permission enum is defined in TypeScript
grep -n "enum Permission" backend/src/stellar/stellar.types.ts -A 10

Repository: Alien-Protocol/Alien-Protocol

Length of output: 55


🏁 Script executed:

# Check if there are any other numeric enum usages in the backend for comparison
rg "enum.*=\s*\d+" backend/src --type ts -B 1 -A 3

Repository: Alien-Protocol/Alien-Protocol

Length of output: 55


Change ChainType and PrivacyMode from string-valued to numeric enums.

The Rust contract defines these as C-like enums compiled to integer discriminants (0, 1, 2, 3), but the TypeScript code passes string values ('Evm', 'Bitcoin', etc.). This causes a type mismatch—the contract receives strings instead of the expected u32 discriminants, resulting in failed calls or silent data corruption.

Update to:

export enum ChainType {
  Evm = 0,
  Bitcoin = 1,
  Solana = 2,
  Cosmos = 3,
}

export enum PrivacyMode {
  Normal = 0,
  Shielded = 1,
}

Match the Rust contract's integer enum discriminants.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/stellar/stellar.types.ts` around lines 5 - 15, Change the
string-valued enums ChainType and PrivacyMode to numeric (C-like) enums so they
emit integer discriminants matching the Rust contract; update the definitions of
ChainType and PrivacyMode (the enum declarations) to assign explicit numeric
values (0,1,2,3 for ChainType and 0,1 for PrivacyMode) instead of string
literals so the values sent to the contract are u32 discriminants rather than
strings.

@ryzen-xp ryzen-xp self-requested a review April 27, 2026 04:15
@ryzen-xp ryzen-xp added the Code Conflict This PR have merge conflicts, Please Resolve it !!! label Apr 27, 2026
@Mmesolove
Copy link
Copy Markdown
Contributor Author

please review and merge.

@Mmesolove
Copy link
Copy Markdown
Contributor Author

please review and merge

@Mmesolove
Copy link
Copy Markdown
Contributor Author

hi,maintainer please merge so i can get my points

@ryzen-xp ryzen-xp added APPROVED This PR is ready for merging . and removed Code Conflict This PR have merge conflicts, Please Resolve it !!! labels May 2, 2026
@ryzen-xp ryzen-xp merged commit bdbafa3 into Alien-Protocol:dev May 2, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

APPROVED This PR is ready for merging .

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: implement Stellar contract interaction methods in StellarService

2 participants