Skip to content

WIP prep for breaking change to SDK - #15

Open
ianhe8x wants to merge 1 commit into
mainfrom
breaking-change
Open

WIP prep for breaking change to SDK#15
ianhe8x wants to merge 1 commit into
mainfrom
breaking-change

Conversation

@ianhe8x

@ianhe8x ianhe8x commented Feb 3, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added TextEncoder/TextDecoder polyfill support for enhanced compatibility in environments lacking native implementation.
  • Improvements

    • Updated network endpoint to OnFinality for improved infrastructure stability.
    • Refactored operation and event handling to support updated ledger data processing architecture.
  • Chores

    • Updated project dependencies and package manager specifications.

@coderabbitai

coderabbitai Bot commented Feb 3, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The PR updates the Soroban starter project to migrate from Horizon-based operations to XDR-based types and patterns. It introduces a text-encoding polyfill, updates the network endpoint and configuration, adjusts dependency resolution to use local Stellar SubQL packages, and refactors mapping handlers to process operations and events through new data structures.

Changes

Cohort / File(s) Summary
Dependencies & Configuration
Stellar/soroban-starter/package.json
Replaces @subql/common with @subql/common-stellar, adds text-encoding and @types/text-encoding dependencies, pins yarn version, and adds local portal resolutions for SubQL packages.
Network & Mapping Configuration
Stellar/soroban-starter/project.ts
Updates network endpoint from Horizon to OnFinality, changes startBlock value, replaces Horizon import with xdr, updates operation filter type to use xdr patterns, and comments out handleCredit and handleDebit handlers.
Core Handler Logic
Stellar/soroban-starter/src/index.ts, Stellar/soroban-starter/src/mappings/mappingHandlers.ts
Adds TextEncoder/TextDecoder polyfill for global availability. Refactors handleOperation to accept StellarOperation<Operation.Payment> with new field extraction logic; replaces handleEvent implementation with StellarEvent-based processing using scValToNative for value decoding; removes legacy Horizon-based operation fields and decodeAddress helper.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 The starter hops to XDR's bright shore,
Leaving Horizon's paths forevermore,
Text-encoding polyfills smooth the way,
Handlers dance with new ledger data today,
Stellar's future shines—let's code and play! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'WIP prep for breaking change to SDK' is vague and generic, using non-descriptive terms like 'WIP' and 'breaking change' without specifying what SDK changes or which aspects of the codebase are being updated. Replace with a specific title describing the main changes, such as 'Update Stellar SDK integration to use xdr types and OnFinality endpoint' or 'Migrate to @subql/common-stellar dependency and refactor handlers for new SDK API'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch breaking-change

Important

Action Needed: IP Allowlist Update

If your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:

  • 136.113.208.247/32 (new)
  • 34.170.211.100/32
  • 35.222.179.152/32

Reviews will stop working after February 8, 2026 if the new IP is not added to your allowlist.


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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5150b8ae0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +44 to 45
endpoint: ["https://stellar.api.onfinality.io/public"],
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore Soroban RPC endpoint for Event handler

The project still registers a StellarHandlerKind.Event handler, but the network config now only sets endpoint (Horizon) and omits sorobanEndpoint. Event handlers are served via Soroban RPC, and the other starter configs in this repo (e.g., soroban-testnet-starter/project.ts) keep sorobanEndpoint when events are enabled. Without it, event indexing will fail at runtime because there is no RPC endpoint to fetch Soroban events.

Useful? React with 👍 / 👎.

Comment on lines 121 to +126
const fromAccount = await checkAndGetAccount(
decodeAddress(from),
event.ledger!.sequence,
scValToNative(from),
event.event.ledger,
);
const toAccount = await checkAndGetAccount(
decodeAddress(to),
event.ledger!.sequence,
scValToNative(to),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid calling scValToNative for addresses without fallback

scValToNative is used directly to decode the from/to address ScVals that come from events, but this function is known to fail for addresses in the other starter templates in this repo (see the comment in soroban-testnet-starter/src/mappings/mappingHandlers.ts). Here you only log failures in a try/catch and then call scValToNative again outside the guard, which will throw and stop indexing whenever an address ScVal can’t be decoded. This will break processing for real transfer events unless a fallback decoder is restored.

Useful? React with 👍 / 👎.

@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: 4

🤖 Fix all issues with AI agents
In `@Stellar/soroban-starter/package.json`:
- Around line 35-38: The resolutions block currently pins local portal paths
which will break external clones; remove or replace the "resolutions" entries
that reference portal:../../../subql/packages (specifically
"@subql/types-stellar" and "@subql/common-stellar") and instead use real
published version specifiers (or remove the block entirely) so the package.json
no longer depends on local filesystem portal paths before merging.

In `@Stellar/soroban-starter/src/mappings/mappingHandlers.ts`:
- Line 130: The debug log contains a typo: change the logger call that currently
logs "VALUE TPE" (the statement using logger.info and referencing
event.event.value.switch().name) to "VALUE TYPE" so the message reads "VALUE
TYPE ${event.event.value.switch().name}" to correct the spelling while
preserving the existing event value output.
- Line 137: The contract field currently uses a non-null assertion after
optional chaining (event.event.contractId?.contractId().toString()!) which can
produce runtime errors; update the mapping in mappingHandlers.ts to handle a
missing contractId explicitly by using nullish coalescing or conditional logic
on event.event.contractId (e.g., supply a default string with ?? or return/throw
when contractId is absent) so that contract is never derived from undefined;
reference the event.event.contractId and its contractId() call when applying the
fix.
- Around line 105-128: The try/catch only logs decoding failures but then calls
scValToNative(from) and scValToNative(to) again, which will rethrow; update
mappingHandlers.ts to decode once and handle failures: call scValToNative(from)
and scValToNative(to) inside the try blocks, assign the results to local
variables (e.g. decodedFrom, decodedTo), and on decode failure either
return/skip processing or set a safe fallback and exit; then pass decodedFrom
and decodedTo into checkAndGetAccount(decodedFrom, event.event.ledger) and
checkAndGetAccount(decodedTo, event.event.ledger) instead of re-invoking
scValToNative. Ensure logger messages include context and keep error handling
consistent.
🧹 Nitpick comments (5)
Stellar/soroban-starter/project.ts (2)

61-74: Commented-out code should be removed or tracked.

These commented-out handlers for handleCredit and handleDebit reference StellarHandlerKind.Effects. If they're being removed as part of the breaking change, consider deleting them entirely. If they're planned for future re-enablement, track this with a TODO or issue reference.


58-58: Use a string literal for the operation type filter.

Since the filter's type field expects a string (as evidenced by other handlers using "account_credited" and "account_debited"), you can simplify xdr.OperationType.payment().name directly to "payment":

Suggested change
             filter: {
-              type: xdr.OperationType.payment().name,
+              type: "payment",
             },

This improves readability and eliminates an unnecessary method call and property extraction.

Stellar/soroban-starter/package.json (2)

24-26: Using "latest" for dependencies reduces reproducibility.

Pinning to "latest" means builds may behave differently over time. Consider pinning to specific versions once the breaking change SDK is released.


31-31: Unusual version specifier "^0" for types package.

While valid (matches any 0.x.x version), this is unconventional. If text-encoding types are stable, consider specifying a more explicit version like "^0.0.39" for clarity.

Stellar/soroban-starter/src/mappings/mappingHandlers.ts (1)

2-2: Unused imports: Credit and Debit.

Since handleCredit and handleDebit are commented out, these imports are unused. Remove them to keep the code clean, or uncomment the handlers if they're still needed.

Comment on lines +35 to 38
"resolutions": {
"@subql/types-stellar": "portal:../../../subql/packages/types",
"@subql/common-stellar": "portal:../../../subql/packages/common-stellar"
}

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

Local portal resolutions will break for external users.

The resolutions block with portal: paths references local filesystem directories (../../../subql/packages/...). This will fail for anyone cloning this repository who doesn't have the same local setup.

For a WIP branch this may be intentional for testing, but ensure these are removed or replaced with proper version specifiers before merging to main.

🤖 Prompt for AI Agents
In `@Stellar/soroban-starter/package.json` around lines 35 - 38, The resolutions
block currently pins local portal paths which will break external clones; remove
or replace the "resolutions" entries that reference
portal:../../../subql/packages (specifically "@subql/types-stellar" and
"@subql/common-stellar") and instead use real published version specifiers (or
remove the block entirely) so the package.json no longer depends on local
filesystem portal paths before merging.

Comment on lines +105 to 128
try {
scValToNative(from);
} catch (e) {
logger.info(
`decode from failed ${from.switch().name}, ${JSON.stringify(from, null, 2)}, error: ${e}`,
);
}

try {
decodeAddress(from);
decodeAddress(to);
scValToNative(to);
} catch (e) {
logger.info(`decode address failed`);
logger.info(
`decode to failed ${event.event.topic.length}, ${JSON.stringify(event.event.topic, null, 2)}, error: ${e}`,
);
}

const fromAccount = await checkAndGetAccount(
decodeAddress(from),
event.ledger!.sequence,
scValToNative(from),
event.event.ledger,
);
const toAccount = await checkAndGetAccount(
decodeAddress(to),
event.ledger!.sequence,
scValToNative(to),
event.event.ledger,
);

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

Error handling does not prevent subsequent failure.

The try-catch blocks at lines 105-111 and 113-119 catch and log decoding errors, but the code proceeds to call scValToNative(from) and scValToNative(to) again at lines 122 and 126. If decoding failed in the try block, it will throw again when creating accounts.

Either:

  1. Store the decoded values from the try block and reuse them, or
  2. Return early / skip processing if decoding fails
🐛 Proposed fix: Store decoded values and handle failures
-  try {
-    scValToNative(from);
-  } catch (e) {
-    logger.info(
-      `decode from failed ${from.switch().name}, ${JSON.stringify(from, null, 2)}, error: ${e}`,
-    );
-  }
-
-  try {
-    scValToNative(to);
-  } catch (e) {
-    logger.info(
-      `decode to failed ${event.event.topic.length}, ${JSON.stringify(event.event.topic, null, 2)}, error: ${e}`,
-    );
-  }
-
-  const fromAccount = await checkAndGetAccount(
-    scValToNative(from),
-    event.event.ledger,
-  );
-  const toAccount = await checkAndGetAccount(
-    scValToNative(to),
-    event.event.ledger,
-  );
+  let fromAddress: string;
+  let toAddress: string;
+  try {
+    fromAddress = scValToNative(from);
+  } catch (e) {
+    logger.warn(
+      `decode from failed ${from.switch().name}, ${JSON.stringify(from, null, 2)}, error: ${e}`,
+    );
+    return;
+  }
+
+  try {
+    toAddress = scValToNative(to);
+  } catch (e) {
+    logger.warn(
+      `decode to failed ${to.switch().name}, ${JSON.stringify(to, null, 2)}, error: ${e}`,
+    );
+    return;
+  }
+
+  const fromAccount = await checkAndGetAccount(fromAddress, event.event.ledger);
+  const toAccount = await checkAndGetAccount(toAddress, event.event.ledger);
📝 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
try {
scValToNative(from);
} catch (e) {
logger.info(
`decode from failed ${from.switch().name}, ${JSON.stringify(from, null, 2)}, error: ${e}`,
);
}
try {
decodeAddress(from);
decodeAddress(to);
scValToNative(to);
} catch (e) {
logger.info(`decode address failed`);
logger.info(
`decode to failed ${event.event.topic.length}, ${JSON.stringify(event.event.topic, null, 2)}, error: ${e}`,
);
}
const fromAccount = await checkAndGetAccount(
decodeAddress(from),
event.ledger!.sequence,
scValToNative(from),
event.event.ledger,
);
const toAccount = await checkAndGetAccount(
decodeAddress(to),
event.ledger!.sequence,
scValToNative(to),
event.event.ledger,
);
let fromAddress: string;
let toAddress: string;
try {
fromAddress = scValToNative(from);
} catch (e) {
logger.warn(
`decode from failed ${from.switch().name}, ${JSON.stringify(from, null, 2)}, error: ${e}`,
);
return;
}
try {
toAddress = scValToNative(to);
} catch (e) {
logger.warn(
`decode to failed ${to.switch().name}, ${JSON.stringify(to, null, 2)}, error: ${e}`,
);
return;
}
const fromAccount = await checkAndGetAccount(fromAddress, event.event.ledger);
const toAccount = await checkAndGetAccount(toAddress, event.event.ledger);
🤖 Prompt for AI Agents
In `@Stellar/soroban-starter/src/mappings/mappingHandlers.ts` around lines 105 -
128, The try/catch only logs decoding failures but then calls
scValToNative(from) and scValToNative(to) again, which will rethrow; update
mappingHandlers.ts to decode once and handle failures: call scValToNative(from)
and scValToNative(to) inside the try blocks, assign the results to local
variables (e.g. decodedFrom, decodedTo), and on decode failure either
return/skip processing or set a safe fallback and exit; then pass decodedFrom
and decodedTo into checkAndGetAccount(decodedFrom, event.event.ledger) and
checkAndGetAccount(decodedTo, event.event.ledger) instead of re-invoking
scValToNative. Ensure logger messages include context and keep error handling
consistent.

event.event.ledger,
);

