Commit 88a06467 authored by Will Cory's avatar Will Cory

chore: Clena up file structure

chore: linter

fix: Better error handling
parent 9aa29eff
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