Skip to content

four issues resolved: multi-currency contracts (37 tests passing), de… - #153

Merged
Obiajulu-gif merged 2 commits into
Obiajulu-gif:mainfrom
harystyleseze:main
May 27, 2026
Merged

four issues resolved: multi-currency contracts (37 tests passing), de…#153
Obiajulu-gif merged 2 commits into
Obiajulu-gif:mainfrom
harystyleseze:main

Conversation

@harystyleseze

@harystyleseze harystyleseze commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Contracts: Implement multi-currency pricing — prompts can now be listed in any Stellar asset (USDC, ARS, etc.)
    via the SAC standard, not just XLM
  • CI: Remove stale legacy ci.yml workflow that duplicated the split frontend/backend/contracts workflows
  • Frontend: Add route-level code splitting with React.lazy and vendor chunk separation to reduce initial bundle
    size
  • Docs: Add "Built on Stellar" case study documenting gas efficiency, security model, and architecture

Closes #47
Closes #143
Closes #144
Closes #137

Changes

Contracts (Issue #47)

  • Added asset: Address field to Prompt struct for per-listing currency
  • Added PricingConfig struct (price + asset) to stay within Soroban's 10-parameter limit
  • Updated create_prompt to accept a PricingConfig and validate the asset contract via token::Client
  • Modified buy_prompt and lease_prompt to use the prompt's asset instead of the global XLM address
  • Added InvalidAsset error variant
  • Updated PromptCreated event to include asset address
  • Updated all existing tests + added 3 new multi-asset purchase/lease tests (37 total)

CI (Issue #143)

  • Deleted .github/workflows/ci.yml (legacy Node 18 + npm workflow, fully replaced by frontend.yml, backend.yml,
    contracts.yml)

Frontend (Issue #144)

  • Converted route imports to React.lazy with Suspense fallback in App.tsx
  • Added manualChunks config in vite.config.ts (vendor-stellar, vendor-charts, vendor-motion, vendor-crypto)

Docs (Issue #137)

  • Created docs/case-study-stellar.md with gas efficiency analysis, security overview, architecture diagram, and
    multi-currency design notes

Test Plan

  • cargo test -p prompt-hash — all contract tests pass including new multi-asset tests
  • yarn build — produces split chunks, no single file > 500 kB warning
  • CI workflows (frontend.yml, contracts.yml) pass
  • Case study renders correctly in GitHub markdown preview

Summary by CodeRabbit

  • New Features

    • Added multi-currency pricing support, enabling prompts to be priced in different token assets beyond XLM.
  • Documentation

    • Added comprehensive case study documentation covering platform architecture, security model, and transaction flows.
  • Performance

    • Optimized bundle splitting and implemented lazy-loaded components for faster initial page load times.

Review Change Stack

…leted stale CI workflow, added

  React.lazy code splitting, created case study doc
@vercel

vercel Bot commented May 26, 2026

Copy link
Copy Markdown

@harystyleseze is attempting to deploy a commit to the obiajulugif's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented May 26, 2026

Copy link
Copy Markdown

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

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@harystyleseze, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 44 minutes and 12 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91cd820a-3b9c-454f-b2fa-c46785bfc84b

📥 Commits

Reviewing files that changed from the base of the PR and between edbc15a and ddd8951.

📒 Files selected for processing (2)
  • .github/workflows/hygiene.yml
  • contracts/prompt-hash/src/test.rs
📝 Walkthrough

Walkthrough

This PR implements multi-currency support for the PromptHash marketplace, optimizes frontend bundle size, documents Soroban capabilities via case study, and removes a stale CI workflow. The contract now accepts configurable payment assets, validates them, and routes purchase/lease transfers accordingly. Frontend routes are lazy-loaded with vendor chunks optimized for caching.

Changes

Multi-Currency Prompt Pricing

Layer / File(s) Summary
Contract Types and Error Enums
contracts/prompt-hash/src/types.rs
New PricingConfig struct bundles price and asset address; Prompt struct gains asset: Address field; create_prompt trait method updated to accept PricingConfig parameter; InvalidAsset error code added to enum.
Prompt Creation with Asset Validation
contracts/prompt-hash/src/contract.rs
create_prompt imports PricingConfig, validates the pricing asset by calling decimals() on a token client, initializes Prompt with both price and asset, and emits updated PromptCreated event with asset.
Purchase and Lease with Asset-Based Transfers
contracts/prompt-hash/src/contract.rs
buy_prompt and lease_prompt replace fixed XLM transfers with token::StellarAssetClient calls using prompt.asset, preserving fee/referral/creator split logic and conditional transfer behavior.
Event Schema with Asset Emission
contracts/prompt-hash/src/events.rs
PromptCreated event struct adds asset: Address field; emit_prompt_created function signature updated to accept and publish asset alongside price and creator.
Contract Tests and Multi-Currency Scenarios
contracts/prompt-hash/src/test.rs
Test helper create_prompt updated to accept asset parameter and construct PricingConfig. All existing tests pass &context.xlm as asset. New multi-currency test section (Issue #47) registers USDC token, verifies prompt creation with non-XLM asset, validates fee splitting and balance effects, and confirms lease access/expiry for multi-asset pricing.

Frontend Bundle Optimization

Layer / File(s) Summary
Route-Level Code Splitting
src/App.tsx
Browse, Sell, Chat, Profile, and Status pages replaced with React.lazy() imports and wrapped in Suspense boundary with loading fallback. Overall routing structure and paths remain unchanged.
Vendor Chunk Configuration
vite.config.ts
Build output configured with Rollup manualChunks to group Stellar SDK, charting, motion, and crypto libraries into named vendor bundles for independent caching and reduced initial bundle size.

Documentation and CI Updates

Layer / File(s) Summary
Stellar Case Study Documentation
docs/case-study-stellar.md
New case study document explains why Soroban is chosen for PromptHash (native multi-asset support, built-in auth, predictable execution), details atomic buy_prompt flow with validation/fee-splits/token transfers, documents security model (authorization guards, reentrancy protection, checked arithmetic, pause mechanism), describes multi-currency design storing asset on-chain and validating via decimals(), compares against EVM and off-chain alternatives, and lists test coverage scenarios including CRUD, multi-buyer fee tracking, edge cases, vouchers, and multi-currency purchases/leases.
CI Cleanup
.github/workflows/ci.yml
Stale CI workflow removed. Prior workflow ran npm ci, frontend tests, lint, build, and contract tests. Now superseded by dedicated frontend/backend/contract workflows.

Sequence Diagram(s)

sequenceDiagram
  participant Buyer
  participant PromptHashContract
  participant TokenClient as StellarAssetClient<br/>(prompt.asset)
  participant Storage
  Buyer->>PromptHashContract: buy_prompt(prompt_id, amount)
  PromptHashContract->>Storage: fetch Prompt (includes asset)
  PromptHashContract->>TokenClient: transfer_from buyer → creator
  TokenClient-->>PromptHashContract: creator payment sent
  PromptHashContract->>TokenClient: transfer_from buyer → platform_fee
  TokenClient-->>PromptHashContract: fee sent (if configured)
  PromptHashContract->>Storage: record access, emit event
  PromptHashContract-->>Buyer: success
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Obiajulu-gif/Prompt-Hash-Stellar#80: Adds purchase-path safety coverage around fee routing and entitlement validation for the same purchase-flow logic that this PR refactors to support multi-currency asset transfers.
  • Obiajulu-gif/Prompt-Hash-Stellar#140: Modifies create_prompt and buy_prompt contract APIs by adding voucher/referral/tipping logic, while this PR changes the same functions to accept PricingConfig and route transfers via stored assets.
  • Obiajulu-gif/Prompt-Hash-Stellar#37: Wraps buy_prompt with reentrancy guard protection around external token transfers, intersecting with this PR's refactored purchase-flow execution path.

Poem

🐰 Hops through the stars with assets new,
Multi-currencies bloom and brew,
Lazy routes split bundles clean,
Soroban's power, brightly seen,
From XLM to USDC's call,
PromptHash marketplace thrives for all!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title partially addresses the changeset by mentioning multi-currency contracts and test count, but truncates mid-word and omits key changes like CI removal, frontend optimization, and documentation.
Linked Issues check ✅ Passed All coding requirements from linked issues are met: #47 adds multi-currency pricing with PricingConfig and asset validation; #143 removes the stale CI workflow; #144 implements React.lazy route splitting and manual chunks; #137 adds case-study documentation.
Out of Scope Changes check ✅ Passed All changes align with the four linked issues. Contract updates support multi-currency, CI cleanup removes legacy workflow, frontend adds route-level code splitting with vendor chunks, and documentation provides the case study.
Docstring Coverage ✅ Passed Docstring coverage is 87.80% which is sufficient. The required threshold is 80.00%.

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

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

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 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 `@contracts/prompt-hash/src/contract.rs`:
- Around line 70-72: Replace the infallible token::Client::new(&env,
&pricing.asset).decimals() call with the fallible client used for transfers
(token::StellarAssetClient); call StellarAssetClient::new(&env,
&pricing.asset).try_decimals() and map any Err or None result into returning
Err(Error::InvalidAsset) instead of allowing a trap—ensure you use the same
client family (StellarAssetClient), call try_decimals(), and propagate/map
failures to Error::InvalidAsset when validating pricing.asset.

In `@contracts/prompt-hash/src/events.rs`:
- Around line 9-10: The indexer is normalizing prices with a fixed divisor and
ignoring the new asset field, so update the indexing and model code to persist
the token and use its decimals for normalization: in
server/src/services/indexer.ts, read the asset field from the PromptCreated
event (and PromptPriceUpdated when present) and compute display price by
dividing price_stroops by 10^decimals instead of 10_000_000; in
server/src/models/Prompt.js persist the asset (or store decimals) on creation so
subsequent PromptPriceUpdated handlers can look up decimals and normalize
correctly; ensure you use the contract fields asset and price_stroops and
validate/convert using the token's decimals() value when available.

In `@contracts/prompt-hash/src/test.rs`:
- Around line 1140-1256: Add a negative unit test that calls
PromptHashContractClient::try_create_prompt with a non-token contract address
(e.g., an Address::generate() value) to exercise the invalid-asset branch and
assert it returns Err(Ok(Error::InvalidAsset)); specifically, create a test
function (similar to existing tests) that builds env/context, generates a fake
asset address, calls client.try_create_prompt(..., &fake_asset_address, ...),
and asserts the result equals Err(Ok(Error::InvalidAsset)) to prevent trap-based
regressions.

In `@docs/case-study-stellar.md`:
- Around line 27-42: The fenced block containing the numbered steps lacks a
language tag; update the block around the steps (the triple-backtick section
listing steps 1–14) to either add a language identifier such as "text" (e.g.,
```text) or replace the fenced code block with a normal Markdown numbered list
so the content renders semantically and satisfies the MD040 lint rule.
- Around line 91-122: The fenced ASCII diagram block that begins with the line
"┌─────────────────┐         ┌──────────────────────────┐" lacks a language
identifier; update the opening ``` of that diagram to include a language token
such as "text" (e.g., ```text) so the block is properly rendered and satisfies
MD040. Ensure only the opening fence is changed and no diagram characters are
modified.
- Around line 71-78: The fenced code block showing the reentrancy guard sequence
lacks a language identifier; update that markdown block (the one containing
lines like "set_reentrancy_guard()", "transfer_from (creator)",
"clear_reentrancy_guard()") to include a language token (e.g., add ```text or
```plain immediately after the opening backticks) so the block renders correctly
and satisfies MD040.
- Line 63: The docs incorrectly state that `#[only_owner]` is "admin-only via
OpenZeppelin's Ownable"; update the wording to reference Soroban ownership
utilities (`stellar_access::ownable::Ownable` and the
`stellar_macros::only_owner` macro) and note that the owner is set in the
constructor with `ownable::set_owner(&env, &admin)` to avoid Solidity/EVM
confusion, and also modify the fenced reentrancy code block (around the security
model paragraph) to include a language identifier (e.g., ```rust or ```text) for
proper rendering.

In `@vite.config.ts`:
- Around line 35-45: manualChunks currently lists "`@stellar/stellar-sdk`" as a
literal entry so imports of subpaths like "`@stellar/stellar-sdk/rpc`" or
"`@stellar/stellar-sdk/contract`" won't be matched; change the "vendor-stellar"
chunking to detect module IDs that start with the package path (e.g., use
manualChunks as a function or a regex test against moduleId and return
"vendor-stellar" when moduleId startsWith or matches
/^`@stellar`\/stellar-sdk(\/|$)/) so all subpath imports (seen in
src/lib/stellar/tx.ts and src/pages/Debugger.tsx) are grouped into the
vendor-stellar chunk.
🪄 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: beeb519d-bb76-4bdb-84d0-696f7be1664a

📥 Commits

Reviewing files that changed from the base of the PR and between fdef45c and edbc15a.

📒 Files selected for processing (8)
  • .github/workflows/ci.yml
  • contracts/prompt-hash/src/contract.rs
  • contracts/prompt-hash/src/events.rs
  • contracts/prompt-hash/src/test.rs
  • contracts/prompt-hash/src/types.rs
  • docs/case-study-stellar.md
  • src/App.tsx
  • vite.config.ts
💤 Files with no reviewable changes (1)
  • .github/workflows/ci.yml

Comment on lines +70 to +72
// Validate that the asset address implements the token interface
token::Client::new(&env, &pricing.asset).decimals();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For soroban_sdk token clients, what is the recommended way to validate a token/SAC contract address without trapping, and does token::StellarAssetClientexposetry_decimals() (or equivalent fallible APIs)?

💡 Result:

Recommended validation approach (no trapping): don’t call the infallible metadata methods (e.g., decimals()), because they are specified to panic if the SAC/token contract “has not yet been initialized” [1]. Instead, for Soroban token/SAC clients, prefer the fallible API that returns a Result (or otherwise gate your call behind a pre-check), so you can handle “not initialized / wrong contract” as an error rather than allowing a trap. For token::StellarAssetClient: yes—StellarAssetClient exposes a fallible equivalent of decimals() named try_decimals(&self) -> Result<..., Error> [2]. The docs also explicitly say decimals() panics when the contract hasn’t been initialized [2]. Caveat/contract-shape expectation: decimals(env) -> u32 is part of the StellarAssetInterface (CAP-46-6 functions) and is defined as panicking in that interface if the contract is not initialized [1][3]. So try_decimals() is the API you want when you need “validate that this address is a suitable SAC/token without trapping.”

Citations:


Fix asset validation to return Error::InvalidAsset via fallible try_decimals (no trapping)

token::Client::new(&env, &pricing.asset).decimals() can panic/trap when the SAC/token contract isn’t initialized, so Error::InvalidAsset isn’t reliably returned. Validate with the same client family used later for transfers (token::StellarAssetClient) and map try_decimals() failure to Error::InvalidAsset.

Suggested fix
-        // Validate that the asset address implements the token interface
-        token::Client::new(&env, &pricing.asset).decimals();
+        // Validate that the asset address is a compatible SAC and return typed error on failure
+        let sac = token::StellarAssetClient::new(&env, &pricing.asset);
+        if sac.try_decimals().is_err() {
+            return Err(Error::InvalidAsset);
+        }
📝 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
// Validate that the asset address implements the token interface
token::Client::new(&env, &pricing.asset).decimals();
// Validate that the asset address is a compatible SAC and return typed error on failure
let sac = token::StellarAssetClient::new(&env, &pricing.asset);
if sac.try_decimals().is_err() {
return Err(Error::InvalidAsset);
}
🤖 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 `@contracts/prompt-hash/src/contract.rs` around lines 70 - 72, Replace the
infallible token::Client::new(&env, &pricing.asset).decimals() call with the
fallible client used for transfers (token::StellarAssetClient); call
StellarAssetClient::new(&env, &pricing.asset).try_decimals() and map any Err or
None result into returning Err(Error::InvalidAsset) instead of allowing a
trap—ensure you use the same client family (StellarAssetClient), call
try_decimals(), and propagate/map failures to Error::InvalidAsset when
validating pricing.asset.

Comment on lines +9 to 10
pub asset: Address,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify downstream PromptCreated handling is multi-asset aware
fd -i 'indexer.ts'
rg -n -C3 'PromptCreated|price_stroops|asset|10_000_000|10_000_0000' server/src/services/indexer.ts

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 954


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect the PromptCreated event definition (asset field presence/types)
rg -n "PromptCreated" contracts/prompt-hash/src/events.rs
rg -n "asset" contracts/prompt-hash/src/events.rs
# Print the relevant sections around the matches (keep output small)
rg -n "PromptCreated" -n -C3 contracts/prompt-hash/src/events.rs
rg -n "asset" -n -C3 contracts/prompt-hash/src/events.rs

# 2) Inspect PromptCreated handling/normalization in the indexer
sed -n '1,160p' server/src/services/indexer.ts

# 3) Check whether asset/decimals is used anywhere near PromptCreated or price_stroops normalization
rg -n "price_stroops" server/src/services/indexer.ts
rg -n "asset" server/src/services/indexer.ts
rg -n "10_000_000" server/src/services/indexer.ts

# 4) Broader search: any other consumer of PromptCreated / price_stroops / asset decimals
rg -n "PromptCreated" server/src | head -n 50
rg -n "price_stroops" server/src | head -n 50
rg -n "\"PromptPriceUpdated\"" server/src | head -n 50
rg -n "10_000_000" server/src | head -n 50

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 4648


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "struct PromptPriceUpdated|PromptPriceUpdated" contracts/prompt-hash/src/events.rs
rg -n "PromptPriceUpdated" -n -C3 contracts/prompt-hash/src/events.rs

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 488


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate PromptCreated emission
rg -n "emit_prompt_created|PromptCreated \{" contracts/prompt-hash/src -S
rg -n "price_stroops|asset" contracts/prompt-hash/src -S

# Show surrounding code for the emission (limit output)
rg -n "emit_prompt_created" -n -C5 contracts/prompt-hash/src

# If emit functions exist, inspect their definitions and any helpers that compute price
rg -n "fn emit_.*prompt.*" contracts/prompt-hash/src -S

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 10010


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect contract.rs around pricing/emit_prompt_created and decimals validation
sed -n '1,220p' contracts/prompt-hash/src/contract.rs

# Inspect server Prompt model to see if it stores asset/decimals
fd -i "*Prompt*" server/src -a
fd -i "prompt" server/src/models -a 2>/dev/null || true
ls -R server/src/models 2>/dev/null || true
rg -n "class Prompt|interface Prompt|mongoose.*Prompt|price|asset|decimals" server/src/models -S || true

# Inspect any DB update for asset during PromptCreated indexing
rg -n "asset" server/src/services/indexer.ts
rg -n "Prompt.findOneAndUpdate\\(" server/src/services/indexer.ts -n

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 7772


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "10_000_000" server/src
rg -n "asset" server/src/models server/src/services/indexer.ts
fd -i "Prompt*" server/src/models -t f || true

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 265


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "10_000_000" server/src
fd -i "Prompt*" server/src/models -t f || true
rg -n "class Prompt|interface Prompt|mongoose.*Prompt|asset|decimals" server/src/models server/src -S
rg -n "price_stroops" server/src -S

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 1251


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,220p' server/src/models/Prompt.js
sed -n '1,120p' server/src/models/PromptVersion.ts
rg -n "asset|decimals|price_stroops|10_000_000" server/src/models/Prompt.js server/src/models/PromptVersion.ts server/src -S

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 2375


Fix indexer price normalization for PromptCreated/PromptPriceUpdated.

PromptCreated now emits asset, and the contract stores price_stroops in the selected token’s smallest units (it validates token decimals() on the contract). However server/src/services/indexer.ts ignores asset and still normalizes with a hard-coded / 10_000_000 for both PromptCreated and PromptPriceUpdated. Since server/src/models/Prompt.js also does not persist asset/decimals, later PromptPriceUpdated events can’t be normalized correctly for non-XLM assets. Store asset (or at least decimals) from PromptCreated and normalize display price using that token’s decimals instead of a fixed divisor.

🤖 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 `@contracts/prompt-hash/src/events.rs` around lines 9 - 10, The indexer is
normalizing prices with a fixed divisor and ignoring the new asset field, so
update the indexing and model code to persist the token and use its decimals for
normalization: in server/src/services/indexer.ts, read the asset field from the
PromptCreated event (and PromptPriceUpdated when present) and compute display
price by dividing price_stroops by 10^decimals instead of 10_000_000; in
server/src/models/Prompt.js persist the asset (or store decimals) on creation so
subsequent PromptPriceUpdated handlers can look up decimals and normalize
correctly; ensure you use the contract fields asset and price_stroops and
validate/convert using the token's decimals() value when available.

Comment on lines +1140 to +1256
#[test]
fn test_buy_prompt_with_non_xlm_asset() {
let env: Env = Default::default();
let context = setup(&env);
let client = PromptHashContractClient::new(&env, &context.contract);

// Register a second token (e.g., USDC)
let usdc = env.register(FungibleTokenContract, (context.admin.clone(),));
let usdc_client = token::StellarAssetClient::new(&env, &usdc);

let creator = Address::generate(&env);
let buyer = Address::generate(&env);
let price: i128 = 5_000_000; // 5 USDC (6 decimals)
let prompt_id = create_prompt(&env, &client, &creator, "USDC Prompt", price, &usdc);

// Fund buyer with USDC
usdc_client.mint(&buyer, &price);
usdc_client.approve(&buyer, &context.contract, &price, &1_000);

let creator_start = usdc_client.balance(&creator);
let fee_start = usdc_client.balance(&context.fee_wallet);

client.buy_prompt(&buyer, &prompt_id, &None::<Address>, &price, &None::<Bytes>);

let expected_fee = price * 500 / 10_000;
let expected_creator = price - expected_fee;

assert_eq!(usdc_client.balance(&creator), creator_start + expected_creator);
assert_eq!(usdc_client.balance(&context.fee_wallet), fee_start + expected_fee);
assert!(client.has_access(&buyer, &prompt_id));
}

#[test]
fn test_create_and_buy_different_assets() {
let env: Env = Default::default();
let context = setup(&env);
let client = PromptHashContractClient::new(&env, &context.contract);
let xlm_client = token::StellarAssetClient::new(&env, &context.xlm);

// Register a second token
let usdc = env.register(FungibleTokenContract, (context.admin.clone(),));
let usdc_client = token::StellarAssetClient::new(&env, &usdc);

let creator = Address::generate(&env);
let buyer = Address::generate(&env);

// Create one prompt priced in XLM, another in USDC
let xlm_price: i128 = 10_000;
let usdc_price: i128 = 2_000_000;
let prompt_xlm = create_prompt(&env, &client, &creator, "XLM Prompt", xlm_price, &context.xlm);
let prompt_usdc = create_prompt(&env, &client, &creator, "USDC Prompt", usdc_price, &usdc);

// Fund buyer with both tokens
fund_buyer(&xlm_client, &buyer, &context.contract, xlm_price);
usdc_client.mint(&buyer, &usdc_price);
usdc_client.approve(&buyer, &context.contract, &usdc_price, &1_000);

// Buy the XLM prompt - XLM balances should change, USDC should not
let creator_xlm_before = xlm_client.balance(&creator);
let creator_usdc_before = usdc_client.balance(&creator);

client.buy_prompt(&buyer, &prompt_xlm, &None::<Address>, &xlm_price, &None::<Bytes>);

let xlm_fee = xlm_price * 500 / 10_000;
assert_eq!(xlm_client.balance(&creator), creator_xlm_before + xlm_price - xlm_fee);
assert_eq!(usdc_client.balance(&creator), creator_usdc_before);

// Buy the USDC prompt - USDC balances should change
let creator_usdc_before = usdc_client.balance(&creator);
client.buy_prompt(&buyer, &prompt_usdc, &None::<Address>, &usdc_price, &None::<Bytes>);

let usdc_fee = usdc_price * 500 / 10_000;
assert_eq!(usdc_client.balance(&creator), creator_usdc_before + usdc_price - usdc_fee);

assert!(client.has_access(&buyer, &prompt_xlm));
assert!(client.has_access(&buyer, &prompt_usdc));
}

#[test]
fn test_lease_prompt_with_non_xlm_asset() {
let env: Env = Default::default();
let context = setup(&env);
let client = PromptHashContractClient::new(&env, &context.contract);

env.ledger().with_mut(|ledger| {
ledger.timestamp = 1_000;
});

// Register a second token
let usdc = env.register(FungibleTokenContract, (context.admin.clone(),));
let usdc_client = token::StellarAssetClient::new(&env, &usdc);

let creator = Address::generate(&env);
let buyer = Address::generate(&env);
let price: i128 = 10_000_000;
let prompt_id = create_prompt(&env, &client, &creator, "USDC Lease Prompt", price, &usdc);

// Lease price = 40% of base price
let lease_price = price * 4_000 / 10_000;
usdc_client.mint(&buyer, &lease_price);
usdc_client.approve(&buyer, &context.contract, &lease_price, &1_000);

let creator_start = usdc_client.balance(&creator);

client.lease_prompt(&buyer, &prompt_id, &600);

let expected_fee = lease_price * 500 / 10_000;
let expected_seller = lease_price - expected_fee;
assert_eq!(usdc_client.balance(&creator), creator_start + expected_seller);
assert!(client.has_access(&buyer, &prompt_id));

// Verify lease expires
env.ledger().with_mut(|ledger| {
ledger.timestamp = 1_700;
});
assert!(!client.has_access(&buyer, &prompt_id));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add a negative test for invalid asset to lock Error::InvalidAsset behavior.

Multi-asset happy paths are covered well; please add one try_create_prompt case with a non-token contract address and assert Err(Ok(Error::InvalidAsset)). This prevents regressions to trap-based failures.

🤖 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 `@contracts/prompt-hash/src/test.rs` around lines 1140 - 1256, Add a negative
unit test that calls PromptHashContractClient::try_create_prompt with a
non-token contract address (e.g., an Address::generate() value) to exercise the
invalid-asset branch and assert it returns Err(Ok(Error::InvalidAsset));
specifically, create a test function (similar to existing tests) that builds
env/context, generates a fake asset address, calls client.try_create_prompt(...,
&fake_asset_address, ...), and asserts the result equals
Err(Ok(Error::InvalidAsset)) to prevent trap-based regressions.

Comment on lines +27 to +42
```
1. Validate listing (active, not duplicate, supply check)
2. Apply voucher discount (if provided)
3. Validate payment amount >= required price
4. Validate referrer constraints
5. Set reentrancy guard
6. Calculate fee, referral, and creator splits
7. Execute transfer_from: buyer → creator
8. Execute transfer_from: buyer → fee_wallet
9. Execute transfer_from: buyer → referrer (if present)
10. Increment sales count
11. Grant purchase access record
12. Clear reentrancy guard
13. Emit PromptPurchased event
14. Emit PromptTipped event (if overpayment)
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifier to code block.

The fenced code block should specify a language for proper rendering and linting compliance.

📝 Proposed fix

Since this is a numbered list rather than code, consider either:

Option 1 - Add a language identifier (e.g., text):

-```
+```text
 1. Validate listing (active, not duplicate, supply check)

Option 2 - Use markdown list formatting instead of a code block for better semantic markup.

As per coding guidelines (static analysis): Fenced code blocks should have a language specified (MD040).

📝 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
```
1. Validate listing (active, not duplicate, supply check)
2. Apply voucher discount (if provided)
3. Validate payment amount >= required price
4. Validate referrer constraints
5. Set reentrancy guard
6. Calculate fee, referral, and creator splits
7. Execute transfer_from: buyer → creator
8. Execute transfer_from: buyer → fee_wallet
9. Execute transfer_from: buyer → referrer (if present)
10. Increment sales count
11. Grant purchase access record
12. Clear reentrancy guard
13. Emit PromptPurchased event
14. Emit PromptTipped event (if overpayment)
```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@docs/case-study-stellar.md` around lines 27 - 42, The fenced block containing
the numbered steps lacks a language tag; update the block around the steps (the
triple-backtick section listing steps 1–14) to either add a language identifier
such as "text" (e.g., ```text) or replace the fenced code block with a normal
Markdown numbered list so the content renders semantically and satisfies the
MD040 lint rule.


- `create_prompt`: `creator.require_auth()`
- `buy_prompt`: `buyer.require_auth()`
- `set_fee_percentage`: `#[only_owner]` macro (admin-only via OpenZeppelin's Ownable)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check for ownership implementation in the contract

# Search for ownership-related macros or implementations
rg -n "only_owner|Ownable|OpenZeppelin" contracts/prompt-hash/

# Search for admin/owner authorization patterns
rg -nC3 "set_fee_percentage|set_pause_status" contracts/prompt-hash/src/contract.rs

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 2013


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant section of the docs with line numbers
sed -n '50,90p' docs/case-study-stellar.md | nl -ba -w2 -s': '

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 119


🏁 Script executed:

sed -n '50,90p' docs/case-study-stellar.md | nl -ba -w2 -s': '

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 119


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '55,88p' docs/case-study-stellar.md | nl -ba -w2 -s': '

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 119


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="docs/case-study-stellar.md"

echo "== Matching docs references =="
rg -n "set_fee_percentage|only_owner|OpenZeppelin|Ownable" "$file" || true

echo
echo "== Docs lines 55-88 with line numbers (no nl) =="
sed -n '55,88p' "$file" | awk '{printf "%4d: %s\n", NR+54, $0}'

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 2065


Clarify ownership source and add a language to the reentrancy code fence in the security model

  • docs/case-study-stellar.md says #[only_owner] is “admin-only via OpenZeppelin's Ownable” at line 63, but the contract uses Soroban ownership utilities (stellar_access::ownable::Ownable + stellar_macros::only_owner), with the owner set in the constructor via ownable::set_owner(&env, &admin)—adjust wording to avoid confusion with Solidity/EVM Ownable.
  • The fenced code block around line 71 starts with ``` without a language identifier; add one (e.g., text/`rust`) for consistency and better rendering.
🤖 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 `@docs/case-study-stellar.md` at line 63, The docs incorrectly state that
`#[only_owner]` is "admin-only via OpenZeppelin's Ownable"; update the wording
to reference Soroban ownership utilities (`stellar_access::ownable::Ownable` and
the `stellar_macros::only_owner` macro) and note that the owner is set in the
constructor with `ownable::set_owner(&env, &admin)` to avoid Solidity/EVM
confusion, and also modify the fenced reentrancy code block (around the security
model paragraph) to include a language identifier (e.g., ```rust or ```text) for
proper rendering.

Comment on lines +71 to +78
```
set_reentrancy_guard() ← blocks re-entry
├─ transfer_from (creator)
├─ transfer_from (fee_wallet)
├─ transfer_from (referrer)
├─ update prompt state
└─ grant purchase record
clear_reentrancy_guard() ← re-enables entry

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifier to code block.

The reentrancy guard illustration should specify a language for proper rendering.

📝 Proposed fix
-```
+```text
 set_reentrancy_guard()       ← blocks re-entry

As per coding guidelines (static analysis): Fenced code blocks should have a language specified (MD040).

📝 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
```
set_reentrancy_guard() ← blocks re-entry
├─ transfer_from (creator)
├─ transfer_from (fee_wallet)
├─ transfer_from (referrer)
├─ update prompt state
└─ grant purchase record
clear_reentrancy_guard() ← re-enables entry
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 71-71: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@docs/case-study-stellar.md` around lines 71 - 78, The fenced code block
showing the reentrancy guard sequence lacks a language identifier; update that
markdown block (the one containing lines like "set_reentrancy_guard()",
"transfer_from (creator)", "clear_reentrancy_guard()") to include a language
token (e.g., add ```text or ```plain immediately after the opening backticks) so
the block renders correctly and satisfies MD040.

Comment on lines +91 to +122
```
┌─────────────────┐ ┌──────────────────────────┐
│ Creator Browser │ │ Buyer Browser │
│ │ │ │
│ encrypt prompt │ │ select prompt + pay │
│ submit listing │ │ unlock after purchase │
└────────┬─────────┘ └────────────┬─────────────┘
│ │
│ create_prompt(pricing) │ buy_prompt(payment)
│ │
▼ ▼
┌──────────────────────────────────────────────────────┐
│ Soroban Contract │
│ │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────┐ │
│ │ Listings │ │ Purchases│ │ Fee/Referral Config │ │
│ │ (Prompt) │ │ (Access) │ │ │ │
│ └──────────┘ └──────────┘ └────────────────────┘ │
│ │
│ transfer_from ──► SAC (XLM, USDC, ARS, etc.) │
└──────────────────────────────────────────────────────┘
│ has_access query
┌──────────────────┐
│ Unlock Service │
│ │
│ verify access │
│ decrypt prompt │
│ return content │
└──────────────────┘
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifier to code block.

The ASCII architecture diagram should specify a language for proper rendering.

📝 Proposed fix
-```
+```text
 ┌─────────────────┐         ┌──────────────────────────┐

As per coding guidelines (static analysis): Fenced code blocks should have a language specified (MD040).

📝 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
```
┌─────────────────┐ ┌──────────────────────────┐
│ Creator Browser │ │ Buyer Browser │
│ │ │ │
│ encrypt prompt │ │ select prompt + pay │
│ submit listing │ │ unlock after purchase │
└────────┬─────────┘ └────────────┬─────────────┘
│ │
│ create_prompt(pricing) │ buy_prompt(payment)
│ │
▼ ▼
┌──────────────────────────────────────────────────────┐
│ Soroban Contract │
│ │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────┐ │
│ │ Listings │ │ Purchases│ │ Fee/Referral Config │ │
│ │ (Prompt) │ │ (Access) │ │ │ │
│ └──────────┘ └──────────┘ └────────────────────┘ │
│ │
│ transfer_from ──► SAC (XLM, USDC, ARS, etc.) │
└──────────────────────────────────────────────────────┘
│ has_access query
┌──────────────────┐
│ Unlock Service │
│ │
│ verify access │
│ decrypt prompt │
│ return content │
└──────────────────┘
```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 91-91: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@docs/case-study-stellar.md` around lines 91 - 122, The fenced ASCII diagram
block that begins with the line "┌─────────────────┐        
┌──────────────────────────┐" lacks a language identifier; update the opening
``` of that diagram to include a language token such as "text" (e.g., ```text)
so the block is properly rendered and satisfies MD040. Ensure only the opening
fence is changed and no diagram characters are modified.

Comment thread vite.config.ts
Comment on lines +35 to +45
manualChunks: {
"vendor-stellar": [
"@stellar/stellar-sdk",
"@stellar/stellar-base",
"@stellar/design-system",
"@creit.tech/stellar-wallets-kit",
],
"vendor-charts": ["chart.js", "react-chartjs-2"],
"vendor-motion": ["framer-motion"],
"vendor-crypto": ["libsodium-wrappers"],
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether manual-chunked packages are imported via subpaths.
# Expected: If subpath imports exist, prefer function-based manualChunks.
rg -nP --type=ts --type=tsx --type=js --type=jsx -C2 \
'from\s+["'\''](`@stellar/stellar-sdk/`[^"'\'']+|`@stellar/stellar-base/`[^"'\'']+|chart\.js/[^"'\'']+|framer-motion/[^"'\'']+|libsodium-wrappers/[^"'\'']+)["'\'']'

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 104


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show relevant part of vite.config.ts
if [ -f "vite.config.ts" ]; then
  echo "=== vite.config.ts (manualChunks area) ==="
  nl -ba vite.config.ts | sed -n '1,120p'
  echo
fi

# Find subpath imports/usages for the packages in question
echo "=== occurrences of `@stellar/stellar-sdk/` (subpaths) ==="
rg -n --hidden --no-ignore -S "`@stellar/stellar-sdk/`" . || true

echo
echo "=== occurrences of `@stellar/stellar-base/` (subpaths) ==="
rg -n --hidden --no-ignore -S "`@stellar/stellar-base/`" . || true

echo
echo "=== occurrences of chart.js/ (subpaths) ==="
rg -n --hidden --no-ignore -S "chart.js/" . || true

echo
echo "=== occurrences of framer-motion/ (subpaths) ==="
rg -n --hidden --no-ignore -S "framer-motion/" . || true

echo
echo "=== occurrences of libsodium-wrappers/ (subpaths) ==="
rg -n --hidden --no-ignore -S "libsodium-wrappers/" . || true

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 180


🌐 Web query:

Rollup output.manualChunks object array of ids matching subpath module ids (e.g., manualChunks: {vendor: ['@stellar/stellar-sdk']} match '@stellar/stellar-sdk/rpc')

💡 Result:

In Rollup, the output.manualChunks option accepts either an object or a function to define custom shared chunks [1]. When you need to match specific subpath imports—such as @stellar/stellar-sdk/rpc—the function form is the required approach, as the object form only accepts exact module names or package identifiers to group those modules and their dependencies [1]. To target subpaths, you should implement a function that inspects the module ID passed to it. Example implementation: // rollup.config.js export default { //... output: { manualChunks(id) { // Check if the module ID contains the subpath if (id.includes('@stellar/stellar-sdk/rpc')) { return 'stellar-rpc'; // Name of the resulting chunk } // Fallback: handle other dependencies if (id.includes('node_modules')) { return 'vendor'; } } } }; Key considerations: 1. Object Form Limitation: The object form, such as manualChunks: { vendor: ['@stellar/stellar-sdk'] }, maps specific listed modules to a chunk [1]. It does not inherently provide pattern matching for subpath modules (e.g., it will not automatically include @stellar/stellar-sdk/rpc just because the parent package is listed) [1]. 2. Function Form Flexibility: The function form receives the resolved module ID as the first argument [1]. This allows you to use string methods like .includes(), .endsWith(), or regular expressions to match specific subpaths dynamically [1][2]. 3. Dependency Handling: When you return a string from the function, Rollup assigns that label to the module and all its dependencies, provided those dependencies have not already been assigned to a different manual chunk [1][3]. 4. Advanced Control: The function receives a second argument containing utility functions like getModuleInfo, which can be used for more complex logic if you need to inspect the dependency graph to determine if a module should be grouped [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show relevant part of vite.config.ts
if [ -f "vite.config.ts" ]; then
  echo "=== vite.config.ts (manualChunks area) ==="
  nl -ba vite.config.ts | sed -n '1,120p'
  echo
fi

# Find subpath imports/usages for the packages in question
echo "=== occurrences of `@stellar/stellar-sdk/` (subpaths) ==="
rg -n --hidden --no-ignore -S "`@stellar/stellar-sdk/`" . || true

echo
echo "=== occurrences of `@stellar/stellar-base/` (subpaths) ==="
rg -n --hidden --no-ignore -S "`@stellar/stellar-base/`" . || true

echo
echo "=== occurrences of chart.js/ (subpaths) ==="
rg -n --hidden --no-ignore -S "chart.js/" . || true

echo
echo "=== occurrences of framer-motion/ (subpaths) ==="
rg -n --hidden --no-ignore -S "framer-motion/" . || true

echo
echo "=== occurrences of libsodium-wrappers/ (subpaths) ==="
rg -n --hidden --no-ignore -S "libsodium-wrappers/" . || true

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 180


🌐 Web query:

Rollup output.manualChunks object array of ids matching subpath module ids (e.g., manualChunks: {vendor: ['@stellar/stellar-sdk']} match '@stellar/stellar-sdk/rpc')

💡 Result:

To match subpath module IDs in Rollup's manualChunks, you must use the function form of the manualChunks configuration option [1][2]. The object form only allows static, exact mapping of modules to chunks, and does not support pattern matching or subpath logic [1]. When you use the function form, Rollup passes the module ID of every resolved file to your function [1]. You can then perform string matching or regex operations on that ID to return the desired chunk name [1][2]. Implementation approach: In your rollup.config.js (or vite.config.js): export default { //... output: { manualChunks(id) { // Check if the module belongs to the specific package or path if (id.includes('@stellar/stellar-sdk')) { return 'stellar-vendor'; // All files matching this path go into this chunk } // Default behavior for other modules if (id.includes('node_modules')) { return 'vendor'; } } } }; Key considerations: 1. Object Form Limitation: The object form, e.g., manualChunks: { vendor: ['@stellar/stellar-sdk'] }, only bundles the specific modules listed [1]. It does not automatically capture subpaths (e.g., @stellar/stellar-sdk/rpc) unless they are explicitly included in the array or handled by a plugin that resolves them [1]. 2. Function Form Flexibility: The function form is the authoritative way to handle complex grouping [1]. Because it receives the resolved ID, you can easily target specific subpaths by checking if the string starts with or includes your target path [2]. 3. Dependency Inclusion: When you return a chunk name for a module ID, Rollup automatically includes that module and all its dependencies in the specified chunk, unless those dependencies are already assigned to a different manual chunk [3][1][4]. 4. Evaluation Order: The function is evaluated for each module [1][4]. You can implement logic to prioritize certain chunks over others if a module belongs to multiple potential groups [3][5][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect vite.config.ts manualChunks
echo "=== vite.config.ts: manualChunks definition ==="
if [ -f "vite.config.ts" ]; then
  rg -n "manualChunks" vite.config.ts || true
  echo
  echo "=== vite.config.ts: lines 1-160 (manualChunks context) ==="
  # Avoid nl (not available). Use cat -n.
  cat -n vite.config.ts | sed -n '1,160p'
else
  echo "vite.config.ts not found"
fi

# 2) Search for subpath imports in the repo
patterns=(
  '`@stellar/stellar-sdk/`'
  '`@stellar/stellar-sdk/rpc`'
  '`@stellar/stellar-base/`'
  'chart.js/'
  'framer-motion/'
  'libsodium-wrappers/'
)

for p in "${patterns[@]}"; do
  echo
  echo "=== occurrences of pattern: $p ==="
  rg -n --hidden --no-ignore -S "$p" . || true
done

Repository: Obiajulu-gif/Prompt-Hash-Stellar

Length of output: 4547


Cover @stellar/stellar-sdk subpath imports in vendor-stellar chunking

vite.config.ts currently uses the object form manualChunks: { "vendor-stellar": ["@stellar/stellar-sdk", ...] }, but the app imports subpaths like @stellar/stellar-sdk/rpc and @stellar/stellar-sdk/contract (e.g., src/lib/stellar/tx.ts, src/pages/Debugger.tsx). Those subpath module IDs won’t reliably be grouped into vendor-stellar, fragmenting cache behavior.

Suggested change
-      rollupOptions: {
-        output: {
-          manualChunks: {
-            "vendor-stellar": [
-              "`@stellar/stellar-sdk`",
-              "`@stellar/stellar-base`",
-              "`@stellar/design-system`",
-              "`@creit.tech/stellar-wallets-kit`",
-            ],
-            "vendor-charts": ["chart.js", "react-chartjs-2"],
-            "vendor-motion": ["framer-motion"],
-            "vendor-crypto": ["libsodium-wrappers"],
-          },
-        },
-      },
+      rollupOptions: {
+        output: {
+          manualChunks(id) {
+            if (
+              id.includes("`@stellar/stellar-sdk`") ||
+              id.includes("`@stellar/stellar-base`") ||
+              id.includes("`@stellar/design-system`") ||
+              id.includes("`@creit.tech/stellar-wallets-kit`")
+            ) return "vendor-stellar";
+            if (id.includes("chart.js") || id.includes("react-chartjs-2")) return "vendor-charts";
+            if (id.includes("framer-motion")) return "vendor-motion";
+            if (id.includes("libsodium-wrappers")) return "vendor-crypto";
+          },
+        },
+      },
📝 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
manualChunks: {
"vendor-stellar": [
"@stellar/stellar-sdk",
"@stellar/stellar-base",
"@stellar/design-system",
"@creit.tech/stellar-wallets-kit",
],
"vendor-charts": ["chart.js", "react-chartjs-2"],
"vendor-motion": ["framer-motion"],
"vendor-crypto": ["libsodium-wrappers"],
},
rollupOptions: {
output: {
manualChunks(id) {
if (
id.includes("`@stellar/stellar-sdk`") ||
id.includes("`@stellar/stellar-base`") ||
id.includes("`@stellar/design-system`") ||
id.includes("`@creit.tech/stellar-wallets-kit`")
) return "vendor-stellar";
if (id.includes("chart.js") || id.includes("react-chartjs-2")) return "vendor-charts";
if (id.includes("framer-motion")) return "vendor-motion";
if (id.includes("libsodium-wrappers")) return "vendor-crypto";
},
},
},
🤖 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 `@vite.config.ts` around lines 35 - 45, manualChunks currently lists
"`@stellar/stellar-sdk`" as a literal entry so imports of subpaths like
"`@stellar/stellar-sdk/rpc`" or "`@stellar/stellar-sdk/contract`" won't be matched;
change the "vendor-stellar" chunking to detect module IDs that start with the
package path (e.g., use manualChunks as a function or a regex test against
moduleId and return "vendor-stellar" when moduleId startsWith or matches
/^`@stellar`\/stellar-sdk(\/|$)/) so all subpath imports (seen in
src/lib/stellar/tx.ts and src/pages/Debugger.tsx) are grouped into the
vendor-stellar chunk.

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

Labels

None yet

Projects

None yet

2 participants