Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ PHOENIX_ENABLED_TESTNET=true
# Reflector oracle contract (56-char C... id) — see https://reflector.network. Empty = oracle disabled.
# A malformed id disables the oracle on this network and logs a warning naming this variable.
REFLECTOR_CONTRACT_ID_TESTNET=
# Blend lending pools (comma-separated 56-char C... ids) on testnet.
BLEND_POOLS_TESTNET=CCEBVDYM32YNYCVNRXQKDFFPISJJCV557CDZEIRBEE4NCV4KHPQ44HGF
# Blend backstop contract on testnet (56-char C... id).
BLEND_BACKSTOP_TESTNET=CBDVWXT433PRVTUNM56C3JREF3HIZHRBA64NB2C3B2UNCKIS65ZYCLZA
# Blend lending rate ingestion enabled on testnet (default: true).
BLEND_ENABLED_TESTNET=true
# SEP-40 publisher (#222): the oracle contract Lens pushes ITS aggregate into,
# so Soroban contracts can read a Lens price. Deploy it from oracle/contract/
# and paste the id `soroban contract deploy` prints — never a placeholder.
Expand Down Expand Up @@ -163,6 +169,12 @@ PHOENIX_ENABLED_MAINNET=true
# Reflector oracle contract on mainnet (56-char C... id) — copy it from https://reflector.network.
# There is no built-in default: leave empty to keep the oracle disabled.
REFLECTOR_CONTRACT_ID_MAINNET=
# Blend lending pools (comma-separated 56-char C... ids) on mainnet.
BLEND_POOLS_MAINNET=CAJJZSGMMM3PD7N33TAPHGBUGTB43OC73HVIK2L2G6BNGGGYOSSYBXBD,CCCCIQSDILITHMM7PBSLVDT5MISSY7R26MNZXCX4H7J5JQ5FPIYOGYFS,CDVQVKOY2YSXS2IC7KN6MNASSHPAO7UN2UR2ON4OI2SKMFJNVAMDX6DP,CBP7NO6F7FRDHSOFQBT2L2UWYIZ2PU76JKVRYAQTG3KZSQLYAOKIF2WB
# Blend backstop contract on mainnet (56-char C... id).
BLEND_BACKSTOP_MAINNET=CAQQR5SWBXKIGZKPBZDH3KM5GQ5GUTPKB7JAFCINLZBC5WXPJKRG3IM7
# Blend lending rate ingestion enabled on mainnet (default: true).
BLEND_ENABLED_MAINNET=true
# SEP-40 publisher on mainnet. Same three variables as testnet above; mainnet is
# additionally gated on a funded publisher account and a real RPC provider
# (RPC_URL_MAINNET), so read docs/sep40-oracle-publisher.md before enabling it.
Expand Down Expand Up @@ -204,6 +216,12 @@ ROUTING_MAX_HOPS=3
ROUTING_INTERMEDIATES=XLM:native,USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
# Reflector oracle contract ID on testnet (falls back from paired REFLECTOR_CONTRACT_ID_TESTNET)
REFLECTOR_CONTRACT_ID=
# Blend lending pools on testnet (falls back from paired BLEND_POOLS_TESTNET)
BLEND_POOLS=CCEBVDYM32YNYCVNRXQKDFFPISJJCV557CDZEIRBEE4NCV4KHPQ44HGF
# Blend backstop contract on testnet (falls back from paired BLEND_BACKSTOP_TESTNET)
BLEND_BACKSTOP=CBDVWXT433PRVTUNM56C3JREF3HIZHRBA64NB2C3B2UNCKIS65ZYCLZA
# Blend lending rate ingestion enabled (falls back from paired BLEND_ENABLED_TESTNET)
BLEND_ENABLED=true
# SEP-40 publisher fallbacks on testnet (fall back from the paired _TESTNET vars above)
SEP40_CONTRACT_ID=
SEP40_PUBLISHER_SECRET_KEY=
Expand Down Expand Up @@ -243,6 +261,8 @@ SDEX_PAGE_SIZE=200
AMM_PAGE_SIZE=200
# How often to poll Soroswap pool reserves in milliseconds (default: 60000 = 60s)
SOROSWAP_POLL_INTERVAL_MS=60000
# How often to poll Blend pool reserves in milliseconds (default: 60000 = 60s)
BLEND_POLL_INTERVAL_MS=60000
# Per-ingester cycle deadline in milliseconds (default: 60000 = 60s). A poll
# cycle that overruns it is aborted and counted in the
# ingester_abandoned_cycles_total metric instead of stalling the ingester loop.
Expand Down Expand Up @@ -469,6 +489,8 @@ MCP_OPENAPI_PATH=
# against a table that has never been pruned cannot hold a long lock or blow
# the WAL. Default 1000.
SNAPSHOT_PRUNE_BATCH_SIZE=1000
# Rows removed by one DELETE during a lending rate retention run (default 1000).
RATE_PRUNE_BATCH_SIZE=1000


# --- MCP agent spending limits ---
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ npx @modelcontextprotocol/inspector npm run mcp:server
| GET | `/supported` | Payment kinds and extensions this facilitator supports |
| POST | `/verify` | Verify an x402 payment payload |
| POST | `/settle` | Settle an x402 payment (idempotent — retries replay the stored result) |
| GET | `/rates` | Query latest lending and borrow rates across pools |
| GET/POST | `/graphql` | GraphQL query/mutation endpoint (GraphiQL IDE at `/graphiql`, docs: [`docs/graphql.md`](docs/graphql.md)) |
<!-- ENDPOINTS:END -->

