mirror of
https://github.com/alexgo-io/gaze-indexer.git
synced 2026-01-12 22:43:22 +08:00
feat: implement get balances by address batch
This commit is contained in:
@@ -88,23 +88,13 @@ func (h *HttpHandler) GetBalancesByAddress(ctx *fiber.Ctx) (err error) {
|
||||
|
||||
balanceList := make([]balance, 0, len(balances))
|
||||
for id, b := range balances {
|
||||
var name string
|
||||
var symbol rune
|
||||
var decimal uint8
|
||||
if runeEntry, ok := runeEntries[id]; ok {
|
||||
name = runeEntry.SpacedRune.String()
|
||||
symbol = runeEntry.Symbol
|
||||
decimal = runeEntry.Divisibility
|
||||
}
|
||||
if symbol == 0 {
|
||||
symbol = '¤'
|
||||
}
|
||||
runeEntry := runeEntries[id]
|
||||
balanceList = append(balanceList, balance{
|
||||
Amount: b.Amount.String(),
|
||||
Id: id.String(),
|
||||
Name: name,
|
||||
Symbol: string(symbol),
|
||||
Decimals: decimal,
|
||||
Name: runeEntry.SpacedRune.String(),
|
||||
Symbol: string(runeEntry.Symbol),
|
||||
Decimals: runeEntry.Divisibility,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
145
modules/runes/api/httphandler/get_balances_by_address_batch.go
Normal file
145
modules/runes/api/httphandler/get_balances_by_address_batch.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package httphandler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/gaze-network/indexer-network/common/errs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type getBalanceQuery struct {
|
||||
Wallet string `json:"wallet"`
|
||||
Id string `json:"id"`
|
||||
BlockHeight uint64 `json:"blockHeight"`
|
||||
}
|
||||
|
||||
type getBalancesByAddressBatchRequest struct {
|
||||
Queries []getBalanceQuery `json:"queries"`
|
||||
}
|
||||
|
||||
func (r getBalancesByAddressBatchRequest) Validate() error {
|
||||
var errList []error
|
||||
for _, query := range r.Queries {
|
||||
if query.Wallet == "" {
|
||||
errList = append(errList, errors.Errorf("queries[%d]: 'wallet' is required"))
|
||||
}
|
||||
if query.Id != "" && !isRuneIdOrRuneName(query.Id) {
|
||||
errList = append(errList, errors.Errorf("queries[%d]: 'id' is not valid rune id or rune name"))
|
||||
}
|
||||
}
|
||||
return errs.WithPublicMessage(errors.Join(errList...), "validation error")
|
||||
}
|
||||
|
||||
type getBalancesByAddressBatchResult struct {
|
||||
List []*getBalancesByAddressResult `json:"list"`
|
||||
}
|
||||
|
||||
type getBalancesByAddressBatchResponse = HttpResponse[getBalancesByAddressBatchResult]
|
||||
|
||||
func (h *HttpHandler) GetBalancesByAddressBatch(ctx *fiber.Ctx) (err error) {
|
||||
var req getBalancesByAddressBatchRequest
|
||||
if err := ctx.BodyParser(&req); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if err := req.Validate(); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
var latestBlockHeight uint64
|
||||
blockHeader, err := h.usecase.GetLatestBlock(ctx.UserContext())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error during GetLatestBlock")
|
||||
}
|
||||
latestBlockHeight = uint64(blockHeader.Height)
|
||||
|
||||
processQuery := func(ctx context.Context, query getBalanceQuery, queryIndex int) (*getBalancesByAddressResult, error) {
|
||||
pkScript, ok := resolvePkScript(h.network, query.Wallet)
|
||||
if !ok {
|
||||
return nil, errs.NewPublicError(fmt.Sprintf("unable to resolve pkscript from \"queries[%d].wallet\"", queryIndex))
|
||||
}
|
||||
|
||||
blockHeight := query.BlockHeight
|
||||
if blockHeight == 0 {
|
||||
blockHeight = latestBlockHeight
|
||||
}
|
||||
|
||||
balances, err := h.usecase.GetBalancesByPkScript(ctx, pkScript, blockHeight)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error during GetBalancesByPkScript")
|
||||
}
|
||||
|
||||
runeId, ok := h.resolveRuneId(ctx, query.Id)
|
||||
if ok {
|
||||
// filter out balances that don't match the requested rune id
|
||||
for key := range balances {
|
||||
if key != runeId {
|
||||
delete(balances, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
balanceRuneIds := lo.Keys(balances)
|
||||
runeEntries, err := h.usecase.GetRuneEntryByRuneIdBatch(ctx, balanceRuneIds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error during GetRuneEntryByRuneIdBatch")
|
||||
}
|
||||
|
||||
balanceList := make([]balance, 0, len(balances))
|
||||
for id, b := range balances {
|
||||
var name string
|
||||
var symbol rune
|
||||
var decimal uint8
|
||||
if runeEntry, ok := runeEntries[id]; ok {
|
||||
name = runeEntry.SpacedRune.String()
|
||||
symbol = runeEntry.Symbol
|
||||
decimal = runeEntry.Divisibility
|
||||
}
|
||||
if symbol == 0 {
|
||||
symbol = '¤'
|
||||
}
|
||||
balanceList = append(balanceList, balance{
|
||||
Amount: b.Amount.String(),
|
||||
Id: id.String(),
|
||||
Name: name,
|
||||
Symbol: string(symbol),
|
||||
Decimals: decimal,
|
||||
})
|
||||
}
|
||||
|
||||
result := getBalancesByAddressResult{
|
||||
BlockHeight: blockHeight,
|
||||
List: balanceList,
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
results := make([]*getBalancesByAddressResult, len(req.Queries))
|
||||
eg, ectx := errgroup.WithContext(ctx.UserContext())
|
||||
for i, query := range req.Queries {
|
||||
i := i
|
||||
query := query
|
||||
eg.Go(func() error {
|
||||
result, err := processQuery(ectx, query, i)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error during processQuery for query %d", i)
|
||||
}
|
||||
results[i] = result
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
resp := getBalancesByAddressBatchResponse{
|
||||
Result: &getBalancesByAddressBatchResult{
|
||||
List: results,
|
||||
},
|
||||
}
|
||||
|
||||
return errors.WithStack(ctx.JSON(resp))
|
||||
}
|
||||
@@ -94,9 +94,6 @@ type getTransactionsResponse = HttpResponse[getTransactionsResult]
|
||||
|
||||
func (h *HttpHandler) GetTransactions(ctx *fiber.Ctx) (err error) {
|
||||
var req getTransactionsRequest
|
||||
if err := ctx.ParamsParser(&req); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if err := ctx.QueryParser(&req); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
@@ -101,12 +101,13 @@ func (h *HttpHandler) GetUTXOsByAddress(ctx *fiber.Ctx) (err error) {
|
||||
for outPoint, balances := range groupedBalances {
|
||||
runeBalances := make([]runeBalance, 0, len(balances))
|
||||
for _, balance := range balances {
|
||||
runeEntry := runeEntries[balance.RuneId]
|
||||
runeBalances = append(runeBalances, runeBalance{
|
||||
RuneId: balance.RuneId,
|
||||
Rune: runeEntries[balance.RuneId].SpacedRune,
|
||||
Symbol: string(runeEntries[balance.RuneId].Symbol),
|
||||
Rune: runeEntry.SpacedRune,
|
||||
Symbol: string(runeEntry.Symbol),
|
||||
Amount: balance.Amount,
|
||||
Divisibility: runeEntries[balance.RuneId].Divisibility,
|
||||
Divisibility: runeEntry.Divisibility,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
func (h *HttpHandler) Mount(router fiber.Router) error {
|
||||
r := router.Group("/v2/runes")
|
||||
|
||||
r.Post("/balances/wallet/batch", h.GetBalancesByAddressBatch)
|
||||
r.Get("/balances/wallet/:wallet", h.GetBalancesByAddress)
|
||||
r.Get("/transactions", h.GetTransactions)
|
||||
r.Get("/holders/:id", h.GetHolders)
|
||||
|
||||
Reference in New Issue
Block a user