Пример #1
0
    def handle(self, *args, **options):
        w3 = get_web3()
        chain = Chain.make(chain_id=int(w3.net.version))

        EthereumToken.ETH(chain=chain)

        erc20_token_addresses = [
            to_checksum_address(t) for t in TRACKED_TOKENS
            if t != EthereumToken.NULL_ADDRESS
        ]

        for token_address in erc20_token_addresses:
            logger.info(f"Checking token {token_address}...")
            try:
                token_data = get_token_information(w3=w3,
                                                   address=token_address)
                EthereumToken.make(address=token_address,
                                   chain=chain,
                                   **token_data)
            except OverflowError:
                logger.error(
                    f"{token_address} is not a valid address or not ERC20-compliant"
                )
            except Exception as exc:
                logger.exception(
                    f"Failed to load token data for {token_address}",
                    exc_info=exc)
Пример #2
0
def process_pending_transfers(w3: Web3, chain: Chain, tx_filter):
    chain.refresh_from_db()

    # Convert the querysets to lists of addresses
    accounts_by_addresses = {
        account.address: account
        for account in EthereumAccount.objects.all()
    }
    tokens_by_address = {
        token.address: token
        for token in EthereumToken.ERC20tokens.filter(chain=chain)
    }
    ETH = EthereumToken.ETH(chain=chain)

    pending_txs = [entry.hex() for entry in tx_filter.get_new_entries()]
    recorded_txs = tuple(
        Transaction.objects.filter(hash__in=pending_txs).values_list(
            "hash", flat=True))
    for tx_hash in set(pending_txs) - set(recorded_txs):
        try:
            tx_data = w3.eth.getTransaction(tx_hash)
            token = tokens_by_address.get(tx_data.to)
            if token:
                recipient_address = get_transfer_recipient_by_tx_data(
                    w3, token, tx_data)
                amount = get_transfer_value_by_tx_data(w3, token, tx_data)
            elif tx_data.to in accounts_by_addresses:
                recipient_address = tx_data.to
                amount = ETH.from_wei(tx_data.value)
            else:
                continue

            recipient = accounts_by_addresses.get(recipient_address)
            if recipient is not None and amount is not None:
                logger.info(f"Processing pending Tx {tx_hash}")
                signals.incoming_transfer_broadcast.send(
                    sender=EthereumToken,
                    account=recipient,
                    amount=amount,
                    transaction_hash=tx_hash,
                )
        except TimeoutError:
            logger.error(f"Failed request to get or check {tx_hash}")
        except TransactionNotFound:
            logger.info(f"Tx {tx_hash} has not yet been mined")
        except ValueError as exc:
            logger.exception(exc)
        except Exception as exc:
            logger.exception(exc)
Пример #3
0
def on_transaction_mined_check_for_deposit(sender, **kw):
    tx = kw["instance"]
    if kw["created"]:
        accounts = EthereumAccount.objects.all()
        accounts_by_address = {
            account.address: account
            for account in accounts
        }

        if tx.to_address in accounts_by_address.keys():
            ETH = EthereumToken.ETH(tx.block.chain)
            eth_amount = EthereumTokenAmount(amount=from_wei(
                tx.value, "ether"),
                                             currency=ETH)
            account_deposit_received.send(
                sender=Transaction,
                account=accounts_by_address[tx.to_address],
                transaction=tx,
                amount=eth_amount,
            )
Пример #4
0
async def track_pending_transactions(w3):
    chain_id = int(w3.net.version)

    tx_filter = w3.eth.filter("pending")

    ETH = EthereumToken.ETH(chain_id)

    while True:
        pending_transaction_data = [
            w3.eth.getTransaction(tx) for tx in tx_filter.get_new_entries()
        ]

        pending_transactions = [
            tx_data for tx_data in pending_transaction_data if tx_data
        ]

        if not pending_transactions:
            await asyncio.sleep(SLEEP_INTERVAL)
            continue

        logger.info(
            f"Checking {len(pending_transactions)} pending transaction(s)")

        wallet_addresses = Wallet.objects.filter(
            paymentordermethod__isnull=False).values_list("account__address",
                                                          flat=True)

        tokens = EthereumToken.ERC20tokens.filter(
            chain=chain_id, paymentorder__payment_method__isnull=False)

        eth_payments = [
            tx for tx in pending_transactions if tx.to in wallet_addresses
        ]

        token_payments = {
            token:
            [tx for tx in pending_transactions if tx.to == token.address]
            for token in tokens
        }

        for token, txs in token_payments.items():
            if not txs:
                continue

            contract = w3.eth.contract(abi=EIP20_ABI, address=token.address)
            for tx in txs:
                logger.info(
                    f"Processing {token.code} transaction: {tx.hash.hex()}")
                fn, args = contract.decode_function_input(tx.input)

                # TODO: is this really the best way to identify the function?
                if fn.function_identifier == contract.functions.transfer.function_identifier:
                    recipient = args["_to"]
                    transfer_amount = token.from_wei(args["_value"])

                    blockchain_payment_sent.send(
                        sender=EthereumToken,
                        recipient=recipient,
                        amount=transfer_amount,
                        transaction_hash=tx.hash.hex(),
                    )

        for tx in eth_payments:
            logger.info(f"Processing ETH transfer: {tx.hash.hex()}")
            blockchain_payment_sent.send(
                sender=EthereumToken,
                recipient=tx.to,
                amount=ETH.from_wei(tx.value),
                transaction_data=tx,
            )