TRANCHE EXECUTION WORKS
This commit is contained in:
@@ -60,7 +60,7 @@ def upgrade() -> None:
|
||||
op.create_index(op.f('ix_transactionjob_state'), 'transactionjob', ['state'], unique=False)
|
||||
op.create_table('tx',
|
||||
sa.Column('id', postgresql.BYTEA(), nullable=False),
|
||||
sa.Column('data', postgresql.JSONB(astext_type=sa.Text()), nullable=False),
|
||||
sa.Column('data', postgresql.BYTEA(), nullable=False),
|
||||
sa.Column('job_id', sa.UUID(), nullable=False),
|
||||
sa.Column('receipt', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.ForeignKeyConstraint(['job_id'], ['transactionjob.id'], ),
|
||||
|
||||
@@ -49,6 +49,14 @@ class Account (LocalAccount):
|
||||
self.name = name
|
||||
self.key_str = key_str
|
||||
self.signing_middleware = construct_sign_and_send_raw_middleware(self)
|
||||
self._nonce: Optional[int] = None
|
||||
|
||||
async def next_nonce(self):
|
||||
if self._nonce is None:
|
||||
self._nonce = await current_w3.get().eth.get_transaction_count(self.address, 'pending')
|
||||
else:
|
||||
self._nonce += 1
|
||||
return self._nonce
|
||||
|
||||
def attach(self, w3):
|
||||
w3.eth.default_account = self.address
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
import eth_account
|
||||
from eth_utils import keccak
|
||||
from web3.types import TxReceipt
|
||||
|
||||
@@ -19,15 +20,15 @@ def call_wrapper(func):
|
||||
|
||||
def transact_wrapper(func):
|
||||
async def f(*args, **kwargs):
|
||||
w3 = current_w3.get()
|
||||
try:
|
||||
account = current_account.get()
|
||||
except LookupError:
|
||||
raise RuntimeError('Cannot invoke a transaction without setting an Account.')
|
||||
tx = await func(*args, **kwargs).build_transaction()
|
||||
tx['from'] = account.address
|
||||
signed = w3.eth.account.sign_transaction(tx, private_key=account.key)
|
||||
return ContractTransaction(signed)
|
||||
tx['nonce'] = await account.next_nonce()
|
||||
signed = eth_account.Account.sign_transaction(tx, private_key=account.key)
|
||||
return ContractTransaction(signed['hash'], signed['rawTransaction'])
|
||||
return f
|
||||
|
||||
|
||||
@@ -88,10 +89,10 @@ class ContractProxy:
|
||||
|
||||
|
||||
class ContractTransaction:
|
||||
def __init__(self, rawtx: bytes):
|
||||
self.data = rawtx
|
||||
self.id_bytes = keccak(rawtx)
|
||||
def __init__(self, id_bytes: bytes, rawtx: bytes):
|
||||
self.id_bytes = id_bytes
|
||||
self.id = hexstr(self.id_bytes)
|
||||
self.data = rawtx
|
||||
self.receipt: Optional[TxReceipt] = None
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -7,6 +7,7 @@ from dexorder.util import defaultdictk, hexstr
|
||||
# values of DELETE are serialized as nulls
|
||||
|
||||
vault_owners: BlockDict[str,str] = BlockDict('v', db=True, redis=True)
|
||||
vault_tokens: dict[str, BlockSet[str]] = defaultdictk(lambda vault: BlockSet(f'vt|{vault}', db=True, redis=True, pub=lambda k,v: ('vt', vault_owners[vault], [k])))
|
||||
pool_prices: BlockDict[str,dec] = BlockDict('p', db=True, redis=True, pub=True, value2str=lambda d:f'{d:f}', str2value=dec)
|
||||
underfunded_vaults: BlockDict[str, list[str]] = BlockDict('uv', db=True, redis=True, value2str=lambda v:','.join(v), str2value=lambda s: s.split(','))
|
||||
vault_balances: dict[str, BlockDict[str,int]] = defaultdictk(lambda vault: BlockDict(f'vb|{vault}', db=True, redis=True,
|
||||
pub=lambda k,v: (vault_owners[vault], 'vb', (vault,k,v))))
|
||||
pool_prices: BlockDict[str,dec] = BlockDict('p', db=True, redis=True, value2str=lambda d:f'{d:f}', str2value=dec,
|
||||
pub=lambda k,v: (f'p|{k}', 'p', (k,str(v))))
|
||||
|
||||
@@ -3,14 +3,14 @@ from uuid import UUID
|
||||
|
||||
from web3.types import EventData
|
||||
|
||||
from dexorder import current_pub, db
|
||||
from dexorder import current_pub, db, dec
|
||||
from dexorder.base.chain import current_chain
|
||||
from dexorder.base.order import TrancheExecutionRequest, TrancheKey, ExecutionRequest, new_tranche_execution_request
|
||||
from dexorder.transaction import handle_create_transactions, submit_transaction_request, handle_transaction_receipts
|
||||
from dexorder.transaction import handle_create_transactions, submit_transaction_request, handle_transaction_receipts, handle_send_transactions
|
||||
from dexorder.blockchain.uniswap import uniswap_price
|
||||
from dexorder.contract.dexorder import get_factory_contract, vault_address, VaultContract, get_dexorder_contract
|
||||
from dexorder.contract import UniswapV3Pool, get_contract_event
|
||||
from dexorder.data import pool_prices, vault_owners, vault_tokens, underfunded_vaults
|
||||
from dexorder.data import pool_prices, vault_owners, vault_balances
|
||||
from dexorder.database.model.block import current_block
|
||||
from dexorder.database.model.transaction import TransactionJob
|
||||
from dexorder.order.orderlib import SwapOrderState, SwapOrderStatus
|
||||
@@ -73,6 +73,7 @@ def setup_logevent_triggers(runner):
|
||||
runner.add_event_trigger(activate_price_triggers)
|
||||
runner.add_event_trigger(process_execution_requests)
|
||||
runner.add_event_trigger(handle_create_transactions)
|
||||
runner.add_event_trigger(handle_send_transactions)
|
||||
|
||||
|
||||
async def handle_order_placed(event: EventData):
|
||||
@@ -111,18 +112,17 @@ def handle_order_error(event: EventData):
|
||||
log.debug(f'DexorderError {event}')
|
||||
|
||||
def handle_transfer(transfer: EventData):
|
||||
# todo handle native transfers incl gas for token transfers
|
||||
from_address = transfer['args']['from']
|
||||
to_address = transfer['args']['to']
|
||||
amount = int(transfer['args']['value'])
|
||||
log.debug(f'transfer {to_address}')
|
||||
if to_address in vault_owners:
|
||||
if to_address in vault_owners and to_address != from_address:
|
||||
token_address = transfer['address']
|
||||
vault_tokens[to_address].add(token_address)
|
||||
if to_address in underfunded_vaults:
|
||||
# todo possibly funded now
|
||||
pass
|
||||
if from_address in Order.open_keys:
|
||||
# todo possibly underfunded now
|
||||
pass
|
||||
vault_balances[to_address].add(token_address, amount, 0)
|
||||
if from_address in vault_owners and to_address != from_address:
|
||||
token_address = transfer['address']
|
||||
vault_balances[to_address].add(token_address, -amount, 0)
|
||||
|
||||
|
||||
new_pool_prices: dict[str, int] = {}
|
||||
@@ -224,9 +224,8 @@ def finish_execution_request(req: TrancheExecutionRequest, error: str):
|
||||
log.debug(f'execution request for tranche {tk} was successful!')
|
||||
elif error in ('IIA', 'STF'): # todo not STF
|
||||
# Insufficient Input Amount or Safe Transfer Failure: suspend execution until new funds are sent
|
||||
# todo replace with vault balance checks
|
||||
# todo vault balance checks
|
||||
token = order.order.tokenIn
|
||||
# underfunded_vaults[req.vault] = underfunded_vaults.get(req.vault, []) + [token]
|
||||
log.debug(f'insufficient funds {req.vault} {token} ')
|
||||
else:
|
||||
log.error(f'Unhandled execution error for transaction request {req} ERROR: "{error}"')
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import logging
|
||||
from uuid import UUID
|
||||
|
||||
from web3.exceptions import ContractPanicError
|
||||
|
||||
from dexorder import db
|
||||
from dexorder.base.order import TrancheExecutionRequest, TrancheKey
|
||||
from dexorder.transaction import TransactionHandler
|
||||
from dexorder.contract.dexorder import get_dexorder_contract
|
||||
@@ -17,6 +20,9 @@ class TrancheExecutionHandler (TransactionHandler):
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
return await get_dexorder_contract().transact.execute(job_id.bytes, (req.vault, req.order_index, req.tranche_index, req.price_proof))
|
||||
except ContractPanicError as px:
|
||||
log.error(f'While executing job {job_id}: {px}')
|
||||
await self.complete_transaction(db.session.get(TransactionJob, job_id))
|
||||
except Exception:
|
||||
log.exception(f'Could not send execution request {req}')
|
||||
|
||||
|
||||
@@ -42,7 +42,11 @@ class Order:
|
||||
|
||||
@staticmethod
|
||||
def of(a, b=None):
|
||||
return Order.instances[a if b is None else OrderKey(a, b)]
|
||||
key = a if b is None else OrderKey(a, b)
|
||||
try:
|
||||
return Order.instances[key]
|
||||
except KeyError:
|
||||
log.error(f'Could not find {key} among:\n{", ".join(str(k) for k in Order.instances.keys())}')
|
||||
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -229,6 +229,7 @@ class BlockStateRunner:
|
||||
if pubs and self.publish_all:
|
||||
await maywait(self.publish_all(pubs))
|
||||
except: # legitimately catch EVERYTHING because we re-raise
|
||||
log.debug('rolling back session')
|
||||
if session is not None:
|
||||
session.rollback()
|
||||
if blockhash is not None and self.state is not None:
|
||||
@@ -238,3 +239,6 @@ class BlockStateRunner:
|
||||
if session is not None:
|
||||
session.commit()
|
||||
log.info(f'completed block {block}')
|
||||
finally:
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
Reference in New Issue
Block a user