Commit 2919e783 authored by Will Cory's avatar Will Cory

comments move handlers to routes, cleaner way of sharing context, clean up...

comments move handlers to routes, cleaner way of sharing context, clean up schema with tx and blocks
parent 88a06467
package handlers
import (
"encoding/json"
"net/http"
"github.com/ethereum/go-ethereum/log"
)
// lazily typing numbers fixme
type Transaction struct {
Timestamp uint64 `json:"timestamp"`
BlockNumber int64 `json:"number"` // viem treats me as a BigInt maybe consider just stringing me too. Not 100% necessary though
BlockHash string `json:"hash"`
TransactionHash string `json:"transactionHash"`
// TODO maybe include me
// ParentBlockHash string `json:"parentHash"`
}
type Extensions struct {
OptimismBridgeAddress string `json:"OptimismBridgeAddress"`
}
type TokenInfo struct {
// TODO lazily typing ints go through them all with fine tooth comb once api is up
ChainId int `json:"chainId"`
Address string `json:"address"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals int `json:"decimals"`
LogoURI string `json:"logoURI"`
Extensions Extensions `json:"extensions"`
}
func jsonResponse(w http.ResponseWriter, logger log.Logger, data interface{}, statusCode int) {
w.Header().Set("Content-Type", "application/json")
jsonData, err := json.Marshal(data)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
logger.Error("Failed to marshal JSON: %v", err)
return
}
w.WriteHeader(statusCode)
_, err = w.Write(jsonData)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
logger.Error("Failed to write JSON data", err)
return
}
}
package handlers
import (
"net/http"
"github.com/ethereum-optimism/optimism/indexer/api/middleware"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum/go-ethereum/common"
"github.com/go-chi/chi/v5"
)
type DepositItem struct {
Guid string `json:"guid"`
From string `json:"from"`
To string `json:"to"`
// TODO could consider OriginTx to be more generic to handling L2 to L2 deposits
// this seems more clear today though
Tx Transaction `json:"Block"`
Amount string `json:"amount"`
L1Token TokenInfo `json:"l1Token"`
L2Token TokenInfo `json:"l2Token"`
}
type DepositResponse struct {
Cursor string `json:"cursor"`
HasNextPage bool `json:"hasNextPage"`
Items []DepositItem `json:"items"`
}
// TODO this is original spec but maybe include the l2 block info too for the relayed tx
func newDepositResponse(deposits []*database.L1BridgeDepositWithTransactionHashes) DepositResponse {
var items []DepositItem
for _, deposit := range deposits {
item := DepositItem{
Guid: deposit.L1BridgeDeposit.TransactionSourceHash.String(),
Tx: Transaction{
BlockNumber: 420420, // TODO
BlockHash: "0x420", // TODO
TransactionHash: "0x420", // TODO
Timestamp: deposit.L1BridgeDeposit.Tx.Timestamp,
},
From: deposit.L1BridgeDeposit.Tx.FromAddress.String(),
To: deposit.L1BridgeDeposit.Tx.ToAddress.String(),
Amount: deposit.L1BridgeDeposit.Tx.Amount.Int.String(),
L1Token: TokenInfo{
ChainId: 1,
Address: deposit.L1BridgeDeposit.TokenPair.L1TokenAddress.String(),
Name: "TODO",
Symbol: "TODO",
Decimals: 420,
LogoURI: "TODO",
Extensions: Extensions{
OptimismBridgeAddress: "0x420", // TODO
},
},
L2Token: TokenInfo{
ChainId: 10,
Address: deposit.L1BridgeDeposit.TokenPair.L2TokenAddress.String(),
Name: "TODO",
Symbol: "TODO",
Decimals: 420,
LogoURI: "TODO",
Extensions: Extensions{
OptimismBridgeAddress: "0x420", // TODO
},
},
}
items = append(items, item)
}
return DepositResponse{
Cursor: "42042042-4204-4204-4204-420420420420", // TODO
HasNextPage: false, // TODO
Items: items,
}
}
func L1DepositsHandler(w http.ResponseWriter, r *http.Request) {
btv := middleware.GetBridgeTransfersView(r.Context())
logger := middleware.GetLogger(r.Context())
address := common.HexToAddress(chi.URLParam(r, "address"))
deposits, err := btv.L1BridgeDepositsByAddress(address)
if err != nil {
http.Error(w, "Internal server error reading deposits", http.StatusInternalServerError)
logger.Error("Unable to read deposits from DB")
logger.Error(err.Error())
}
response := newDepositResponse(deposits)
jsonResponse(w, logger, response, http.StatusOK)
}
package handlers
import (
"net/http"
"github.com/ethereum-optimism/optimism/indexer/api/middleware"
)
func HealthzHandler(w http.ResponseWriter, r *http.Request) {
logger := middleware.GetLogger(r.Context())
jsonResponse(w, logger, "ok", http.StatusOK)
}
package handlers
import (
"net/http"
"github.com/ethereum-optimism/optimism/indexer/api/middleware"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum/go-ethereum/common"
"github.com/go-chi/chi/v5"
)
type Proof struct {
TransactionHash string `json:"transactionHash"`
BlockTimestamp uint64 `json:"blockTimestamp"`
BlockNumber int `json:"blockNumber"`
}
type Claim struct {
TransactionHash string `json:"transactionHash"`
BlockTimestamp uint64 `json:"blockTimestamp"`
BlockNumber int `json:"blockNumber"`
}
type WithdrawalItem struct {
Guid string `json:"guid"`
BlockTimestamp uint64 `json:"blockTimestamp"`
From string `json:"from"`
To string `json:"to"`
TransactionHash string `json:"transactionHash"`
Amount string `json:"amount"`
BlockNumber int `json:"blockNumber"`
Proof Proof `json:"proof"`
Claim Claim `json:"claim"`
WithdrawalState string `json:"withdrawalState"`
L1Token TokenInfo `json:"l1Token"`
L2Token TokenInfo `json:"l2Token"`
}
type WithdrawalResponse struct {
Cursor string `json:"cursor"`
HasNextPage bool `json:"hasNextPage"`
Items []WithdrawalItem `json:"items"`
}
func newWithdrawalResponse(withdrawals []*database.L2BridgeWithdrawalWithTransactionHashes) WithdrawalResponse {
var items []WithdrawalItem
for _, withdrawal := range withdrawals {
item := WithdrawalItem{
Guid: withdrawal.L2BridgeWithdrawal.TransactionWithdrawalHash.String(),
BlockTimestamp: withdrawal.L2BridgeWithdrawal.Tx.Timestamp,
From: withdrawal.L2BridgeWithdrawal.Tx.FromAddress.String(),
To: withdrawal.L2BridgeWithdrawal.Tx.ToAddress.String(),
TransactionHash: withdrawal.L2TransactionHash.String(),
Amount: withdrawal.L2BridgeWithdrawal.Tx.Amount.Int.String(),
BlockNumber: 420, // TODO
Proof: Proof{
TransactionHash: withdrawal.ProvenL1TransactionHash.String(),
BlockTimestamp: withdrawal.L2BridgeWithdrawal.Tx.Timestamp,
BlockNumber: 420, // TODO Block struct instead
},
Claim: Claim{
TransactionHash: withdrawal.FinalizedL1TransactionHash.String(),
BlockTimestamp: withdrawal.L2BridgeWithdrawal.Tx.Timestamp, // Using L2 timestamp for now, might need adjustment
BlockNumber: 420, // TODO block struct
},
WithdrawalState: "COMPLETE", // TODO
L1Token: TokenInfo{
ChainId: 1,
Address: withdrawal.L2BridgeWithdrawal.TokenPair.L1TokenAddress.String(),
Name: "Example", // TODO
Symbol: "EXAMPLE", // TODO
Decimals: 18, // TODO
LogoURI: "https://ethereum-optimism.github.io/data/OP/logo.svg", // TODO
Extensions: Extensions{
OptimismBridgeAddress: "0x636Af16bf2f682dD3109e60102b8E1A089FedAa8",
},
},
L2Token: TokenInfo{
ChainId: 10,
Address: withdrawal.L2BridgeWithdrawal.TokenPair.L2TokenAddress.String(),
Name: "Example", // TODO
Symbol: "EXAMPLE", // TODO
Decimals: 18, // TODO
LogoURI: "https://ethereum-optimism.github.io/data/OP/logo.svg", // TODO
Extensions: Extensions{
OptimismBridgeAddress: "0x36Af16bf2f682dD3109e60102b8E1A089FedAa86",
},
},
}
items = append(items, item)
}
return WithdrawalResponse{
Cursor: "42042042-0420-4204-2042-420420420420", // TODO
HasNextPage: true, // TODO
Items: items,
}
}
func L2WithdrawalsHandler(w http.ResponseWriter, r *http.Request) {
btv := middleware.GetBridgeTransfersView(r.Context())
logger := middleware.GetLogger(r.Context())
address := common.HexToAddress(chi.URLParam(r, "address"))
withdrawals, err := btv.L2BridgeWithdrawalsByAddress(address)
if err != nil {
http.Error(w, "Internal server error fetching withdrawals", http.StatusInternalServerError)
logger.Error("Unable to read deposits from DB")
logger.Error(err.Error())
return
}
response := newWithdrawalResponse(withdrawals)
jsonResponse(w, logger, response, http.StatusOK)
}
package middleware
import (
"context"
"net/http"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum/go-ethereum/log"
)
type contextKey string
const (
loggerKey contextKey = "logger"
bridgeTransfersViewKey contextKey = "bridgeTransfersView"
)
// Setters
func setLogger(ctx context.Context, logger log.Logger) context.Context {
return context.WithValue(ctx, loggerKey, logger)
}
func setBridgeTransfersView(ctx context.Context, bv database.BridgeTransfersView) context.Context {
return context.WithValue(ctx, bridgeTransfersViewKey, bv)
}
// Getters
func GetLogger(ctx context.Context) log.Logger {
logger, ok := ctx.Value(loggerKey).(log.Logger)
if !ok {
panic("Logger not found in context!")
}
return logger
}
func GetBridgeTransfersView(ctx context.Context) database.BridgeTransfersView {
bv, ok := ctx.Value(bridgeTransfersViewKey).(database.BridgeTransfersView)
if !ok {
panic("BridgeTransfersView not found in context!")
}
return bv
}
func ContextMiddleware(logger log.Logger, bv database.BridgeTransfersView) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := setLogger(r.Context(), logger)
ctx = setBridgeTransfersView(ctx, bv)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment