kopia lustrzana https://github.com/bugout-dev/moonstream
Implemented /txinfo/ethereum_blockchain
This is an authentiated endpoint which currently returns decoded ABI information from input bytecode in an Ethereum transaction. In the future, we should add all transaction display enrichment code to this endpoint (for Ethereum blockchain transactions).pull/18/head
rodzic
c02fabe967
commit
b9aebfddf7
|
@ -9,6 +9,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||
from . import data
|
||||
from .routes.subscriptions import app as subscriptions_api
|
||||
from .routes.users import app as users_api
|
||||
from .routes.txinfo import app as txinfo_api
|
||||
from .settings import ORIGINS
|
||||
from .version import MOONSTREAM_VERSION
|
||||
|
||||
|
@ -38,3 +39,4 @@ async def version_handler() -> data.VersionResponse:
|
|||
|
||||
app.mount("/subscriptions", subscriptions_api)
|
||||
app.mount("/users", users_api)
|
||||
app.mount("/txinfo", txinfo_api)
|
||||
|
|
|
@ -88,3 +88,24 @@ class EVMEventSignature(BaseModel):
|
|||
class ContractABI(BaseModel):
|
||||
functions: List[EVMFunctionSignature]
|
||||
events: List[EVMEventSignature]
|
||||
|
||||
|
||||
class EthereumTransaction(BaseModel):
|
||||
gas: int
|
||||
gasPrice: int
|
||||
value: int
|
||||
from_address: str = Field(alias="from")
|
||||
to_address: Optional[str] = Field(default=None, alias="to")
|
||||
hash: Optional[str] = None
|
||||
input: Optional[str] = None
|
||||
|
||||
|
||||
class TxinfoEthereumBlockchainRequest(BaseModel):
|
||||
tx: EthereumTransaction
|
||||
|
||||
|
||||
class TxinfoEthereumBlockchainResponse(BaseModel):
|
||||
tx: EthereumTransaction
|
||||
abi: Optional[ContractABI] = None
|
||||
errors: List[str] = Field(default_factory=list)
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
"""
|
||||
Moonstream's /txinfo endpoints.
|
||||
|
||||
These endpoints enrich raw blockchain transactions (as well as pending transactions, hypothetical
|
||||
transactions, etc.) with side information and return objects that are better suited for displaying to
|
||||
end users.
|
||||
"""
|
||||
import logging
|
||||
from typing import Any, Dict
|
||||
|
||||
from fastapi import (
|
||||
FastAPI,
|
||||
Depends,
|
||||
HTTPException,
|
||||
Request,
|
||||
)
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from moonstreamdb.db import yield_db_session
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..abi_decoder import decode_abi
|
||||
from ..data import TxinfoEthereumBlockchainRequest, TxinfoEthereumBlockchainResponse
|
||||
from ..middleware import BroodAuthMiddleware
|
||||
from ..settings import (
|
||||
MOONSTREAM_APPLICATION_ID,
|
||||
DOCS_TARGET_PATH,
|
||||
ORIGINS,
|
||||
DOCS_PATHS,
|
||||
bugout_client as bc,
|
||||
)
|
||||
from ..version import MOONSTREAM_VERSION
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
tags_metadata = [
|
||||
{"name": "users", "description": "Operations with users."},
|
||||
{"name": "tokens", "description": "Operations with user tokens."},
|
||||
]
|
||||
|
||||
app = FastAPI(
|
||||
title=f"Moonstream users API.",
|
||||
description="User, token and password handlers.",
|
||||
version=MOONSTREAM_VERSION,
|
||||
openapi_tags=tags_metadata,
|
||||
openapi_url="/openapi.json",
|
||||
docs_url=None,
|
||||
redoc_url=f"/{DOCS_TARGET_PATH}",
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=ORIGINS,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
whitelist_paths: Dict[str, str] = {}
|
||||
whitelist_paths.update(DOCS_PATHS)
|
||||
app.add_middleware(BroodAuthMiddleware, whitelist=whitelist_paths)
|
||||
|
||||
|
||||
@app.post(
|
||||
"/ethereum_blockchain",
|
||||
tags=["txinfo"],
|
||||
response_model=TxinfoEthereumBlockchainResponse,
|
||||
)
|
||||
async def txinfo_ethereum_blockchain_handler(
|
||||
txinfo_request: TxinfoEthereumBlockchainRequest,
|
||||
db_session: Session = Depends(yield_db_session),
|
||||
) -> TxinfoEthereumBlockchainResponse:
|
||||
response = TxinfoEthereumBlockchainResponse(tx=txinfo_request.tx)
|
||||
if txinfo_request.tx.input is not None:
|
||||
try:
|
||||
response.abi = decode_abi(txinfo_request.tx.input, db_session)
|
||||
except Exception as err:
|
||||
logger.error(r"Could not decode ABI:")
|
||||
logger.error(err)
|
||||
response.errors.append("Could not decode ABI from the given input")
|
||||
return response
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
TIMESTAMP="$(date +%s)"
|
||||
SCRIPT_DIR=$(realpath $(dirname $0))
|
||||
|
||||
API_URL="${MOONSTREAM_DEV_API_URL:-http://localhost:7481}"
|
||||
|
||||
MOONSTREAM_USERNAME="devuser_$TIMESTAMP"
|
||||
MOONSTREAM_PASSWORD="peppercat"
|
||||
MOONSTREAM_EMAIL="devuser_$TIMESTAMP@example.com"
|
||||
|
||||
OUTPUT_DIR=$(mktemp -d)
|
||||
echo "Writing responses to directory: $OUTPUT_DIR"
|
||||
|
||||
# Create a new user
|
||||
curl -X POST \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
"$API_URL/users/" \
|
||||
-F "username=$MOONSTREAM_USERNAME" \
|
||||
-F "password=$MOONSTREAM_PASSWORD" \
|
||||
-F "email=$MOONSTREAM_EMAIL" \
|
||||
-o $OUTPUT_DIR/user.json
|
||||
|
||||
# Create a token for this user
|
||||
curl -X POST \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
"$API_URL/users/token" \
|
||||
-F "username=$MOONSTREAM_USERNAME" \
|
||||
-F "password=$MOONSTREAM_PASSWORD" \
|
||||
-o $OUTPUT_DIR/token.json
|
||||
|
||||
API_TOKEN=$(jq -r '.id' $OUTPUT_DIR/token.json)
|
||||
|
||||
set -e
|
||||
|
||||
ETHEREUM_TXINFO_REQUEST_BODY_JSON=$(jq -r . $SCRIPT_DIR/txinfo_ethereum_blockchain_request.json)
|
||||
curl -f -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $API_TOKEN" \
|
||||
"$API_URL/txinfo/ethereum_blockchain" \
|
||||
-d "$ETHEREUM_TXINFO_REQUEST_BODY_JSON" \
|
||||
-o $OUTPUT_DIR/txinfo_response.json
|
||||
|
||||
echo "Response:"
|
||||
jq . $OUTPUT_DIR/txinfo_response.json
|
||||
|
||||
if [ "$DEBUG" != true ]
|
||||
then
|
||||
echo "Deleting output directory: $OUTPUT_DIR"
|
||||
echo "Please set DEBUG=true if you would prefer to retain this directory in the future"
|
||||
rm -r $OUTPUT_DIR
|
||||
fi
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"tx": {
|
||||
"to": null,
|
||||
"from": "0x2E337E0Fb68F5e51ce9295E80BCd02273d7420c4",
|
||||
"gas": 2265656,
|
||||
"gasPrice": 1000000000,
|
||||
"hash": "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
|
||||
"value": 0,
|
||||
"input": "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca"
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue