diff --git a/src/dexorder/bin/main.py b/src/dexorder/bin/main.py index c95a402..1933516 100644 --- a/src/dexorder/bin/main.py +++ b/src/dexorder/bin/main.py @@ -15,6 +15,7 @@ from dexorder.contract.dexorder import get_dexorder_contract from dexorder.event_handler import (init, dump_log, handle_vault_created, handle_order_placed, handle_transfer, handle_swap_filled, handle_order_canceled, handle_order_cancel_all, handle_uniswap_swaps, handle_vault_impl_changed, update_metrics) +from dexorder.marks import publish_marks from dexorder.memcache import memcache from dexorder.memcache.memcache_state import RedisState, publish_all from dexorder.order.executionhandler import handle_dexorderexecutions, execute_tranches @@ -83,6 +84,7 @@ def setup_logevent_triggers(runner): # runner.add_callback(adjust_gas) runner.add_callback(cleanup_jobs) + runner.add_callback(publish_marks) runner.add_callback(update_metrics) diff --git a/src/dexorder/configuration/schema.py b/src/dexorder/configuration/schema.py index 609ac19..b40d4cf 100644 --- a/src/dexorder/configuration/schema.py +++ b/src/dexorder/configuration/schema.py @@ -42,6 +42,8 @@ class Config: fee_leeway = 0.1 # do not adjust fees if they are within this proportion min_gas: str = '0' + mark_publish_seconds: float = 60 # publish mark prices every this number of seconds + # Order slashing slash_kill_count: int = 5 slash_delay_base: float = 60 # one minute diff --git a/src/dexorder/marks.py b/src/dexorder/marks.py new file mode 100644 index 0000000..5130dd7 --- /dev/null +++ b/src/dexorder/marks.py @@ -0,0 +1,44 @@ +""" +"marks" are mark-to-market USD values of a selected set of tokens called quote tokens. Publishing a set of USD marks +for the quote tokens allows almost any token to be marked to USD via one hop. +""" + +import logging +import time + +from dexorder import dec, NATIVE_TOKEN, config +from dexorder.base.chain import current_chain +from dexorder.blockstate import BlockDict +from dexorder.pools import quotes, mark_to_market + +log = logging.getLogger(__name__) + +def pub_marks(_s,k,v): + chain_id = current_chain.get().id + return str(chain_id), 'marks.usd', (chain_id, k, str(v)) + + +marks: BlockDict[str, dec] = BlockDict('mark.usd', db=False, redis=True, pub=pub_marks, value2str=str) + +class RateLimiter: + def __init__(self, rate: float): + self.rate = rate + self.last_update = 0.0 + + def ready(self): + now = time.monotonic() + if now - self.last_update < self.rate: + return False + self.last_update = now + return True + +mark_publish_rate = RateLimiter(config.mark_publish_seconds) + +def publish_marks(): + if mark_publish_rate.ready(): + for token_addr in [NATIVE_TOKEN]+quotes: + # overwrite=False checks the previous value and does not generate a diff if the values match. This prevents + # excessive updates to Redis + value = mark_to_market(token_addr) + if value is not None: + marks.setitem(token_addr, value, overwrite=False) diff --git a/src/dexorder/pools.py b/src/dexorder/pools.py index ba6a7e8..719ffea 100644 --- a/src/dexorder/pools.py +++ b/src/dexorder/pools.py @@ -148,7 +148,7 @@ class MarkPool: mark_pools: dict[str, MarkPool] = {} -quotes = [] # ordered list of preferred quote tokens +quotes = [] # ordered list of preferred quote token addresses def add_mark_pool(addr: str, base: str, quote: str, fee: int): @@ -200,7 +200,7 @@ async def mark_to_market_adj_dec(token: str, amount: dec, adjust_decimals=True) return mark_to_market(token, amount) -def mark_to_market(token: str, amount: dec) -> Optional[dec]: +def mark_to_market(token: str, amount: dec = dec(1)) -> Optional[dec]: """ amount must already be adjusted for decimals """