feat: list Ref's classic exchange for pools holding the asset
#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:
@@ -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, };
|
||||
@@ -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, };
|
||||
@@ -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,
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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'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's own {symbol} balance
|
||||
is also one of the named holders in the supply reconciliation.
|
||||
</p>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user