Expand Down
171 changes: 171 additions & 0 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2783,6 +2783,75 @@
}
}
}
},
"/rates": {
"get": {
"operationId": "getLendingRates",
"summary": "Query latest lending and borrow rates across pools",
"description": "Returns the latest supply and borrow rates, utilisation, and reserves for lending markets.",
"security": [],
"parameters": [
{
"name": "asset",
"in": "query",
"required": false,
"description": "Filter by asset symbol (e.g. USDC, XLM)",
"schema": {
"type": "string"
}
},
{
"name": "poolId",
"in": "query",
"required": false,
"description": "Filter by pool contract ID",
"schema": {
"type": "string"
}
},
{
"name": "network",
"in": "query",
"required": false,
"description": "Stellar network to query (testnet or mainnet)",
"schema": {
"type": "string",
"enum": [
"testnet",
"mainnet"
]
}
},
{
"name": "limit",
"in": "query",
"required": false,
"description": "Maximum number of rate records to return",
"schema": {
"type": "integer",
"default": 100
}
}
],
"responses": {
"200": {
"description": "Latest lending rates",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LendingRatesResponse"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"429": {
"$ref": "#/components/responses/TooManyRequests"
}
}
}
}
},
"components": {
Expand Down Expand Up @@ -2935,6 +3004,108 @@
}
},
"schemas": {
"LendingRateEntry": {
"type": "object",
"required": [
"id",
"venue",
"source",
"network",
"poolId",
"asset",
"supplyApy",
"borrowApy",
"timestamp"
],
"properties": {
"id": {
"type": "string"
},
"venue": {
"type": "string",
"example": "blend"
},
"source": {
"type": "string",
"example": "blend"
},
"network": {
"type": "string",
"example": "mainnet"
},
"poolId": {
"type": "string"
},
"poolName": {
"type": "string",
"nullable": true
},
"asset": {
"type": "string",
"example": "USDC"
},
"assetAddress": {
"type": "string",
"nullable": true
},
"supplyApy": {
"type": "number"
},
"borrowApy": {
"type": "number"
},
"supplyApr": {
"type": "number",
"nullable": true
},
"borrowApr": {
"type": "number",
"nullable": true
},
"utilization": {
"type": "number",
"nullable": true,
"description": "Borrowed / supplied as a fraction. Null for venues that publish rates only."
},
"totalSupply": {
"type": "number",
"nullable": true
},
"totalBorrowed": {
"type": "number",
"nullable": true
},
"reserves": {
"type": "number",
"nullable": true
},
"ledger": {
"type": "integer"
},
"timestamp": {
"type": "string",
"format": "date-time"
}
}
},
"LendingRatesResponse": {
"type": "object",
"required": [
"network",
"rates"
],
"properties": {
"network": {
"type": "string"
},
"rates": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LendingRateEntry"
}
}
}
},
"InternalErrorResponse": {
"type": "object",
"required": [
Expand Down
111 changes: 111 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1874,6 +1874,51 @@ paths:
'402':
$ref: '#/components/responses/PaymentRequired'

/rates:
get:
operationId: getLendingRates
summary: Query latest lending and borrow rates across pools
description: Returns the latest supply and borrow rates, utilisation, and reserves for lending markets.
security: []
parameters:
- name: asset
in: query
required: false
description: Filter by asset symbol (e.g. USDC, XLM)
schema:
type: string
- name: poolId
in: query
required: false
description: Filter by pool contract ID
schema:
type: string
- name: network
in: query
required: false
description: Stellar network to query (testnet or mainnet)
schema:
type: string
enum: [testnet, mainnet]
- name: limit
in: query
required: false
description: Maximum number of rate records to return
schema:
type: integer
default: 100
responses:
'200':
description: Latest lending rates
content:
application/json:
schema:
$ref: '#/components/schemas/LendingRatesResponse'
'400':
$ref: '#/components/responses/BadRequest'
'429':
$ref: '#/components/responses/TooManyRequests'

components:
securitySchemes:
x402:
Expand Down Expand Up @@ -1994,6 +2039,72 @@ components:
example: 'public, max-age=300'

schemas:
LendingRateEntry:
type: object
required: [id, venue, source, network, poolId, asset, supplyApy, borrowApy, timestamp]
properties:
id:
type: string
venue:
type: string
example: blend
source:
type: string
example: blend
network:
type: string
example: mainnet
poolId:
type: string
poolName:
type: string
nullable: true
asset:
type: string
example: USDC
assetAddress:
type: string
nullable: true
supplyApy:
type: number
borrowApy:
type: number
supplyApr:
type: number
nullable: true
borrowApr:
type: number
nullable: true
utilization:
type: number
nullable: true
description: Borrowed / supplied as a fraction. Null for venues that publish rates only.
totalSupply:
type: number
nullable: true
totalBorrowed:
type: number
nullable: true
reserves:
type: number
nullable: true
ledger:
type: integer
timestamp:
type: string
format: date-time

LendingRatesResponse:
type: object
required: [network, rates]
properties:
network:
type: string
rates:
type: array
items:
$ref: '#/components/schemas/LendingRateEntry'

InternalErrorResponse:
type: object
required: [code, message, correlationId]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- AlterTable
ALTER TABLE "lending_rates" ADD COLUMN "asset_address" TEXT,
ADD COLUMN "borrow_apr" DECIMAL(18,8),
ADD COLUMN "reserves" DECIMAL(36,7),
ADD COLUMN "supply_apr" DECIMAL(18,8),
ADD COLUMN "total_borrowed" DECIMAL(36,7),
ADD COLUMN "total_supply" DECIMAL(36,7),
ADD COLUMN "utilization" DECIMAL(18,8);

-- CreateIndex
CREATE INDEX "lending_rates_network_pool_id_asset_timestamp_idx" ON "lending_rates"("network", "pool_id", "asset", "timestamp" DESC);
Loading