Load tokens from Tycho RPC

This commit is contained in:
Thales Lima
2024-07-11 19:14:32 +02:00
committed by tvinagre
parent 6b98cee57c
commit 27c5a7580b
4 changed files with 93 additions and 3 deletions

View File

@@ -0,0 +1,8 @@
class TychoDecodeError(Exception):
def __init__(self, msg: str, pool_id: str):
super().__init__(msg)
self.pool_id = pool_id
class APIRequestError(Exception):
pass

View File

@@ -1,5 +1,7 @@
import datetime import datetime
from enum import Enum from enum import Enum
from typing import Union
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@@ -18,3 +20,10 @@ class EVMBlock(BaseModel):
class ThirdPartyPool: class ThirdPartyPool:
pass pass
class EthereumToken(BaseModel):
symbol: str
address: str
decimals: int
gas: Union[int, list[int]] = 29000

View File

@@ -1,13 +1,16 @@
import asyncio import asyncio
import json import json
import platform import platform
import requests
import time import time
from asyncio.subprocess import STDOUT, PIPE from asyncio.subprocess import STDOUT, PIPE
from collections import defaultdict from collections import defaultdict
from datetime import datetime from datetime import datetime
from decimal import Decimal from decimal import Decimal
from http.client import HTTPException
from logging import getLogger from logging import getLogger
from typing import Tuple, Any, Optional from typing import Tuple, Any, Optional, Dict
from eth_utils import to_checksum_address from eth_utils import to_checksum_address
from protosim_py import ( from protosim_py import (
@@ -25,7 +28,8 @@ from tycho.tycho.constants import (
MAX_BALANCE, MAX_BALANCE,
) )
from tycho.tycho.decoders import ThirdPartyPoolTychoDecoder from tycho.tycho.decoders import ThirdPartyPoolTychoDecoder
from tycho.tycho.models import Blockchain, EVMBlock, ThirdPartyPool from tycho.tycho.exceptions import APIRequestError
from tycho.tycho.models import Blockchain, EVMBlock, ThirdPartyPool, EthereumToken
log = getLogger(__name__) log = getLogger(__name__)
@@ -34,6 +38,65 @@ class TychoClientException(Exception):
pass pass
class TokenLoader:
def __init__(
self,
tycho_url: str,
blockchain: Blockchain,
min_token_quality: Optional[int] = 51,
):
self.tycho_url = tycho_url
self.blockchain = blockchain
self.min_token_quality = min_token_quality
self.endpoint = "/v1/{}/tokens"
self._token_limit = 10000
def get_tokens(self) -> dict[str, EthereumToken]:
"""Loads all tokens from Tycho RPC"""
url = self.tycho_url + self.endpoint.format(self.blockchain.value)
page = 0
start = time.monotonic()
all_tokens = []
while data := self._get_all_with_pagination(
url=url,
page=page,
limit=self._token_limit,
params={"min_quality": self.min_token_quality},
):
all_tokens.extend(data)
page += 1
if len(data) < self._token_limit:
break
log.info(f"Loaded {len(all_tokens)} tokens in {time.monotonic() - start:.2f}s")
formatted_tokens = dict()
for token in all_tokens:
token["address"] = to_checksum_address(token["address"])
formatted = EthereumToken(**token)
formatted_tokens[formatted.address] = formatted
return formatted_tokens
@staticmethod
def _get_all_with_pagination(
url: str, params: Optional[Dict] = None, page: int = 0, limit: int = 50
) -> Dict:
if params is None:
params = {}
params["pagination"] = {"page": page, "page_size": limit}
r = requests.post(url, json=params)
try:
r.raise_for_status()
except HTTPException as e:
log.error(f"Request status {r.status_code} with content {r.json()}")
raise APIRequestError("Failed to load token configurations")
return r.json()["tokens"]
class TychoPoolStateStreamAdapter: class TychoPoolStateStreamAdapter:
def __init__( def __init__(
self, self,
@@ -56,7 +119,7 @@ class TychoPoolStateStreamAdapter:
self.tycho_url = tycho_url self.tycho_url = tycho_url
self.min_tvl = min_tvl self.min_tvl = min_tvl
self.tycho_client = None self.tycho_client = None
self.protocol = "vm:protocol" self.protocol = f"vm:{protocol}"
self._include_state = include_state self._include_state = include_state
self._blockchain = blockchain self._blockchain = blockchain
@@ -70,6 +133,13 @@ class TychoPoolStateStreamAdapter:
permanent_storage=None, permanent_storage=None,
) )
# Loads tokens from Tycho
self._tokens: dict[str, EthereumToken] = TokenLoader(
tycho_url=self.tycho_url,
blockchain=self._blockchain,
min_token_quality=self.min_token_quality,
).get_tokens()
# TODO: Check if it's necessary # TODO: Check if it's necessary
self.ignored_pools = [] self.ignored_pools = []
self.vm_contracts = defaultdict(list) self.vm_contracts = defaultdict(list)

3
tycho/tycho/utils.py Normal file
View File

@@ -0,0 +1,3 @@
def decode_tycho_exchange(exchange: str) -> (str, bool):
# removes vm prefix if present, returns True if vm prefix was present (vm protocol) or False if native protocol
return (exchange.split(":")[1], False) if "vm:" in exchange else (exchange, True)