[Internal] Infrastructure for Polygon tokenlist (#14136)

* [Internal] Infrastructure for Polygon tokenlist

* Lint fix

* Dynamic date parameter

* More pairs
This commit is contained in:
Adam R 2021-10-06 12:25:07 +02:00 committed by GitHub
parent 4c9ed3dbee
commit f89a7f6be4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 347 additions and 0 deletions

View File

@ -0,0 +1,170 @@
{
"name": "Trust Wallet: Polygon",
"logoURI": "https://trustwallet.com/assets/images/favicon.png",
"timestamp": "2021-10-06T10:22:28.269Z",
"tokens": [
{
"asset": "c966_t0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
"type": "POLYGON",
"address": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
"name": "Wrapped Ether",
"symbol": "WETH",
"decimals": 0,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619/logo.png",
"pairs": [
{
"base": "c966_t0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"
},
{
"base": "c966_t0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
},
{
"base": "c966_t0x831753DD7087CaC61aB5644b308642cc1c33Dc13"
},
{
"base": "c966_t0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063"
},
{
"base": "c966_t0xc2132D05D31c914a87C6611C10748AEb04B58e8F"
},
{
"base": "c966_t0xD6DF932A45C0f255f85145f286eA0b292B21C90B"
}
]
},
{
"asset": "c966_t0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
"type": "POLYGON",
"address": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
"name": "Wrapped Matic",
"symbol": "WMATIC",
"decimals": 18,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270/logo.png",
"pairs": [
{
"base": "c966_t0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
},
{
"base": "c966_t0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"
},
{
"base": "c966_t0x831753DD7087CaC61aB5644b308642cc1c33Dc13"
},
{
"base": "c966_t0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063"
},
{
"base": "c966_t0xc2132D05D31c914a87C6611C10748AEb04B58e8F"
}
]
},
{
"asset": "c966_t0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"type": "POLYGON",
"address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"name": "USD Coin (PoS)",
"symbol": "USDC",
"decimals": 0,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174/logo.png",
"pairs": [
{
"base": "c966_t0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"
},
{
"base": "c966_t0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"
},
{
"base": "c966_t0x831753DD7087CaC61aB5644b308642cc1c33Dc13"
},
{
"base": "c966_t0xa3Fa99A148fA48D14Ed51d610c367C61876997F1"
},
{
"base": "c966_t0xc2132D05D31c914a87C6611C10748AEb04B58e8F"
}
]
},
{
"asset": "c966_t0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
"type": "POLYGON",
"address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
"name": "(PoS) Tether USD",
"symbol": "USDT",
"decimals": 0,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0xc2132D05D31c914a87C6611C10748AEb04B58e8F/logo.png",
"pairs": [
{
"base": "c966_t0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"
},
{
"base": "c966_t0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
},
{
"base": "c966_t0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"
}
]
},
{
"asset": "c966_t0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
"type": "POLYGON",
"address": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
"name": "(PoS) Dai Stablecoin",
"symbol": "DAI",
"decimals": 0,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063/logo.png",
"pairs": [
{
"base": "c966_t0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"
},
{
"base": "c966_t0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"
}
]
},
{
"asset": "c966_t0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39",
"type": "POLYGON",
"address": "0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39",
"name": "ChainLink Token",
"symbol": "LINK",
"decimals": 0,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39/logo.png",
"pairs": []
},
{
"asset": "c966_t0x831753DD7087CaC61aB5644b308642cc1c33Dc13",
"type": "POLYGON",
"address": "0x831753DD7087CaC61aB5644b308642cc1c33Dc13",
"name": "QuickSwap",
"symbol": "QUICK",
"decimals": 0,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0x831753DD7087CaC61aB5644b308642cc1c33Dc13/logo.png",
"pairs": []
},
{
"asset": "c966_t0xa3Fa99A148fA48D14Ed51d610c367C61876997F1",
"type": "POLYGON",
"address": "0xa3Fa99A148fA48D14Ed51d610c367C61876997F1",
"name": "miMATIC",
"symbol": "miMATIC",
"decimals": 18,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0xa3Fa99A148fA48D14Ed51d610c367C61876997F1/logo.png",
"pairs": []
},
{
"asset": "c966_t0xD6DF932A45C0f255f85145f286eA0b292B21C90B",
"type": "POLYGON",
"address": "0xD6DF932A45C0f255f85145f286eA0b292B21C90B",
"name": "Aave (PoS)",
"symbol": "AAVE",
"decimals": 0,
"logoURI": "https://assets.trustwalletapp.com/blockchains/polygon/assets/0xD6DF932A45C0f255f85145f286eA0b292B21C90B/logo.png",
"pairs": []
}
],
"version": {
"major": 3,
"minor": 0,
"patch": 0
}
}

View File

@ -0,0 +1,122 @@
import { ActionInterface, CheckStepInterface } from "../generic/interface";
import {
checkTradingPair,
getTradingPairsBitquery,
PairInfoBitquery,
PairInfo,
primaryTokenIndex,
TokenInfo,
TokenInfoBitquery
} from "../generic/subgraph";
import { Polygon } from "../generic/blockchains";
import {
parseForceList,
rebuildTokenlist,
TokenItem
} from "../generic/tokenlists";
import { toChecksum } from "../generic/eth-address";
import { assetID, logoURI } from "../generic/asset";
import * as config from "../config"
const PrimaryTokens: string[] = ["WMATIC", "MATIC", "WETH", "USDC", "USDT", "DAI"];
function convertTokenInfo(token: TokenInfoBitquery): TokenInfo {
return {
id: token.address,
symbol: token.symbol,
name: token.name,
decimals: token.decimals
} as TokenInfo;
}
function convertPairInfo(pair: PairInfoBitquery): PairInfo {
return {
id: '?',
reserveUSD: 1,
volumeUSD: pair.tradeAmount,
txCount: pair.trade,
token0: convertTokenInfo(pair.buyCurrency),
token1: convertTokenInfo(pair.sellCurrency)
} as PairInfo;
}
// Return the date 1,5 days ago in the form 2021-10-06
function dateOfYesterday() {
const now = new Date();
const yesterday = new Date(now.getTime() - 36*3600*1000);
return yesterday.toISOString().substr(0, 10);
}
async function retrievePolygonSwapPairs(): Promise<PairInfo[]> {
console.log(`Retrieving pairs from Polygon, limit volume ${config.PolygonSwap_MinVol24} txcount ${config.PolygonSwap_MinTxCount24}`);
console.log(` forceIncludeList: ${config.PolygonSwap_ForceInclude}`);
const includeList = parseForceList(config.PolygonSwap_ForceInclude);
const query = config.PolygonSwap_TradingPairsQuery;
const date = dateOfYesterday();
const queryReplaced = query.replace("$DATE$", date);
console.log(queryReplaced);
const pairs = await getTradingPairsBitquery(config.PolygonSwap_TradingPairsUrl, queryReplaced);
const filtered: PairInfo[] = [];
pairs.forEach(x => {
try {
if (typeof(x) === "object") {
const pairInfo = convertPairInfo(x as PairInfoBitquery);
if (pairInfo) {
if (checkTradingPair(pairInfo, 0, config.PolygonSwap_MinVol24, config.PolygonSwap_MinTxCount24, PrimaryTokens, includeList)) {
filtered.push(pairInfo);
}
}
}
} catch (err) {
console.log("Exception:", err);
}
});
console.log("Retrieved & filtered", filtered.length, "pairs:");
filtered.forEach(p => {
console.log(`pair: ${p.token0.symbol} -- ${p.token1.symbol} \t USD ${Math.round(p.reserveUSD)} ${Math.round(p.volumeUSD)} ${p.txCount}`);
});
return filtered;
}
function tokenInfoFromSubgraphToken(token: TokenInfo): TokenItem {
const idChecksum = toChecksum(token.id);
return new TokenItem(
assetID(966, idChecksum),
"POLYGON",
idChecksum, token.name, token.symbol, parseInt(token.decimals.toString()),
logoURI(idChecksum, "polygon", "--"),
[]);
}
// Retrieve trading pairs from Polygon
async function generateTokenlist(): Promise<void> {
// note: if [] is returned here for some reason, all pairs will be *removed*. In case of error (e.g. timeout) it should throw
const tradingPairs = await retrievePolygonSwapPairs();
// convert
const pairs2: [TokenItem, TokenItem][] = [];
tradingPairs.forEach(p => {
let tokenItem0 = tokenInfoFromSubgraphToken(p.token0);
let tokenItem1 = tokenInfoFromSubgraphToken(p.token1);
if (primaryTokenIndex(p, PrimaryTokens) == 2) {
// reverse
const tmp = tokenItem1; tokenItem1 = tokenItem0; tokenItem0 = tmp;
}
pairs2.push([tokenItem0, tokenItem1]);
});
await rebuildTokenlist(Polygon, pairs2, "Polygon", config.PolygonSwap_ForceExclude);
}
export class PolygonAction implements ActionInterface {
getName(): string { return "Polygon"; }
getSanityChecks(): CheckStepInterface[] { return []; }
async updateManual(): Promise<void> {
await generateTokenlist();
}
}

View File

@ -50,3 +50,22 @@ export const Uniswap_MinLiquidity = 2000000;
export const Uniswap_MinVol24 = 1000000;
export const Uniswap_MinTxCount24 = 480;
// Force include & exclude config: list of token symbols, or symbol pairs (e.g. ["Cake", "DAI-WBNB"]).
export const PolygonSwap_ForceInclude: string[] = [];
export const PolygonSwap_ForceExclude: string[] = [];
export const PolygonSwap_TradingPairsUrl = "https://graphql.bitquery.io";
export const PolygonSwap_TradingPairsQuery = `
{
ethereum(network: matic) {
dexTrades(date: {is: "$DATE$"}) {
sellCurrency {address symbol name decimals}
buyCurrency {address symbol name decimals}
trade: count
tradeAmount(in: USD)
}
}
}
`;
//export const PolygonSwap_MinLiquidity = 1000000;
export const PolygonSwap_MinVol24 = 500000;
export const PolygonSwap_MinTxCount24 = 288;

View File

@ -19,6 +19,20 @@ export interface PairInfo {
token1: TokenInfo;
}
export interface TokenInfoBitquery {
address: string;
symbol: string;
name: string;
decimals: number;
}
export interface PairInfoBitquery {
sellCurrency: TokenInfoBitquery;
buyCurrency: TokenInfoBitquery;
trade: number; // trade count
tradeAmount: number; // trade volume usd
}
export async function getTradingPairs(apiUrl: string, subgraphQuery: string): Promise<unknown[]> {
// compact the query string
const compactQuery = subgraphQuery.replace(/(?:\r\n|\r|\n)/g, ' ').replace(/\s[\s]+/g, ' ');
@ -39,6 +53,26 @@ export async function getTradingPairs(apiUrl: string, subgraphQuery: string): Pr
}
}
export async function getTradingPairsBitquery(apiUrl: string, subgraphQuery: string): Promise<unknown[]> {
// compact the query string
const compactQuery = subgraphQuery.replace(/(?:\r\n|\r|\n)/g, ' ').replace(/\s[\s]+/g, ' ');
const postData = {"query": compactQuery, "variables":{}};
console.log(`Retrieving trading pair infos from: ${apiUrl}`);
try {
const result = await axios.post(apiUrl, postData).then(r => r.data);
if (!result || !result.data || !result.data.ethereum || !result.data.ethereum.dexTrades) {
throw `Unexpected result: ${JSON.stringify(result)}`;
}
const pairs = result.data.ethereum.dexTrades;
console.log(`Retrieved ${pairs.length} trading pair infos`);
return pairs;
} catch (err) {
console.log("Exception from graph api:", err, apiUrl, JSON.stringify(postData));
throw err;
}
}
function isTokenPrimary(token: TokenInfo, primaryTokens: string[]): boolean {
return (primaryTokens.find(t => (t === token.symbol.toUpperCase())) != undefined);
}

View File

@ -13,6 +13,7 @@ import { TezosAction } from "../blockchain/tezos";
import { TronAction } from "../blockchain/tron";
import { Validators } from "../generic/validators";
import { WavesAction } from "../blockchain/waves";
import { PolygonAction } from "../blockchain/polygon";
import { ActionInterface, CheckStepInterface } from "../generic/interface";
import * as chalk from 'chalk';
import * as bluebird from "bluebird";
@ -30,6 +31,7 @@ const actionList: ActionInterface[] = [
new EthereumAction(),
new CosmosAction(),
new KavaAction(),
new PolygonAction(),
new TerraAction(),
new TezosAction(),
new TronAction(),