Skip to content

Feature/stellar gifting - #54

Open
TheBigWealth89 wants to merge 8 commits into
Deen-Bridge:devfrom
TheBigWealth89:feature/stellar-gifting
Open

Feature/stellar gifting#54
TheBigWealth89 wants to merge 8 commits into
Deen-Bridge:devfrom
TheBigWealth89:feature/stellar-gifting

Conversation

@TheBigWealth89

@TheBigWealth89 TheBigWealth89 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Add Stellar Claimable Balances & Gifting Flow

Resolves: #43

Description

This PR introduces the highly requested "Stellar Gifting" functionality, allowing users to securely purchase books and courses on behalf of other users without the platform ever taking custody of funds.

It accomplishes this via strict, client-signed Stellar XDR envelopes. Depending on the creator's wallet state, this system seamlessly dynamically routes payments as either a standard payment operation or as a trustline-free create_claimable_balance operation.

Key Changes

1. New GiftClaim Data Model

  • Introduced a dedicated GiftClaim schema to track the lifecycle of a gift (pending_signature, open, claimed, reclaimed, expired).
  • Intentionally separated from standard Transaction TTL logic; relies on a rigorous claimExpiryDate checked by an interval worker.

2. Core Gifting API (/api/stellar/gifts)

  • POST /initialize: Validates the recipient's wallet, ensures they don't already own the item, checks for duplicate pending gifts, and builds the correct unsigned XDR variant based on the creator's USDC trustline status.
  • POST /submit: Accepts the signed XDR, performs immediate strict on-chain validation via Horizon, and officially grants the item access to the recipient (not the payer).
  • POST /claim/initialize & POST /claim/submit: Handles the recipient claiming a claimable_balance gift, verifying that the caller is the legitimate creator of the item, and processing the on-chain claim.
  • GET / & GET /:id: Allows users to fetch their sent/received gifts and queries Horizon for live status of open claimable balances.

3. Expiry Sweep Background Job

  • Added sweepExpiredGifts.js interval worker that scans the database for open gifts that are strictly past their claimExpiryDate.
  • Double-checks the live Stellar network (getClaimableBalance) to avoid race conditions. If the balance was genuinely reclaimed or expired on-chain, it permanently locks the local DB state to expired.

4. claimable_balance Fallback for Normal Purchases

  • Extends the core /api/stellar/payment/initialize path to gracefully handle cases where a creator lacks a USDC trustline during a standard purchase.
  • Replaces the generic "No trustline" failure with a create_claimable_balance fallback path, tagging the API response with fallback: "claimable_balance".
  • Updates Transaction logic to persist balanceId and correctly verify claimable balance settlements upon submission.

Security & Verification

  • 100% Non-Custodial: All transactions are built server-side as unsigned XDR and strictly signed by the end user on the client.
  • On-chain Source of Truth: Database state is entirely subordinate to Horizon verification.
  • Tests: Added comprehensive Jest tests for claimableBalanceService, giftController, and sweepExpiredGifts fully mocking the Horizon client to ensure zero network requests during CI/CD.

Testing Instructions

  1. Check out branch feature/stellar-gifting.
  2. Run unit tests using npm test.
  3. Test gifting an item to a user using the API (or frontend integration).
  4. Simulate a creator without a trustline and verify it falls back to a claimable balance.

Summary by CodeRabbit

  • New Features
    • Added Stellar gift/claim API endpoints under /api/stellar/gifts for initializing, submitting, listing, and fetching gifts.
    • Added claimable-balance support for Stellar payments when direct settlement isn’t available.
    • Added an automatic “expired gifts” sweep that runs every 10 minutes.
    • Added optional Horizon configuration knobs to .env.example.
  • Bug Fixes
    • Improved behavior when Stellar network connectivity is unavailable by returning a clear 503 NETWORK_UNAVAILABLE response.
  • Tests
    • Expanded Jest coverage for gift flows, claimable-balance builders, environment validation, Horizon reliability, models, and the expiration sweep.

BountySpaghetti and others added 7 commits July 21, 2026 20:22
- Apply cacheMiddleware to GET endpoints for books, courses, users,
  spaces, and search routes with appropriate TTLs
- Add cache invalidation middleware to POST, PUT, DELETE operations
  to ensure cache consistency when data changes
- Add Redis environment variables to validateEnv.js optional vars
- Create .env.example documenting all environment variables including
  Redis configuration options

Closes Deen-Bridge#2
feat: configure Redis cache layer for production use
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds resilient Horizon networking, claimable-balance payment fallback, Stellar gift and claim APIs, GiftClaim persistence, recipient access grants, and scheduled expiry handling with Jest coverage.

Changes

Stellar payment and gifting flows

Layer / File(s) Summary
Resilient Horizon client and service integration
.env.example, src/config/*, src/services/stellar/horizonClient.*, src/services/stellar/stellarService.js, src/middlewares/errorHandler.js
Adds configurable retries, timeouts, circuit breakers, submission verification, shared Horizon execution, health reporting, and standardized 503 handling.
Claimable-balance settlement support
src/services/stellar/claimableBalanceService.js, src/controllers/stellar/paymentController.js, src/models/Transaction.js, test/services/stellar/claimableBalanceService.test.js
Builds and verifies claimable-balance transactions, stores balance IDs, adds the settlement mode, and exposes fallback payment metadata.
Gift and claim API flow
src/models/GiftClaim.js, src/controllers/stellar/giftController.js, src/routes/stellar/giftRoutes.js, app.js, test/controllers/stellar/giftController.test.js, test/models/GiftClaim.test.js
Adds authenticated gift initialization, submission, listing, claim initialization/submission, on-chain verification, recipient access grants, and GiftClaim persistence.
Expired-gift sweep and startup wiring
src/jobs/sweepExpiredGifts.js, app.js, test/jobs/sweepExpiredGifts.test.js
Marks expired open gifts after Horizon status checks and starts the ten-minute sweep outside test environments.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GiftRoutes
  participant GiftController
  participant HorizonClient
  participant GiftClaim
  Client->>GiftRoutes: initialize or submit gift
  GiftRoutes->>GiftController: authenticated gift request
  GiftController->>HorizonClient: build, submit, and verify Stellar transaction
  HorizonClient-->>GiftController: transaction result and balance ID
  GiftController->>GiftClaim: save gift state and access grant
  GiftController-->>Client: gift or claim response
Loading

Possibly related PRs

Suggested reviewers: tijesunimi004, abimbolaalabi, zeemscript

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Most issue #43 requirements are met, but claim authorization appears sender-only and omits the required recipient-before-expiry claim path. Add expiry-based claim authorization so recipients can claim before expiry and senders can reclaim after expiry, then cover both paths in tests.
✅ 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 points to the main change: Stellar gifting support.
Out of Scope Changes check ✅ Passed No obvious out-of-scope changes; the new client, job, routes, models, and config all support Stellar gifting.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Biome (2.5.3)
src/controllers/stellar/paymentController.js

File contains syntax errors that prevent linting: Line 420: Expected a catch clause but instead found 'const'.; Line 483: Expected a semicolon or an implicit semicolon after a statement, but found none; Line 492: Expected a statement but instead found 'finally'.; Line 495: Expected a statement but instead found '}'.


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (5)
app.js (1)

193-198: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move this import to the top with the others, and consider a shutdown hook.

Two small things (both optional, welcome-to-open-source style nits):

  • ESM hoists this import, so it works, but placing it mid-file after route wiring makes the module harder to scan — grouping it with the other imports at the top keeps intent obvious.
  • startGiftSweepJob() registers a setInterval that nothing clears. On graceful shutdown (or repeated startup in some harnesses) the timer keeps the event loop alive and sweeps can overlap. Exposing a stop hook (clearInterval) wired into your SIGTERM/SIGINT handling would tidy that up.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app.js` around lines 193 - 198, Move the startGiftSweepJob import to the
existing top-level import block in app.js. Update the gift sweep job API to
expose a stop hook that clears its interval, then invoke that hook from the
existing SIGTERM/SIGINT shutdown handling so graceful shutdown cannot leave the
timer running.
src/services/stellar/horizonClient.js (1)

154-184: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Nice safe-submit design; two small resilience notes.

The single-resubmit-via-verifyFn logic is the right call for non-idempotent submits — good defensive thinking. Two things worth considering (both optional):

  • Submit-mode failures never call recordFailure(endpoint), so a persistently failing submit endpoint won't trip its circuit breaker the way read-mode failures do.
  • If maxRetries were ever 0, a resubmit path (attempt++; continue) would exit the loop and let execute() resolve to undefined. The runtime default is 3, so it's not reachable today, but a guarded return/throw at the end of the loop would future-proof it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/stellar/horizonClient.js` around lines 154 - 184, Update the
submit-mode branch in execute so retriable submit failures call
recordFailure(endpoint) before retry or rethrow, matching read-mode
circuit-breaker accounting. Also ensure the retry loop cannot fall through and
resolve undefined when maxRetries is zero, by adding an explicit terminal return
or throw after the loop while preserving the single verifyFn resubmit behavior.
src/models/GiftClaim.js (1)

70-72: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Add an index for the expiry-sweep query. 🗂️

sweepExpiredGifts runs GiftClaim.find({ status: "open", claimExpiryDate: { $lt: now } }) every 10 minutes, but the only indexes are recipient+status and sender+status. Neither serves this predicate, so the sweep will collection-scan and get slower as GiftClaim grows. A compound index on { status: 1, claimExpiryDate: 1 } keeps it efficient. As per path instructions: flag "missing indexes for new query patterns."

🗂️ Proposed index
 giftClaimSchema.index({ recipient: 1, status: 1 });
 giftClaimSchema.index({ sender: 1, status: 1 });
+// Supports the periodic expired-gift sweep query
+giftClaimSchema.index({ status: 1, claimExpiryDate: 1 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/GiftClaim.js` around lines 70 - 72, Add a compound index on
giftClaimSchema for status and claimExpiryDate, ordered as { status: 1,
claimExpiryDate: 1 }, to support the predicate used by sweepExpiredGifts while
preserving the existing list-endpoint indexes.

Source: Path instructions

src/controllers/stellar/giftController.js (2)

216-243: 🩺 Stability & Availability | 🔵 Trivial

Move the Stellar network call out of the open Mongo transaction. ⏱️

session.startTransaction() opens at line 217-218, but submitTransaction(signedXdr) (plus the follow-up verifyTransaction/resolveBalanceId Horizon round-trips) runs while that transaction is still open. Since Horizon calls now carry retries/timeouts, the Mongo transaction can stay open for many seconds and risks hitting transactionLifetimeLimitSeconds (60s default) and holding write locks — the same pattern also appears in submitClaim and src/controllers/stellar/paymentController.js submitPayment. Consider: do the on-chain submit+verify first (no session), then open a short transaction only for the DB writes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/stellar/giftController.js` around lines 216 - 243,
Restructure submitGift so submitTransaction and all follow-up Horizon calls,
including verifyTransaction and resolveBalanceId, execute before
session.startTransaction. Start a short Mongo transaction only after the Stellar
workflow succeeds, then perform the required GiftClaim writes and commit;
preserve the existing failure responses and status updates without holding the
session during network calls. Apply the same separation to submitClaim and
paymentController’s submitPayment.

194-202: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider aligning gift responses with the project's { success, message, data } shape. 📦

These handlers return ad-hoc top-level fields (giftId, variant, payment, gift, sent, received, xdr) instead of nesting under data. It works, but as per path instructions this API expects "consistent response shapes ({ success, message, data })", and clients/tests are easier to write against a uniform envelope. This is pervasive across initializeGift, submitGift, getGifts, getGift, initializeClaim, and submitClaim, so it's a low-priority cleanup rather than a blocker.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/stellar/giftController.js` around lines 194 - 202, Update the
response bodies in initializeGift, submitGift, getGifts, getGift,
initializeClaim, and submitClaim to use the consistent { success, message, data
} envelope, moving existing ad-hoc fields such as giftId, variant, payment,
gift, sent, received, and xdr under data while preserving their values and
existing success behavior.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/controllers/stellar/paymentController.js`:
- Around line 327-335: Strengthen verification in both settlement flows: in
src/controllers/stellar/paymentController.js lines 327-335, update the
claimable_balance branch to call verifyClaimableBalanceOp with result.hash,
transaction.creatorWallet, and transaction.amount before setting verified or
resolving balanceId; in src/controllers/stellar/giftController.js lines 252-269,
replace the direct_payment verifyTransaction check with verifyPaymentOperations
using the expected split from initializeGift, including applyPlatformFee based
on destinationPublicKey versus PLATFORM_WALLET_PUBLIC_KEY, and remove the dead
comment block.

In `@src/middlewares/errorHandler.js`:
- Around line 82-87: Hoist the AllEndpointsOpenError check above the NODE_ENV
development/production split in errorHandler, return the standard response shape
with success, status, message, and the existing network-unavailable code, and
remove both duplicated branches at src/middlewares/errorHandler.js lines 82-87
and 99-104.

In `@src/models/GiftClaim.js`:
- Around line 65-68: Replace the virtual itemTypeModel getter in giftClaimSchema
with a persisted itemTypeModel schema path that refPath can resolve during
populate("itemId"). Ensure it is populated consistently from the existing
itemType values, mapping book to Book and course to Course, and update any
related schema configuration without relying on the virtual.

---

Nitpick comments:
In `@app.js`:
- Around line 193-198: Move the startGiftSweepJob import to the existing
top-level import block in app.js. Update the gift sweep job API to expose a stop
hook that clears its interval, then invoke that hook from the existing
SIGTERM/SIGINT shutdown handling so graceful shutdown cannot leave the timer
running.

In `@src/controllers/stellar/giftController.js`:
- Around line 216-243: Restructure submitGift so submitTransaction and all
follow-up Horizon calls, including verifyTransaction and resolveBalanceId,
execute before session.startTransaction. Start a short Mongo transaction only
after the Stellar workflow succeeds, then perform the required GiftClaim writes
and commit; preserve the existing failure responses and status updates without
holding the session during network calls. Apply the same separation to
submitClaim and paymentController’s submitPayment.
- Around line 194-202: Update the response bodies in initializeGift, submitGift,
getGifts, getGift, initializeClaim, and submitClaim to use the consistent {
success, message, data } envelope, moving existing ad-hoc fields such as giftId,
variant, payment, gift, sent, received, and xdr under data while preserving
their values and existing success behavior.

In `@src/models/GiftClaim.js`:
- Around line 70-72: Add a compound index on giftClaimSchema for status and
claimExpiryDate, ordered as { status: 1, claimExpiryDate: 1 }, to support the
predicate used by sweepExpiredGifts while preserving the existing list-endpoint
indexes.

In `@src/services/stellar/horizonClient.js`:
- Around line 154-184: Update the submit-mode branch in execute so retriable
submit failures call recordFailure(endpoint) before retry or rethrow, matching
read-mode circuit-breaker accounting. Also ensure the retry loop cannot fall
through and resolve undefined when maxRetries is zero, by adding an explicit
terminal return or throw after the loop while preserving the single verifyFn
resubmit behavior.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7659d852-2f63-4926-a499-05449483fb88

📥 Commits

Reviewing files that changed from the base of the PR and between aebaa00 and 0d9cf9b.

📒 Files selected for processing (19)
  • .env.example
  • app.js
  • src/config/validateEnv.js
  • src/config/validateEnv.test.js
  • src/controllers/stellar/giftController.js
  • src/controllers/stellar/paymentController.js
  • src/jobs/sweepExpiredGifts.js
  • src/middlewares/errorHandler.js
  • src/models/GiftClaim.js
  • src/models/Transaction.js
  • src/routes/stellar/giftRoutes.js
  • src/services/stellar/claimableBalanceService.js
  • src/services/stellar/horizonClient.js
  • src/services/stellar/horizonClient.test.js
  • src/services/stellar/stellarService.js
  • test/controllers/stellar/giftController.test.js
  • test/jobs/sweepExpiredGifts.test.js
  • test/models/GiftClaim.test.js
  • test/services/stellar/claimableBalanceService.test.js

Comment thread src/controllers/stellar/paymentController.js
Comment thread src/middlewares/errorHandler.js
Comment thread src/models/GiftClaim.js
@coderabbitai coderabbitai Bot mentioned this pull request Jul 22, 2026
5 tasks
@zeemscript
zeemscript changed the base branch from main to dev July 23, 2026 20:36
@zeemscript

Copy link
Copy Markdown
Collaborator

@TheBigWealth89 Please fix conflicts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
src/controllers/stellar/paymentController.js (2)

280-372: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

settlementMode is destructured as const but reassigned in the fallback branch.

Line 326 declares settlementMode with const, but line 387 (settlementMode = "claimable_balance";) reassigns it. This throws TypeError: Assignment to constant variable every time the fallback path is actually needed — i.e., precisely when the creator lacks a USDC trustline, which is the scenario this whole PR is built to handle.

🐛 Proposed fix
-    const { item, creator, destinationPublicKey, settlementMode } = resolved;
+    const { item, creator, destinationPublicKey } = resolved;
+    let { settlementMode } = resolved;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/stellar/paymentController.js` around lines 280 - 372, Change
the settlementMode binding in initializePayment from const to a reassignable
declaration, since the fallback branch later assigns "claimable_balance".
Preserve the resolved settlement mode for normal paths and allow the fallback
path to update it without throwing.

373-472: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Dangling merge-conflict leftover crashes every initializePayment call.

After the trustline/settlement-mode switch (373-394) fully builds paymentTx, an extra unconditional block runs at 396-418:

  • It reads preflight.okpreflight is never declared anywhere in this function, so this throws ReferenceError: preflight is not defined (ES modules are always strict) before a single request can succeed.
  • It unconditionally re-invokes buildPaymentTransaction(...), overwriting whatever paymentTx the switch above produced — so even if preflight existed, the claimable-balance fallback branch's result would be silently discarded.
  • It assigns to sep7Uri without ever declaring it (let/const), which is itself a ReferenceError in strict mode.
  • Later, the response payload (468-472) references sep7Uri and isPathPayment, neither of which exists anywhere else in the file. pathInput (destructured at line 286) and the imported buildPathPaymentTransaction (line 9) are also unused, confirming the path-payment branch this leftover code belonged to was never reconnected.

This matches the maintainer comment asking to resolve merge conflicts — this reads exactly like an unresolved merge where the old path-payment/preflight/SEP-7 logic was left dangling next to the new trustline-fallback switch. As written, initializePayment cannot return a successful response for any input.

🐛 Minimal fix to remove the dead/broken block
     }

-      if (!preflight.ok) {
-        await session.abortTransaction();
-        return res.status(400).json({
-          success: false,
-          message: "Payment failed pre-flight safety checks",
-          reasons: preflight.reasons,
-        });
-      }
-
-      paymentTx = await buildPaymentTransaction({
-        sourcePublicKey: buyer.stellarWallet.publicKey,
-        destinationPublicKey,
-        amount: item.price.toString(),
-        memo,
-        applyPlatformFee: settlementMode === "direct",
-      });
-
-      sep7Uri = buildSep7Uri({
-        destination: destinationPublicKey,
-        amount: item.price.toString(),
-        memo,
-      });
-    }

And drop the now-undefined references in the response payload:

       payment: {
         xdr: paymentTx.xdr,
         networkPassphrase: paymentTx.networkPassphrase,
         expectedHash: paymentTx.hash,
       },
-      ...(sep7Uri && { sep7Uri }),
-      ...(isPathPayment && {
-        pathPaymentNote:
-          "Path payment XDR provided. SEP-7 URI is not available for path payments; use the XDR signing flow.",
-      }),

If SEP-7 URI generation (for the non-fallback path) and path-payment support (sendAsset/sendMax/path inputs, buildPathPaymentTransaction) are still intended features, they need to be properly reintegrated into the surviving trustline/settlement-mode switch rather than left as orphaned code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/stellar/paymentController.js` around lines 373 - 472, Remove
the dangling preflight and unconditional payment rebuild block from
initializePayment, including its undeclared sep7Uri assignment, so the
trustline/settlement-mode switch remains the sole builder of paymentTx and
preserves claimable-balance fallback behavior. Remove response fields
referencing undefined sep7Uri and isPathPayment; do not reintroduce path-payment
or SEP-7 logic unless it is properly integrated with the existing inputs and
builders.
♻️ Duplicate comments (1)
src/controllers/stellar/paymentController.js (1)

561-600: 🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

Claimable-balance verification still doesn't check amount/claimant — unresolved from a prior review round.

This branch only checks verification.exists && verification.successful; it never confirms the created balance's amount and claimant match transaction.amount/transaction.creatorWallet. A buyer can submit a completely different, cheap/self-directed transaction that succeeds on-chain and still get verified = true here, since signedXdr is never compared against the server-built XDR. This is the same gap raised in a previous review round (then at lines 327-335 in the old numbering) and it remains unaddressed at the current lines 564-572.

🔒 Suggested fix
     if (transaction.settlement === "claimable_balance") {
-      const verification = await verifyTransaction(result.hash);
-      if (!verification.exists || !verification.successful) {
+      const verification = await verifyClaimableBalanceOp(
+        result.hash,
+        transaction.creatorWallet,
+        transaction.amount
+      );
+      if (!verification.exists || !verification.successful || !verification.matches) {
         verified = false;
         failureReason = "On-chain verification failed";
       } else {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/stellar/paymentController.js` around lines 561 - 600, Update
the claimable_balance branch in the payment verification flow to validate that
the successfully verified balance matches transaction.amount and
transaction.creatorWallet as claimant, rather than relying only on
verification.exists and verification.successful. Reuse the server-built
transaction/XDR validation path where available, and set verified to false with
the existing failureReason handling whenever the amount, claimant, or
transaction authenticity does not match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/controllers/stellar/paymentController.js`:
- Around line 280-372: Change the settlementMode binding in initializePayment
from const to a reassignable declaration, since the fallback branch later
assigns "claimable_balance". Preserve the resolved settlement mode for normal
paths and allow the fallback path to update it without throwing.
- Around line 373-472: Remove the dangling preflight and unconditional payment
rebuild block from initializePayment, including its undeclared sep7Uri
assignment, so the trustline/settlement-mode switch remains the sole builder of
paymentTx and preserves claimable-balance fallback behavior. Remove response
fields referencing undefined sep7Uri and isPathPayment; do not reintroduce
path-payment or SEP-7 logic unless it is properly integrated with the existing
inputs and builders.

---

Duplicate comments:
In `@src/controllers/stellar/paymentController.js`:
- Around line 561-600: Update the claimable_balance branch in the payment
verification flow to validate that the successfully verified balance matches
transaction.amount and transaction.creatorWallet as claimant, rather than
relying only on verification.exists and verification.successful. Reuse the
server-built transaction/XDR validation path where available, and set verified
to false with the existing failureReason handling whenever the amount, claimant,
or transaction authenticity does not match.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b911e1e-dd1d-4969-ad43-404227969dc3

📥 Commits

Reviewing files that changed from the base of the PR and between 0d9cf9b and 00ab5ab.

📒 Files selected for processing (4)
  • app.js
  • src/controllers/stellar/paymentController.js
  • src/models/Transaction.js
  • src/services/stellar/stellarService.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • app.js
  • src/models/Transaction.js
  • src/services/stellar/stellarService.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants