109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
import datetime
|
|
from decimal import Decimal, localcontext, Context, ROUND_FLOOR, InvalidOperation
|
|
from enum import Enum, IntEnum, auto
|
|
from fractions import Fraction
|
|
from logging import getLogger
|
|
from typing import Union
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
Address = str
|
|
|
|
log = getLogger(__name__)
|
|
|
|
|
|
class Blockchain(Enum):
|
|
ethereum = "ethereum"
|
|
arbitrum = "arbitrum"
|
|
polygon = "polygon"
|
|
zksync = "zksync"
|
|
|
|
|
|
class EVMBlock(BaseModel):
|
|
id: int
|
|
ts: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
|
|
hash_: str
|
|
|
|
|
|
class EthereumToken(BaseModel):
|
|
symbol: str
|
|
address: str
|
|
decimals: int
|
|
gas: Union[int, list[int]] = 29000
|
|
|
|
def to_onchain_amount(self, amount: Union[float, Decimal, str]) -> int:
|
|
"""Converts floating-point numerals to an integer, by shifting right by the
|
|
token's maximum amount of decimals (e.g.: 1.000000 becomes 1000000).
|
|
For the reverse operation please see self.from_onchain_amount
|
|
"""
|
|
if not isinstance(amount, Decimal):
|
|
log.warning(f"Expected variable of type Decimal. Got {type(amount)}.")
|
|
|
|
with localcontext(Context(rounding=ROUND_FLOOR, prec=256)):
|
|
amount = Decimal(str(amount)) * (10 ** self.decimals)
|
|
try:
|
|
amount = amount.quantize(Decimal("1.0"))
|
|
except InvalidOperation:
|
|
log.error(
|
|
f"Quantize failed for {self.symbol}, {amount}, {self.decimals}"
|
|
)
|
|
return int(amount)
|
|
|
|
def from_onchain_amount(
|
|
self, onchain_amount: Union[int, Fraction], quantize: bool = True
|
|
) -> Decimal:
|
|
"""Converts an Integer to a quantized decimal, by shifting left by the token's
|
|
maximum amount of decimals (e.g.: 1000000 becomes 1.000000 for a 6-decimal token
|
|
For the reverse operation please see self.to_onchain_amount
|
|
|
|
If the onchain_amount is too low, then using quantize can underflow without
|
|
raising and the offchain amount returned is 0.
|
|
See _decimal.Decimal.quantize docstrings for details.
|
|
|
|
Quantize is needed for UniswapV2.
|
|
"""
|
|
with localcontext(self._dec_context):
|
|
if isinstance(onchain_amount, Fraction):
|
|
return (
|
|
Decimal(onchain_amount.numerator)
|
|
/ Decimal(onchain_amount.denominator)
|
|
/ Decimal(10 ** self.decimals)
|
|
).quantize(Decimal(f"{1 / 10 ** self.decimals}"))
|
|
if quantize is True:
|
|
try:
|
|
amount = (
|
|
Decimal(str(onchain_amount)) / 10 ** self.decimals
|
|
).quantize(Decimal(f"{1 / 10 ** self.decimals}"))
|
|
except InvalidOperation:
|
|
amount = Decimal(str(onchain_amount)) / Decimal(10 ** self.decimals)
|
|
else:
|
|
amount = Decimal(str(onchain_amount)) / Decimal(10 ** self.decimals)
|
|
return amount
|
|
|
|
|
|
class DatabaseType(Enum):
|
|
# Make call to the node each time it needs a storage (unless cached from a previous call).
|
|
rpc_reader = "rpc_reader"
|
|
# Connect to Tycho and cache the whole state of a target contract, the state is continuously updated by Tycho.
|
|
# To use this we need Tycho to be configured to index the target contract state.
|
|
tycho = "tycho"
|
|
|
|
|
|
class Capability(IntEnum):
|
|
SellSide = auto()
|
|
BuySide = auto()
|
|
PriceFunction = auto()
|
|
FeeOnTransfer = auto()
|
|
ConstantPrice = auto()
|
|
TokenBalanceIndependent = auto()
|
|
ScaledPrice = auto()
|
|
|
|
|
|
class SynchronizerState(Enum):
|
|
started = "started"
|
|
ready = "ready"
|
|
stale = "stale"
|
|
delayed = "delayed"
|
|
advanced = "advanced"
|
|
ended = "ended"
|