文章/教程 rpc 批量请求某地址所有 token 价格和钱包余额

wuaoxiang · 2024年10月08日 · 95 次阅读

只需要 2 次 HTTP 请求就实现批量查余额和批量询价 类似幻影钱包的功能

RAY 1.7363*25.3996=44.101$
MEW 0.0068*870.0655=5.907$
USDC 0.9997*779.6599=779.393$
SLERF 0.1427*28.4659=4.061$
POPCAT 1.1863*0.6269=0.744$
USDT 1.0000*198.3104=198.314$
SOL 142.6512*0.0085=1.213$
walletEquity = 1033.733

solana go 客户端的例子不是很全,我自己摸索了下给出完整实例分享给大家

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "math"
    "net/http"
    "strconv"
    "strings"

    bin "github.com/gagliardetto/binary"
    token_metadata "github.com/gagliardetto/metaplex-go/clients/token-metadata"
    "github.com/gagliardetto/solana-go"
    "github.com/gagliardetto/solana-go/programs/token"
    "github.com/gagliardetto/solana-go/rpc"
)

type soltokenctx struct {
    mint      token.Mint
    metadata  token_metadata.Metadata
    myaccount token.Account
    price     float64
    uiamount  float64
}

type jupprice struct {
    Data map[string]struct {
        Id    solana.PublicKey
        Price string
    }
}

func main() {
    walletEquity := 0.
    ctx := context.Background()
    solClient := rpc.New("https://api.mainnet-beta.solana.com")
    addr := solana.MustPublicKeyFromBase58("GhyfPX5JMfb2HjvbvfRihm9hoPZP8e3VZ8fGfu2fFafK")
    accounts, err := solClient.GetTokenAccountsByOwner(ctx, addr, &rpc.GetTokenAccountsConfig{
        ProgramId: &solana.TokenProgramID,
    }, nil)
    if err != nil {
        log.Fatalln(err)
    }
    mints := make([]solana.PublicKey, 0)
    metadatas := make([]solana.PublicKey, 0)
    myaccounts := make([]*soltokenctx, 0)
    for _, each := range accounts.Value {
        var myaccount token.Account
        err := myaccount.UnmarshalWithDecoder(bin.NewBinDecoder(each.Account.Data.GetBinary()))
        if err != nil {
            log.Fatalln(err)
        }
        if myaccount.Amount == 0 {
            continue
        }
        metadata, _, err := solana.FindTokenMetadataAddress(myaccount.Mint)
        if err != nil {
            log.Fatalln(err)
        }
        mints = append(mints, myaccount.Mint)
        metadatas = append(metadatas, metadata)
        myaccounts = append(myaccounts, &soltokenctx{
            myaccount: myaccount,
        })
    }
    tokenmints, err := solClient.GetMultipleAccounts(ctx, append(mints, metadatas...)...)
    if err != nil {
        log.Fatalln(err)
    }
    length := len(mints)
    for i := 0; i < length; i++ {
        mintbytes := tokenmints.Value[i].Data.GetBinary()
        var mint token.Mint
        err := mint.UnmarshalWithDecoder(bin.NewBinDecoder(mintbytes))
        if err != nil {
            log.Fatalln(err)
        }
        myaccounts[i].mint = mint

        metadatabytes := tokenmints.Value[i+length].Data.GetBinary()
        // log.Println(len(metadatabytes), unsafe.Sizeof(token_metadata.Metadata{}))
        var metadata token_metadata.Metadata
        metadata.UnmarshalWithDecoder(bin.NewBorshDecoder(metadatabytes))
        myaccounts[i].metadata = metadata
    }
    jupapi := "https://api.jup.ag/price/v2?ids="
    for i, each := range mints {
        if i > 0 {
            jupapi += ","
        }
        jupapi += each.String()
    }
    resp, err := http.Get(jupapi)
    if err != nil {
        log.Fatalln(err)
    }
    defer resp.Body.Close()
    respBody, err := io.ReadAll(resp.Body)
    if err != nil {
        log.Fatalln(err)
    }
    var r jupprice
    err = json.Unmarshal(respBody, &r)
    if err != nil {
        log.Fatalln(err)
    }
    for _, each := range r.Data {
        for _, acc := range myaccounts {
            if acc.myaccount.Mint == each.Id {
                price, err := strconv.ParseFloat(each.Price, 64)
                if err != nil {
                    log.Fatalln(err)
                }
                acc.price = price
                acc.uiamount = float64(acc.myaccount.Amount) / math.Pow10(int(acc.mint.Decimals))
                namewithnul := acc.metadata.Data.Symbol
                name := namewithnul[:strings.IndexByte(namewithnul, '\x00')]
                // Symbol: (string) (len=10) "POPCAT\x00\x00\x00\x00",
                // 有没有必要隐藏小额资产...
                value := price * acc.uiamount
                walletEquity += value
                fmt.Printf("%s %.4f*%.4f=%.3f$\n", name, price, acc.uiamount, value)
                break
            }
        }
    }
    fmt.Printf("walletEquity = %.3f\n", walletEquity)
}

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号