只需要 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)
}