-3

I've written a Python code to get a set of NFT prices from opensea's API and return it's total USD value below:

# Downgraded to python-telegram-bot 13.7 : pip install python-telegram-bot==13.7

# Set your bot token here.
bot_token = ''

# Import necessary libs
import os
import requests
from telegram.ext import Updater, CommandHandler, MessageHandler, filters

# ETH NFT portfolio contained in the dictionary.
eth_nfts_dict = {'pudgypenguins': 1,
                     'lilpudgys': 1,
                     'pudgyrods': 1}

# Set up logging
import logging
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)

# Setting up their polling stuff
updater = Updater(token=bot_token, use_context=True)
dispatcher = updater.dispatcher


## Functions

'''Fetch spot prices frm coinbase'''
def coinbase_spot(symbol):
    cb_url = f"https://api.coinbase.com/v2/exchange-rates?currency={symbol}"
    cb_response = requests.get(cb_url)
    return float(cb_response.json()['data']['rates']['USD'])


'''Print ETH NFT prices in portfolio, and total USD value'''
def get_eth_nfts(nfts_dict, name):

    eth_counter = 0

    for nft, qty in nfts_dict.items():
        url = f"https://api.opensea.io/api/v1/collection/{nft}/stats"
        headers = {"accept": "application/json"}
        response = requests.get(url, headers=headers)
        eth_floor_price = response.json()['stats']['floor_price']
        eth_counter += eth_floor_price * qty
        nfts_dict[nft] = eth_floor_price

    # Below code is to format the data to appear visually aligned on TG.
    # Wrap ``` to the string (for Markdown formatting)
    message = "```\n"

    for key, value in nfts_dict.items():
        message = message + "{0:<40} {1}".format(key, value) + "\n"

    message = message + f"\nTotal value of {name}'s ETH NFTs is {round(eth_counter, 3)} ETH ({'${:,.2f}'.format(eth_counter * coinbase_spot('eth'))})" + "\n```"

    return message

# Commands
def eth_nfts(update, context):
    context.bot.send_message(chat_id=update.effective_chat.id, text=get_eth_nfts(eth_nfts_dict, 'Ben'), parse_mode='Markdown') # parse_mode set to Markdown

# Create and add command handlers
eth_nfts_handler = CommandHandler('Ben_eth', eth_nfts)
dispatcher.add_handler(eth_nfts_handler)  # basically it's: updater.dispatcher.add_handler(CommandHandler('<command>', <command function>))

updater.start_polling()
updater.idle()  # make sure that program won't fail if 2 programs are attempted to run simultaneously.

The results in the image below shows what happens when I try to ping my Telegram bot: enter image description here

The intial '/ben_eth' command returns the correct Total value. But subsequent '/ben_eth' seem to be returning wrong Total values (multiples of the intial value). What is the bug here that is causing the subsequent Total values to be wrong?

spidermarn
  • 959
  • 1
  • 10
  • 18
  • Possibly `eth_counter += eth_floor_price * qty`. It feels to me that this shouldn't be += – Lexpj Feb 24 '23 at 21:50

1 Answers1

-1

at this line

nfts_dict[nft] = eth_floor_price

you are editing nfts_dict inside the method get_eth_nfts, which is actually editing the original dictionary eth_nfts_dict, although it is out of this method get_eth_nfts scope so every time you call this method get_eth_nfts the values of eth_nfts_dict got updated and feed to the method again with incremented values. here's the original value for eth_nfts_dict

eth_nfts_dict = {'pudgypenguins': 1, 'lilpudgys': 1, 'pudgyrods': 1}

after first call for this method get_eth_nfts, eth_nfts_dict will be like this

eth_nfts_dict = {'pudgypenguins': 5.799, 'lilpudgys': 0.49, 'pudgyrods': 0.6238}

which will lead to a complete different results.

you can just replace this line here

nfts_dict[nft] = eth_floor_price

with another empty dict, and use if for your printed message

results_nfts_dict = {}

results_nfts_dict[nft] = eth_floor_price

generally speaking, in python it is not a good practice to pass a whole dictionary as an argument to a method and updating it inside this method, as it will update the original version of it also, this goes for lists also

Amr Alaa
  • 367
  • 1
  • 4
  • or i could create a copy, nfts_dict.copy() of the existing dict and iterate through that. – spidermarn Feb 28 '23 at 18:32
  • deep copy can help you with your issue https://docs.python.org/3/library/copy.html#:~:text=The%20difference%20between%20shallow%20and%20deep%20copying – Amr Alaa Mar 03 '23 at 15:18