feat(api): index swaps settled by NEAR Intents, off by default
The price of a token on NEAR Intents is the ratio inside a trade that
`intents.near` actually executed; there is no pool, oracle or stored price,
and a 1Click quote is an offer. This reads `execute_intents` transactions on
the contract's shard, keeps the `token_diff` legs whose receipt succeeded and
whose intent is in `intents_executed`, and records one trade per asset/counter
pair per outcome, counting each unit once whichever side the taker was on.
- core: event parsing, trade building, shard lookup, price and VWAP, tested
against the logs of mainnet tx 85uy9uCF (USDT on Tron for ZEC).
- data: a NEAR client over the existing RpcClient, live then archival;
migration 0009 (intents_trade, intents_scan, near_token).
- api: a contiguous-cursor scan and a supply/listing poll per chain, and
GET /v1/chains/{chain}/intents/{swaps,price}. Prices are in counter-token
units; no USD until a stablecoin is named by contract.
Gated on `[chains.intents]`, which the config template leaves commented out:
FastNEAR's free RPC sustains about two requests a second against ~1.7 needed
to follow the tip, and neardata allows 30 blocks a minute. It waits for our
own node. A test renders the template and fails if the block is enabled.
Verified end to end against mainnet with ZEC configured: the trade at NEAR
218,261,895 was recorded and served by both routes.
Refs #27
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,53 @@
|
||||
// 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";
|
||||
|
||||
/**
|
||||
* The asset's price against one counter token, over its latest trades.
|
||||
*/
|
||||
export type CounterPrice = {
|
||||
/**
|
||||
* The counter token, as a multi-token id.
|
||||
*/
|
||||
counter_token: string,
|
||||
/**
|
||||
* Its self-reported symbol. Display only.
|
||||
*/
|
||||
symbol: string | null,
|
||||
/**
|
||||
* Its decimals, when it is a NEP-141 token that said.
|
||||
*/
|
||||
decimals: number | null,
|
||||
/**
|
||||
* How many trades the figures below cover. Every figure is only as good
|
||||
* as this count, and one trade is one trade however it is labelled.
|
||||
*/
|
||||
trades: number,
|
||||
/**
|
||||
* The latest trade's price.
|
||||
*/
|
||||
last_price: number | null,
|
||||
/**
|
||||
* When it settled.
|
||||
*/
|
||||
last_at: string,
|
||||
/**
|
||||
* Where it settled.
|
||||
*/
|
||||
last_near_height: number,
|
||||
/**
|
||||
* Volume-weighted over the trades counted — the ratio of the summed
|
||||
* amounts, so a dust trade at a silly price moves it by its size.
|
||||
*/
|
||||
vwap: number | null,
|
||||
/**
|
||||
* Asset traded over those trades, base units.
|
||||
*/
|
||||
asset_volume: BigUintDec,
|
||||
/**
|
||||
* Counter token traded over those trades, base units.
|
||||
*/
|
||||
counter_volume: BigUintDec,
|
||||
/**
|
||||
* When the oldest of them settled.
|
||||
*/
|
||||
first_at: string, };
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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";
|
||||
|
||||
/**
|
||||
* Whether there is anything to trade yet, read rather than assumed.
|
||||
*
|
||||
* Until the asset exists on NEAR there can be no swap, and saying so with
|
||||
* the evidence beats an empty panel — or a price from somewhere else.
|
||||
*/
|
||||
export type IntentsListing = {
|
||||
/**
|
||||
* When these were read.
|
||||
*/
|
||||
checked_at: string,
|
||||
/**
|
||||
* The token contract's `ft_total_supply`: everything bridged to NEAR.
|
||||
*/
|
||||
total_supply: BigUintDec | null,
|
||||
/**
|
||||
* What `intents.near` holds of it: what can be traded at all.
|
||||
*/
|
||||
in_intents: BigUintDec | null,
|
||||
/**
|
||||
* Whether 1Click's public token list names the asset. Off-chain, and only
|
||||
* a listing — it says swaps can be *requested*, not that any settled.
|
||||
*/
|
||||
oneclick_listed: boolean | null, };
|
||||
@@ -0,0 +1,46 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ChainId } from "./ChainId";
|
||||
import type { CounterPrice } from "./CounterPrice";
|
||||
import type { IntentsListing } from "./IntentsListing";
|
||||
|
||||
/**
|
||||
* The asset's price on NEAR Intents, per counter token.
|
||||
*/
|
||||
export type IntentsPrice = {
|
||||
/**
|
||||
* Which chain's token.
|
||||
*/
|
||||
chain: ChainId,
|
||||
/**
|
||||
* The tracked asset, as a multi-token id.
|
||||
*/
|
||||
asset: string,
|
||||
/**
|
||||
* Its decimals, from its own `ft_metadata`.
|
||||
*/
|
||||
asset_decimals: number | null,
|
||||
/**
|
||||
* Trades per counter token the figures are taken over, at most.
|
||||
*/
|
||||
window_trades: number,
|
||||
/**
|
||||
* One entry per counter token ever traded in the indexed range, most
|
||||
* recently traded first.
|
||||
*/
|
||||
counters: Array<CounterPrice>,
|
||||
/**
|
||||
* Supply and listing, when they have been read.
|
||||
*/
|
||||
listing: IntentsListing | null,
|
||||
/**
|
||||
* What the indexer reads, in words — and so what it cannot see.
|
||||
*/
|
||||
reads: string,
|
||||
/**
|
||||
* Lowest NEAR height read.
|
||||
*/
|
||||
indexed_from: number,
|
||||
/**
|
||||
* Highest NEAR height read.
|
||||
*/
|
||||
indexed_to: number, };
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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";
|
||||
|
||||
/**
|
||||
* One settled trade of the asset against one counter token.
|
||||
*/
|
||||
export type IntentsSwap = {
|
||||
/**
|
||||
* NEAR block it settled in.
|
||||
*/
|
||||
near_height: number,
|
||||
/**
|
||||
* Position among the trades in that block. With the height, the cursor.
|
||||
*/
|
||||
trade_index: number,
|
||||
/**
|
||||
* That block's own timestamp.
|
||||
*/
|
||||
at: string,
|
||||
/**
|
||||
* The `execute_intents` transaction.
|
||||
*/
|
||||
tx_hash: string,
|
||||
/**
|
||||
* The receipt whose outcome logged it.
|
||||
*/
|
||||
receipt_id: string,
|
||||
/**
|
||||
* The other token, as a multi-token id (`nep141:…`).
|
||||
*/
|
||||
counter_token: string,
|
||||
/**
|
||||
* That token's own `ft_metadata.symbol`. A label it chose for itself —
|
||||
* never an identity, because anyone can deploy a token called USDC.
|
||||
*/
|
||||
counter_symbol: string | null,
|
||||
/**
|
||||
* The asset that changed hands, in base units.
|
||||
*/
|
||||
asset_amount: BigUintDec,
|
||||
/**
|
||||
* The counter token that changed hands, in base units.
|
||||
*/
|
||||
counter_amount: BigUintDec,
|
||||
/**
|
||||
* Counter tokens per one whole unit of the asset. Absent when either
|
||||
* token's decimals are unknown.
|
||||
*/
|
||||
price: number | null,
|
||||
/**
|
||||
* `buy` or `sell`, from the taker's side. **Inferred** from the one leg
|
||||
* that carried a `referral`; absent when that could not be told.
|
||||
*/
|
||||
side: string | null,
|
||||
/**
|
||||
* The account inferred to be the taker.
|
||||
*/
|
||||
taker: string | null,
|
||||
/**
|
||||
* The front end the taker came through, as it named itself.
|
||||
*/
|
||||
referral: string | null,
|
||||
/**
|
||||
* Every account with a leg in the trade — solvers by their named
|
||||
* accounts, nothing more is claimed about who they are.
|
||||
*/
|
||||
accounts: Array<string>,
|
||||
/**
|
||||
* Every intent in the trade.
|
||||
*/
|
||||
intent_hashes: Array<string>, };
|
||||
@@ -0,0 +1,34 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ChainId } from "./ChainId";
|
||||
import type { IntentsSwap } from "./IntentsSwap";
|
||||
|
||||
/**
|
||||
* A page of swaps, oldest first.
|
||||
*/
|
||||
export type IntentsSwaps = {
|
||||
/**
|
||||
* Which chain's token.
|
||||
*/
|
||||
chain: ChainId,
|
||||
/**
|
||||
* The tracked asset, as a multi-token id.
|
||||
*/
|
||||
asset: string,
|
||||
/**
|
||||
* The swaps.
|
||||
*/
|
||||
swaps: Array<IntentsSwap>,
|
||||
/**
|
||||
* Cursor for the next page, `near_height:trade_index`, when this one was
|
||||
* full. Absent when there is nothing more *in the indexed range*.
|
||||
*/
|
||||
next: string | null,
|
||||
/**
|
||||
* Lowest NEAR height read. A swap below it is missing from this answer,
|
||||
* not from the chain.
|
||||
*/
|
||||
indexed_from: number,
|
||||
/**
|
||||
* Highest NEAR height read.
|
||||
*/
|
||||
indexed_to: number, };
|
||||
Reference in New Issue
Block a user