jb-loan-queries
Query REVLoans data via Bendystraw GraphQL. Use when: (1) displaying a user's loans across all revnets, (2) showing all loans for a specific revnet/project, (3) checking borrow permissions, (4) building loan management UIs. Covers LoansByAccount query, permission checking, and multi-chain loan aggregation.
Install
mkdir -p .claude/skills/jb-loan-queries && curl -L -o skill.zip "https://mcp.directory/api/skills/download/8232" && unzip -o skill.zip -d .claude/skills/jb-loan-queries && rm skill.zipInstalls to .claude/skills/jb-loan-queries
About this skill
Querying REVLoans via Bendystraw
Problem
Displaying loan data in revnet UIs requires querying Bendystraw's GraphQL API with the correct queries and understanding how to filter/aggregate loans across chains and projects.
Context / Trigger Conditions
- Building UI to show a user's outstanding loans
- Displaying all loans for a specific revnet
- Checking if a user has permission to borrow
- Calculating loan headroom (refinanceable amount)
- Multi-chain loan aggregation
Solution
GraphQL Queries
Get All Loans for a User
query LoansByAccount($owner: String!, $version: Int!) {
loans(where: { owner: $owner, version: $version }) {
items {
borrowAmount
collateral
prepaidDuration
projectId
terminal
token
chainId
createdAt
id
project {
version
}
}
}
}
Variables:
owner: User's wallet address (lowercase)version: Protocol version (5 for V5)
Get Loans for Specific Project
query LoansDetailsByAccount($owner: String!, $projectId: Int!, $version: Int!) {
loans(where: { owner: $owner, projectId: $projectId, version: $version }) {
items {
borrowAmount
collateral
prepaidDuration
createdAt
projectId
terminal
token
chainId
id
project {
version
}
}
}
}
Check Borrow Permission
query HasPermission(
$account: String!
$chainId: Float!
$projectId: Float!
$operator: String!
$version: Float!
) {
permissionHolder(
account: $account
chainId: $chainId
projectId: $projectId
operator: $operator
version: $version
) {
permissions
}
}
Permission ID 1 = Borrow permission. Check if permissions array includes 1.
Loan Entity Fields
type Loan = {
id: BigInt // Unique loan ID
owner: String // Borrower address
beneficiary: String // Recipient of borrowed funds
borrowAmount: BigInt // Amount borrowed (in base token wei)
collateral: BigInt // Tokens locked as collateral
prepaidDuration: Int // Seconds of prepaid fee time
prepaidFeePercent: Int // Basis points of prepaid fee
projectId: Int // Revnet project ID
chainId: Int // Chain where loan exists
terminal: String // Terminal address
token: String // Base token address (ETH = 0x0...0)
createdAt: Int // Unix timestamp
sourceFeeAmount: BigInt // Total fees charged
tokenUri: String | null // NFT metadata URI (loans are ERC-721)
version: Int // Protocol version
}
React Hook Usage (revnet-app pattern)
import { useBendystrawQuery } from 'juice-sdk-react'
import { LoansByAccountDocument } from '@/generated/graphql'
const LOAN_POLL_INTERVAL = 3000 // 3 seconds
function useUserLoans(address: string, version: number = 5) {
const { data, loading, error } = useBendystrawQuery(
LoansByAccountDocument,
{ owner: address.toLowerCase(), version },
{ pollInterval: LOAN_POLL_INTERVAL }
)
return {
loans: data?.loans.items ?? [],
loading,
error
}
}
Filter Loans by Revnet
When showing loans for a specific revnet (which may span multiple chains):
function filterLoansByRevnet(
loans: Loan[],
revnetProjectIds: number[] // projectIds across all chains
): Loan[] {
return loans.filter(loan =>
revnetProjectIds.includes(Number(loan.projectId))
)
}
// Usage: Get projectIds from suckerGroup
const { data: projectData } = useBendystrawQuery(ProjectDocument, { ... })
const revnetProjectIds = projectData.project.suckerGroup?.projects_rel
.map(p => Number(p.projectId)) ?? [Number(projectData.project.projectId)]
const filteredLoans = filterLoansByRevnet(loans, revnetProjectIds)
Calculate Loan Headroom (Refinanceable Amount)
Use contract call to get borrowable amount for existing collateral:
import { useReadContract } from 'wagmi'
import { revLoansAbi } from '@/abi/revLoans'
function useLoanHeadroom(loan: Loan) {
const { data: borrowableAmount } = useReadContract({
address: REVLOANS_ADDRESS,
abi: revLoansAbi,
functionName: 'borrowableAmountFrom',
args: [
BigInt(loan.projectId),
BigInt(loan.collateral),
18, // decimals
1, // currency (ETH)
],
})
// Headroom = what you could borrow - what you already borrowed
const headroom = borrowableAmount
? borrowableAmount - BigInt(loan.borrowAmount)
: 0n
return headroom
}
Multi-Chain Token Resolution
Loans may use different tokens on different chains. Get token config from suckerGroup:
query GetSuckerGroup($id: String!) {
suckerGroup(id: $id) {
projects_rel {
projectId
chainId
decimals # 18 for ETH, 6 for USDC
currency # 1 for ETH, 2 for USDC
}
}
}
function getTokenConfigForLoan(loan: Loan, suckerGroup: SuckerGroup) {
const project = suckerGroup.projects_rel.find(
p => p.chainId === loan.chainId && p.projectId === loan.projectId
)
return {
decimals: project?.decimals ?? 18,
currency: project?.currency ?? 1,
}
}
Verification
Test with known loan data:
- Query loans for an address known to have loans
- Verify
borrowAmountmatches on-chainREVLoans.loanOf() - Check that
prepaidDurationdecreases over time (fee time consumed)
Example
Complete component for displaying user loans:
function UserLoansTable({ address, revnetProjectIds }) {
const { loans, loading } = useUserLoans(address)
// Filter to this revnet only
const revnetLoans = filterLoansByRevnet(loans, revnetProjectIds)
if (loading) return <Spinner />
if (revnetLoans.length === 0) return <EmptyState />
return (
<Table>
<thead>
<tr>
<th>Chain</th>
<th>Borrowed</th>
<th>Collateral</th>
<th>Fee Time</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{revnetLoans.map(loan => (
<LoanRow key={loan.id} loan={loan} />
))}
</tbody>
</Table>
)
}
Notes
- Loans are ERC-721 NFTs - each loan has a unique
tokenUri prepaidDurationis in seconds, decreases as time passes- After 10 years (
LOAN_LIQUIDATION_DURATION), loans can be liquidated - Permission checking uses Bendystraw, but actual borrow calls use on-chain contracts
- Poll interval of 3 seconds keeps UI responsive to loan state changes
References
- loansByAccount.graphql
- LoansDetailsTable.tsx
- useHasBorrowPermission.ts
- REVLoans contract:
/jb-revloansskill for contract mechanics
More by openclaw
View all skills by openclaw →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversMorpho: Query DeFi market data, vaults, positions and historical APY via Morpho's GraphQL API for portfolio management a
Build persistent semantic networks for enterprise & engineering data management. Enable data persistence and memory acro
MCP Toolbox for Databases by Google. An open-source server that lets AI agents query Cloud SQL, Spanner, AlloyDB, and ot
Explore official Google BigQuery MCP servers. Find resources and examples to build context-aware apps in Google's ecosys
Connect Supabase projects to AI with Supabase MCP Server. Standardize LLM communication for secure, efficient developmen
Safely connect cloud Grafana to AI agents with MCP: query, inspect, and manage Grafana resources using simple, focused o
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.