Merge pull request #139 from bugout-dev/smartcontract-source-info

Smartcontract source info
pull/154/head^2
Neeraj Kashyap 2021-08-23 09:09:03 -07:00 zatwierdzone przez GitHub
commit 9dfce91357
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
6 zmienionych plików z 102 dodań i 18 usunięć

Wyświetl plik

@ -17,8 +17,9 @@ from sqlalchemy.orm import Session
from . import data
from .settings import DEFAULT_STREAM_TIMEINTERVAL
from .settings import DEFAULT_STREAM_TIMEINTERVAL, ETHERSCAN_SMARTCONTRACTS_BUCKET
import boto3
import json
logger = logging.getLogger(__name__)
@ -263,6 +264,40 @@ 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":
object_uri = label.label_data["object_uri"]
key = object_uri.split("s3://etherscan-smart-contracts/")[1]
s3 = boto3.client("s3")
bucket = ETHERSCAN_SMARTCONTRACTS_BUCKET
try:
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
except:
logger.error(f"Failed to load smart contract {contract_address}")
return None
def get_address_labels(
db_session: Session, start: int, limit: int, addresses: Optional[List[str]] = None
) -> List[EthereumAddress]:

Wyświetl plik

@ -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)

Wyświetl plik

@ -8,6 +8,8 @@ end users.
import logging
from typing import Dict, Optional
from sqlalchemy.sql.expression import true
from fastapi import FastAPI, Depends, HTTPException, Query
from fastapi.middleware.cors import CORSMiddleware
from moonstreamdb.db import yield_db_session
@ -71,19 +73,22 @@ async def txinfo_ethereum_blockchain_handler(
logger.error(err)
response.errors.append("Could not decode ABI from the given input")
smart_contract = (
db_session.query(EthereumAddress)
.filter(EthereumAddress.transaction_hash == txinfo_request.tx.hash)
.one_or_none()
)
if smart_contract is not None:
response.smart_contract_address = smart_contract.address
if txinfo_request.tx.to_address is None:
# transaction is contract deployment:
if txinfo_request.tx.to_address is None:
response.is_smart_contract_deployment = True
smart_contract = (
db_session.query(EthereumAddress)
.filter(EthereumAddress.transaction_hash == txinfo_request.tx.hash)
.one_or_none()
)
if smart_contract is not None:
response.is_smart_contract_deployment = True
elif txinfo_request.tx.to_address == smart_contract.address:
response.is_smart_contract_call = True
else:
response.smart_contract_info = actions.get_source_code(
db_session, txinfo_request.tx.to_address
)
response.smart_contract_address = txinfo_request.tx.to_address
response.is_smart_contract_call = True
return response

Wyświetl plik

@ -41,3 +41,6 @@ for path in MOONSTREAM_OPENAPI_LIST:
DOCS_PATHS[f"/{path}/{DOCS_TARGET_PATH}/openapi.json"] = "GET"
DEFAULT_STREAM_TIMEINTERVAL = 5 * 60
# S3 Bucket
ETHERSCAN_SMARTCONTRACTS_BUCKET = "etherscan-smart-contracts"

Wyświetl plik

@ -0,0 +1,29 @@
import React from "react";
import {
VStack,
Code,
} from "@chakra-ui/react";
import { Table, Thead, Tbody, Tr, Th, Td } from "@chakra-ui/react";
const ContractSource = ({ source_info }) => {
return (
<VStack spacing={3}>
<Table>
<Thead>
<Tr>
<Th>Contract Name</Th>
<Th>Compiler version</Th>
</Tr>
</Thead>
<Tbody>
<Tr key={source_info.name}>
<Td>{source_info.name} </Td>
<Td>{source_info.compiler_version}</Td>
</Tr>
</Tbody>
</Table>
<Code colorScheme="blackAlpha" w="110%" >{source_info.source_code}</Code>
</VStack>)
}
export default ContractSource;

Wyświetl plik

@ -9,6 +9,7 @@ import {
Box,
VStack,
} from "@chakra-ui/react";
import ContractSource from './ContractSource'
import { Table, Thead, Tbody, Tr, Th, Td } from "@chakra-ui/react";
const toEth = (wei) => {
return wei / Math.pow(10, 18);
@ -94,10 +95,13 @@ const TxInfo = (props) => {
)}
</Tbody>
</Table>
{transaction.tx.input && transaction.tx.input !== "0x" && (
<TxABI byteCode={transaction.tx.input} abi={transaction.abi} />
)}
</Box>
{transaction.smart_contract_info && <ContractSource source_info={transaction.smart_contract_info} />}
{
transaction.tx.input && transaction.tx.input !== "0x" && (
<TxABI byteCode={transaction.tx.input} abi={transaction.abi} />
)
}
</Box >
);
};
export default TxInfo;