gagliardetto / solana-go

Go SDK library and RPC client for the Solana Blockchain
Apache License 2.0
811 stars 239 forks source link

transaction fee is sufficient and simulate transaction success,but transaction is dropped. #236

Open BillInUK opened 1 month ago

BillInUK commented 1 month ago

Hello, I recently encountered an issue that occurs with a relatively high frequency. When I send a transaction to Solana's mainnet, I ensure that my gas fee is sufficient and I simulate the transaction successfully before sending it. However, after sending the transaction and receiving the txID, I am unable to find it on the blockchain explorer. Could you please help me understand the reason for this?

here is my code to transfer the spl token:

func TransferSPLToken(rpcClient *rpc.Client, tokenMintAccount solana.PublicKey,
    fromPrivateKey solana.PrivateKey, toNativeAccount solana.PublicKey, amount uint64, decimals uint8, memo string) (*solana.Signature, error) {

    ctx := context.Background()

    fromNativeAccount := fromPrivateKey.PublicKey()

    recent, err := rpcClient.GetLatestBlockhash(context.Background(), rpc.CommitmentProcessed)
    if err != nil {
        return nil, err
    }

    //fmt.Printf("transfer spl token from token account %v\n", fromNativeAccount)
    //fmt.Printf("transfer spl token to token account %v\n", toNativeAccount)
    //fmt.Printf("transfer spl token token mint account %v\n", tokenMintAccount)
    //fmt.Printf("transfer spl token owner native account %v\n", fromNativeAccount)
    //fmt.Printf("transfer spl token amount %v\n", amount)
    //fmt.Printf("transfer spl token decimals %v\n", decimals)

    fromTokenAccount, _, err := solana.FindAssociatedTokenAddress(fromNativeAccount, tokenMintAccount)
    if err != nil {
        return nil, err
    }
    //fmt.Printf("get from token account %v \n", fromTokenAccount)

    toTokenAccountExist := true
    toTokenAccount, _, err := solana.FindAssociatedTokenAddress(toNativeAccount, tokenMintAccount)
    if err != nil {
        return nil, err
    }
    if _, err := GetSPLTokenAccountByNative(rpcClient, toNativeAccount, tokenMintAccount); err != nil {
        toTokenAccountExist = false
    }
    //fmt.Printf("get to token account %v \n", toTokenAccount)

    var instructions []solana.Instruction
    computeBudgetPriceInst := computebudget.NewSetComputeUnitPriceInstructionBuilder().SetMicroLamports(1000).Build()
    computeBudgetLimitInst := computebudget.NewSetComputeUnitLimitInstructionBuilder().SetUnits(600000).Build()

    if !toTokenAccountExist {
        associated := associatedtokenaccount.NewCreateInstruction(fromNativeAccount, toNativeAccount, tokenMintAccount).Build()
        instructions = append(instructions, associated)
    }

    transferInst := token.NewTransferCheckedInstructionBuilder().
        SetAmount(amount).
        SetSourceAccount(fromTokenAccount).
        SetDestinationAccount(toTokenAccount).
        SetDecimals(decimals).
        SetMintAccount(tokenMintAccount).
        SetOwnerAccount(fromNativeAccount).
        Build()

    instructions = append(instructions, computeBudgetPriceInst)
    instructions = append(instructions, computeBudgetLimitInst)
    instructions = append(instructions, transferInst)
    if memo != "" {
        programID := solana.MemoProgramID
        accounts := []*solana.AccountMeta{solana.Meta(fromNativeAccount).SIGNER().WRITE()}
        data := []byte(memo)
        memoInst := solana.NewInstruction(programID, accounts, data)
        instructions = append(instructions, memoInst)
    }

    tx, err := solana.NewTransaction(instructions, recent.Value.Blockhash, solana.TransactionPayer(fromNativeAccount))
    if err != nil {
        return nil, err
    }

    if _, err = tx.Sign(
        func(key solana.PublicKey) *solana.PrivateKey {
            if fromNativeAccount.Equals(key) {
                return &fromPrivateKey
            }
            return nil
        },
    ); err != nil {
        return nil, err
    }

    // 模拟发送交易
    simulateResult, err := rpcClient.SimulateTransactionWithOpts(ctx, tx, &rpc.SimulateTransactionOpts{
        ReplaceRecentBlockhash: true,
    })
    if err != nil {
        return nil, fmt.Errorf("simulate transaction error %v", err)
    }
    if simulateResult.Value.Err != nil {
        return nil, fmt.Errorf("simulate transaction failed %v", simulateResult.Value.Err)
    }

    txId, err := rpcClient.SendTransactionWithOpts(ctx, tx, rpc.TransactionOpts{SkipPreflight: true})
    return &txId, err
}