diff --git a/apps/cic-eth/cic_eth/runnable/daemons/filters/__init__.py b/apps/cic-eth/cic_eth/runnable/daemons/filters/__init__.py index feed42c9..d2a9823b 100644 --- a/apps/cic-eth/cic_eth/runnable/daemons/filters/__init__.py +++ b/apps/cic-eth/cic_eth/runnable/daemons/filters/__init__.py @@ -2,3 +2,4 @@ from .callback import CallbackFilter from .tx import TxFilter from .gas import GasFilter from .register import RegistrationFilter +from .transferauth import TransferAuthFilter diff --git a/apps/cic-eth/cic_eth/runnable/daemons/filters/gas.py b/apps/cic-eth/cic_eth/runnable/daemons/filters/gas.py index 697b30f0..3fee3d9f 100644 --- a/apps/cic-eth/cic_eth/runnable/daemons/filters/gas.py +++ b/apps/cic-eth/cic_eth/runnable/daemons/filters/gas.py @@ -1,7 +1,7 @@ # standard imports import logging -# third-party imports +# external imports from cic_registry.chain import ChainSpec from hexathon import add_0x @@ -24,7 +24,7 @@ class GasFilter(SyncFilter): self.chain_spec = chain_spec - def filter(self, conn, block, tx, session): #rcpt, chain_str, session=None): + def filter(self, conn, block, tx, session): tx_hash_hex = add_0x(tx.hash) if tx.value > 0: logg.debug('gas refill tx {}'.format(tx_hash_hex)) diff --git a/apps/cic-eth/cic_eth/runnable/daemons/filters/transferauth.py b/apps/cic-eth/cic_eth/runnable/daemons/filters/transferauth.py new file mode 100644 index 00000000..8a7ead1a --- /dev/null +++ b/apps/cic-eth/cic_eth/runnable/daemons/filters/transferauth.py @@ -0,0 +1,85 @@ +# standard imports +import logging + +# external imports +import celery +from hexathon import ( + strip_0x, + add_0x, + ) +from chainlib.eth.address import to_checksum +from .base import SyncFilter + + +logg = logging.getLogger(__name__) + +transfer_request_signature = 'ed71262a' + +def unpack_create_request(data): + + data = strip_0x(data) + cursor = 0 + f = data[cursor:cursor+8] + cursor += 8 + + if f != transfer_request_signature: + raise ValueError('Invalid create request data ({})'.format(f)) + + o = {} + o['sender'] = data[cursor+24:cursor+64] + cursor += 64 + o['recipient'] = data[cursor+24:cursor+64] + cursor += 64 + o['token'] = data[cursor+24:cursor+64] + cursor += 64 + o['value'] = int(data[cursor:], 16) + return o + + +class TransferAuthFilter(SyncFilter): + + def __init__(self, registry, chain_spec, queue=None): + self.queue = queue + self.chain_spec = chain_spec + self.transfer_request_contract = registry.get_contract(self.chain_spec, 'TransferAuthorization') + + + def filter(self, conn, block, tx, session): #rcpt, chain_str, session=None): + + payloadlength = len(tx.payload) + if len(tx.payload) != 8+256: + logg.debug('{} below minimum length for a transfer auth call'.format(payloadlength)) + logg.debug('payload {}'.format(tx.payload)) + return False + + recipient = tx.inputs[0] + if recipient != self.transfer_request_contract.address(): + logg.debug('not our transfer auth contract address {}'.format(recipient)) + return False + + o = unpack_create_request(tx.payload) + + sender = add_0x(to_checksum(o['sender'])) + recipient = add_0x(to_checksum(recipient)) + token = add_0x(to_checksum(o['token'])) + s = celery.signature( + 'cic_eth.eth.token.approve', + [ + [ + { + 'address': token, + }, + ], + sender, + recipient, + o['value'], + str(self.chain_spec), + ], + queue=self.queue, + ) + t = s.apply_async() + return True + + + def __str__(self): + return 'cic-eth transfer auth filter' diff --git a/apps/cic-eth/cic_eth/runnable/daemons/tracker.py b/apps/cic-eth/cic_eth/runnable/daemons/tracker.py index 3bb58b74..bd05d2ba 100644 --- a/apps/cic-eth/cic_eth/runnable/daemons/tracker.py +++ b/apps/cic-eth/cic_eth/runnable/daemons/tracker.py @@ -58,6 +58,7 @@ from cic_eth.runnable.daemons.filters import ( GasFilter, TxFilter, RegistrationFilter, + TransferAuthFilter, ) script_dir = os.path.realpath(os.path.dirname(__file__)) @@ -146,6 +147,8 @@ def main(): gas_filter = GasFilter(chain_spec, config.get('_CELERY_QUEUE')) + transfer_auth_filter = TransferAuthFilter(registry, chain_spec, config.get('_CELERY_QUEUE')) + i = 0 for syncer in syncers: logg.debug('running syncer index {}'.format(i)) @@ -153,6 +156,7 @@ def main(): syncer.add_filter(registration_filter) # TODO: the two following filter functions break the filter loop if return uuid. Pro: less code executed. Con: Possibly unintuitive flow break syncer.add_filter(tx_filter) + syncer.add_filter(transfer_auth_filter) for cf in callback_filters: syncer.add_filter(cf) diff --git a/docker-compose.yml b/docker-compose.yml index adac706f..f277b714 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -161,7 +161,7 @@ services: - -c - | if [[ -f /tmp/cic/config/.env ]]; then source /tmp/cic/config/.env; fi - /usr/local/bin/cic-cache-tracker -v + /usr/local/bin/cic-cache-tracker -vv volumes: - contract-config:/tmp/cic/config/:ro @@ -274,7 +274,7 @@ services: - -c - | if [[ -f /tmp/cic/config/.env ]]; then source /tmp/cic/config/.env; fi - ./start_tracker.sh -v -c /usr/local/etc/cic-eth + ./start_tracker.sh -vv -c /usr/local/etc/cic-eth # command: "/root/start_manager.sh head -vv"