def get_account_balance(w3: Web3, token: EthereumToken, address) -> EthereumTokenAmount: if token.is_ERC20: contract = w3.eth.contract(abi=EIP20_ABI, address=token.address) return token.from_wei(contract.functions.balanceOf(address).call()) else: return token.from_wei(w3.eth.getBalance(address))
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)
def handle(self, *args, **options): for token_address in TRACKED_TOKENS: logger.info(f"Checking token {token_address}...") try: EthereumToken.make(to_checksum_address(token_address)) 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)
def sync_token_networks(client: RaidenClient, w3: Web3): logger.info("Updating Token Networks") chain_id = int(w3.net.version) known_tokens = client.raiden.token_networks.values_list("token__address", flat=True) for token_address in client.get_token_addresses(): if token_address in known_tokens: continue logger.info(f"Getting information about token on {token_address}") token = EthereumToken.make(token_address, chain_id) token_network_registry_contract = get_token_network_registry_contract(w3) token_network = models.TokenNetwork.make(token, token_network_registry_contract) client.raiden.token_networks.add(token_network)
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)
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, )
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, )
def get_transfer_value_by_tx_data(w3: Web3, token: EthereumToken, tx_data) -> Optional[EthereumTokenAmount]: args = _decode_transfer_arguments(w3, token, tx_data) if args is not None: return token.from_wei(args["_value"])