Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to get token owner of a token account #206

Open
BillInUK opened this issue May 4, 2024 · 4 comments
Open

how to get token owner of a token account #206

BillInUK opened this issue May 4, 2024 · 4 comments

Comments

@BillInUK
Copy link

BillInUK commented May 4, 2024

I use the following code to get owner of token account, but returned me a program id 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'。

	rpcClient := rpc.New(RpcMainNet)
	tokenMintPubKey := solana.MPK(TokenMainNetAddress)
	tokenAccountPubKey := solana.MustPublicKeyFromBase58("3XRNhFEXkV7itJEJMDBN8iRHBgwhgk83XB5K3s3re3Ew")

	tokenAccountInfo, err := rpcClient.GetAccountInfo(context.Background(), tokenAccountPubKey)
	if err != nil {
		fmt.Printf("get account info error %v\n", err)
	}
	fmt.Printf("get token account owner %v\n", tokenAccountInfo.Value)

how can i get the token owner of this token account? like below:
image

@theghostmac
Copy link

theghostmac commented May 7, 2024

Here is how you do it @BillInUK:

package main

import (
	"context"
	"fmt"
	"github.com/gagliardetto/solana-go"
	"github.com/gagliardetto/solana-go/rpc"
)

func main() {
	rpcClient := rpc.New(rpc.MainNetBeta_RPC)
	tokenAccountPubKey := solana.MustPublicKeyFromBase58("3XRNhFEXkV7itJEJMDBN8iRHBgwhgk83XB5K3s3re3Ew")

	// Fetch account info
	accountInfo, err := rpcClient.GetAccountInfo(context.Background(), tokenAccountPubKey)
	if err != nil {
		fmt.Printf("Error retrieving account info: %v\n", err)
		return
	}

	owner := accountInfo.Value.Owner

	// Output the owner of the token account
	fmt.Printf("Token account owner: %v\n", owner.String())
	// OUTPUT: Token account owner: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA

	// Ensure that data is available
	if accountInfo.Value == nil || accountInfo.Value.Data.GetBinary() == nil {
		fmt.Println("Account data is not available")
		return
	}

	fmt.Println("Trying the second method...")

	data := accountInfo.Value.Data.GetBinary()

	// Check if data length is sufficient to contain Mint and Owner public keys
	if len(data) < 64 {
		fmt.Println("Account data is too short to contain required information")
		return
	}

	// Owner public key starts at byte 32 and spans 32 bytes
	ownerPubKey := solana.PublicKeyFromBytes(data[32:64])

	// Output the owner of the token account
	fmt.Printf("Token account owner from metadata: %v\n", ownerPubKey)
	// OUTPUT: Token account owner: GmKsGRytiVoeMZGmBVCWPcUzJGHVqcvzhP5K9cstdr3E
}

@BillInUK
Copy link
Author

thanks for your help, i will try it !!!

@BillInUK
Copy link
Author

BillInUK commented May 12, 2024

I implemented this functionality by defining my own structure to parse the results of GetAccountInfoWithOpts. The code is as follows:

const (
	SPLTokenProgramId = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
)

type SPLTokenAccountInfo struct {
	IsNative    bool             `json:"isNative"`
	Mint        solana.PublicKey `json:"mint"`
	Owner       solana.PublicKey `json:"owner"`
	State       string           `json:"state"`
	TokenAmount struct {
		Amount      string  `json:"amount"`
		Decimals    int     `json:"decimals"`
		UIAmount    float64 `json:"uiAmount"`
		UIAmountStr string  `json:"uiAmountString"`
	} `json:"tokenAmount"`
}

type SPLTokenAccountData struct {
	TokenAccountInfo SPLTokenAccountInfo `json:"info"`
	Type             string              `json:"type"`
}

type ParsedData struct {
	Parsed  SPLTokenAccountData `json:"parsed"`
	Program string              `json:"program"`
	Space   int                 `json:"space"`
}
func TestGetTokenAccountOwner(t *testing.T) {
	client := rpc.New(DevRpc)

	pubKey := solana.MustPublicKeyFromBase58("EgyMZLY7DrHpYgmQHCrQ8fXJCv7ekfBepxNNizMST9Dh")
	out, err := client.GetAccountInfoWithOpts(
		context.TODO(),
		pubKey,
		&rpc.GetAccountInfoOpts{
			Encoding: solana.EncodingJSONParsed,
		},
	)
	if err != nil {
		panic(err)
	}
	var parsedData ParsedData
	dataBytes, _ := out.Value.Data.MarshalJSON()
	fmt.Println(string(dataBytes))

	err = json.Unmarshal(dataBytes, &parsedData)
	if err != nil {
		fmt.Println("Error parsing JSON:", err)
		return
	}
	// Access parsed data
	fmt.Println("Type:", parsedData.Parsed.Type)
	fmt.Println("Program:", parsedData.Program)
	fmt.Println("Space:", parsedData.Space)
	fmt.Println("IsNative:", parsedData.Parsed.TokenAccountInfo.IsNative)
	fmt.Println("Mint:", parsedData.Parsed.TokenAccountInfo.Mint)
	fmt.Println("Owner:", parsedData.Parsed.TokenAccountInfo.Owner)
	fmt.Println("State:", parsedData.Parsed.TokenAccountInfo.State)
	fmt.Println("Amount:", parsedData.Parsed.TokenAccountInfo.TokenAmount.Amount)
	fmt.Println("Decimals:", parsedData.Parsed.TokenAccountInfo.TokenAmount.Decimals)
	fmt.Println("UIAmount:", parsedData.Parsed.TokenAccountInfo.TokenAmount.UIAmount)
	fmt.Println("UIAmountString:", parsedData.Parsed.TokenAccountInfo.TokenAmount.UIAmountStr)
}

@BillInUK BillInUK reopened this May 12, 2024
@BillInUK
Copy link
Author

Overall, the code you provided is simpler, avoiding unnecessary struct definitions and JSON parsing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants