diff --git a/backend/moonstream/actions.py b/backend/moonstream/actions.py index 9ee8130d..05a61f56 100644 --- a/backend/moonstream/actions.py +++ b/backend/moonstream/actions.py @@ -18,7 +18,8 @@ from sqlalchemy.orm import Session from . import data from .settings import DEFAULT_STREAM_TIMEINTERVAL - +import boto3 +import json logger = logging.getLogger(__name__) @@ -263,6 +264,38 @@ def parse_search_query_to_sqlalchemy_filters(q: str, allowed_addresses: List[str return constructed_filters +def get_source_code( + db_session: Session, contract_address: str +) -> Optional[data.EthereumSmartContractSourceInfo]: + query = db_session.query(EthereumAddress.id).filter( + EthereumAddress.address == contract_address + ) + id = query.one_or_none() + if id is None: + return None + labels = ( + db_session.query(EthereumLabel).filter(EthereumLabel.address_id == id[0]).all() + ) + + for label in labels: + if label.label == "etherscan_smartcontract": + name = label.label_data["name"] + uri = label.label_data["object_uri"] + key = uri.split("s3://etherscan-smart-contracts/")[1] + s3 = boto3.client("s3") + bucket = "etherscan-smart-contracts" + raw_obj = s3.get_object(Bucket=bucket, Key=key) + obj_data = json.loads(raw_obj["Body"].read().decode("utf-8"))["data"] + contract_source_info = data.EthereumSmartContractSourceInfo( + name=obj_data["ContractName"], + source_code=obj_data["SourceCode"], + compiler_version=obj_data["CompilerVersion"], + abi=obj_data["ABI"], + ) + return contract_source_info + return None + + def get_address_labels( db_session: Session, start: int, limit: int, addresses: Optional[List[str]] = None ) -> List[EthereumAddress]: diff --git a/backend/moonstream/data.py b/backend/moonstream/data.py index 9f79adfa..93b8ecb0 100644 --- a/backend/moonstream/data.py +++ b/backend/moonstream/data.py @@ -133,11 +133,19 @@ class TxinfoEthereumBlockchainRequest(BaseModel): tx: EthereumTransaction +class EthereumSmartContractSourceInfo(BaseModel): + name: str + source_code: str + abi: str + compiler_version: str + + class TxinfoEthereumBlockchainResponse(BaseModel): tx: EthereumTransaction is_smart_contract_deployment: bool = False is_smart_contract_call: bool = False smart_contract_address: Optional[str] = None + smart_contract_info: Optional[EthereumSmartContractSourceInfo] = None abi: Optional[ContractABI] = None errors: List[str] = Field(default_factory=list) diff --git a/backend/moonstream/routes/txinfo.py b/backend/moonstream/routes/txinfo.py index 65377893..e352954a 100644 --- a/backend/moonstream/routes/txinfo.py +++ b/backend/moonstream/routes/txinfo.py @@ -71,11 +71,18 @@ async def txinfo_ethereum_blockchain_handler( logger.error(err) response.errors.append("Could not decode ABI from the given input") + # Checking if it is contract deployment: smart_contract = ( db_session.query(EthereumAddress) .filter(EthereumAddress.transaction_hash == txinfo_request.tx.hash) .one_or_none() ) + is_contract_deployment = smart_contract is not None + + if txinfo_request.tx.to_address: + response.smart_contract_info = actions.get_source_code( + db_session, txinfo_request.tx.to_address + ) if smart_contract is not None: response.smart_contract_address = smart_contract.address