logger.info(`VALUE TPE ${event.event.value.switch().name} `);

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

Typo in debug log: "TPE" should be "TYPE".

-  logger.info(`VALUE TPE ${event.event.value.switch().name} `);
+  logger.info(`VALUE TYPE ${event.event.value.switch().name}`);
📝 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
logger.info(`VALUE TPE ${event.event.value.switch().name} `);
logger.info(`VALUE TYPE ${event.event.value.switch().name}`);
🤖 Prompt for AI Agents
In `@Stellar/soroban-starter/src/mappings/mappingHandlers.ts` at line 130, The
debug log contains a typo: change the logger call that currently logs "VALUE
TPE" (the statement using logger.info and referencing
event.event.value.switch().name) to "VALUE TYPE" so the message reads "VALUE
TYPE ${event.event.value.switch().name}" to correct the spelling while
preserving the existing event value output.

id: event.event.id,
ledger: event.event.ledger,
date: new Date(event.event.ledgerClosedAt),
contract: event.event.contractId?.contractId().toString()!,

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

Non-null assertion after optional chaining can cause runtime errors.

event.event.contractId?.contractId().toString()! — if contractId is nullish, the optional chain returns undefined, but the ! assertion incorrectly claims it's non-null. This creates a type-safety gap and could cause issues downstream.

