kopia lustrzana https://github.com/bugout-dev/moonstream
Merge pull request #139 from bugout-dev/smartcontract-source-info
Smartcontract source infopull/154/head^2
commit
9dfce91357
|
@ -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]:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
Ładowanie…
Reference in New Issue