From b6005249477af8b1fdec9f24d17edaba4a00ee11 Mon Sep 17 00:00:00 2001 From: revantark Date: Sat, 20 Jul 2024 19:24:17 +0530 Subject: [PATCH] refactor --- btc/batcher.go | 79 ++++++++++++++------------------------------------ btc/cpfp.go | 34 +++++++++++----------- btc/rbf.go | 52 ++++++++++++++++----------------- btc/wallet.go | 17 ++++++++--- 4 files changed, 77 insertions(+), 105 deletions(-) diff --git a/btc/batcher.go b/btc/batcher.go index 7ed10e1..9ade0a4 100644 --- a/btc/batcher.go +++ b/btc/batcher.go @@ -19,8 +19,8 @@ import ( ) var ( - SegwitSpendWeight int = txsizes.RedeemP2WPKHInputWitnessWeight - DefaultContextTimeout = 5 * time.Second + SegwitSpendWeight = txsizes.RedeemP2WPKHInputWitnessWeight + DefaultAPITimeout = 5 * time.Second ) var ( ErrBatchNotFound = errors.New("batch not found") @@ -107,16 +107,20 @@ type BatcherRequest struct { } type BatcherOptions struct { - PTI time.Duration // Periodic Time Interval for batching + // Periodic Time Interval for batching + PTI time.Duration TxOptions TxOptions Strategy Strategy } -// Strategy defines the batching strategy to be used by the BatcherWallet -// It can be one of RBF, CPFP, RBF_CPFP, Multi_CPFP -// RBF - Replace By Fee -// CPFP - Child Pays For Parent -// Multi_CPFP - Multiple CPFP threads are maintained across multiple addresses +// Strategy defines the batching strategy to be used by the BatcherWallet. +// It can be one of RBF, CPFP, RBF_CPFP, Multi_CPFP. +// +// 1. RBF - Replace By Fee +// +// 2. CPFP - Child Pays For Parent +// +// 3. Multi_CPFP - Multiple CPFP threads are maintained across multiple addresses type Strategy string var ( @@ -127,14 +131,6 @@ var ( ) type TxOptions struct { - MaxOutputs int - MaxInputs int - - MaxUnconfirmedAge int - - MaxBatches int - MaxBatchSize int - FeeLevel FeeLevel MaxFeeRate int MinFeeDelta int @@ -157,9 +153,10 @@ type batcherWallet struct { cache Cache } type Batch struct { - Tx Transaction - RequestIds map[string]bool - IsStable bool + Tx Transaction + RequestIds map[string]bool + // true indicates that the batch is finalized and will not be replaced by more fee. + isFinalized bool IsConfirmed bool Strategy Strategy SelfUtxos UTXOs @@ -202,14 +199,6 @@ func defaultBatcherOptions() BatcherOptions { return BatcherOptions{ PTI: 1 * time.Minute, TxOptions: TxOptions{ - MaxOutputs: 0, - MaxInputs: 0, - - MaxUnconfirmedAge: 0, - - MaxBatches: 0, - MaxBatchSize: 0, - FeeLevel: HighFee, MaxFeeRate: 0, MinFeeDelta: 0, @@ -456,7 +445,7 @@ func (w *batcherWallet) validateBatchRequest(ctx context.Context, strategy Strat spendsAmount := int64(0) spendsUtxos := UTXOs{} - err = withContextTimeout(ctx, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error { spendsUtxos, _, spendsAmount, err = getUTXOsForSpendRequest(ctx, w.indexer, spends) return err }) @@ -466,8 +455,8 @@ func (w *batcherWallet) validateBatchRequest(ctx context.Context, strategy Strat var sacpsIn int64 var sacpOut int64 - err = withContextTimeout(ctx, DefaultContextTimeout, func(ctx context.Context) error { - sacpsIn, sacpOut, err = getTotalInAndOutSACPs(ctx, sacps, w.indexer) + err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error { + sacpsIn, sacpOut, err = getSACPAmounts(ctx, sacps, w.indexer) return err }) @@ -527,7 +516,7 @@ func filterPendingBatches(batches []Batch, indexer IndexerClient) ([]Batch, []st confirmedTxs := []string{} pendingTxs := []string{} for _, batch := range batches { - ctx, cancel := context.WithTimeout(context.Background(), DefaultContextTimeout) + ctx, cancel := context.WithTimeout(context.Background(), DefaultAPITimeout) defer cancel() tx, err := indexer.GetTx(ctx, batch.Tx.TxID) if err != nil { @@ -548,7 +537,7 @@ func getTransaction(indexer IndexerClient, txid string) (Transaction, error) { return Transaction{}, ErrTxIdEmpty } for i := 1; i < 5; i++ { - ctx, cancel := context.WithTimeout(context.Background(), DefaultContextTimeout) + ctx, cancel := context.WithTimeout(context.Background(), DefaultAPITimeout) defer cancel() tx, err := indexer.GetTx(ctx, txid) if err != nil { @@ -566,32 +555,6 @@ func withContextTimeout(parentContext context.Context, duration time.Duration, f return fn(ctx) } -// getFeeUsedInSACPs returns the amount of fee used in the given SACPs -func getTotalInAndOutSACPs(ctx context.Context, sacps [][]byte, indexer IndexerClient) (int64, int64, error) { - tx, _, err := buildTxFromSacps(sacps) - if err != nil { - return 0, 0, err - } - - // go through each input and get the amount it holds - // add all the inputs and subtract the outputs to get the fee - totalInputAmount := int64(0) - for _, in := range tx.TxIn { - txFromIndexer, err := indexer.GetTx(ctx, in.PreviousOutPoint.Hash.String()) - if err != nil { - return 0, 0, err - } - totalInputAmount += int64(txFromIndexer.VOUTs[in.PreviousOutPoint.Index].Value) - } - - totalOutputAmount := int64(0) - for _, out := range tx.TxOut { - totalOutputAmount += out.Value - } - - return totalInputAmount, totalOutputAmount, nil -} - // unpackBatcherRequests unpacks the batcher requests into spend requests, send requests and SACPs func unpackBatcherRequests(reqs []BatcherRequest) ([]SpendRequest, []SendRequest, [][]byte, map[string]bool) { spendRequests := []SpendRequest{} diff --git a/btc/cpfp.go b/btc/cpfp.go index 923cdd9..2229d66 100644 --- a/btc/cpfp.go +++ b/btc/cpfp.go @@ -25,7 +25,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { // Read all pending requests added to the cache // All requests are executed in a single batch - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { requests, err = w.cache.ReadPendingRequests(ctx) return err }) @@ -43,7 +43,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { // Read pending batches from the cache var batches []Batch - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy) return err }) @@ -57,7 +57,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { return err } - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP) }) if err != nil { @@ -79,7 +79,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { // Fetch UTXOs from the indexer var utxos []UTXO - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { utxos, err = w.indexer.GetUTXOs(ctx, w.address) return err }) @@ -105,7 +105,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { } // Submit the CPFP transaction to the indexer - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.indexer.SubmitTx(ctx, tx) }) if err != nil { @@ -114,7 +114,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { // Retrieve the transaction details from the indexer var transaction Transaction - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { transaction, err = getTransaction(w.indexer, tx.TxHash().String()) return err }) @@ -126,7 +126,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { batch := Batch{ Tx: transaction, RequestIds: reqIds, - IsStable: true, + isFinalized: true, IsConfirmed: false, Strategy: CPFP, SelfUtxos: UTXOs{ @@ -138,7 +138,7 @@ func (w *batcherWallet) createCPFPBatch(c context.Context) error { }, } - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.cache.SaveBatch(ctx, batch) }) if err != nil { @@ -155,7 +155,7 @@ func (w *batcherWallet) updateCPFP(c context.Context, requiredFeeRate int) error var err error // Read pending batches from the cache - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { batches, err = w.cache.ReadPendingBatches(ctx, w.opts.Strategy) return err }) @@ -169,7 +169,7 @@ func (w *batcherWallet) updateCPFP(c context.Context, requiredFeeRate int) error return err } - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.cache.ConfirmBatchStatuses(ctx, confirmedTxs, false, CPFP) }) if err != nil { @@ -183,7 +183,7 @@ func (w *batcherWallet) updateCPFP(c context.Context, requiredFeeRate int) error // Fetch UTXOs from the indexer var utxos []UTXO - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { utxos, err = w.indexer.GetUTXOs(ctx, w.address) return err }) @@ -220,7 +220,7 @@ func (w *batcherWallet) updateCPFP(c context.Context, requiredFeeRate int) error } // Submit the CPFP transaction to the indexer - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.indexer.SubmitTx(ctx, tx) }) if err != nil { @@ -228,7 +228,7 @@ func (w *batcherWallet) updateCPFP(c context.Context, requiredFeeRate int) error } // Update the fee of all batches that got bumped - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.cache.UpdateBatchFees(ctx, pendingTxs, int64(requiredFeeRate)) }) if err != nil { @@ -266,7 +266,7 @@ func (w *batcherWallet) buildCPFPTx(c context.Context, utxos []UTXO, spendReques var err error // Get UTXOs for spend requests - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { spendUTXOs, spendUTXOsMap, balanceOfScripts, err = getUTXOsForSpendRequest(ctx, w.indexer, spendRequests) return err }) @@ -322,7 +322,7 @@ func (w *batcherWallet) buildCPFPTx(c context.Context, utxos []UTXO, spendReques } // Sign the spend inputs - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return signSpendTx(ctx, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey) }) if err != nil { @@ -341,8 +341,8 @@ func (w *batcherWallet) buildCPFPTx(c context.Context, utxos []UTXO, spendReques var sacpsInAmount int64 var sacpOutAmount int64 - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { - sacpsInAmount, sacpOutAmount, err = getTotalInAndOutSACPs(ctx, sacps, w.indexer) + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { + sacpsInAmount, sacpOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer) return err }) diff --git a/btc/rbf.go b/btc/rbf.go index 9a006db..130212a 100644 --- a/btc/rbf.go +++ b/btc/rbf.go @@ -22,7 +22,7 @@ func (w *batcherWallet) createRBFBatch(c context.Context) error { var err error // Read pending requests from the cache . - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { pendingRequests, err = w.cache.ReadPendingRequests(ctx) return err }) @@ -37,7 +37,7 @@ func (w *batcherWallet) createRBFBatch(c context.Context) error { var latestBatch Batch // Read the latest RBF batch from the cache . - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { latestBatch, err = w.cache.ReadLatestBatch(ctx, RBF) return err }) @@ -73,7 +73,7 @@ func (w *batcherWallet) reSubmitRBFBatch(c context.Context, batch Batch, pending var err error // Read batched requests from the cache . - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { batchedRequests, err = w.cache.ReadRequests(ctx, maps.Keys(batch.RequestIds)) return err }) @@ -91,7 +91,7 @@ func (w *batcherWallet) reSubmitRBFBatch(c context.Context, batch Batch, pending // Get the confirmed batch. var confirmedBatch Batch - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { confirmedBatch, err = w.getConfirmedBatch(ctx) return err }) @@ -100,7 +100,7 @@ func (w *batcherWallet) reSubmitRBFBatch(c context.Context, batch Batch, pending } // Delete the pending batch from the cache. - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.cache.DeletePendingBatches(ctx, map[string]bool{batch.Tx.TxID: true}, RBF) }) if err != nil { @@ -109,7 +109,7 @@ func (w *batcherWallet) reSubmitRBFBatch(c context.Context, batch Batch, pending // Read the missing requests from the cache. var missingRequests []BatcherRequest - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { missingRequestIds := getMissingRequestIds(batch.RequestIds, confirmedBatch.RequestIds) missingRequests, err = w.cache.ReadRequests(ctx, missingRequestIds) return err @@ -128,7 +128,7 @@ func (w *batcherWallet) getConfirmedBatch(c context.Context) (Batch, error) { var err error // Read pending batches from the cache - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { batches, err = w.cache.ReadPendingBatches(ctx, RBF) return err }) @@ -141,7 +141,7 @@ func (w *batcherWallet) getConfirmedBatch(c context.Context) (Batch, error) { // Loop through the batches to find a confirmed batch for _, batch := range batches { var tx Transaction - err := withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err := withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { tx, err = w.indexer.GetTx(ctx, batch.Tx.TxID) return err }) @@ -186,7 +186,7 @@ func (w *batcherWallet) createNewRBFBatch(c context.Context, pendingRequests []B var err error // Get unconfirmed UTXOs to avoid them in the new transaction - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { avoidUtxos, err = w.getUnconfirmedUtxos(ctx, RBF) return err }) @@ -197,7 +197,7 @@ func (w *batcherWallet) createNewRBFBatch(c context.Context, pendingRequests []B // Determine the required fee rate if not provided if requiredFeeRate == 0 { var feeRates FeeSuggestion - err := withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err := withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { feeRates, err = w.feeEstimator.FeeSuggestion() return err }) @@ -218,7 +218,7 @@ func (w *batcherWallet) createNewRBFBatch(c context.Context, pendingRequests []B var fundingUtxos UTXOs var selfUtxos UTXOs // Create a new RBF transaction - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { tx, fundingUtxos, selfUtxos, err = w.createRBFTx( c, nil, @@ -239,7 +239,7 @@ func (w *batcherWallet) createNewRBFBatch(c context.Context, pendingRequests []B } // Submit the new RBF transaction to the indexer - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.indexer.SubmitTx(ctx, tx) }) if err != nil { @@ -249,7 +249,7 @@ func (w *batcherWallet) createNewRBFBatch(c context.Context, pendingRequests []B w.logger.Info("submitted rbf tx", zap.String("txid", tx.TxHash().String())) var transaction Transaction - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { transaction, err = getTransaction(w.indexer, tx.TxHash().String()) return err }) @@ -261,7 +261,7 @@ func (w *batcherWallet) createNewRBFBatch(c context.Context, pendingRequests []B batch := Batch{ Tx: transaction, RequestIds: reqIds, - IsStable: false, // RBF transactions are not stable meaning they can be replaced + isFinalized: false, // RBF transactions are not stable meaning they can be replaced IsConfirmed: false, Strategy: RBF, SelfUtxos: selfUtxos, @@ -269,7 +269,7 @@ func (w *batcherWallet) createNewRBFBatch(c context.Context, pendingRequests []B } // Save the new RBF batch to the cache - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return w.cache.SaveBatch(ctx, batch) }) if err != nil { @@ -285,7 +285,7 @@ func (w *batcherWallet) updateRBF(c context.Context, requiredFeeRate int) error var latestBatch Batch var err error // Read the latest RBF batch from the cache - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { latestBatch, err = w.cache.ReadLatestBatch(ctx, RBF) return err }) @@ -298,7 +298,7 @@ func (w *batcherWallet) updateRBF(c context.Context, requiredFeeRate int) error var tx Transaction // Check if the transaction is already confirmed - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { tx, err = getTransaction(w.indexer, latestBatch.Tx.TxID) return err }) @@ -307,7 +307,7 @@ func (w *batcherWallet) updateRBF(c context.Context, requiredFeeRate int) error } if tx.Status.Confirmed && !latestBatch.Tx.Status.Confirmed { - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { if err = w.cache.ConfirmBatchStatuses(ctx, []string{tx.TxID}, true, RBF); err == nil { return ErrFeeUpdateNotNeeded } @@ -376,8 +376,8 @@ func (w *batcherWallet) createRBFTx( var sacpsInAmount int64 var sacpsOutAmount int64 var err error - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { - sacpsInAmount, sacpsOutAmount, err = getTotalInAndOutSACPs(ctx, sacps, w.indexer) + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { + sacpsInAmount, sacpsOutAmount, err = getSACPAmounts(ctx, sacps, w.indexer) return err }) @@ -386,7 +386,7 @@ func (w *batcherWallet) createRBFTx( var balanceOfSpendScripts int64 // Fetch UTXOs for spend requests - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { spendUTXOs, spendUTXOsMap, balanceOfSpendScripts, err = getUTXOsForSpendRequest(ctx, w.indexer, spendRequests) return err }) @@ -416,7 +416,7 @@ func (w *batcherWallet) createRBFTx( } // Sign the inputs related to spend requests - err = withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { return signSpendTx(ctx, tx, signIdx, spendRequests, spendUTXOsMap, w.indexer, w.privateKey) }) if err != nil { @@ -467,7 +467,7 @@ func (w *batcherWallet) createRBFTx( zap.Int64("totalOut", totalOut), zap.Int("newFeeEstimate", newFeeEstimate), ) - err := withContextTimeout(c, DefaultContextTimeout, func(ctx context.Context) error { + err := withContextTimeout(c, DefaultAPITimeout, func(ctx context.Context) error { utxos, _, err = w.getUtxosWithFee(ctx, totalOut+int64(newFeeEstimate)-totalIn, int64(feeRate), avoidUtxos) return err }) @@ -510,7 +510,7 @@ func (w *batcherWallet) getUtxosWithFee(ctx context.Context, amount, feeRate int var err error // Read pending funding UTXOs - err = withContextTimeout(ctx, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error { prevUtxos, err = w.cache.ReadPendingFundingUtxos(ctx, RBF) return err }) @@ -519,7 +519,7 @@ func (w *batcherWallet) getUtxosWithFee(ctx context.Context, amount, feeRate int } // Get UTXOs from the indexer - err = withContextTimeout(ctx, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error { coverUtxos, err = w.indexer.GetUTXOs(ctx, w.address) return err }) @@ -567,7 +567,7 @@ func (w *batcherWallet) getUnconfirmedUtxos(ctx context.Context, strategy Strate var err error // Read pending change UTXOs - err = withContextTimeout(ctx, DefaultContextTimeout, func(ctx context.Context) error { + err = withContextTimeout(ctx, DefaultAPITimeout, func(ctx context.Context) error { pendingChangeUtxos, err = w.cache.ReadPendingChangeUtxos(ctx, strategy) return err }) diff --git a/btc/wallet.go b/btc/wallet.go index 16c4686..fd90518 100644 --- a/btc/wallet.go +++ b/btc/wallet.go @@ -369,11 +369,11 @@ func (sw *SimpleWallet) Status(ctx context.Context, id string) (Transaction, boo // ------------------ Helper functions ------------------ -// getFeeUsedInSACPs returns the amount of fee used in the given SACPs -func getFeeUsedInSACPs(ctx context.Context, sacps [][]byte, indexer IndexerClient) (int, error) { +// getSACPAmounts returns the total input and output amounts for the given SACPs +func getSACPAmounts(ctx context.Context, sacps [][]byte, indexer IndexerClient) (int64, int64, error) { tx, _, err := buildTxFromSacps(sacps) if err != nil { - return 0, err + return 0, 0, err } // go through each input and get the amount it holds @@ -382,7 +382,7 @@ func getFeeUsedInSACPs(ctx context.Context, sacps [][]byte, indexer IndexerClien for _, in := range tx.TxIn { txFromIndexer, err := indexer.GetTx(ctx, in.PreviousOutPoint.Hash.String()) if err != nil { - return 0, err + return 0, 0, err } totalInputAmount += int64(txFromIndexer.VOUTs[in.PreviousOutPoint.Index].Value) } @@ -392,6 +392,15 @@ func getFeeUsedInSACPs(ctx context.Context, sacps [][]byte, indexer IndexerClien totalOutputAmount += out.Value } + return totalInputAmount, totalOutputAmount, nil +} + +// getFeeUsedInSACPs returns the amount of fee used in the given SACPs +func getFeeUsedInSACPs(ctx context.Context, sacps [][]byte, indexer IndexerClient) (int, error) { + totalInputAmount, totalOutputAmount, err := getSACPAmounts(ctx, sacps, indexer) + if err != nil { + return 0, err + } return int(totalInputAmount - totalOutputAmount), nil }