Skip to content

Instantly share code, notes, and snippets.

@jatubio
Created July 25, 2024 13:06
Show Gist options
  • Save jatubio/121f12d777fcc082413cc06b453e5940 to your computer and use it in GitHub Desktop.
Save jatubio/121f12d777fcc082413cc06b453e5940 to your computer and use it in GitHub Desktop.
Python class used to check balance of a NFT token on a wallet
from web3 import Web3
class NFTUtils:
def __init__(self, w3, contract_address):
self.w3 = w3
self.contract_address = self.w3.to_checksum_address(contract_address)
# La usamos con una ABI simple para comprobar si admite unos parámetro o no
# Y así detectamos el tipo de contrato
def _call_simple_function(self, function_name, *args):
# Utility method to call a contract function and handle exceptions
try:
contract = self.w3.eth.contract(address=self.contract_address, abi=self._get_abi(function_name))
return contract.functions[function_name](*args).call()
except Exception as e:
print(f"Error calling function {function_name}: {e}")
return None
# Proporciona un ABI mínimo para las funciones balanceOf, balanceOfBatch, y supportsInterface.
# Se adapta según la función que se necesite llamar.
def _get_abi(self, function_name):
# Provide a minimal ABI for calling functions
if function_name in ['balanceOf', 'balanceOfBatch']:
return [{
"constant": True,
"inputs": [{"name": "account", "type": "address"}, {"name": "id", "type": "uint256"}] if function_name == 'balanceOf' else [{"name": "accounts", "type": "address[]"}, {"name": "ids", "type": "uint256[]"}],
"name": function_name,
"outputs": [{"name": "", "type": "uint256"}] if function_name == 'balanceOf' else {"name": "", "type": "uint256[]"},
"payable": False,
"stateMutability": "view",
"type": "function"
}]
elif function_name == 'supportsInterface':
return [{
"constant": True,
"inputs": [{"name": "interfaceId", "type": "bytes4"}],
"name": function_name,
"outputs": [{"name": "", "type": "bool"}],
"payable": False,
"stateMutability": "view",
"type": "function"
}]
return []
# Verifica si el contrato soporta una interfaz específica utilizando la función supportsInterface.
def _supports_interface(self, interface_id):
try:
return self._call_simple_function('supportsInterface', interface_id)
except Exception as e:
print(f"Error checking interface support: {e}")
return False
# Identifica si el contrato es ERC-721 o ERC-1155 basándose en el soporte de interfaces.
def detect_contract_type(self):
# Check ERC-721 and ERC-1155 support
ERC721_INTERFACE_ID = '0x80ac58cd' # ERC-721
ERC1155_INTERFACE_ID = '0xd9b67a26' # ERC-1155
if self._supports_interface(ERC721_INTERFACE_ID):
return 'ERC-721'
elif self._supports_interface(ERC1155_INTERFACE_ID):
return 'ERC-1155'
else:
return 'Unknown'
# Verifica el balance de NFT en una wallet dada el tipo de contrato detectado.
def is_nft_in_wallet(self, wallet_address, token_id=None):
contract_type = self.detect_contract_type()
# print(f"Detected contract type: {contract_type}")
if contract_type == 'ERC-721':
# Check if the NFT is in the wallet for ERC-721
balance = self._call_simple_function('balanceOf', wallet_address)
if balance is None:
raise ValueError("Failed to retrieve balance for ERC-721")
return balance > 0
elif contract_type == 'ERC-1155':
# Check if the NFT is in the wallet for ERC-1155
if token_id is None:
raise ValueError("token_id is required for ERC-1155")
balance = self._call_simple_function('balanceOf', wallet_address, token_id)
if balance is None:
raise ValueError("Failed to retrieve balance for ERC-1155")
return balance > 0
else:
raise ValueError("Unknown contract type")
@jatubio
Copy link
Author

jatubio commented Jul 25, 2024

Description

This Python script allows you to check if an NFT is present in a wallet on EVM-compatible blockchains. It supports both ERC-721 and ERC-1155 standards.

The core of the solution involves:

  • Using a Simple ABI: We utilize a simplified ABI that includes only the balanceOf function. This approach allows us to interact with both ERC-721 and ERC-1155 contracts with a single ABI definition.
  • Interface Detection: To determine whether a contract implements ERC-721 or ERC-1155, we use the supportsInterface function. This function checks if the contract supports specific interfaces by their unique identifier.

Sample of use:

from web3 import Web3

w3 = Web3(Web3.HTTPProvider("https://1rpc.io/base"))
contract_address_nft="0x2aa80a13395425ef3897c9684a0249a5226ea779"
wallet_address="0xEAa73d06320C1aCb1F7C947e1B6c5c9F326c2C3d"
nft_token_id=2

try:
    nftutils=NFTUtils(w3, contract_address_nft)
    return nftutils.is_nft_in_wallet(wallet_address, nft_token_id)
except ValueError as e:
    print(f'Error: {e}')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment