Skip to content

feat: implement Stellar Explorer Integration and Transaction Links#154

Merged
0xdevcollins merged 8 commits intoboundlessfi:mainfrom
ekumamatthew:steller_explorer
Mar 30, 2026
Merged

feat: implement Stellar Explorer Integration and Transaction Links#154
0xdevcollins merged 8 commits intoboundlessfi:mainfrom
ekumamatthew:steller_explorer

Conversation

@ekumamatthew
Copy link
Copy Markdown
Contributor

@ekumamatthew ekumamatthew commented Mar 26, 2026

  • Add stellar-explorer.ts utility helper with URL generation functions
  • Create stellar-link.tsx component for transaction/account/contract links
  • Update bounty submission card to display transaction hashes with explorer links
  • Update transaction history table with transaction hash column and links
  • Add transactionHash field to WalletActivity type
  • Support stellar.expert and stellarchain.io explorers
  • Support testnet/mainnet network detection
  • Add copy-to-clipboard functionality and truncated display
  • Include validation functions for Stellar addresses and hashes

Closes #150

Summary by CodeRabbit

  • New Features

    • Integrated Stellar explorer links for transactions, accounts, and contracts throughout the app (clickable, with optional copy and external icon)
    • Transaction column added to wallet activity and CSV export; submission cards now show transaction when available
    • Wallet address surfaces as a linked account view with one-click copy
  • Bug Fixes / UX

    • Safer date formatting in CSV export and consistent empty-state rendering

- Add stellar-explorer.ts utility helper with URL generation functions
- Create stellar-link.tsx component for transaction/account/contract links
- Update bounty submission card to display transaction hashes with explorer links
- Update transaction history table with transaction hash column and links
- Add transactionHash field to WalletActivity type
- Support stellar.expert and stellarchain.io explorers
- Support testnet/mainnet network detection
- Add copy-to-clipboard functionality and truncated display
- Include validation functions for Stellar addresses and hashes

Closes boundlessfi#150
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 26, 2026

@ekumamatthew is attempting to deploy a commit to the Threadflow Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave
Copy link
Copy Markdown

drips-wave bot commented Mar 26, 2026

@ekumamatthew 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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds Stellar explorer integration: new URL utilities, a reusable StellarLink component (with Transaction/Account/Contract wrappers, truncation, copy, and tooltips), and replaces local address/transaction displays across wallet and bounty UIs to render explorer links.

Changes

Cohort / File(s) Summary
Stellar Explorer Utilities
lib/utils/stellar-explorer.ts
New module: network detection, URL builders for transactions/accounts/contracts, validators, explorer registry, and helper getters.
Stellar Link Component
components/ui/stellar-link.tsx
New client-side component StellarLink plus TransactionLink / AccountLink / ContractLink wrappers: validation, memoized URL/text, external link + tooltip, optional external icon and copy-to-clipboard with transient state.
Wallet Types
types/wallet.ts
Added optional transactionHash?: string to WalletActivity; minor reformatting of type declarations.
Bounty Submissions UI
components/bounty-detail/bounty-detail-submissions-card.tsx
Render TransactionLink for submission.rewardTransactionHash when present (truncated + copy). Imports reordered.
Wallet Transaction History
components/wallet/transaction-history.tsx
Added Transaction column (renders item.transactionHash via TransactionLink), updated empty-state colspan and CSV export to include transaction column and safe date formatting.
Wallet Address UI
components/wallet/wallet-overview.tsx, components/wallet/wallet-sheet.tsx
Replaced local clipboard/truncate logic with AccountLink (uses showCopy/maxLength), simplified imports and removed local copy state/handlers.
Minor UI/Hook Cleanups
components/bounty-detail/..., components/bounty-detail/bounty-detail-sidebar-cta.tsx, hooks/...
Cosmetic JSX/format changes and small hook refactors (arrow syntax, whitespace) with no behavioral changes.
Smart Wallet Config
lib/smart-wallet/config.ts
requireEnv relaxed to optional fallback and adjusted return/validation logic (throws only when both env and fallback absent).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant UI as StellarLink Component
  participant Utils as stellar-explorer.ts
  participant Browser as Navigator/Clipboard
  participant Explorer as External Explorer

  User->>UI: view page with transaction/account link
  UI->>Utils: validate value & build URL (getTransactionUrl / getAccountUrl)
  Utils-->>UI: return explorer URL (including network)
  UI->>Explorer: open link in new tab (on click)
  User->>UI: click copy button
  UI->>Browser: navigator.clipboard.writeText(value)
  Browser-->>UI: success/failure
  UI-->>User: show copied / error tooltip feedback
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • Benjtalkshow

