trigger fixes

This commit is contained in:
tim
2025-03-10 21:09:40 -04:00
parent be8c8bf019
commit f3bdfdf97b
4 changed files with 33 additions and 13 deletions

View File

@@ -22,6 +22,11 @@ from dexorder.util import hexbytes
log = logging.getLogger(__name__)
def blocktime():
""" timestamp of the most recent block seen in real-time, NOT the current block being worked on """
return latest_block[current_chain.get().id].timestamp
async def get_block_timestamp(block_id: Union[bytes,int]) -> int:
block = await get_block(block_id)
if block is None:

View File

@@ -48,6 +48,9 @@ class Config:
slash_delay_mul: float = 2 # double the delay each time
slash_delay_max: int = 15 * 60
# Tranches are paused for this long after they trigger a slippage control
slippage_control_delay: float = 10 # matches the 10-second TWAP used by our uniswap router
walker_name: str = 'default'
walker_flush_interval: float = 300
walker_stop: Optional[int] = None # block number of the last block the walker should process

View File

@@ -137,7 +137,7 @@ async def handle_transfer(transfer: EventData):
vault = None
if vault is not None:
await adjust_balance(vault, token_address, amount)
await update_balance_triggers(vault, token_address, amount)
await update_balance_triggers(vault, token_address)
# This wuold double-count fill fees. Instead, we book the transfer when sending money to the account as part of a refill.
# if is_tracked_address(to_address):
# # noinspection PyTypeChecker

View File

@@ -2,8 +2,9 @@ import asyncio
import logging
from abc import abstractmethod
from collections import defaultdict
from datetime import timedelta
from enum import Enum, auto
from typing import Optional, Sequence
from typing import Optional, Sequence, Union
import numpy as np
from sortedcontainers import SortedList
@@ -99,7 +100,8 @@ def start_trigger_updates():
PriceLineTrigger.clear_data()
async def update_balance_triggers(vault: str, token: str, balance: int):
async def update_balance_triggers(vault: str, token: str):
balance = vault_balances.get(vault, {}).get(token)
updates = [bt.update(balance) for bt in BalanceTrigger.by_vault_token.get((vault, token), [])]
await asyncio.gather(*updates)
@@ -226,20 +228,20 @@ async def has_funds(tk: TrancheKey):
async def input_amount_is_sufficient(order, token_balance):
log.debug(f'input is sufficient? {order.min_fill_amount}')
# log.debug(f'input is sufficient? {order.min_fill_amount}')
if order.amount_is_input:
log.debug(f'amount is input: {token_balance} >= {order.min_fill_amount}')
# log.debug(f'amount is input: {token_balance} >= {order.min_fill_amount}')
return token_balance >= order.min_fill_amount
# amount is an output amount, so we need to know the price
price = pool_prices.get(order.pool_address)
log.debug(f'amount is output amount. price={price}')
# log.debug(f'amount is output amount. price={price}')
if price is None:
return token_balance > 0 # we don't know the price so we allow any nonzero amount to be sufficient
pool = await get_pool(order.pool_address)
price *= dec(10) ** -pool['decimals']
inverted = order.order.tokenIn != pool['base']
minimum = dec(order.min_fill_amount)*price if inverted else dec(order.min_fill_amount)/price
log.debug(f'order minimum amount is {order.min_fill_amount} '+ ("input" if order.amount_is_input else f"output @ {price} = {minimum} ")+f'< {token_balance} balance')
# log.debug(f'order minimum amount is {order.min_fill_amount} '+ ("input" if order.amount_is_input else f"output @ {price} = {minimum} ")+f'< {token_balance} balance')
return token_balance >= minimum
@@ -261,7 +263,7 @@ class BalanceTrigger (Trigger):
async def update(self, balance):
self.value = await input_amount_is_sufficient(self.order, balance)
log.debug(f'update balance {balance} was sufficient? {self.value} {self.order.key}')
# log.debug(f'update balance {balance} was sufficient? {self.value} {self.order.key}')
def remove(self):
try:
@@ -316,8 +318,8 @@ class TimeTrigger (Trigger):
if time == self._time:
return
self._time = time
self.remove()
self.update_active(time_now)
in_future = time_now >= time
self.value = in_future is self.is_start
def update_active(self, time_now: int = None, time: int = None):
if time_now is None:
@@ -599,7 +601,8 @@ class TrancheTrigger:
else:
order_log.debug(f'tranche part-filled {self.tk} in:{_amount_in} out:{_amount_out} remaining:{remaining}')
if self.market_order:
self.expire()
order_log.debug(f'tranche {self.tk} delayed {config.slippage_control_delay} seconds due to slippage control')
self.deactivate(config.slippage_control_delay)
self.slash_count = 0 # reset slash count
def touch(self):
@@ -631,15 +634,24 @@ class TrancheTrigger:
self.kill()
else:
delay = round(config.slash_delay_base * config.slash_delay_mul ** (self.slash_count-1))
self.deactivate(timestamp()+delay)
self.deactivate(delay)
def deactivate(self, until):
def deactivate(self, interval: Union[timedelta, int, float]):
# todo this timestamp should be consistent with the trigger time which is blockchain
now = current_clock.get().timestamp
self.deactivate_until(now + (interval.total_seconds() if isinstance(interval, timedelta) else interval))
def deactivate_until(self, until):
# Temporarily deactivate the tranche due to a rate limit. Use disable() to permanently halt the trigger.
log.debug(f'deactivating tranche {self.tk} until {from_timestamp(until)}')
if self.activation_trigger is None:
self.activation_trigger = TimeTrigger.create(True, self.tk, until)
else:
self.activation_trigger.time = until
try:
del active_tranches[self.tk]
except KeyError:
pass
def disable(self):
# permanently stop this trigger and deconstruct