Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add endpoints for Dexscreener support #422 #446

Merged
merged 8 commits into from
Dec 17, 2024
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
6 changes: 5 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions src/typescript/frontend/src/app/dexscreener/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# DEX Screener Adapter Specs

<!-- markdownlint-disable -->

<b>Taken from https://dexscreener.notion.site/DEX-Screener-Adapter-Specs-cc1223cdf6e74a7799599106b65dcd0e </b>

<!-- markdownlint-enable -->

v1.1 / Dec 2023

The DEX Screener Adapter is a set of HTTP endpoints that allows DEX Screener to
track historical and real-time data for any Partner Decentralized Exchange.
Adapters are responsible for supplying accurate and up-to-date data, whereas DEX
Screener handles all data ingestion, processing and serving.

## Overview

- The DEX Screener Indexer queries Adapter endpoints to continuously index
events as they become available, in chunks of one or many blocks at a time.
Each block is only queried once, so caution must be taken to ensure that all
returned data is accurate at the time of indexing.
- Adapters are to be deployed, served and maintained by the Partner
- If adapter endpoints become unreachable indexing will halt and automatically
resume once they become available again
- The Indexer allows for customizable rate limits and block chunk size to ensure
Adapter endpoints are not overloaded

## Endpoints

- An in-depth explanation of the schemas expected for each endpoint is described
on the `Schemas` section below

- Numbers for amounts and price can be both `number` and `string`. Strings are
more suitable when dealing with extremely small or extremely large numbers
that can't be accurately serialized into JSON numbers.

- Indexing will halt if schemas are invalid or contain unexpected values
(i.e.: `swapEvent.priceNative=0` or `pair.name=""`)
90 changes: 90 additions & 0 deletions src/typescript/frontend/src/app/dexscreener/asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/***
Request: GET /asset?id=:string

Response Schema:
// interface AssetResponse {
// asset: Asset;
// }

Example Response:
// {
// "asset": {
// "id": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
// "name": "Wrapped Ether",
// "symbol": "WETH",
// "totalSupply": 10000000,
// "circulatingSupply": 900000,
// "coinGeckoId": "ether",
// "coinMarketCapId": "ether"
// }
// }
**/

import { type NextRequest, NextResponse } from "next/server";
import { toMarketEmojiData } from "@sdk/emoji_data";
import { EMOJICOIN_SUPPLY } from "@sdk/const";
import { calculateCirculatingSupply } from "@sdk/markets";
import { symbolEmojiStringToArray } from "./util";
import { fetchMarketState } from "@/queries/market";

/**
* - In most cases, asset ids will correspond to contract addresses. Ids are case-sensitive.
* - All `Asset` props aside from `id` may be mutable. The Indexer will periodically query assets for their most
* up-to-date info
* - `totalSupply` is optional but DEX Screener cannot calculate FDV/Market Cap if not available
* - `circulatingSupply` is optional but DEX Screener may not be able to show accurate market cap if not available
* - `coinGeckoId` and `coinMarketCapId` are optional but may be used for displaying additional token information such
* as image, description and self-reported/off-chain circulating supply
* - `metadata` includes any optional auxiliary info not covered in the default schema and not required in most cases
*/
export interface Asset {
id: string;
name: string;
symbol: string;
totalSupply: number | string;
circulatingSupply?: number | string;
coinGeckoId?: string;
coinMarketCapId?: string;
metadata?: Record<string, string>;
}

export interface AssetResponse {
asset: Asset;
}

/**
* Fetches an asset by a string of the emojis that represent the asset
* @param assetId
*/
export async function getAsset(assetId: string): Promise<Asset> {
const marketEmojiData = toMarketEmojiData(assetId);
const symbolEmojis = symbolEmojiStringToArray(assetId);
const marketState = await fetchMarketState({ searchEmojis: symbolEmojis });

const circulatingSupply: { circulatingSupply?: number | string } = {};
if (marketState && marketState.state) {
circulatingSupply.circulatingSupply = calculateCirculatingSupply(marketState.state).toString();
}

return {
id: assetId,
name: marketEmojiData.symbolData.name,
symbol: marketEmojiData.symbolData.symbol,
totalSupply: Number(EMOJICOIN_SUPPLY),
...circulatingSupply,
// coinGeckoId: assetId,
// coinMarketCapId: assetId,
};
}

// NextJS JSON response handler
export async function GET(request: NextRequest): Promise<NextResponse<AssetResponse>> {
const searchParams = request.nextUrl.searchParams;
const assetId = searchParams.get("id");
if (!assetId) {
// This is a required field, and is an error otherwise
return new NextResponse("id is a parameter", { status: 400 });
}
const asset = await getAsset(assetId);
return NextResponse.json({ asset });
}
Loading
Loading