diff --git a/backend/moonstream/actions.py b/backend/moonstream/actions.py index 1c786e9b..112fc36e 100644 --- a/backend/moonstream/actions.py +++ b/backend/moonstream/actions.py @@ -64,6 +64,7 @@ def get_contract_source_info( class LabelNames(Enum): ETHERSCAN_SMARTCONTRACT = "etherscan_smartcontract" COINMARKETCAP_TOKEN = "coinmarketcap_token" + ERC721 = "erc721" def get_ethereum_address_info( @@ -78,6 +79,7 @@ def get_ethereum_address_info( address_info = data.EthereumAddressInfo(address=address) etherscan_address_url = f"https://etherscan.io/address/{address}" + etherscan_token_url = f"https://etherscan.io/token/{address}" blockchain_com_url = f"https://www.blockchain.com/eth/address/{address}" # Checking for token: coinmarketcap_label: Optional[EthereumLabel] = ( @@ -94,7 +96,7 @@ def get_ethereum_address_info( symbol=coinmarketcap_label.label_data["symbol"], external_url=[ coinmarketcap_label.label_data["coinmarketcap_url"], - etherscan_address_url, + etherscan_token_url, blockchain_com_url, ], ) @@ -114,6 +116,23 @@ def get_ethereum_address_info( external_url=[etherscan_address_url, blockchain_com_url], ) + # Checking for NFT + # Checking for smart contract + erc721_label: Optional[EthereumLabel] = ( + db_session.query(EthereumLabel) + .filter(EthereumLabel.address_id == id[0]) + .filter(EthereumLabel.label == LabelNames.ERC721.value) + .order_by(text("created_at desc")) + .limit(1) + .one_or_none() + ) + if erc721_label is not None: + address_info.nft = data.EthereumNFTDetails( + name=erc721_label.label_data.get("name"), + symbol=erc721_label.label_data.get("symbol"), + total_supply=erc721_label.label_data.get("totalSupply"), + external_url=[etherscan_token_url, blockchain_com_url], + ) return address_info diff --git a/backend/moonstream/data.py b/backend/moonstream/data.py index ceb496e3..05e49ea2 100644 --- a/backend/moonstream/data.py +++ b/backend/moonstream/data.py @@ -3,6 +3,7 @@ Pydantic schemas for the Moonstream HTTP API """ from typing import List, Optional, Dict, Any + from pydantic import BaseModel, Field from datetime import datetime @@ -164,20 +165,25 @@ class EthereumSmartContractSourceInfo(BaseModel): class EthereumTokenDetails(BaseModel): - name: Optional[str] - symbol: Optional[str] - external_url: List[str] = [] + name: Optional[str] = None + symbol: Optional[str] = None + external_url: List[str] = Field(default_factory=list) class EthereumSmartContractDetails(BaseModel): - name: Optional[str] - external_url: List[str] = [] + name: Optional[str] = None + external_url: List[str] = Field(default_factory=list) + + +class EthereumNFTDetails(EthereumTokenDetails): + total_supply: Optional[int] = None class EthereumAddressInfo(BaseModel): address: str - token: Optional[EthereumTokenDetails] - smart_contract: Optional[EthereumSmartContractDetails] + token: Optional[EthereumTokenDetails] = None + smart_contract: Optional[EthereumSmartContractDetails] = None + nft: Optional[EthereumNFTDetails] = None class TxinfoEthereumBlockchainResponse(BaseModel): diff --git a/backend/moonstream/routes/address_info.py b/backend/moonstream/routes/address_info.py index c985c683..a2bcbf65 100644 --- a/backend/moonstream/routes/address_info.py +++ b/backend/moonstream/routes/address_info.py @@ -53,7 +53,11 @@ async def addressinfo_handler( address: str, db_session: Session = Depends(yield_db_session), ) -> Optional[data.EthereumAddressInfo]: - response = actions.get_ethereum_address_info(db_session, address) + try: + response = actions.get_ethereum_address_info(db_session, address) + except Exception as e: + logger.error(f"Unable to get info about Ethereum address {e}") + raise MoonstreamHTTPException(status_code=500, internal_error=e) return response