Skip to content

Read Juplend positions via Borrow API#115

Merged
imbingox merged 6 commits into
mainfrom
feat/juplend-borrow-api-reader
Jul 6, 2026
Merged

Read Juplend positions via Borrow API#115
imbingox merged 6 commits into
mainfrom
feat/juplend-borrow-api-reader

Conversation

@imbingox

@imbingox imbingox commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Update Trellis to 0.6.5 in an isolated commit.
  • Replace the Juplend @jup-ag/lend-read reader with Jupiter Lend Borrow REST GET /lend/v1/borrow/positions?users=....
  • Require options.walletAddress for Juplend accounts and treat vaultId / positionId as local filters over returned wallet positions.
  • Remove Juplend Solana RPC config/dependencies and keep Juplend read-only: no borrow, repay, withdraw, or order support.
  • Update docs, specs, live smoke script, tests, and add a changeset.
  • Archive the previously stale Trellis websocket liveness task.

Validation

  • bun run lint
  • bun run type-check
  • bun test --max-concurrency=1 tests/integration/account.test.ts
  • bun run test

Summary by CodeRabbit

  • New Features

    • Added support for Trae IDE across platform detection, hooks, and task setup.
    • Juplend now reads borrow positions from the official REST API and supports filtering by wallet, vault, and position.
  • Bug Fixes

    • Improved hook startup reliability by avoiding hangs when input stays open.
    • Kiro and Trae platform behavior now handles context output more consistently.
  • Documentation

    • Updated platform and Juplend docs to reflect the new Trae IDE support and the updated Juplend account requirements.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@imbingox, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 92ec8966-6476-4bc8-a2a5-67c1fa72a021

📥 Commits

Reviewing files that changed from the base of the PR and between 5e75398 and 60176a0.

⛔ Files ignored due to path filters (3)
  • .trellis/workspace/codex-agent/index.md is excluded by !.trellis/workspace/**
  • .trellis/workspace/codex-agent/journal-2.md is excluded by !.trellis/workspace/**
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .claude/hooks/inject-workflow-state.py
  • .trellis/spec/sdk/venues/juplend.md
  • src/adapters/juplend/borrow-api.ts
  • src/adapters/juplend/private-adapter.ts
  • tests/integration/account.test.ts
📝 Walkthrough

Walkthrough

This PR migrates the Juplend adapter from an on-chain @jup-ag/lend-read SDK to Jupiter's Borrow REST API, requiring walletAddress and removing rpcUrl across types, adapter, runtime, docs, scripts, and tests. Separately, it adds Trae IDE platform support to Trellis scripts/hooks, hardens hook stdin handling and Kiro output, and updates Trellis workflow/skill documentation with a PRD convergence pass and stricter JSONL readiness gates.

Changes

Juplend Borrow REST Migration

Layer / File(s) Summary
Account option and type contract changes
src/types/shared.ts, .changeset/juplend-borrow-api-reader.md, .trellis/spec/sdk/venues/juplend.md, .trellis/spec/sdk/adapters.md, .trellis/spec/sdk/architecture.md
JuplendAccountOptions now requires walletAddress and drops rpcUrl; spec docs reference the new borrow-api.ts module and REST-based contract.
New Borrow REST API adapter
src/adapters/juplend/borrow-api.ts
New module exports types and readJuplendPositions(), fetching and filtering borrow positions from api.jup.ag.
Private adapter refactor
src/adapters/juplend/private-adapter.ts
JuplendPrivateAdapter now uses readJuplendPositions, requires walletAddress, computes balances via token decimals, and drops rpcUrl/cache helpers.
Runtime client wiring
src/client/runtime.ts
createJuplendAdapterGroup passes jupApiKey instead of rpcUrl.
Documentation updates
docs/managers.md, docs/quickstart.md, docs/types.md
Docs updated to reflect required walletAddress and removed rpcUrl.
Live smoke script updates
scripts/live-juplend-account-smoke.ts
CLI requires --wallet-address, drops --rpc-url.
Test suite updates
tests/integration/account.test.ts, tests/support/exchanges/juplend.ts, tests/type/register-account-input.ts
Tests and fixtures updated for Borrow REST endpoint, wallet-required registration, and error cases.

Trellis Trae Platform Support and Workflow Docs

Layer / File(s) Summary
Trae platform detection
.trellis/scripts/common/cli_adapter.py, active_task.py, task_store.py
Adds "trae" platform support with IDE-only CLI restrictions and config directory mapping.
Hook stdin timeout, Kiro output, Trae detection
.claude/hooks/inject-workflow-state.py, .claude/hooks/session-start.py, .codex/hooks/inject-workflow-state.py
Adds non-blocking stdin reading with timeout, Trae detection, and plain-text output for Kiro.
Trae IDE platform docs
.agents/skills/trellis-meta/references/*, .claude/skills/trellis-meta/references/*
Adds Trae IDE rows/entries to platform reference documentation.
PRD convergence pass and JSONL gates
.agents/skills/trellis-brainstorm/SKILL.md, .claude/skills/trellis-brainstorm/SKILL.md, .trellis/workflow.md
Adds convergence pass requirements and stricter curated-entry gates for implement.jsonl/check.jsonl.
Version bump and template hashes
.trellis/.version, package.json, .trellis/.template-hashes.json
Bumps Trellis version to 0.6.5 and refreshes template hash entries.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PrivateAdapter as JuplendPrivateAdapter
  participant BorrowAPI as readJuplendPositions
  participant JupAPI as api.jup.ag

  Client->>PrivateAdapter: bootstrapAccount/mapAccount
  PrivateAdapter->>BorrowAPI: readJuplendPositions({walletAddress, vaultId, positionId})
  BorrowAPI->>JupAPI: GET /lend/v1/borrow/positions?users=wallet
  JupAPI-->>BorrowAPI: raw positions JSON
  BorrowAPI-->>PrivateAdapter: filtered JuplendReadPosition[]
  PrivateAdapter-->>Client: mapped balances/risk
Loading

Possibly related PRs

  • imbingox/acex#36: Modifies src/adapters/juplend/private-adapter.ts account validation/mapping and shared HTTP transport, directly related to this migration.
  • imbingox/acex#42: Touches Juplend private-adapter/client wiring in private-adapter.ts and src/client/runtime.ts, overlapping with the same adapter/runtime integration points.
  • imbingox/acex#81: Restructures venue configuration and runtime adapter-group wiring, overlapping with the rpcUrljupApiKey change in shared.ts and runtime.ts.

Poem

A rabbit hops from chain to REST,
No more RPC, wallet knows best!
Borrow positions fetched with glee,
Trae joins the platform family tree 🐇
Hooks now breathe without a hitch—
Convergence passes, docs enrich!

🚥 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 accurately summarizes the main change: Juplend position reads now use the Borrow API instead of the previous reader.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/juplend-borrow-api-reader

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/adapters/juplend/private-adapter.ts (1)

217-284: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include position.dustBorrowAmount in Juplend debt totals. readJuplendPositions exposes it separately, but mapAccount only folds position.borrowAmount into accumulator.borrowed and totalDebtUsd, so positions with dust debt will underreport borrowed, totalDebtUSD, and the resulting risk metrics. Add the dust amount with the borrow token decimals alongside borrowAmount.

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

In `@src/adapters/juplend/private-adapter.ts` around lines 217 - 284, `mapAccount`
is missing `position.dustBorrowAmount` in Juplend debt aggregation, so debt and
risk metrics can be understated. Update the debt handling inside `mapAccount` to
combine `position.borrowAmount` with `position.dustBorrowAmount` using the
borrow token decimals before calculating `borrowedQuantity`, then use that
combined amount for both `accumulator.borrowed` and `totalDebtUsd` while leaving
the rest of the position mapping logic unchanged.
🧹 Nitpick comments (2)
.claude/hooks/inject-workflow-state.py (1)

310-340: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Narrow the stdin reader exception handler Catch Exception instead of BaseException in the daemon reader so shutdown signals aren’t swallowed.

🤖 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 @.claude/hooks/inject-workflow-state.py around lines 310 - 340, The stdin
reader in _load_hook_input is catching too broadly by using BaseException inside
the _read daemon helper, which can swallow shutdown/control-flow signals. Update
the exception handling in _read to catch Exception only, while keeping the
existing queue-based read and the fallback-to-empty-dict behavior in
_load_hook_input unchanged. Use the _load_hook_input and _read symbols to locate
the handler.

Source: Linters/SAST tools

src/adapters/juplend/private-adapter.ts (1)

217-231: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate getJupApiKey implementation across two files.

private-adapter.ts defines its own getJupApiKey (used at bootstrapAccount's call site) while borrow-api.ts also defines a getJupApiKey with the same explicitApiKey || process.env.JUP_API fallback logic, and readJuplendPositions re-resolves the key a second time internally. Consider exporting a single getJupApiKey from borrow-api.ts and reusing it here to avoid the two implementations silently diverging over time.

Also applies to: 341-353

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

In `@src/adapters/juplend/private-adapter.ts` around lines 217 - 231, The Juplend
API key resolution logic is duplicated in both private-adapter.ts and
borrow-api.ts, and readJuplendPositions is resolving it again internally;
consolidate this by exporting and reusing the existing getJupApiKey from
borrow-api.ts in bootstrapAccount/mapAccount so there is only one fallback path.
Update the call sites around mapAccount and readJuplendPositions to accept the
already-resolved key instead of recomputing it, keeping the explicitApiKey ||
process.env.JUP_API behavior in one shared place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/adapters/juplend/borrow-api.ts`:
- Around line 78-80: The asString helper currently only guards against
undefined, so null values from the Juplend borrow API can still reach toString()
and fail mapping. Update asString in borrow-api.ts to treat null the same as
undefined before conversion, and keep the existing behavior for StringLike,
string, and number inputs used by the supply/borrow/dustBorrow mapping.

In `@src/adapters/juplend/private-adapter.ts`:
- Around line 205-215: The token decimal handling in tokenDecimals and
divideTokenAmount currently falls back to 0 when JuplendTokenMetadata.decimals
is missing or invalid, which can silently skew amounts. Update the
JuplendTokenMetadata parsing path to treat missing/malformed decimals as an
error condition or skip the affected position instead of defaulting to zero, and
ensure the caller that uses divideTokenAmount handles that failure explicitly.

---

Outside diff comments:
In `@src/adapters/juplend/private-adapter.ts`:
- Around line 217-284: `mapAccount` is missing `position.dustBorrowAmount` in
Juplend debt aggregation, so debt and risk metrics can be understated. Update
the debt handling inside `mapAccount` to combine `position.borrowAmount` with
`position.dustBorrowAmount` using the borrow token decimals before calculating
`borrowedQuantity`, then use that combined amount for both
`accumulator.borrowed` and `totalDebtUsd` while leaving the rest of the position
mapping logic unchanged.

---

Nitpick comments:
In @.claude/hooks/inject-workflow-state.py:
- Around line 310-340: The stdin reader in _load_hook_input is catching too
broadly by using BaseException inside the _read daemon helper, which can swallow
shutdown/control-flow signals. Update the exception handling in _read to catch
Exception only, while keeping the existing queue-based read and the
fallback-to-empty-dict behavior in _load_hook_input unchanged. Use the
_load_hook_input and _read symbols to locate the handler.

In `@src/adapters/juplend/private-adapter.ts`:
- Around line 217-231: The Juplend API key resolution logic is duplicated in
both private-adapter.ts and borrow-api.ts, and readJuplendPositions is resolving
it again internally; consolidate this by exporting and reusing the existing
getJupApiKey from borrow-api.ts in bootstrapAccount/mapAccount so there is only
one fallback path. Update the call sites around mapAccount and
readJuplendPositions to accept the already-resolved key instead of recomputing
it, keeping the explicitApiKey || process.env.JUP_API behavior in one shared
place.
🪄 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 Plus

Run ID: 53aaa119-6158-4c8d-9201-b87bedfb935e

📥 Commits

Reviewing files that changed from the base of the PR and between 39d4f8f and 5e75398.

⛔ Files ignored due to path filters (7)
  • .trellis/tasks/archive/2026-07/07-03-ws-periodic-business-liveness/check.jsonl is excluded by !.trellis/tasks/**
  • .trellis/tasks/archive/2026-07/07-03-ws-periodic-business-liveness/design.md is excluded by !.trellis/tasks/**
  • .trellis/tasks/archive/2026-07/07-03-ws-periodic-business-liveness/implement.jsonl is excluded by !.trellis/tasks/**
  • .trellis/tasks/archive/2026-07/07-03-ws-periodic-business-liveness/implement.md is excluded by !.trellis/tasks/**
  • .trellis/tasks/archive/2026-07/07-03-ws-periodic-business-liveness/prd.md is excluded by !.trellis/tasks/**
  • .trellis/tasks/archive/2026-07/07-03-ws-periodic-business-liveness/task.json is excluded by !.trellis/tasks/**
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (38)
  • .agents/skills/trellis-brainstorm/SKILL.md
  • .agents/skills/trellis-meta/references/customize-local/change-hooks.md
  • .agents/skills/trellis-meta/references/local-architecture/generated-files.md
  • .agents/skills/trellis-meta/references/platform-files/hooks-and-settings.md
  • .agents/skills/trellis-meta/references/platform-files/overview.md
  • .agents/skills/trellis-meta/references/platform-files/platform-map.md
  • .changeset/juplend-borrow-api-reader.md
  • .claude/hooks/inject-workflow-state.py
  • .claude/hooks/session-start.py
  • .claude/skills/trellis-brainstorm/SKILL.md
  • .claude/skills/trellis-meta/references/customize-local/change-hooks.md
  • .claude/skills/trellis-meta/references/local-architecture/generated-files.md
  • .claude/skills/trellis-meta/references/platform-files/hooks-and-settings.md
  • .claude/skills/trellis-meta/references/platform-files/overview.md
  • .claude/skills/trellis-meta/references/platform-files/platform-map.md
  • .codex/hooks/inject-workflow-state.py
  • .trellis/.template-hashes.json
  • .trellis/.version
  • .trellis/scripts/common/active_task.py
  • .trellis/scripts/common/cli_adapter.py
  • .trellis/scripts/common/task_store.py
  • .trellis/spec/sdk/adapters.md
  • .trellis/spec/sdk/architecture.md
  • .trellis/spec/sdk/venues/juplend.md
  • .trellis/workflow.md
  • docs/managers.md
  • docs/quickstart.md
  • docs/types.md
  • package.json
  • scripts/live-juplend-account-smoke.ts
  • src/adapters/juplend/borrow-api.ts
  • src/adapters/juplend/lend-read.ts
  • src/adapters/juplend/private-adapter.ts
  • src/client/runtime.ts
  • src/types/shared.ts
  • tests/integration/account.test.ts
  • tests/support/exchanges/juplend.ts
  • tests/type/register-account-input.ts
💤 Files with no reviewable changes (1)
  • src/adapters/juplend/lend-read.ts

Comment thread src/adapters/juplend/borrow-api.ts Outdated
Comment thread src/adapters/juplend/private-adapter.ts Outdated
@imbingox
imbingox merged commit ec0e637 into main Jul 6, 2026
2 checks passed
@imbingox
imbingox deleted the feat/juplend-borrow-api-reader branch July 6, 2026 07:58
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.

1 participant