🛡️ Proposed fix: Use nullish coalescing
-    contract: event.event.contractId?.contractId().toString()!,
+    contract: event.event.contractId?.contractId().toString() ?? "",

Or handle the missing contract case explicitly if an empty string is not appropriate.

📝 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
contract: event.event.contractId?.contractId().toString()!,
contract: event.event.contractId?.contractId().toString() ?? "",
🧰 Tools
🪛 Biome (2.3.13)

[error] 137-137: Forbidden non-null assertion after optional chaining.

Optional chaining already handles nullish values. Using non-null assertion defeats its purpose and may cause runtime errors.
Consider using the nullish coalescing operator ?? or optional chaining throughout the chain instead.

(lint/suspicious/noNonNullAssertedOptionalChain)

🤖 Prompt for AI Agents
In `@Stellar/soroban-starter/src/mappings/mappingHandlers.ts` at line 137, The
contract field currently uses a non-null assertion after optional chaining
(event.event.contractId?.contractId().toString()!) which can produce runtime
errors; update the mapping in mappingHandlers.ts to handle a missing contractId
explicitly by using nullish coalescing or conditional logic on
event.event.contractId (e.g., supply a default string with ?? or return/throw
when contractId is absent) so that contract is never derived from undefined;
reference the event.event.contractId and its contractId() call when applying the
fix.

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.

2 participants