python orderspec refactor
This commit is contained in:
@@ -10,6 +10,7 @@ from typing import Sequence, Union
|
|||||||
from alembic import op
|
from alembic import op
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import dexorder.database
|
import dexorder.database
|
||||||
|
import dexorder.database.column_types
|
||||||
${imports if imports else ""}
|
${imports if imports else ""}
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from typing import Sequence, Union
|
|||||||
from alembic import op
|
from alembic import op
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import dexorder.database
|
import dexorder.database
|
||||||
|
import dexorder.database.column_types
|
||||||
from sqlalchemy.dialects import postgresql
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
@@ -47,14 +48,14 @@ def upgrade() -> None:
|
|||||||
sa.PrimaryKeyConstraint('chain', 'series', 'key')
|
sa.PrimaryKeyConstraint('chain', 'series', 'key')
|
||||||
)
|
)
|
||||||
op.create_table('transactionjob',
|
op.create_table('transactionjob',
|
||||||
sa.Column('id', sa.UUID(), nullable=False),
|
sa.Column('id', sa.UUID(), nullable=False),
|
||||||
sa.Column('chain', dexorder.database.column_types.Blockchain(), nullable=False),
|
sa.Column('chain', dexorder.database.column_types.Blockchain(), nullable=False),
|
||||||
sa.Column('height', sa.Integer(), nullable=False),
|
sa.Column('height', sa.Integer(), nullable=False),
|
||||||
# sa.Column('state', sa.Enum(name='transactionjobstate'), nullable=False),
|
# sa.Column('state', sa.Enum(name='transactionjobstate'), nullable=False),
|
||||||
sa.Column('state', sa.Enum('Requested', 'Signed', 'Sent', 'Mined', name='transactionjobstate'), nullable=False),
|
sa.Column('state', sa.Enum('Requested', 'Signed', 'Sent', 'Mined', name='transactionjobstate'), nullable=False),
|
||||||
sa.Column('request', dexorder.database.column_types._DataclassDict(astext_type=sa.Text()), nullable=False),
|
sa.Column('request', dexorder.database.column_types.DataclassDictBase(astext_type=sa.Text()), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_index(op.f('ix_transactionjob_chain'), 'transactionjob', ['chain'], unique=False)
|
op.create_index(op.f('ix_transactionjob_chain'), 'transactionjob', ['chain'], unique=False)
|
||||||
op.create_index(op.f('ix_transactionjob_height'), 'transactionjob', ['height'], unique=False)
|
op.create_index(op.f('ix_transactionjob_height'), 'transactionjob', ['height'], unique=False)
|
||||||
op.create_index(op.f('ix_transactionjob_state'), 'transactionjob', ['state'], unique=False)
|
op.create_index(op.f('ix_transactionjob_state'), 'transactionjob', ['state'], unique=False)
|
||||||
@@ -73,9 +74,19 @@ def upgrade() -> None:
|
|||||||
sa.Column('state', sa.Enum('Open', 'Canceled', 'Filled', 'Expired', 'Underfunded', name='swaporderstate'), nullable=False),
|
sa.Column('state', sa.Enum('Open', 'Canceled', 'Filled', 'Expired', 'Underfunded', name='swaporderstate'), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('chain', 'vault', 'order_index')
|
sa.PrimaryKeyConstraint('chain', 'vault', 'order_index')
|
||||||
)
|
)
|
||||||
|
op.create_table('pool',
|
||||||
|
sa.Column('chain', dexorder.database.column_types.Blockchain(), nullable=False),
|
||||||
|
sa.Column('address', dexorder.database.column_types.Address(), nullable=False),
|
||||||
|
sa.Column('exchange', sa.Enum('UniswapV2', 'UniswapV3', name='exchange'), nullable=False),
|
||||||
|
sa.Column('base', dexorder.database.column_types.Address(), nullable=False),
|
||||||
|
sa.Column('quote', dexorder.database.column_types.Address(), nullable=False),
|
||||||
|
sa.Column('fee', sa.Integer(), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('chain', 'address')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
def downgrade() -> None:
|
||||||
|
op.drop_table('pool')
|
||||||
op.drop_table('orderindex')
|
op.drop_table('orderindex')
|
||||||
op.drop_table('seriesset')
|
op.drop_table('seriesset')
|
||||||
op.drop_table('seriesdict')
|
op.drop_table('seriesdict')
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ def Fixed(bits, dbits, signed=False):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class _DataclassDict(TypeDecorator):
|
class DataclassDictBase(TypeDecorator):
|
||||||
impl = JSONB
|
impl = JSONB
|
||||||
|
|
||||||
def process_bind_param(self, value, dialect):
|
def process_bind_param(self, value, dialect):
|
||||||
@@ -82,6 +82,6 @@ class _DataclassDict(TypeDecorator):
|
|||||||
return self.Constructor(**value)
|
return self.Constructor(**value)
|
||||||
|
|
||||||
def DataclassDict(constructor):
|
def DataclassDict(constructor):
|
||||||
result = _DataclassDict()
|
result = DataclassDictBase()
|
||||||
result.Constructor = constructor
|
result.Constructor = constructor
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ from .block import Block
|
|||||||
from .series import SeriesSet, SeriesDict
|
from .series import SeriesSet, SeriesDict
|
||||||
from .transaction import Transaction, TransactionJob
|
from .transaction import Transaction, TransactionJob
|
||||||
from .orderindex import OrderIndex
|
from .orderindex import OrderIndex
|
||||||
|
from .pool import Pool
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from dexorder.database.model import Base
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
class PoolModel (Base):
|
class Pool (Base):
|
||||||
__tablename__ = 'pool'
|
__tablename__ = 'pool'
|
||||||
|
|
||||||
chain: Mapped[Blockchain] = mapped_column(primary_key=True)
|
chain: Mapped[Blockchain] = mapped_column(primary_key=True)
|
||||||
@@ -16,4 +16,4 @@ class PoolModel (Base):
|
|||||||
exchange: Mapped[Exchange]
|
exchange: Mapped[Exchange]
|
||||||
base: Mapped[Address]
|
base: Mapped[Address]
|
||||||
quote: Mapped[Address]
|
quote: Mapped[Address]
|
||||||
fee: int # in millionths aka 100ths of a bip
|
fee: Mapped[int] # in millionths aka 100ths of a bip
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ from dexorder import current_pub, db, dec
|
|||||||
from dexorder.base.chain import current_chain
|
from dexorder.base.chain import current_chain
|
||||||
from dexorder.base.order import TrancheExecutionRequest, TrancheKey, ExecutionRequest, new_tranche_execution_request, OrderKey
|
from dexorder.base.order import TrancheExecutionRequest, TrancheKey, ExecutionRequest, new_tranche_execution_request, OrderKey
|
||||||
from dexorder.transaction import create_transactions, submit_transaction_request, handle_transaction_receipts, send_transactions
|
from dexorder.transaction import create_transactions, submit_transaction_request, handle_transaction_receipts, send_transactions
|
||||||
from dexorder.uniswap import uniswap_price
|
from dexorder.pools import uniswap_price
|
||||||
from dexorder.contract.dexorder import get_factory_contract, vault_address, VaultContract, get_dexorder_contract
|
from dexorder.contract.dexorder import get_factory_contract, vault_address, VaultContract, get_dexorder_contract
|
||||||
from dexorder.contract import get_contract_event, ERC20
|
from dexorder.contract import get_contract_event, ERC20
|
||||||
from dexorder.data import vault_owners, vault_balances
|
from dexorder.data import vault_owners, vault_balances
|
||||||
from dexorder.pool import new_pool_prices, pool_prices
|
from dexorder.pools import new_pool_prices, pool_prices, pool_decimals, Pools
|
||||||
from dexorder.database.model.block import current_block
|
from dexorder.database.model.block import current_block
|
||||||
from dexorder.database.model.transaction import TransactionJob
|
from dexorder.database.model.transaction import TransactionJob
|
||||||
from dexorder.base.orderlib import SwapOrderStatus, SwapOrderState
|
from dexorder.base.orderlib import SwapOrderStatus, SwapOrderState
|
||||||
@@ -192,7 +192,7 @@ async def handle_uniswap_swap(swap: EventData):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
addr = swap['address']
|
addr = swap['address']
|
||||||
price: dec = await uniswap_price(addr, sqrt_price)
|
price: dec = await uniswap_price(await Pools.get(addr), sqrt_price)
|
||||||
log.debug(f'pool {addr} {price}')
|
log.debug(f'pool {addr} {price}')
|
||||||
pool_prices[addr] = price
|
pool_prices[addr] = price
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ from enum import Enum, auto
|
|||||||
from typing import Callable, Optional, Union, Awaitable
|
from typing import Callable, Optional, Union, Awaitable
|
||||||
|
|
||||||
from dexorder.blockstate import BlockSet, BlockDict
|
from dexorder.blockstate import BlockSet, BlockDict
|
||||||
from dexorder.base.orderlib import SwapOrderState, PriceProof
|
from dexorder.base.orderlib import SwapOrderState, PriceProof, DISTANT_FUTURE, DISTANT_PAST
|
||||||
from dexorder.util import defaultdictk
|
from dexorder.util import defaultdictk
|
||||||
from .orderstate import Order
|
from .orderstate import Order
|
||||||
from .. import dec
|
from .. import dec
|
||||||
from ..base.order import OrderKey, TrancheKey, ExecutionRequest
|
from ..base.order import OrderKey, TrancheKey, ExecutionRequest
|
||||||
from ..pool import ensure_pool_price, Pool
|
from ..pools import ensure_pool_price, Pools, pool_decimals
|
||||||
from ..database.model.block import current_block
|
from ..database.model.block import current_block
|
||||||
from ..routing import pool_address
|
from ..routing import pool_address
|
||||||
|
|
||||||
@@ -36,8 +36,8 @@ async def activate_order(order: Order):
|
|||||||
Call this to enable triggers on an order which is already in the state.
|
Call this to enable triggers on an order which is already in the state.
|
||||||
"""
|
"""
|
||||||
address = pool_address(order.status.order)
|
address = pool_address(order.status.order)
|
||||||
await ensure_pool_price(address)
|
pool = await Pools.get(address)
|
||||||
pool = await Pool.get(address)
|
await ensure_pool_price(pool)
|
||||||
inverted = pool.base != order.order.tokenIn
|
inverted = pool.base != order.order.tokenIn
|
||||||
if inverted:
|
if inverted:
|
||||||
assert pool.base == order.order.tokenOut
|
assert pool.base == order.order.tokenOut
|
||||||
@@ -56,6 +56,8 @@ def intersect_ranges( a_low, a_high, b_low, b_high):
|
|||||||
|
|
||||||
async def line_passes(lc: tuple[float,float], is_min: bool, price: dec) -> bool:
|
async def line_passes(lc: tuple[float,float], is_min: bool, price: dec) -> bool:
|
||||||
b, m = lc
|
b, m = lc
|
||||||
|
if b == 0 and m == 0:
|
||||||
|
return True
|
||||||
limit = m * current_block.get().timestamp + b
|
limit = m * current_block.get().timestamp + b
|
||||||
# todo ratios
|
# todo ratios
|
||||||
# prices AT the limit get zero volume, so we only trigger on >, not >=
|
# prices AT the limit get zero volume, so we only trigger on >, not >=
|
||||||
@@ -81,24 +83,27 @@ class TrancheTrigger:
|
|||||||
tranche_remaining = tranche_amount - tranche_filled
|
tranche_remaining = tranche_amount - tranche_filled
|
||||||
|
|
||||||
# time and price constraints
|
# time and price constraints
|
||||||
self.time_constraint = tranche.startTime, tranche.endTime
|
self.time_constraint = [tranche.startTime, tranche.endTime]
|
||||||
if tranche.startTimeIsRelative:
|
if tranche.startTimeIsRelative:
|
||||||
self.time_constraint[0] += self.order.status.start
|
self.time_constraint[0] += self.order.status.start
|
||||||
if tranche.endTimeIsRelative:
|
if tranche.endTimeIsRelative:
|
||||||
self.time_constraint[1] += self.order.status.start
|
self.time_constraint[1] += self.order.status.start
|
||||||
|
if self.time_constraint[0] <= DISTANT_PAST and self.time_constraint[1] >= DISTANT_FUTURE:
|
||||||
|
self.time_constraint = None
|
||||||
self.min_line_constraint = (0.,0.) if tranche.marketOrder else (tranche.minIntercept, tranche.minSlope)
|
self.min_line_constraint = (0.,0.) if tranche.marketOrder else (tranche.minIntercept, tranche.minSlope)
|
||||||
self.max_line_constraint = (0.,0.) if tranche.marketOrder else (tranche.maxIntercept, tranche.maxSlope)
|
self.max_line_constraint = (0.,0.) if tranche.marketOrder else (tranche.maxIntercept, tranche.maxSlope)
|
||||||
self.has_line_constraint = any( a or b for a,b in (self.min_line_constraint, self.max_line_constraint))
|
self.has_line_constraint = any( a or b for a,b in (self.min_line_constraint, self.max_line_constraint))
|
||||||
if not tranche.marketOrder and inverted:
|
if not tranche.marketOrder and inverted:
|
||||||
self.min_line_constraint, self.max_line_constraint = self.max_line_constraint, self.min_line_constraint
|
self.min_line_constraint, self.max_line_constraint = self.max_line_constraint, self.min_line_constraint
|
||||||
self.slippage = tranche.minIntercept if tranche.marketOrder else 0
|
self.slippage = tranche.minIntercept if tranche.marketOrder else 0
|
||||||
|
self.pool_price_multiplier = None
|
||||||
|
|
||||||
# compute status and set relevant triggers
|
# compute status and set relevant triggers
|
||||||
if tranche_remaining <= 0:
|
if tranche_remaining <= 0:
|
||||||
self.status = TrancheStatus.Filled
|
self.status = TrancheStatus.Filled
|
||||||
return
|
return
|
||||||
timestamp = current_block.get().timestamp
|
timestamp = current_block.get().timestamp
|
||||||
self.status = TrancheStatus.Early if timestamp < tranche.startTime else TrancheStatus.Expired if timestamp > tranche.endTime else TrancheStatus.Pricing
|
self.status = TrancheStatus.Early if timestamp < self.time_constraint[0] else TrancheStatus.Expired if timestamp > self.time_constraint[1] else TrancheStatus.Pricing
|
||||||
self.enable_time_trigger()
|
self.enable_time_trigger()
|
||||||
if self.status == TrancheStatus.Pricing:
|
if self.status == TrancheStatus.Pricing:
|
||||||
self.enable_price_trigger()
|
self.enable_price_trigger()
|
||||||
@@ -146,6 +151,11 @@ class TrancheTrigger:
|
|||||||
if self.closed:
|
if self.closed:
|
||||||
log.debug(f'price trigger ignored because trigger status is {self.status}')
|
log.debug(f'price trigger ignored because trigger status is {self.status}')
|
||||||
return
|
return
|
||||||
|
if self.pool_price_multiplier is None:
|
||||||
|
pool = await Pools.get(pool_address(self.order.order))
|
||||||
|
pool_dec = await pool_decimals(pool)
|
||||||
|
self.pool_price_multiplier = dec(10) ** dec(-pool_dec)
|
||||||
|
cur *= self.pool_price_multiplier
|
||||||
if not self.has_line_constraint or all(await asyncio.gather(
|
if not self.has_line_constraint or all(await asyncio.gather(
|
||||||
line_passes(self.min_line_constraint, True, cur),
|
line_passes(self.min_line_constraint, True, cur),
|
||||||
line_passes(self.max_line_constraint, False, cur))):
|
line_passes(self.max_line_constraint, False, cur))):
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import logging
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from dexorder import dec, db, current_w3
|
|
||||||
from dexorder.base.chain import current_chain
|
|
||||||
from dexorder.base.orderlib import Exchange
|
|
||||||
from dexorder.blockstate import BlockDict
|
|
||||||
from dexorder.blockstate.blockdata import K, V
|
|
||||||
from dexorder.database.model.pool import PoolModel
|
|
||||||
from dexorder.uniswap import UniswapV3Pool
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class Pool:
|
|
||||||
instances: dict[tuple[int,str], PoolModel] = {}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def get(address, chain=None) -> Optional[PoolModel]:
|
|
||||||
if not chain:
|
|
||||||
chain = current_chain.get()
|
|
||||||
key = (chain.chain_id, address)
|
|
||||||
found = Pool.instances.get(key)
|
|
||||||
if not found:
|
|
||||||
found = db.session.get(key)
|
|
||||||
if not found:
|
|
||||||
# todo other exchanges
|
|
||||||
t0, t1, fee = await asyncio.gather(UniswapV3Pool(address).token0(), UniswapV3Pool(address).token1(), UniswapV3Pool(address).fee())
|
|
||||||
found = PoolModel(chain=chain, address=address, exchange=Exchange.UniswapV3, base=t0, quote=t1, fee=fee)
|
|
||||||
db.session.add(found)
|
|
||||||
Pool.instances[key] = found
|
|
||||||
return found
|
|
||||||
|
|
||||||
|
|
||||||
class PoolPrices (BlockDict[str, dec]):
|
|
||||||
def __setitem__(self, item: K, value: V) -> None:
|
|
||||||
super().__setitem__(item, value)
|
|
||||||
new_pool_prices[item] = value
|
|
||||||
|
|
||||||
|
|
||||||
def pub_pool_price(k,v):
|
|
||||||
chain_id = current_chain.get().chain_id
|
|
||||||
return f'{chain_id}|{k}', 'p', (chain_id, k, str(v))
|
|
||||||
|
|
||||||
|
|
||||||
new_pool_prices: dict[str, dec] = {} # tracks which prices were set during the current block. cleared every block.
|
|
||||||
pool_prices: PoolPrices = PoolPrices('p', db=True, redis=True, pub=pub_pool_price, value2str=lambda d: f'{d:f}', str2value=dec)
|
|
||||||
|
|
||||||
|
|
||||||
async def ensure_pool_price(pool_addr):
|
|
||||||
if pool_addr not in pool_prices:
|
|
||||||
log.debug(f'querying price for pool {pool_addr}')
|
|
||||||
pool_prices[pool_addr] = await UniswapV3Pool(pool_addr).price()
|
|
||||||
|
|
||||||
88
src/dexorder/pools.py
Normal file
88
src/dexorder/pools.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from dexorder import dec, db
|
||||||
|
from dexorder.base.chain import current_chain
|
||||||
|
from dexorder.base.orderlib import Exchange
|
||||||
|
from dexorder.blockstate import BlockDict
|
||||||
|
from dexorder.blockstate.blockdata import K, V
|
||||||
|
from dexorder.contract.decimals import token_decimals
|
||||||
|
from dexorder.database.model.pool import Pool
|
||||||
|
from dexorder.uniswap import UniswapV3Pool
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class Pools:
|
||||||
|
instances: dict[tuple[int,str], Pool] = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def get(address, *, chain=None) -> Optional[Pool]:
|
||||||
|
if not chain:
|
||||||
|
chain = current_chain.get()
|
||||||
|
key = (chain, address)
|
||||||
|
found = Pools.instances.get(key)
|
||||||
|
if not found:
|
||||||
|
found = db.session.get(Pool, key)
|
||||||
|
if not found:
|
||||||
|
# todo other exchanges
|
||||||
|
t0, t1, fee = await asyncio.gather(UniswapV3Pool(address).token0(), UniswapV3Pool(address).token1(), UniswapV3Pool(address).fee())
|
||||||
|
found = Pool(chain=chain, address=address, exchange=Exchange.UniswapV3, base=t0, quote=t1, fee=fee)
|
||||||
|
db.session.add(found)
|
||||||
|
Pools.instances[key] = found
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
class PoolPrices (BlockDict[str, dec]):
|
||||||
|
def __setitem__(self, item: K, value: V) -> None:
|
||||||
|
super().__setitem__(item, value)
|
||||||
|
new_pool_prices[item] = value
|
||||||
|
|
||||||
|
|
||||||
|
def pub_pool_price(k,v):
|
||||||
|
chain_id = current_chain.get().chain_id
|
||||||
|
return f'{chain_id}|{k}', 'p', (chain_id, k, str(v))
|
||||||
|
|
||||||
|
|
||||||
|
new_pool_prices: dict[str, dec] = {} # tracks which prices were set during the current block. cleared every block.
|
||||||
|
pool_prices: PoolPrices = PoolPrices('p', db=True, redis=True, pub=pub_pool_price, value2str=lambda d: f'{d:f}', str2value=dec)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def uniswap_price(pool, sqrt_price=None) -> dec:
|
||||||
|
if sqrt_price is None:
|
||||||
|
sqrt_price = (await UniswapV3Pool(pool.address).slot0())[0]
|
||||||
|
pool_dec = await pool_decimals(pool)
|
||||||
|
price = dec(sqrt_price*sqrt_price) / 2 ** (96 * 2)
|
||||||
|
result = price * dec(10) ** dec(pool_dec)
|
||||||
|
log.debug(f'pool sqrtX96 {sqrt_price} with {pool_dec} decimals = {result}')
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
async def ensure_pool_price(pool):
|
||||||
|
# todo refactor to accept a Pool and switch on exchange type
|
||||||
|
if pool not in pool_prices:
|
||||||
|
log.debug(f'querying price for pool {pool.address}')
|
||||||
|
if pool.exchange == Exchange.UniswapV3:
|
||||||
|
pool_prices[pool.address] = await uniswap_price(pool)
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
|
_pool_decimals = {}
|
||||||
|
async def pool_decimals(pool):
|
||||||
|
found = _pool_decimals.get(pool)
|
||||||
|
if found is None:
|
||||||
|
key = f'pd|{pool.address}'
|
||||||
|
try:
|
||||||
|
found = db.kv[key]
|
||||||
|
log.debug('got decimals from db')
|
||||||
|
except KeyError:
|
||||||
|
found = _pool_decimals[pool] = await token_decimals(pool.base) - await token_decimals(pool.quote)
|
||||||
|
decimals0 = await token_decimals(pool.base)
|
||||||
|
decimals1 = await token_decimals(pool.quote)
|
||||||
|
decimals = decimals0 - decimals1
|
||||||
|
db.kv[key] = decimals
|
||||||
|
log.debug(f'pool decimals: {decimals0} - {decimals1}')
|
||||||
|
log.debug(f'pool decimals {pool.address} {found}')
|
||||||
|
return found
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
from charset_normalizer.md import getLogger
|
from charset_normalizer.md import getLogger
|
||||||
from eth_utils import keccak, to_bytes, to_checksum_address
|
from eth_utils import keccak, to_bytes, to_checksum_address
|
||||||
|
|
||||||
from dexorder import dec, db
|
|
||||||
from dexorder.base.chain import Ethereum, Polygon, Goerli, Mumbai, Arbitrum, Mock, Alpha
|
from dexorder.base.chain import Ethereum, Polygon, Goerli, Mumbai, Arbitrum, Mock, Alpha
|
||||||
from dexorder.blockchain import ByBlockchainDict
|
from dexorder.blockchain import ByBlockchainDict
|
||||||
from dexorder.contract import ContractProxy
|
from dexorder.contract import ContractProxy
|
||||||
from dexorder.util.abiencode import abi_encoder
|
from dexorder.util.abiencode import abi_encoder
|
||||||
from dexorder.contract.decimals import token_decimals
|
|
||||||
from dexorder.util import hexbytes
|
from dexorder.util import hexbytes
|
||||||
|
|
||||||
UNISWAPV3_POOL_INIT_CODE_HASH = hexbytes('0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54')
|
UNISWAPV3_POOL_INIT_CODE_HASH = hexbytes('0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54')
|
||||||
@@ -48,32 +46,6 @@ def uniswap_pool_address(factory_addr: str, addr_a: str, addr_b: str, fee: int)
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
async def uniswap_price(addr, sqrt_price) -> dec:
|
|
||||||
price = dec(sqrt_price*sqrt_price) / 2 ** (96 * 2)
|
|
||||||
decimals = await pool_decimals(addr)
|
|
||||||
result = price * dec(10) ** dec(decimals)
|
|
||||||
log.debug(f'pool sqrtX96 {sqrt_price} with {decimals} decimals = {result}')
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def pool_decimals(addr):
|
|
||||||
key = f'pd|{addr}'
|
|
||||||
try:
|
|
||||||
decimals = db.kv[key]
|
|
||||||
log.debug('got decimals from db')
|
|
||||||
except KeyError:
|
|
||||||
pool = UniswapV3Pool(addr)
|
|
||||||
token0 = await pool.token0()
|
|
||||||
token1 = await pool.token1()
|
|
||||||
decimals0 = await token_decimals(token0)
|
|
||||||
decimals1 = await token_decimals(token1)
|
|
||||||
decimals = decimals0 - decimals1
|
|
||||||
db.kv[key] = decimals
|
|
||||||
log.debug(f'pool decimals: {decimals0} - {decimals1}')
|
|
||||||
log.debug(f'pool decimals {addr} {decimals}')
|
|
||||||
return decimals
|
|
||||||
|
|
||||||
|
|
||||||
class _UniswapContracts (ByBlockchainDict[ContractProxy]):
|
class _UniswapContracts (ByBlockchainDict[ContractProxy]):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def tick_to_sqrtPriceX96(tick):
|
|||||||
return round(math.sqrt(tick_to_price(tick)) * 2**96)
|
return round(math.sqrt(tick_to_price(tick)) * 2**96)
|
||||||
|
|
||||||
def encode_IEEE754(value: float) -> int:
|
def encode_IEEE754(value: float) -> int:
|
||||||
return struct.pack('>I', struct.pack('>f', value))[0]
|
return struct.unpack('>I', struct.pack('>f', value))[0]
|
||||||
|
|
||||||
def decode_IEEE754(value: int) -> float:
|
def decode_IEEE754(value: int) -> float:
|
||||||
return struct.unpack('>f', struct.pack('>I', value))[0]
|
return struct.unpack('>f', struct.pack('>I', value))[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user