Poem

🐰 I hop on hashes, bright and bold,
Links to explorers, stories told.
Copy clicks with joyful cheer,
Testnet, mainnet — both appear,
A tiny rabbit, proud and cold.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR attempts to implement #150 requirements but has critical issues: incomplete imports (TransactionLink not imported in some files), incorrect explorer URL formats (stellar.expert requires /explorer paths not /tx), invalid contract ID validation (confuses contract IDs with account addresses), and table column ordering bugs. Fix missing imports in bounty-detail-submissions-card.tsx and transaction-history.tsx; correct stellar.expert URL paths; fix isValidStellarContractId to handle C-prefix contracts; resolve transaction-history table column header/cell ordering mismatch.
Docstring Coverage ⚠️ Warning Docstring coverage is 59.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Most changes are scope-aligned to #150 (explorer integration, link components, network detection). However, modifications to wallet-overview.tsx, wallet-sheet.tsx, and requireEnv configuration in smart-wallet/config.ts extend beyond the core acceptance criteria. Clarify whether refactoring existing wallet address displays and making requireEnv fallback optional are intended supporting changes or incidental scope creep; document rationale if intentional.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: implement Stellar Explorer Integration and Transaction Links' directly and clearly describes the main feature being implemented across multiple files.

✏️ 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

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

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: 6

🧹 Nitpick comments (3)
components/wallet/transaction-history.tsx (1)

53-71: Consider including transactionHash in CSV export.

The new Transaction column is displayed in the UI but transactionHash is not included in the CSV export. For consistency, you may want to add it to the exported data.

