Open scottywm opened 2 years ago
Old question but could be useful to someone
import (
"context"
"fmt"
"math"
"strconv"
"github.com/gagliardetto/solana-go"
associatedtokenaccount "github.com/gagliardetto/solana-go/programs/associated-token-account"
"github.com/gagliardetto/solana-go/programs/token"
"github.com/gagliardetto/solana-go/rpc"
)
func tokenTransfer(sender solana.PrivateKey, receiver solana.PublicKey, tokenMint solana.PublicKey) (solana.Signature, error) {
httpClient := rpc.New(rpc.DevNet_RPC)
ixs := []solana.Instruction{}
tokenAta := solana.PublicKey{}
//get list of ata associated to the token mint address
atas, err := httpClient.GetTokenAccountsByOwner(
context.TODO(),
receiver,
&rpc.GetTokenAccountsConfig{
Mint: &tokenMint,
},
&rpc.GetTokenAccountsOpts{})
//create new ata if none found
if err != nil || len(atas.Value) == 0 {
if err != nil {
panic(err)
}
ix, err := associatedtokenaccount.NewCreateInstruction(
sender.PublicKey(),
receiver,
tokenMint).ValidateAndBuild()
if err != nil {
panic(err)
}
ixs = append(ixs, ix)
tokenAta = ix.Accounts()[1].PublicKey
} else {
//if token atas found i just get the first one
tokenAta = atas.Value[0].Pubkey
}
//transfer instruction
amount := uint64(10 * math.Pow10(9)) //Sending n10 tokens of a token that has 9 decimals
fromAccountAtas, err := httpClient.GetTokenAccountsByOwner(
context.TODO(),
sender.PublicKey(),
&rpc.GetTokenAccountsConfig{
Mint: &tokenMint,
},
&rpc.GetTokenAccountsOpts{})
if err != nil {
panic(err)
}
if len(fromAccountAtas.Value) == 0 {
panic(fmt.Errorf("sender does not have any tokens"))
}
//get sender wallet token ata + check if sender have enough tokens
fromAccountAta := solana.PublicKey{}
hasEnoughTokens := true
for _, ata := range fromAccountAtas.Value {
hasEnoughTokens = true
balance, err := httpClient.GetTokenAccountBalance(context.TODO(), ata.Pubkey, rpc.CommitmentFinalized)
if err != nil {
continue
}
a, err := strconv.ParseUint(balance.Value.Amount, 10, 64)
if err != nil {
continue
}
if a < amount {
hasEnoughTokens = false
continue
}
fromAccountAta = ata.Pubkey
break
}
if fromAccountAta == solana.SystemProgramID {
if !hasEnoughTokens {
err = fmt.Errorf("sender does not have enough tokens")
}
panic(err)
}
//transfer instruction
ix := token.NewTransferInstruction(
amount,
fromAccountAta,
tokenAta,
sender.PublicKey(),
[]solana.PublicKey{}).Build()
ixs = append(ixs, ix)
recentBlockHash, err := httpClient.GetRecentBlockhash(context.TODO(), rpc.CommitmentFinalized)
if err != nil {
panic(err)
}
tx, err := solana.NewTransaction(
ixs,
recentBlockHash.Value.Blockhash,
solana.TransactionPayer(sender.PublicKey()),
)
if err != nil {
panic(err)
}
//sign transaction
_, err = tx.Sign(
func(key solana.PublicKey) *solana.PrivateKey {
if sender.PublicKey().Equals(key) {
return &sender
}
return nil
},
)
if err != nil {
panic(err)
}
//send transaction
sig, err := httpClient.SendTransaction(
context.TODO(),
tx,
)
if err != nil {
panic(err)
}
// send transaction and wait for confirmation
// import confirm "github.com/gagliardetto/solana-go/rpc/sendAndConfirmTransaction"
// sig, err := confirm.SendAndConfirmTransaction(
// context.TODO(),
// httpClient,
// wsClient,
// tx,
// )
return sig, nil
}
doesnt work for me i have empty transaction idk why 2AtiEsBtknVgEhNL4Hv8a3hq6Z7GiL4x4hmx64ZVg7CZmkZnXpQPtNX68amYnvhrCkcWwvCDhj4kMnnTyjGUb2Y6
Is there a way that I can use this library to send tokens from one wallet to another?
If so please tell me where.