github.com/gagliardetto/solana-go@v1.11.0/rpc/sendAndConfirmTransaction/sendAndConfirmTransaction.go (about) 1 // Copyright 2021 github.com/gagliardetto 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sendandconfirmtransaction 16 17 import ( 18 "context" 19 "fmt" 20 "time" 21 22 "github.com/gagliardetto/solana-go" 23 "github.com/gagliardetto/solana-go/rpc" 24 "github.com/gagliardetto/solana-go/rpc/ws" 25 ) 26 27 // Send and wait for confirmation of a transaction. 28 func SendAndConfirmTransaction( 29 ctx context.Context, 30 rpcClient *rpc.Client, 31 wsClient *ws.Client, 32 transaction *solana.Transaction, 33 ) (signature solana.Signature, err error) { 34 opts := rpc.TransactionOpts{ 35 SkipPreflight: false, 36 PreflightCommitment: rpc.CommitmentFinalized, 37 } 38 39 return SendAndConfirmTransactionWithOpts( 40 ctx, 41 rpcClient, 42 wsClient, 43 transaction, 44 opts, 45 nil, 46 ) 47 } 48 49 func SendAndConfirmTransactionWithTimeout( 50 ctx context.Context, 51 rpcClient *rpc.Client, 52 wsClient *ws.Client, 53 transaction *solana.Transaction, 54 timeout time.Duration, 55 ) (signature solana.Signature, err error) { 56 opts := rpc.TransactionOpts{ 57 SkipPreflight: false, 58 PreflightCommitment: rpc.CommitmentFinalized, 59 } 60 61 return SendAndConfirmTransactionWithOpts( 62 ctx, 63 rpcClient, 64 wsClient, 65 transaction, 66 opts, 67 &timeout, 68 ) 69 } 70 71 var ErrTimeout = fmt.Errorf("timeout") 72 73 // Send and wait for confirmation of a transaction. 74 func SendAndConfirmTransactionWithOpts( 75 ctx context.Context, 76 rpcClient *rpc.Client, 77 wsClient *ws.Client, 78 transaction *solana.Transaction, 79 opts rpc.TransactionOpts, 80 timeout *time.Duration, 81 ) (sig solana.Signature, err error) { 82 sig, err = rpcClient.SendTransactionWithOpts( 83 ctx, 84 transaction, 85 opts, 86 ) 87 if err != nil { 88 return sig, err 89 } 90 _, err = WaitForConfirmation( 91 ctx, 92 wsClient, 93 sig, 94 timeout, 95 ) 96 return sig, err 97 } 98 99 // WaitForConfirmation waits for a transaction to be confirmed. 100 // If the transaction was confirmed, but it failed while executing (one of the instructions failed), 101 // then this function will return an error (true, error). 102 // If the transaction was confirmed, and it succeeded, then this function will return nil (true, nil). 103 func WaitForConfirmation( 104 ctx context.Context, 105 wsClient *ws.Client, 106 sig solana.Signature, 107 timeout *time.Duration, 108 ) (confirmed bool, err error) { 109 sub, err := wsClient.SignatureSubscribe( 110 sig, 111 rpc.CommitmentFinalized, 112 ) 113 if err != nil { 114 return false, err 115 } 116 defer sub.Unsubscribe() 117 118 if timeout == nil { 119 t := 2 * time.Minute // random default timeout 120 timeout = &t 121 } 122 123 for { 124 select { 125 case <-ctx.Done(): 126 return false, ctx.Err() 127 case <-time.After(*timeout): 128 return false, ErrTimeout 129 case resp, ok := <-sub.Response(): 130 if !ok { 131 return false, fmt.Errorf("subscription closed") 132 } 133 if resp.Value.Err != nil { 134 // The transaction was confirmed, but it failed while executing (one of the instructions failed). 135 return true, fmt.Errorf("confirmed transaction with execution error: %v", resp.Value.Err) 136 } else { 137 // Success! Confirmed! And there was no error while executing the transaction. 138 return true, nil 139 } 140 case err := <-sub.Err(): 141 return false, err 142 } 143 } 144 }