orderindex
This commit is contained in:
@@ -66,13 +66,22 @@ def upgrade() -> None:
|
|||||||
sa.ForeignKeyConstraint(['job_id'], ['transactionjob.id'], ),
|
sa.ForeignKeyConstraint(['job_id'], ['transactionjob.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
|
op.create_table('orderindex',
|
||||||
|
sa.Column('chain', dexorder.database.column_types.Blockchain(), nullable=False),
|
||||||
|
sa.Column('vault', sa.String(), nullable=False),
|
||||||
|
sa.Column('order_index', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('state', sa.Enum('Open', 'Canceled', 'Filled', 'Expired', 'Underfunded', name='swaporderstate'), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('chain', 'vault', 'order_index')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
def downgrade() -> None:
|
||||||
|
op.drop_table('orderindex')
|
||||||
op.drop_table('seriesset')
|
op.drop_table('seriesset')
|
||||||
op.drop_table('seriesdict')
|
op.drop_table('seriesdict')
|
||||||
op.drop_table('keyvalue')
|
op.drop_table('keyvalue')
|
||||||
op.drop_table('block')
|
op.drop_table('block')
|
||||||
op.drop_table('tx')
|
op.drop_table('tx')
|
||||||
op.drop_table('transactionjob')
|
op.drop_table('transactionjob')
|
||||||
|
op.execute('drop type swaporderstate') # enum type
|
||||||
op.execute('drop type transactionjobstate') # enum type
|
op.execute('drop type transactionjobstate') # enum type
|
||||||
@@ -15,7 +15,7 @@ class OrderKey:
|
|||||||
return OrderKey(vault, int(order_index))
|
return OrderKey(vault, int(order_index))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'{self.vault}|{self.order_index}'
|
return f'{self.vault}|{self.order_index:05}'
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, eq=True)
|
@dataclass(frozen=True, eq=True)
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ from enum import Enum
|
|||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from dexorder import dec
|
from dexorder import dec
|
||||||
from dexorder.uniswap import uniswapV3_pool_address, uniswap_price
|
from dexorder.util.abiencode import abi_decoder, abi_encoder
|
||||||
from dexorder.contract import abi_decoder, abi_encoder
|
|
||||||
from dexorder.util import hexbytes
|
from dexorder.util import hexbytes
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -22,6 +21,7 @@ class SwapOrderState (Enum):
|
|||||||
Canceled = 1
|
Canceled = 1
|
||||||
Filled = 2
|
Filled = 2
|
||||||
Expired = 3
|
Expired = 3
|
||||||
|
Underfunded = 14 # todo this is a pseudostate...
|
||||||
|
|
||||||
class Exchange (Enum):
|
class Exchange (Enum):
|
||||||
UniswapV2 = 0
|
UniswapV2 = 0
|
||||||
@@ -58,12 +58,6 @@ class SwapOrder:
|
|||||||
return (self.tokenIn, self.tokenOut, self.route.dump(), str(self.amount), self.amountIsInput,
|
return (self.tokenIn, self.tokenOut, self.route.dump(), str(self.amount), self.amountIsInput,
|
||||||
self.outputDirectlyToOwner, self.chainOrder, [t.dump() for t in self.tranches])
|
self.outputDirectlyToOwner, self.chainOrder, [t.dump() for t in self.tranches])
|
||||||
|
|
||||||
@property
|
|
||||||
def pool_address(self):
|
|
||||||
if self.route.exchange == Exchange.UniswapV3:
|
|
||||||
return uniswapV3_pool_address( self.tokenIn, self.tokenOut, self.route.fee )
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SwapStatus:
|
class SwapStatus:
|
||||||
@@ -184,13 +178,6 @@ class LineConstraint (Constraint):
|
|||||||
def dump(self):
|
def dump(self):
|
||||||
return self._dump(LineConstraint.TYPES, (self.isAbove, self.isRatio, self.time, self.valueSqrtX96, self.slopeSqrtX96))
|
return self._dump(LineConstraint.TYPES, (self.isAbove, self.isRatio, self.time, self.valueSqrtX96, self.slopeSqrtX96))
|
||||||
|
|
||||||
async def passes(self, pool_addr: str, price: dec) -> bool:
|
|
||||||
limit = await uniswap_price(pool_addr, self.valueSqrtX96)
|
|
||||||
# todo slopes
|
|
||||||
# todo ratios
|
|
||||||
# prices AT the limit get zero volume, so we only trigger on >, not >=
|
|
||||||
return self.isAbove and price > limit or not self.isAbove and price < limit
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Tranche:
|
class Tranche:
|
||||||
@@ -29,6 +29,7 @@ class BlockData:
|
|||||||
series2str=None, series2key=None, # defaults to key2str and str2key
|
series2str=None, series2key=None, # defaults to key2str and str2key
|
||||||
key2str=util_key2str, str2key=util_str2key,
|
key2str=util_key2str, str2key=util_str2key,
|
||||||
value2str=json.dumps, str2value=json.loads, # serialize/deserialize value to something JSON-able
|
value2str=json.dumps, str2value=json.loads, # serialize/deserialize value to something JSON-able
|
||||||
|
savecb:Callable[[Any,Any],None]=None, # callback(key, value) where value may be DELETE
|
||||||
**opts):
|
**opts):
|
||||||
assert series not in BlockData.registry
|
assert series not in BlockData.registry
|
||||||
BlockData.registry[series] = self
|
BlockData.registry[series] = self
|
||||||
@@ -41,6 +42,7 @@ class BlockData:
|
|||||||
self.series2key = series2key or self.str2key
|
self.series2key = series2key or self.str2key
|
||||||
self.value2str = value2str
|
self.value2str = value2str
|
||||||
self.str2value = str2value
|
self.str2value = str2value
|
||||||
|
self.savecb = savecb
|
||||||
self.lazy_getitem = None
|
self.lazy_getitem = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ class DbState(SeriesCollection):
|
|||||||
found.value = value
|
found.value = value
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
if d.savecb:
|
||||||
|
d.savecb(diff.key, diff.value)
|
||||||
|
# save root block info
|
||||||
db.kv[f'root_block|{root_block.chain}'] = [root_block.height, root_block.hash]
|
db.kv[f'root_block|{root_block.chain}'] = [root_block.height, root_block.hash]
|
||||||
|
|
||||||
# noinspection PyShadowingBuiltins
|
# noinspection PyShadowingBuiltins
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from eth_abi.codec import ABIDecoder, ABIEncoder
|
|
||||||
from eth_abi.registry import registry as default_registry
|
|
||||||
|
|
||||||
from .. import current_w3 as _current_w3
|
from .. import current_w3 as _current_w3
|
||||||
from .abi import abis
|
from .abi import abis
|
||||||
from .contract_proxy import ContractProxy
|
from .contract_proxy import ContractProxy
|
||||||
|
|
||||||
abi_decoder = ABIDecoder(default_registry)
|
|
||||||
abi_encoder = ABIEncoder(default_registry)
|
|
||||||
|
|
||||||
|
|
||||||
def get_contract_data(name):
|
def get_contract_data(name):
|
||||||
with open(f'../contract/out/{name}.sol/{name}.json', 'rt') as file:
|
with open(f'../contract/out/{name}.sol/{name}.json', 'rt') as file:
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from .base import Base
|
from .base import Base
|
||||||
|
from .kv import KeyValue
|
||||||
from .block import Block
|
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
|
||||||
|
|||||||
23
src/dexorder/database/model/orderindex.py
Normal file
23
src/dexorder/database/model/orderindex.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from sqlalchemy import SMALLINT
|
||||||
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
|
from dexorder.database.column import Blockchain
|
||||||
|
from dexorder.database.model import Base
|
||||||
|
from dexorder.base.orderlib import SwapOrderState
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class OrderIndex (Base):
|
||||||
|
chain: Mapped[Blockchain] = mapped_column(primary_key=True)
|
||||||
|
vault: Mapped[str] = mapped_column(primary_key=True)
|
||||||
|
order_index: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
state: Mapped[SwapOrderState]
|
||||||
|
|
||||||
|
|
||||||
|
# class FillIndex (Base):
|
||||||
|
# chain: Mapped[Blockchain] = mapped_column(index=True)
|
||||||
|
# vault: Mapped[str] = mapped_column(index=True)
|
||||||
|
# order_index: Mapped[SMALLINT] = mapped_column(index=True)
|
||||||
|
# tranche_index:
|
||||||
@@ -15,7 +15,7 @@ from dexorder.contract import get_contract_event, ERC20
|
|||||||
from dexorder.data import pool_prices, vault_owners, vault_balances, new_pool_prices
|
from dexorder.data import pool_prices, vault_owners, vault_balances, new_pool_prices
|
||||||
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.order.orderlib import SwapOrderStatus, SwapOrderState
|
from dexorder.base.orderlib import SwapOrderStatus, SwapOrderState
|
||||||
from dexorder.order.orderstate import Order
|
from dexorder.order.orderstate import Order
|
||||||
from dexorder.order.triggers import OrderTriggers, price_triggers, time_triggers, \
|
from dexorder.order.triggers import OrderTriggers, price_triggers, time_triggers, \
|
||||||
unconstrained_price_triggers, execution_requests, inflight_execution_requests, TrancheStatus, active_tranches, new_price_triggers, activate_order
|
unconstrained_price_triggers, execution_requests, inflight_execution_requests, TrancheStatus, active_tranches, new_price_triggers, activate_order
|
||||||
|
|||||||
@@ -3,12 +3,15 @@ import logging
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import overload
|
from typing import overload
|
||||||
|
|
||||||
from dexorder import DELETE
|
from dexorder import DELETE, db
|
||||||
from dexorder.base.chain import current_chain
|
from dexorder.base.chain import current_chain
|
||||||
from dexorder.base.order import OrderKey, TrancheKey
|
from dexorder.base.order import OrderKey, TrancheKey
|
||||||
from dexorder.blockstate import BlockDict, BlockSet
|
from dexorder.blockstate import BlockDict, BlockSet
|
||||||
from dexorder.data import vault_owners
|
from dexorder.data import vault_owners
|
||||||
from dexorder.order.orderlib import SwapOrderStatus, SwapOrderState
|
from dexorder.database.model.orderindex import OrderIndex
|
||||||
|
from dexorder.base.orderlib import SwapOrderStatus, SwapOrderState
|
||||||
|
|
||||||
|
from dexorder.routing import pool_address
|
||||||
from dexorder.util import json
|
from dexorder.util import json
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -96,7 +99,7 @@ class Order:
|
|||||||
assert key not in Order.instances
|
assert key not in Order.instances
|
||||||
self.key = key
|
self.key = key
|
||||||
self.status: SwapOrderStatus = Order.order_statuses[key].copy()
|
self.status: SwapOrderStatus = Order.order_statuses[key].copy()
|
||||||
self.pool_address: str = self.status.order.pool_address
|
self.pool_address: str = pool_address(self.status.order)
|
||||||
self.tranche_keys = [TrancheKey(key.vault, key.order_index, i) for i in range(len(self.status.trancheFilledIn))]
|
self.tranche_keys = [TrancheKey(key.vault, key.order_index, i) for i in range(len(self.status.trancheFilledIn))]
|
||||||
# flattenings of various static data
|
# flattenings of various static data
|
||||||
self.order = self.status.order
|
self.order = self.status.order
|
||||||
@@ -203,6 +206,22 @@ class Order:
|
|||||||
log.warning(f'No vault owner for {k}')
|
log.warning(f'No vault owner for {k}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_order_index(key, status):
|
||||||
|
key: OrderKey
|
||||||
|
status: SwapOrderStatus
|
||||||
|
sess = db.session
|
||||||
|
oi = sess.get(OrderIndex, (current_chain.get(), key.vault, key.order_index))
|
||||||
|
if status is DELETE:
|
||||||
|
if oi:
|
||||||
|
oi.delete()
|
||||||
|
else:
|
||||||
|
if oi:
|
||||||
|
oi.state = status.state
|
||||||
|
else:
|
||||||
|
oi = OrderIndex(chain=current_chain.get(), vault=key.vault, order_index=key.order_index, state=status.state)
|
||||||
|
sess.add(oi)
|
||||||
|
|
||||||
|
|
||||||
# ORDER STATE
|
# ORDER STATE
|
||||||
# various blockstate fields hold different aspects of an order's state.
|
# various blockstate fields hold different aspects of an order's state.
|
||||||
@@ -212,7 +231,7 @@ class Order:
|
|||||||
# it holds "everything" about an order in the canonical format specified by the contract orderlib, except that
|
# it holds "everything" about an order in the canonical format specified by the contract orderlib, except that
|
||||||
# the filled amount fields for active orders are maintained in the order_remainings and tranche_remainings series.
|
# the filled amount fields for active orders are maintained in the order_remainings and tranche_remainings series.
|
||||||
order_statuses: BlockDict[OrderKey, SwapOrderStatus] = BlockDict(
|
order_statuses: BlockDict[OrderKey, SwapOrderStatus] = BlockDict(
|
||||||
'o', db='lazy', redis=True, pub=pub_order_status,
|
'o', db='lazy', redis=True, pub=pub_order_status, savecb=save_order_index,
|
||||||
str2key=OrderKey.str2key, value2str=lambda v: json.dumps(v.dump()), str2value=lambda s:SwapOrderStatus.load(json.loads(s)),
|
str2key=OrderKey.str2key, value2str=lambda v: json.dumps(v.dump()), str2value=lambda s:SwapOrderStatus.load(json.loads(s)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,15 @@ 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 .orderlib import TimeConstraint, LineConstraint, ConstraintMode, SwapOrderState, PriceProof
|
from dexorder.base.orderlib import TimeConstraint, LineConstraint, ConstraintMode, SwapOrderState, PriceProof
|
||||||
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 ..data import ensure_pool_price
|
from ..data import ensure_pool_price
|
||||||
from ..database.model.block import current_block
|
from ..database.model.block import current_block
|
||||||
|
from ..routing import pool_address
|
||||||
|
from ..uniswap import uniswap_price
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -30,11 +32,11 @@ execution_requests:BlockDict[TrancheKey, ExecutionRequest] = BlockDict('e') # g
|
|||||||
inflight_execution_requests:BlockDict[TrancheKey, int] = BlockDict('ei') # value is block height when the request was sent
|
inflight_execution_requests:BlockDict[TrancheKey, int] = BlockDict('ei') # value is block height when the request was sent
|
||||||
|
|
||||||
|
|
||||||
async def activate_order(order):
|
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.
|
||||||
"""
|
"""
|
||||||
await ensure_pool_price(order.pool_address)
|
await ensure_pool_price(pool_address(order.status.order))
|
||||||
triggers = OrderTriggers(order)
|
triggers = OrderTriggers(order)
|
||||||
if triggers.closed:
|
if triggers.closed:
|
||||||
log.debug(f'order {order.key} was immediately closed')
|
log.debug(f'order {order.key} was immediately closed')
|
||||||
@@ -47,6 +49,15 @@ def intersect_ranges( a_low, a_high, b_low, b_high):
|
|||||||
low, high = None, None
|
low, high = None, None
|
||||||
return low, high
|
return low, high
|
||||||
|
|
||||||
|
|
||||||
|
async def line_passes(lc: LineConstraint, pool_addr: str, price: dec) -> bool:
|
||||||
|
limit = await uniswap_price(pool_addr, lc.valueSqrtX96)
|
||||||
|
# todo slopes
|
||||||
|
# todo ratios
|
||||||
|
# prices AT the limit get zero volume, so we only trigger on >, not >=
|
||||||
|
return lc.isAbove and price > limit or not lc.isAbove and price < limit
|
||||||
|
|
||||||
|
|
||||||
class TrancheStatus (Enum):
|
class TrancheStatus (Enum):
|
||||||
Early = auto() # first time trigger hasnt happened yet
|
Early = auto() # first time trigger hasnt happened yet
|
||||||
Pricing = auto() # we are inside the time window and checking prices
|
Pricing = auto() # we are inside the time window and checking prices
|
||||||
@@ -137,7 +148,7 @@ 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 not self.line_constraints or all(await asyncio.gather(*[pc.passes(self.order.pool_address, cur) for pc in self.line_constraints])):
|
if not self.line_constraints or all(await asyncio.gather(*[line_passes(lc, self.order.pool_address, cur) for lc in self.line_constraints])):
|
||||||
active_tranches[self.tk] = None # or PriceProof(...)
|
active_tranches[self.tk] = None # or PriceProof(...)
|
||||||
|
|
||||||
def fill(self, _amount_in, _amount_out ):
|
def fill(self, _amount_in, _amount_out ):
|
||||||
|
|||||||
14
src/dexorder/routing.py
Normal file
14
src/dexorder/routing.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from dexorder.base.orderlib import Exchange, SwapOrder
|
||||||
|
from dexorder.uniswap import uniswapV3_pool_address
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def pool_address(so: SwapOrder):
|
||||||
|
if so.route.exchange == Exchange.UniswapV3:
|
||||||
|
return uniswapV3_pool_address(so.tokenIn, so.tokenOut, so.route.fee)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@@ -4,7 +4,8 @@ from eth_utils import keccak, to_bytes, to_checksum_address
|
|||||||
from dexorder import dec, db
|
from dexorder import dec, db
|
||||||
from dexorder.base.chain import Ethereum, Polygon, Goerli, Mumbai, Arbitrum, Mock
|
from dexorder.base.chain import Ethereum, Polygon, Goerli, Mumbai, Arbitrum, Mock
|
||||||
from dexorder.blockchain import ByBlockchainDict
|
from dexorder.blockchain import ByBlockchainDict
|
||||||
from dexorder.contract import abi_encoder, ContractProxy
|
from dexorder.contract import ContractProxy
|
||||||
|
from dexorder.util.abiencode import abi_encoder
|
||||||
from dexorder.contract.decimals import token_decimals
|
from dexorder.contract.decimals import token_decimals
|
||||||
from dexorder.util import hexbytes
|
from dexorder.util import hexbytes
|
||||||
|
|
||||||
@@ -50,13 +51,16 @@ def uniswap_pool_address(factory_addr: str, addr_a: str, addr_b: str, fee: int)
|
|||||||
async def uniswap_price(addr, sqrt_price) -> dec:
|
async def uniswap_price(addr, sqrt_price) -> dec:
|
||||||
price = dec(sqrt_price*sqrt_price) / 2 ** (96 * 2)
|
price = dec(sqrt_price*sqrt_price) / 2 ** (96 * 2)
|
||||||
decimals = await pool_decimals(addr)
|
decimals = await pool_decimals(addr)
|
||||||
return price * dec(10) ** dec(decimals)
|
result = price * dec(10) ** dec(decimals)
|
||||||
|
log.debug(f'pool sqrtX96 {sqrt_price} with {decimals} decimals = {result}')
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
async def pool_decimals(addr):
|
async def pool_decimals(addr):
|
||||||
key = f'pd|{addr}'
|
key = f'pd|{addr}'
|
||||||
try:
|
try:
|
||||||
return db.kv[key]
|
decimals = db.kv[key]
|
||||||
|
log.debug('got decimals from db')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pool = UniswapV3Pool(addr)
|
pool = UniswapV3Pool(addr)
|
||||||
token0 = await pool.token0()
|
token0 = await pool.token0()
|
||||||
@@ -65,7 +69,9 @@ async def pool_decimals(addr):
|
|||||||
decimals1 = await token_decimals(token1)
|
decimals1 = await token_decimals(token1)
|
||||||
decimals = decimals0 - decimals1
|
decimals = decimals0 - decimals1
|
||||||
db.kv[key] = decimals
|
db.kv[key] = decimals
|
||||||
return 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]):
|
||||||
|
|||||||
8
src/dexorder/util/abiencode.py
Normal file
8
src/dexorder/util/abiencode.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from eth_abi.codec import ABIDecoder, ABIEncoder
|
||||||
|
from eth_abi.registry import registry as default_registry
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
abi_decoder = ABIDecoder(default_registry)
|
||||||
|
abi_encoder = ABIEncoder(default_registry)
|
||||||
Reference in New Issue
Block a user