diff --git a/alembic/versions/db62e7db828d_initial_schema.py b/alembic/versions/db62e7db828d_initial_schema.py index ef5121a..5c26284 100644 --- a/alembic/versions/db62e7db828d_initial_schema.py +++ b/alembic/versions/db62e7db828d_initial_schema.py @@ -77,6 +77,7 @@ def upgrade() -> None: op.create_table('token', sa.Column('chain', dexorder.database.column_types.Blockchain(), nullable=False), sa.Column('address', dexorder.database.column_types.Address(), nullable=False), + sa.Column('name', sa.String(), nullable=False), sa.Column('symbol', sa.String(), nullable=False), sa.Column('decimals', sa.SMALLINT(), nullable=False), sa.PrimaryKeyConstraint('chain', 'address') diff --git a/src/dexorder/bin/metadata.py b/src/dexorder/bin/metadata.py new file mode 100644 index 0000000..0bdebc8 --- /dev/null +++ b/src/dexorder/bin/metadata.py @@ -0,0 +1,75 @@ +import json +import logging +import sys + +from sqlalchemy import select + +from dexorder import db +from dexorder.configuration import parse_args +from dexorder.database.model import Pool, Token + +log = logging.getLogger(__name__) + + +token_map: dict[str,Token] = {} + + +def dump(*args): + print(*args, end='') + + +def json_dump(**kwargs): + dump(json.dumps(dict(**kwargs),separators=(',', ':'))) + +def dump_tokens(): + first = True + for token in db.session.scalars(select(Token)): + token: Token + token_map[token.address] = token + if first: + first = False + else: + dump(',') + json_dump( + a=token.address, + n=token.name, + s=token.symbol, + d=token.decimals, + ) + + +def dump_pools(): + first = True + for pool in db.session.scalars(select(Pool)): + pool: Pool + if first: + first = False + else: + dump(',') + json_dump( + a=pool.address, + b=pool.base, + q=pool.quote, + f=pool.fee, + e=pool.exchange.value, + d=pool.decimals, + ) + +def generate_metadata(): + dump('{"t":[') + dump_tokens() + dump('],"p":[') + dump_pools() + dump(']}') + + +def main(): + logging.basicConfig(level=logging.INFO, stream=sys.stderr) + log.setLevel(logging.DEBUG) + parse_args() + db.connect(migrate=False) + generate_metadata() + + +if __name__ == '__main__': + main() diff --git a/src/dexorder/configuration/schema.py b/src/dexorder/configuration/schema.py index 9581877..f845c61 100644 --- a/src/dexorder/configuration/schema.py +++ b/src/dexorder/configuration/schema.py @@ -26,3 +26,4 @@ class Config: deployments: Optional[dict[str,str]] = field(default_factory=dict) min_gas: str = '0' + tokens_dir: str = '.' diff --git a/src/dexorder/database/model/token.py b/src/dexorder/database/model/token.py index 88d564a..8c1ac2d 100644 --- a/src/dexorder/database/model/token.py +++ b/src/dexorder/database/model/token.py @@ -14,6 +14,7 @@ class TokenDict (TypedDict): type: str chain: int address: str + name: str symbol: str decimals: int @@ -25,6 +26,7 @@ class Token (Base): chain: Mapped[Blockchain] = mapped_column(primary_key=True) address: Mapped[Address] = mapped_column(primary_key=True) + name: Mapped[str] symbol: Mapped[str] decimals: Mapped[Uint8] @@ -32,10 +34,10 @@ class Token (Base): @staticmethod def load(token_dict: TokenDict) -> 'Token': return Token(chain=Blockchain.get(token_dict['chain']), address=token_dict['address'], - symbol=token_dict['symbol'], decimals=token_dict['decimals']) + name=token_dict['name'], symbol=token_dict['symbol'], decimals=token_dict['decimals']) def dump(self): return TokenDict(type='Token', chain=self.chain.chain_id, address=self.address, - symbol=self.symbol, decimals=self.decimals) + name=self.name, symbol=self.symbol, decimals=self.decimals) diff --git a/src/dexorder/tokens.py b/src/dexorder/tokens.py index e29681c..a743b29 100644 --- a/src/dexorder/tokens.py +++ b/src/dexorder/tokens.py @@ -1,3 +1,4 @@ +import asyncio import logging from eth_abi.exceptions import InsufficientDataBytes @@ -11,7 +12,7 @@ from dexorder.database.model.token import TokenDict log = logging.getLogger(__name__) -async def get_token(address): +async def get_token(address) -> TokenDict: try: return address_metadata[address] except KeyError: @@ -21,13 +22,13 @@ async def get_token(address): async def load_token(address: str) -> TokenDict: contract = ERC20(address) - symbolProm = contract.symbol() + prom = asyncio.gather(contract.name(), contract.symbol()) try: decimals = await contract.decimals() except (InsufficientDataBytes, ContractLogicError, BadFunctionCallOutput): log.warning(f'token {address} has no decimals()') decimals = 0 - symbol = await symbolProm - log.debug(f'new token {symbol} {address}') + name, symbol = await prom + log.debug(f'new token {name} {symbol} {address}') return TokenDict(type='Token', chain=current_chain.get().chain_id, address=address, - symbol=symbol, decimals=decimals) + name=name, symbol=symbol, decimals=decimals)