2021-02-17 09:19:42 +01:00
|
|
|
# standard imports
|
|
|
|
import logging
|
|
|
|
|
2021-04-16 22:24:07 +02:00
|
|
|
# external imports
|
2021-02-17 09:19:42 +01:00
|
|
|
import celery
|
2021-05-12 08:48:50 +02:00
|
|
|
from cic_eth_registry.error import (
|
|
|
|
UnknownContractError,
|
|
|
|
NotAContractError,
|
|
|
|
)
|
2021-03-01 21:15:17 +01:00
|
|
|
from chainlib.status import Status as TxStatus
|
2021-03-29 15:27:53 +02:00
|
|
|
from chainlib.eth.address import to_checksum_address
|
|
|
|
from chainlib.eth.error import RequestMismatchException
|
2021-03-01 21:15:17 +01:00
|
|
|
from chainlib.eth.constant import ZERO_ADDRESS
|
2021-04-16 22:24:07 +02:00
|
|
|
from hexathon import (
|
|
|
|
strip_0x,
|
|
|
|
add_0x,
|
|
|
|
)
|
2021-05-05 18:25:21 +02:00
|
|
|
from eth_erc20 import ERC20
|
2021-05-02 19:02:45 +02:00
|
|
|
from erc20_faucet import Faucet
|
2021-02-17 09:19:42 +01:00
|
|
|
|
|
|
|
# local imports
|
|
|
|
from .base import SyncFilter
|
2021-03-29 15:27:53 +02:00
|
|
|
from cic_eth.eth.meta import ExtendedTx
|
2021-10-07 15:48:54 +02:00
|
|
|
from cic_eth.encode import tx_normalize
|
2021-03-29 15:27:53 +02:00
|
|
|
|
|
|
|
logg = logging.getLogger().getChild(__name__)
|
|
|
|
|
|
|
|
|
2021-02-17 09:19:42 +01:00
|
|
|
|
|
|
|
class CallbackFilter(SyncFilter):
|
|
|
|
|
|
|
|
trusted_addresses = []
|
|
|
|
|
2021-04-16 22:24:07 +02:00
|
|
|
def __init__(self, chain_spec, method, queue, caller_address=ZERO_ADDRESS):
|
2021-02-17 09:19:42 +01:00
|
|
|
self.queue = queue
|
|
|
|
self.method = method
|
2021-03-01 21:15:17 +01:00
|
|
|
self.chain_spec = chain_spec
|
2021-04-16 22:24:07 +02:00
|
|
|
self.caller_address = caller_address
|
|
|
|
|
|
|
|
|
|
|
|
def parse_transfer(self, tx, conn):
|
|
|
|
if not tx.payload:
|
|
|
|
return (None, None)
|
|
|
|
r = ERC20.parse_transfer_request(tx.payload)
|
|
|
|
transfer_data = {}
|
2021-10-07 15:48:54 +02:00
|
|
|
transfer_data['to'] = tx_normalize.wallet_address(r[0])
|
2021-04-16 22:24:07 +02:00
|
|
|
transfer_data['value'] = r[1]
|
2021-10-07 15:48:54 +02:00
|
|
|
transfer_data['from'] = tx_normalize.wallet_address(tx.outputs[0])
|
2021-04-16 22:24:07 +02:00
|
|
|
transfer_data['token_address'] = tx.inputs[0]
|
|
|
|
return ('transfer', transfer_data)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_transferfrom(self, tx, conn):
|
|
|
|
if not tx.payload:
|
|
|
|
return (None, None)
|
|
|
|
r = ERC20.parse_transfer_from_request(tx.payload)
|
|
|
|
transfer_data = {}
|
2021-10-07 15:48:54 +02:00
|
|
|
transfer_data['from'] = tx_normalize.wallet_address(r[0])
|
|
|
|
transfer_data['to'] = tx_normalize.wallet_address(r[1])
|
2021-04-16 22:24:07 +02:00
|
|
|
transfer_data['value'] = r[2]
|
|
|
|
transfer_data['token_address'] = tx.inputs[0]
|
|
|
|
return ('transferfrom', transfer_data)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_giftto(self, tx, conn):
|
|
|
|
if not tx.payload:
|
|
|
|
return (None, None)
|
|
|
|
r = Faucet.parse_give_to_request(tx.payload)
|
|
|
|
transfer_data = {}
|
2021-10-07 15:48:54 +02:00
|
|
|
transfer_data['to'] = tx_normalize.wallet_address(r[0])
|
2021-04-16 22:24:07 +02:00
|
|
|
transfer_data['value'] = tx.value
|
2021-10-07 15:48:54 +02:00
|
|
|
transfer_data['from'] = tx_normalize.wallet_address(tx.outputs[0])
|
2021-04-16 22:24:07 +02:00
|
|
|
#transfer_data['token_address'] = tx.inputs[0]
|
|
|
|
faucet_contract = tx.inputs[0]
|
|
|
|
|
2021-05-19 17:11:08 +02:00
|
|
|
c = Faucet(self.chain_spec)
|
|
|
|
|
|
|
|
o = c.token(faucet_contract, sender_address=self.caller_address)
|
2021-04-16 22:24:07 +02:00
|
|
|
r = conn.do(o)
|
|
|
|
transfer_data['token_address'] = add_0x(c.parse_token(r))
|
|
|
|
|
2021-05-02 19:02:45 +02:00
|
|
|
o = c.token_amount(faucet_contract, sender_address=self.caller_address)
|
2021-04-16 22:24:07 +02:00
|
|
|
r = conn.do(o)
|
2021-05-02 19:02:45 +02:00
|
|
|
transfer_data['value'] = c.parse_token_amount(r)
|
2021-04-16 22:24:07 +02:00
|
|
|
|
|
|
|
return ('tokengift', transfer_data)
|
2021-02-17 09:19:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
def call_back(self, transfer_type, result):
|
2021-04-16 22:24:07 +02:00
|
|
|
result['chain_spec'] = result['chain_spec'].asdict()
|
2021-02-17 09:19:42 +01:00
|
|
|
s = celery.signature(
|
|
|
|
self.method,
|
|
|
|
[
|
|
|
|
result,
|
|
|
|
transfer_type,
|
2021-04-16 22:24:07 +02:00
|
|
|
int(result['status_code'] != 0),
|
2021-02-17 09:19:42 +01:00
|
|
|
],
|
2021-02-19 08:06:05 +01:00
|
|
|
queue=self.queue,
|
2021-02-17 09:19:42 +01:00
|
|
|
)
|
|
|
|
# s_translate = celery.signature(
|
|
|
|
# 'cic_eth.ext.address.translate',
|
|
|
|
# [
|
|
|
|
# result,
|
|
|
|
# self.trusted_addresses,
|
|
|
|
# chain_str,
|
|
|
|
# ],
|
|
|
|
# queue=self.queue,
|
|
|
|
# )
|
|
|
|
# s_translate.link(s)
|
|
|
|
# s_translate.apply_async()
|
2021-03-01 21:15:17 +01:00
|
|
|
t = s.apply_async()
|
2021-04-16 22:24:07 +02:00
|
|
|
return t
|
2021-02-17 09:19:42 +01:00
|
|
|
|
|
|
|
|
2021-04-16 22:24:07 +02:00
|
|
|
def parse_data(self, tx, conn):
|
2021-03-01 21:15:17 +01:00
|
|
|
transfer_type = None
|
2021-02-17 09:19:42 +01:00
|
|
|
transfer_data = None
|
2021-03-29 15:27:53 +02:00
|
|
|
# TODO: what's with the mix of attributes and dict keys
|
2021-03-01 21:15:17 +01:00
|
|
|
logg.debug('have payload {}'.format(tx.payload))
|
2021-02-17 09:19:42 +01:00
|
|
|
|
2021-03-01 21:15:17 +01:00
|
|
|
logg.debug('tx status {}'.format(tx.status))
|
2021-03-29 15:27:53 +02:00
|
|
|
|
|
|
|
for parser in [
|
2021-04-16 22:24:07 +02:00
|
|
|
self.parse_transfer,
|
|
|
|
self.parse_transferfrom,
|
|
|
|
self.parse_giftto,
|
2021-03-29 15:27:53 +02:00
|
|
|
]:
|
|
|
|
try:
|
2021-04-16 22:24:07 +02:00
|
|
|
if tx:
|
|
|
|
(transfer_type, transfer_data) = parser(tx, conn)
|
|
|
|
if transfer_type == None:
|
|
|
|
continue
|
2021-05-12 08:48:50 +02:00
|
|
|
break
|
2021-03-29 15:27:53 +02:00
|
|
|
except RequestMismatchException:
|
|
|
|
continue
|
|
|
|
|
2021-03-01 21:15:17 +01:00
|
|
|
|
|
|
|
logg.debug('resolved method {}'.format(transfer_type))
|
2021-02-17 09:19:42 +01:00
|
|
|
|
2021-03-01 21:15:17 +01:00
|
|
|
if transfer_data != None:
|
|
|
|
transfer_data['status'] = tx.status
|
2021-02-17 09:19:42 +01:00
|
|
|
|
2021-03-01 21:15:17 +01:00
|
|
|
return (transfer_type, transfer_data)
|
2021-02-17 09:19:42 +01:00
|
|
|
|
|
|
|
|
2021-03-01 21:15:17 +01:00
|
|
|
def filter(self, conn, block, tx, db_session=None):
|
2021-02-17 09:19:42 +01:00
|
|
|
transfer_data = None
|
2021-03-01 21:15:17 +01:00
|
|
|
transfer_type = None
|
|
|
|
try:
|
2021-04-16 22:24:07 +02:00
|
|
|
(transfer_type, transfer_data) = self.parse_data(tx, conn)
|
2021-03-01 21:15:17 +01:00
|
|
|
except TypeError:
|
|
|
|
logg.debug('invalid method data length for tx {}'.format(tx.hash))
|
2021-02-17 09:19:42 +01:00
|
|
|
return
|
|
|
|
|
2021-03-01 21:15:17 +01:00
|
|
|
if len(tx.payload) < 8:
|
|
|
|
logg.debug('callbacks filter data length not sufficient for method signature in tx {}, skipping'.format(tx.hash))
|
|
|
|
return
|
|
|
|
|
|
|
|
logg.debug('checking callbacks filter input {}'.format(tx.payload[:8]))
|
2021-02-17 09:19:42 +01:00
|
|
|
|
|
|
|
if transfer_data != None:
|
|
|
|
token_symbol = None
|
|
|
|
result = None
|
|
|
|
try:
|
2021-03-29 15:27:53 +02:00
|
|
|
tokentx = ExtendedTx(conn, tx.hash, self.chain_spec)
|
2021-04-16 22:24:07 +02:00
|
|
|
tokentx.set_actors(transfer_data['from'], transfer_data['to'], self.trusted_addresses, caller_address=self.caller_address)
|
2021-02-17 09:19:42 +01:00
|
|
|
tokentx.set_tokens(transfer_data['token_address'], transfer_data['value'])
|
2021-03-01 21:15:17 +01:00
|
|
|
if transfer_data['status'] == 0:
|
|
|
|
tokentx.set_status(1)
|
|
|
|
else:
|
|
|
|
tokentx.set_status(0)
|
2021-04-16 22:24:07 +02:00
|
|
|
result = tokentx.asdict()
|
|
|
|
t = self.call_back(transfer_type, result)
|
|
|
|
logg.info('callback success task id {} tx {} queue {}'.format(t, tx.hash, t.queue))
|
2021-02-17 09:19:42 +01:00
|
|
|
except UnknownContractError:
|
2021-05-12 08:48:50 +02:00
|
|
|
logg.debug('callback filter {}:{} skipping "transfer" method on unknown contract {} tx {}'.format(self.queue, self.method, transfer_data['to'], tx.hash))
|
|
|
|
except NotAContractError:
|
|
|
|
logg.debug('callback filter {}:{} skipping "transfer" on non-contract address {} tx {}'.format(self.queue, self.method, transfer_data['to'], tx.hash))
|
2021-03-01 21:15:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return 'cic-eth callbacks'
|