♻️ Proposed enhancement
     const headers = [
       "ID",
       "Type",
       "Description",
       "Amount",
       "Currency",
+      "Transaction Hash",
       "Date",
       "Status",
     ];
     const rows = filteredActivity.map((item) => [
       item.id,
       item.type,
       item.description || "",
       item.amount.toString(),
       item.currency,
+      item.transactionHash || "",
       format(new Date(item.date), "yyyy-MM-dd HH:mm:ss"),
       item.status,
     ]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/wallet/transaction-history.tsx` around lines 53 - 71, The CSV
export implemented in handleExportCsv builds headers and rows from
filteredActivity but omits the transactionHash field shown in the UI; update the
headers array to include a "Transaction" (or "TransactionHash") column and
update the rows mapping for each item in filteredActivity to include
item.transactionHash (or an empty string fallback) in the corresponding position
so exported CSV rows align with the new header; ensure format/new Date logic
remains unchanged and use the existing handleExportCsv, headers, rows, and
filteredActivity identifiers to locate the changes.
lib/utils/stellar-explorer.ts (2)

174-177: Address validation regex may be too permissive.

Stellar public keys are base32-encoded using only characters A-Z and 2-7. The current regex [A-Z0-9] allows digits 0, 1, 8, 9 which are not valid in Stellar addresses.

♻️ Proposed fix for stricter validation
 export function isValidStellarAddress(address: string): boolean {
-  // Basic validation - Stellar addresses start with 'G' and are 56 characters long
-  return /^G[A-Z0-9]{55}$/.test(address);
+  // Stellar addresses are base32-encoded: start with 'G' and use only A-Z, 2-7
+  return /^G[A-Z2-7]{55}$/.test(address);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils/stellar-explorer.ts` around lines 174 - 177, The
isValidStellarAddress function uses a too-permissive regex; update it to
validate base32 characters only by replacing the character class [A-Z0-9] with
the Stellar Base32 alphabet [A-Z2-7] so the function still enforces a leading
'G' and total length 56 but rejects invalid digits like 0,1,8,9; adjust the
regex in isValidStellarAddress accordingly.

52-64: Network detection is non-functional.

getStellarNetwork always returns 'mainnet' regardless of input. The comments acknowledge this is simplified, but callers may expect actual detection. Consider either implementing proper detection or making the limitation more explicit in the function name/documentation.

Since testnet vs mainnet cannot be reliably determined from addresses alone (they use the same format), you could:

  1. Rename to getDefaultNetwork() to clarify behavior
  2. Remove auto-detection and require explicit network parameter
  3. Use environment variable (e.g., NEXT_PUBLIC_STELLAR_NETWORK) as the default
♻️ Example: Use environment-based default
+const NETWORK_ENV = (process.env.NEXT_PUBLIC_STELLAR_NETWORK as StellarNetwork) || 'mainnet';
+
 export function getStellarNetwork(addressOrHash: string): StellarNetwork {
-  // Testnet addresses typically start with 'G' and are testnet-specific
-  // This is a simplified detection - in production, you might want more sophisticated detection
-  if (addressOrHash.startsWith('G') && addressOrHash.length === 56) {
-    // You could maintain a list of known testnet prefixes or use other heuristics
-    // For now, we'll assume mainnet for most cases
-    return 'mainnet';
-  }
-  
-  // Testnet transaction hashes often have different patterns
-  // This is a placeholder - implement proper testnet detection based on your needs
-  return DEFAULT_NETWORK;
+  // Network cannot be reliably determined from address format alone.
+  // Returns environment-configured default network.
+  return NETWORK_ENV;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils/stellar-explorer.ts` around lines 52 - 64, The current
getStellarNetwork function uses a broken heuristic (startsWith('G')) and always
returns 'mainnet'; replace that auto-detection with an environment-backed
default: have getStellarNetwork read process.env.NEXT_PUBLIC_STELLAR_NETWORK (or
use DEFAULT_NETWORK when unset) and remove the G-prefix/length heuristic, or
alternatively rename the function to getDefaultNetwork to make the behavior
explicit; update all callers of getStellarNetwork accordingly and ensure
DEFAULT_NETWORK and the env var are used as the single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/bounty-detail/bounty-detail-submissions-card.tsx`:
- Around line 325-336: The file uses the TransactionLink component in
bounty-detail-submissions-card.tsx but never imports it; add an import for
TransactionLink at the top of the file alongside the other imports, referencing
the correct module that exports TransactionLink so the JSX usage
(TransactionLink with props value, type, maxLength, showCopy, className)
resolves and the build/runtime error is fixed.

In `@components/wallet/transaction-history.tsx`:
- Around line 202-217: The table body cell order is mismatched with the header:
the code currently renders the date cell (using formatSafeDate(item.date, "MMM
d, yyyy")) before the Transaction cell
(TransactionLink/value=item.transactionHash), so swap those two cells so the
transaction column appears before the date column; locate the JSX in the row
that contains formatSafeDate and the TransactionLink and reorder them so
TransactionLink (or the placeholder span for missing item.transactionHash) is
rendered first and formatSafeDate(item.date, "MMM d, yyyy") is rendered
immediately after, preserving existing classes and props.
- Around line 206-217: The TransactionLink component is referenced in
transaction-history.tsx (used inside the JSX at the render of
item.transactionHash) but not imported; add an import for TransactionLink at the
top of the file (alongside other component imports) from its module where your
wallet/ui components live so the component resolves and the build error is
fixed.

In `@lib/utils/stellar-explorer.ts`:
- Around line 194-197: The function isValidStellarContractId currently delegates
to isValidStellarAddress (which expects a 'G' prefix) and thus rejects valid
Soroban contract IDs; change isValidStellarContractId to validate Soroban
contract IDs directly by checking the string starts with 'C' and matches 55
base32 characters (A-Z and 2-7) — e.g. replace the call to isValidStellarAddress
with a validation using a regex that enforces /^C[A-Z2-7]{55}$/ (or equivalent
logic) so contract IDs are accepted correctly.

In `@test-stellar-explorer.ts`:
- Around line 62-72: The catch blocks call error.message but TypeScript treats
caught exceptions as unknown; update the handlers around getTransactionUrl('')
and getAccountUrl('') to narrow the error before accessing .message (for
example, check if error is an instance of Error and use error.message, otherwise
stringify or log the error object), or cast to Error only after ensuring it's
safe; ensure both catch blocks use the same safe narrowing/formatting so
compilation no longer errors.
- Around line 18-21: Replace the placeholder test values with properly formatted
Stellar values so the validation functions pass: ensure testAddress is a
56-character Stellar address starting with 'G' (use 55 valid base32 chars after
'G'), ensure testContractId is a 56-character contract/account id starting with
'C' (or the expected prefix used by your
isValidStellarAddress/isValidStellarContractId logic) with 55 valid characters
after the prefix, and ensure testTxHash is exactly 64 hex characters (0-9a-f) so
isValidStellarTxHash and the address/contract validations succeed in the
existing checks referencing testTxHash, testAddress, testContractId and the
isValidStellarAddress/isValidStellarTxHash validators.

---

Nitpick comments:
In `@components/wallet/transaction-history.tsx`:
- Around line 53-71: The CSV export implemented in handleExportCsv builds
headers and rows from filteredActivity but omits the transactionHash field shown
in the UI; update the headers array to include a "Transaction" (or
"TransactionHash") column and update the rows mapping for each item in
filteredActivity to include item.transactionHash (or an empty string fallback)
in the corresponding position so exported CSV rows align with the new header;
ensure format/new Date logic remains unchanged and use the existing
handleExportCsv, headers, rows, and filteredActivity identifiers to locate the
changes.

In `@lib/utils/stellar-explorer.ts`:
- Around line 174-177: The isValidStellarAddress function uses a too-permissive
regex; update it to validate base32 characters only by replacing the character
class [A-Z0-9] with the Stellar Base32 alphabet [A-Z2-7] so the function still
enforces a leading 'G' and total length 56 but rejects invalid digits like
0,1,8,9; adjust the regex in isValidStellarAddress accordingly.
- Around line 52-64: The current getStellarNetwork function uses a broken
heuristic (startsWith('G')) and always returns 'mainnet'; replace that
auto-detection with an environment-backed default: have getStellarNetwork read
process.env.NEXT_PUBLIC_STELLAR_NETWORK (or use DEFAULT_NETWORK when unset) and
remove the G-prefix/length heuristic, or alternatively rename the function to
getDefaultNetwork to make the behavior explicit; update all callers of
getStellarNetwork accordingly and ensure DEFAULT_NETWORK and the env var are
used as the single source of truth.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 526df00a-4778-42d9-9885-169919789e53

📥 Commits

Reviewing files that changed from the base of the PR and between 3aad250 and a5ba752.

📒 Files selected for processing (6)
  • components/bounty-detail/bounty-detail-submissions-card.tsx
  • components/ui/stellar-link.tsx
  • components/wallet/transaction-history.tsx
  • lib/utils/stellar-explorer.ts
  • test-stellar-explorer.ts
  • types/wallet.ts

Comment on lines +202 to +217
<td className="py-4 px-4 text-right text-muted-foreground">
{formatSafeDate(item.date, "MMM d, yyyy")}
</td>
<td className="py-4 px-4">
{item.transactionHash ? (
<TransactionLink
value={item.transactionHash}
type="transaction"
maxLength={10}
showCopy={true}
className="text-xs"
/>
) : (
<span className="text-xs text-muted-foreground">—</span>
)}
</td>
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

Table column order mismatch between headers and cells.

The header row defines columns as: Type, Description, Amount, Transaction, Date, Status (lines 136-155). However, the table body renders cells in order: Type, Description, Amount, Date (line 202-204), Transaction (line 205-217), Status — which is swapped.

🐛 Proposed fix: Swap the cell order to match headers
                     <td className="py-4 px-4 text-right">
                       <span
                         className={`font-semibold ${item.type === "earning" ? "text-green-500" : ""}`}
                       >
                         {item.type === "earning" ? "+" : "-"}{" "}
                         {formatCurrency(item.amount, item.currency)}
                       </span>
                     </td>
-                    <td className="py-4 px-4 text-right text-muted-foreground">
-                      {formatSafeDate(item.date, "MMM d, yyyy")}
-                    </td>
                     <td className="py-4 px-4">
                       {item.transactionHash ? (
                         <TransactionLink
                           value={item.transactionHash}
                           type="transaction"
                           maxLength={10}
                           showCopy={true}
                           className="text-xs"
                         />
                       ) : (
                         <span className="text-xs text-muted-foreground">—</span>
                       )}
                     </td>
+                    <td className="py-4 px-4 text-right text-muted-foreground">
+                      {formatSafeDate(item.date, "MMM d, yyyy")}
+                    </td>
                     <td className="py-4 px-4 text-right">
📝 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
<td className="py-4 px-4 text-right text-muted-foreground">
{formatSafeDate(item.date, "MMM d, yyyy")}
</td>
<td className="py-4 px-4">
{item.transactionHash ? (
<TransactionLink
value={item.transactionHash}
type="transaction"
maxLength={10}
showCopy={true}
className="text-xs"
/>
) : (
<span className="text-xs text-muted-foreground"></span>
)}
</td>
<td className="py-4 px-4">
{item.transactionHash ? (
<TransactionLink
value={item.transactionHash}
type="transaction"
maxLength={10}
showCopy={true}
className="text-xs"
/>
) : (
<span className="text-xs text-muted-foreground"></span>
)}
</td>
<td className="py-4 px-4 text-right text-muted-foreground">
{formatSafeDate(item.date, "MMM d, yyyy")}
</td>
🧰 Tools
🪛 ESLint

[error] 207-207: 'TransactionLink' is not defined.

(react/jsx-no-undef)

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

In `@components/wallet/transaction-history.tsx` around lines 202 - 217, The table
body cell order is mismatched with the header: the code currently renders the
date cell (using formatSafeDate(item.date, "MMM d, yyyy")) before the
Transaction cell (TransactionLink/value=item.transactionHash), so swap those two
cells so the transaction column appears before the date column; locate the JSX
in the row that contains formatSafeDate and the TransactionLink and reorder them
so TransactionLink (or the placeholder span for missing item.transactionHash) is
rendered first and formatSafeDate(item.date, "MMM d, yyyy") is rendered
immediately after, preserving existing classes and props.

Comment on lines +18 to +21
// Test data
const testTxHash = 'a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef1234567890';
const testAddress = 'GD1234567890ABCDEF1234567890ABCDEF12345678';
const testContractId = 'C1234567890ABCDEF1234567890ABCDEF12345678';
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

Test data will fail validation checks.

The test values don't match the validation rules in stellar-explorer.ts:

  • testAddress is 40 characters but isValidStellarAddress requires exactly 56 characters (G + 55 alphanumeric).
  • testContractId is 41 characters but requires 56 characters.
  • testTxHash is 68 characters but isValidStellarTxHash requires exactly 64 hex characters.

This will cause the validation tests at lines 52-58 to report these as invalid, which may be misleading for a demonstration script.

🐛 Proposed fix: Use correctly formatted test data
 // Test data
-const testTxHash = 'a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef1234567890';
-const testAddress = 'GD1234567890ABCDEF1234567890ABCDEF12345678';
-const testContractId = 'C1234567890ABCDEF1234567890ABCDEF12345678';
+const testTxHash = 'a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef12345678';
+const testAddress = 'GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOUJ3NBSN2QDMA5V';
+const testContractId = 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC';
📝 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
// Test data
const testTxHash = 'a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef1234567890';
const testAddress = 'GD1234567890ABCDEF1234567890ABCDEF12345678';
const testContractId = 'C1234567890ABCDEF1234567890ABCDEF12345678';
// Test data
const testTxHash = 'a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef12345678';
const testAddress = 'GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOUJ3NBSN2QDMA5V';
const testContractId = 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test-stellar-explorer.ts` around lines 18 - 21, Replace the placeholder test
values with properly formatted Stellar values so the validation functions pass:
ensure testAddress is a 56-character Stellar address starting with 'G' (use 55
valid base32 chars after 'G'), ensure testContractId is a 56-character
contract/account id starting with 'C' (or the expected prefix used by your
isValidStellarAddress/isValidStellarContractId logic) with 55 valid characters
after the prefix, and ensure testTxHash is exactly 64 hex characters (0-9a-f) so
isValidStellarTxHash and the address/contract validations succeed in the
existing checks referencing testTxHash, testAddress, testContractId and the
isValidStellarAddress/isValidStellarTxHash validators.

Comment on lines +62 to +72
try {
getTransactionUrl('');
} catch (error) {
console.log(' Empty tx hash error:', error.message);
}

try {
getAccountUrl('');
} catch (error) {
console.log(' Empty address error:', error.message);
}
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

TypeScript error: error is of type unknown.

In strict TypeScript, caught errors have type unknown, so accessing error.message directly will cause a compilation error.

🐛 Proposed fix: Add proper type handling
 try {
   getTransactionUrl('');
 } catch (error) {
-  console.log('   Empty tx hash error:', error.message);
+  console.log('   Empty tx hash error:', error instanceof Error ? error.message : String(error));
 }

 try {
   getAccountUrl('');
 } catch (error) {
-  console.log('   Empty address error:', error.message);
+  console.log('   Empty address error:', error instanceof Error ? error.message : String(error));
 }
📝 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 {
getTransactionUrl('');
} catch (error) {
console.log(' Empty tx hash error:', error.message);
}
try {
getAccountUrl('');
} catch (error) {
console.log(' Empty address error:', error.message);
}
try {
getTransactionUrl('');
} catch (error) {
console.log(' Empty tx hash error:', error instanceof Error ? error.message : String(error));
}
try {
getAccountUrl('');
} catch (error) {
console.log(' Empty address error:', error instanceof Error ? error.message : String(error));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test-stellar-explorer.ts` around lines 62 - 72, The catch blocks call
error.message but TypeScript treats caught exceptions as unknown; update the
handlers around getTransactionUrl('') and getAccountUrl('') to narrow the error
before accessing .message (for example, check if error is an instance of Error
and use error.message, otherwise stringify or log the error object), or cast to
Error only after ensuring it's safe; ensure both catch blocks use the same safe
narrowing/formatting so compilation no longer errors.

@0xdevcollins
Copy link
Copy Markdown
Contributor

Hey @ekumamatthew, nice work on this! The structure looks solid the StellarLink component and explorer utility are well thought out. A few things to address before we can merge:

Build blockers:

TransactionLink is used in both bounty-detail-submissions-card.tsx and transaction-history.tsx but never imported from @/components/ui/stellar-link this will break the build.

Explorer URLs won't resolve:
The generated URLs look like https://stellar.expert/tx/{hash}, but stellar.expert uses https://stellar.expert/explorer/public/tx/{hash} (and /explorer/testnet/ for testnet). The testnet. subdomain approach in getExplorerBaseUrl doesn't match either explorer's actual scheme, so all links will 404.
Validation issues:

isValidStellarContractId delegates to isValidStellarAddress which requires a G prefix but Soroban contracts start with C, so valid contracts will always fail validation.
The test data in test-stellar-explorer.ts doesn't pass the PR's own validators (hash is 70 chars instead of 64, address is 42 instead of 56).
A few smaller things:

In transaction-history.tsx, the table header has Transaction before Date, but the cells have Date before Transaction columns are swapped.
transactionHash should probably be included in the CSV export too for consistency.
test-stellar-explorer.ts is at the project root with a wrong import path and uses console.log instead of a test framework best to either move it to a proper test dir or remove it.
getStellarNetwork() always returns mainnet might be cleaner to just pull the network from an env var like NEXT_PUBLIC_STELLAR_NETWORK instead.

The issue also mentions linking wallet addresses and contract addresses to the explorer the AccountLink/ContractLink components are exported but not used yet. Would be great to wire those up too.
Overall really nice foundation just needs these fixes and it should be good to go!

@ekumamatthew
Copy link
Copy Markdown
Contributor Author

Hi, Please can you merge my PR

@ekumamatthew
Copy link
Copy Markdown
Contributor Author

Okay. I'm just seeing your review. Let me implement it

- Fix TransactionLink import issues in bounty-detail and transaction-history
- Update stellar.expert URLs to use /explorer/public/ paths
- Fix contract validation to support C prefix for Soroban contracts
- Fix transaction history column order (Date before Transaction)
- Add transactionHash to CSV export
- Replace wallet address displays with AccountLink component
- Remove test file from project root

All critical issues from feedback have been addressed.
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: 3

♻️ Duplicate comments (1)
components/wallet/transaction-history.tsx (1)

3-10: ⚠️ Potential issue | 🔴 Critical

TransactionLink is referenced but not imported.

Line 209 uses TransactionLink, but there is no import, so this will fail with react/jsx-no-undef.

🐛 Proposed fix
 import { Badge } from "@/components/ui/badge";
 import { Button } from "@/components/ui/button";
 import { Input } from "@/components/ui/input";
+import { TransactionLink } from "@/components/ui/stellar-link";
 import { WalletActivity } from "@/types/wallet";
 import { format, isValid } from "date-fns";
 import { ArrowDownLeft, ArrowUpRight, Download, Search } from "lucide-react";
 import { useState } from "react";

Also applies to: 209-214

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

In `@components/wallet/transaction-history.tsx` around lines 3 - 10, The component
references the TransactionLink component but never imports it, causing a
react/jsx-no-undef error; fix by adding an import for TransactionLink at the top
of the file (alongside imports like Badge, Button, Input) — import the correct
TransactionLink export (default or named) from its module and use that import
where TransactionLink is used (around the JSX at TransactionLink references) so
the symbol is defined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/wallet/transaction-history.tsx`:
- Around line 64-73: The CSV row mapping in filteredActivity.map uses format(new
Date(item.date), ...) which will throw on invalid dates; update the mapping that
builds rows (the rows constant/filteredActivity.map callback) to validate the
date before formatting—create a Date instance, check validity (e.g., using
isValid(date) from date-fns or date.getTime() !== NaN), and if invalid use a
safe fallback like an empty string or item.date, otherwise call format(...) so
an invalid date won’t break the entire CSV export.

In `@components/wallet/wallet-overview.tsx`:
- Around line 59-63: The anchor in wallet-overview.tsx currently hardcodes a
mainnet stellar.expert URL using walletInfo.address; replace this with the
shared Stellar explorer utility so the URL is network-aware. Locate the anchor
inside the Button and call the project's explorer helper (e.g.,
buildStellarExplorerAccountUrl or getStellarExplorerUrl) passing the current
network and walletInfo.address, and use that returned string for href while
keeping target and rel unchanged. Ensure you import the correct helper at the
top of the file and remove the hardcoded template string so testnet/mainnet
links resolve correctly.

In `@components/wallet/wallet-sheet.tsx`:
- Around line 16-22: The import list for lucide-react in the wallet-sheet
component is missing the Check icon, causing JSX to reference an undefined
<Check />; update the existing import statement that currently lists
ArrowDownLeft, ArrowUpRight, ExternalLink, Shield, Wallet to also include Check
so the component can render <Check /> without error.

---

Duplicate comments:
In `@components/wallet/transaction-history.tsx`:
- Around line 3-10: The component references the TransactionLink component but
never imports it, causing a react/jsx-no-undef error; fix by adding an import
for TransactionLink at the top of the file (alongside imports like Badge,
Button, Input) — import the correct TransactionLink export (default or named)
from its module and use that import where TransactionLink is used (around the
JSX at TransactionLink references) so the symbol is defined.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 90711122-1359-4b5b-85db-bf0ba73b4cce

📥 Commits

Reviewing files that changed from the base of the PR and between a5ba752 and 4328d4d.

📒 Files selected for processing (5)
  • components/bounty-detail/bounty-detail-submissions-card.tsx
  • components/wallet/transaction-history.tsx
  • components/wallet/wallet-overview.tsx
  • components/wallet/wallet-sheet.tsx
  • lib/utils/stellar-explorer.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/bounty-detail/bounty-detail-submissions-card.tsx
  • lib/utils/stellar-explorer.ts

@ekumamatthew
Copy link
Copy Markdown
Contributor Author

hi @0xdevcollins I've made the changes

Copy link
Copy Markdown
Contributor

@Benjtalkshow Benjtalkshow left a comment

Choose a reason for hiding this comment

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

Hi @ekumamatthew, the Stellar Explorer utility and StellarLink component are well-structured with good validation, copy-to-clipboard, and multi-explorer support — nice foundation!

The critical blockers are that TransactionLink is still not imported in transaction-history.tsx and bounty-detail-submissions-card.tsx, and Check is missing from the lucide-react imports in wallet-sheet.tsx. These will crash the build, so the fix commit didn’t fully resolve the original CodeRabbit feedback.

Please address the following:

getStellarNetwork() always returns "mainnet" regardless of input. Use an environment variable like NEXT_PUBLIC_STELLAR_NETWORK instead.

The testnet URL for stellar.expert uses a subdomain pattern (testnet.stellar.expert) that doesn’t exist. It should be stellar.expert/explorer/testnet/.

The StrKey validation regexes accept 0-9, but Stellar base32 only uses A-Z and 2-7.

wallet-overview.tsx line 61 still hardcodes the explorer URL instead of using the getAccountUrl() utility.

Guard the CSV export date formatting with isValid() just like the render path does.
Fix CI failure and conflict

@0xdevcollins 0xdevcollins merged commit 438811e into boundlessfi:main Mar 30, 2026
1 of 3 checks passed
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.

Implement Stellar Explorer Integration and Transaction Links

3 participants