feat: list Ref's classic exchange for pools holding the asset
ci / gate (push) Successful in 4m7s
deploy / validate (push) Skipped
deploy / build (push) Failing after 11m44s
deploy / deploy-api (push) Skipped
deploy / deploy-web (push) Skipped

#39 item 2. Every pool on v2.ref-finance.near is listed every ten
minutes — nine thousand-pool pages, three seconds on quadbrat, which
tracks the exchange's shard and is asked first while at the tip — and
each pool naming the asset is reported on the Ref market page, empty or
not. Today that is pool 8900, the empty QTC/QTEST test pool #39 found by
hand. A listing that fails part way publishes nothing.

The exchange's own balance of the asset joins the supply reconciliation
as a named holder, so a venue opening there is never "unaccounted".

Refs #39

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015pkwBsR54NRmZyU4QVhvfj
This commit is contained in:
2026-10-06 19:13:08 +03:00
co-authored by Claude Opus 5.5
parent 6152ba85c2
commit b3dc4ef4f6
14 changed files with 427 additions and 1 deletions
+28
View File
@@ -0,0 +1,28 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { BigUintDec } from "./BigUintDec";
/**
* A pool on Ref Finance's classic exchange holding the asset
* (blackbeard/observer#39).
*/
export type RefV1Pool = {
/**
* Its index on the exchange.
*/
pool_id: number,
/**
* `SIMPLE_POOL`, `STABLE_SWAP`, … as the contract names it.
*/
kind: string,
/**
* Its tokens' contracts.
*/
tokens: Array<string>,
/**
* What it holds of each, base units, same order.
*/
amounts: Array<BigUintDec>,
/**
* Fee in basis points as the contract keeps it (25 = 0.25%).
*/
fee: number, };
+23
View File
@@ -0,0 +1,23 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RefV1Pool } from "./RefV1Pool";
/**
* Every classic Ref pool holding the asset, found by listing them all.
*/
export type RefV1Pools = {
/**
* The exchange contract.
*/
contract: string,
/**
* Pools on it, all of which were read.
*/
scanned: number,
/**
* The ones holding the asset, empty or not.
*/
pools: Array<RefV1Pool>,
/**
* When.
*/
checked_at: string, };
+6
View File
@@ -8,6 +8,7 @@
import type { BidSide } from './generated/BidSide'
import type { IntentsFlows } from './generated/IntentsFlows'
import type { RefV1Pools } from './generated/RefV1Pools'
import type { AccountDetail } from './generated/AccountDetail'
import type { AccountEvent } from './generated/AccountEvent'
import type { AccountRow } from './generated/AccountRow'
@@ -330,6 +331,11 @@ export async function fetchIntentsSeries(
)
}
/** Classic Ref pools holding the asset; null until first listed. */
export async function fetchRefV1(chain: string, signal?: AbortSignal): Promise<RefV1Pools | null> {
return get<RefV1Pools | null>(`/chains/${chain}/ref/v1`, signal)
}
/** The asset moving into and out of NEAR Intents (blackbeard/observer#39). */
export async function fetchIntentsFlows(
chain: string,
+9
View File
@@ -34,6 +34,7 @@ import {
import { href } from '../lib/routes'
import { Field } from './Field'
import { BidSidePanel } from './BidSidePanel'
import { RefV1Panel } from './RefV1Panel'
import { SeriesBody } from './PriceChart'
const EXPLORER = 'https://nearblocks.io/txns/'
@@ -342,6 +343,14 @@ export function RefDclMarket({
<p className="panel-note">What is read: {pools.reads}</p>
</section>
)}
{pools?.asset && (
<RefV1Panel
chain={chain}
assetContract={pools.asset.replace(/^nep141:/, '')}
decimals={assetDecimals}
symbol={asset}
/>
)}
</>
)
}
+120
View File
@@ -0,0 +1,120 @@
/**
* Pools on Ref Finance's classic exchange holding the asset
* (blackbeard/observer#39, item 2).
*
* The asset trades in the DCL pool above. This is the watch for a venue
* opening somewhere else on Ref: every classic pool is listed every ten
* minutes, and each one naming the asset is shown, empty or not.
*/
import { useEffect, useState } from 'react'
import type { RefV1Pools } from '../api/generated/RefV1Pools'
import { RequestFailed, fetchRefV1 } from '../api/rest'
import { height as fmtHeight, shortAddress, tokens, when } from '../lib/format'
const REFRESH_MS = 120_000
export function RefV1Panel({
chain,
assetContract,
decimals,
symbol,
}: {
chain: string
/** The asset's token contract, which identifies its column in each pool. */
assetContract: string
decimals: number
symbol: string
}) {
const [data, setData] = useState<RefV1Pools | null | undefined>(undefined)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const controller = new AbortController()
const load = () =>
fetchRefV1(chain, controller.signal)
.then((d) => {
setData(d)
setError(null)
})
.catch((e: unknown) => {
if (controller.signal.aborted) return
setError(e instanceof RequestFailed ? e.message : 'Could not reach the observer.')
})
load()
const id = window.setInterval(load, REFRESH_MS)
return () => {
window.clearInterval(id)
controller.abort()
}
}, [chain])
const label = (t: string) => (t.endsWith('.near') ? t : shortAddress(t))
return (
<section className="panel" style={{ marginBottom: 26 }}>
<div className="panel-head">
<h2 className="panel-title">Ref classic exchange</h2>
<span className="eyebrow">
{data
? `${data.contract} · ${fmtHeight(data.scanned)} pools checked · ${when(data.checked_at)}`
: 'pools holding the asset'}
</span>
</div>
{error && <p className="empty">{error}</p>}
{!error && data === undefined && <p className="empty">Reading…</p>}
{!error && data === null && (
<p className="empty">Not listed yet — the first listing runs shortly after a restart.</p>
)}
{data && data.pools.length === 0 && (
<p className="empty">No pool on the classic exchange holds {symbol}.</p>
)}
{data && data.pools.length > 0 && (
<div className="scroll-x">
<table className="board">
<caption className="visually-hidden">Classic Ref pools holding {symbol}</caption>
<thead>
<tr>
<th scope="col" className="left">
Pool
</th>
<th scope="col" className="left">
Kind
</th>
<th scope="col" className="left">
Paired with
</th>
<th scope="col">{symbol} in it</th>
<th scope="col">Fee</th>
</tr>
</thead>
<tbody>
{data.pools.map((p) => {
const at = p.tokens.indexOf(assetContract)
const others = p.tokens.filter((_, i) => i !== at)
return (
<tr key={p.pool_id}>
<td className="left numeral">#{p.pool_id}</td>
<td className="left">{p.kind.toLowerCase().replace('_', ' ')}</td>
<td className="left">{others.map(label).join(', ')}</td>
<td className="numeral">
{at >= 0 ? `${tokens(p.amounts[at] ?? '0', decimals)}` : '—'}
</td>
<td className="numeral">{(p.fee / 100).toFixed(2)}%</td>
</tr>
)
})}
</tbody>
</table>
</div>
)}
<p className="panel-note">
Every pool on Ref&apos;s classic exchange is listed every ten minutes, and each naming{' '}
{symbol} is shown here, empty or not — it is where a new venue for {symbol} could open
without trading anywhere this page already follows. The exchange&apos;s own {symbol} balance
is also one of the named holders in the supply reconciliation.
</p>
</section>
)
}