diff --git a/core/BRWallet.c b/core/BRWallet.c index 6434349..2a3baf2 100755 --- a/core/BRWallet.c +++ b/core/BRWallet.c @@ -543,6 +543,77 @@ BRTransaction *BRWalletCreateTransaction(BRWallet *wallet, uint64_t amount, cons return BRWalletCreateTxForOutputs(wallet, &o, 1); } +// this method is used in sweeping assets, fees must be added from current wallet +// adds one output to given transaction for fees to a constructed transaction +// in case of insufficient fees, transaction is freed by calling TransactionFree() +void BRWalletAddFeeToTransaction(BRWallet *wallet, BRTransaction *transaction) { + + BRTransaction *tx; + uint64_t feeAmount, balance = 0, minAmount; + size_t i, j, cpfpSize = 0; + UTXO *o; + BRAddress addr = ADDRESS_NONE; + size_t outCount = 1; + const BRTxOutput *outputs; + + assert(wallet != NULL); + assert(transaction != NULL); + + minAmount = BRWalletMinOutputAmount(wallet); + pthread_mutex_lock(&wallet->lock); + feeAmount = _txFee(wallet->feePerKb, BRTransactionSize(transaction) + TX_OUTPUT_SIZE); + + for (i = 0; i < array_count(wallet->utxos); i++) { + o = &wallet->utxos[i]; + tx = BRSetGet(wallet->allTx, o); + + if (!tx || tx->outputs[o->n].amount == 0 || o->n >= tx->outCount) continue; + BRTransactionAddInput(transaction, tx->txHash, o->n, tx->outputs[o->n].amount, + tx->outputs[o->n].script, tx->outputs[o->n].scriptLen, NULL, 0, TXIN_SEQUENCE); + + if (BRTransactionSize(transaction) + TX_OUTPUT_SIZE > TX_MAX_SIZE) { // transaction size-in-bytes too large + BRTransactionFree(transaction); + transaction = NULL; + + // check for sufficient total funds before building a smaller transaction + if (wallet->balance < _txFee(wallet->feePerKb, 10 + array_count(wallet->utxos)*TX_INPUT_SIZE + + (outCount + 1)*TX_OUTPUT_SIZE + cpfpSize)) break; + pthread_mutex_unlock(&wallet->lock); + + transaction = BRWalletCreateTxForOutputs(wallet, outputs, outCount - 1); // remove last output + + balance = feeAmount = 0; + pthread_mutex_lock(&wallet->lock); + break; + } + + balance += tx->outputs[o->n].amount; + + // fee amount after adding a change output + feeAmount = _txFee(wallet->feePerKb, BRTransactionSize(transaction) + TX_OUTPUT_SIZE + cpfpSize); + + // increase fee to round off remaining wallet balance to nearest 100 satoshi + if (wallet->balance > feeAmount) feeAmount += (wallet->balance - feeAmount) % 100; + + if (balance == feeAmount || balance >= feeAmount + minAmount) break; + } + + pthread_mutex_unlock(&wallet->lock); + + if (transaction && (outCount < 1 || balance < feeAmount)) { // no outputs/insufficient funds + BRTransactionFree(transaction); + transaction = NULL; + } else if (transaction && balance - feeAmount > minAmount) { // add change output + BRWalletUnusedAddrs(wallet, &addr, 1, 1); + uint8_t script[BRAddressScriptPubKey(NULL, 0, addr.s)]; + size_t scriptLen = BRAddressScriptPubKey(script, sizeof(script), addr.s); + + BRTransactionAddOutput(transaction, balance - feeAmount, script, scriptLen); + BRTransactionShuffleOutputs(transaction); + } + +} + // returns an unsigned transaction that sends the specified amount from the wallet to the given address // one asset output is added + network fees and change if any // result must be freed by calling TransactionFree() @@ -1161,7 +1232,7 @@ BRTransaction *BRWalletBurnRootAsset(BRWallet *wallet, BRAsset *asst) { return transaction; } -// returns an unsigned transaction that satisifes the given transaction outputs +// returns an unsigned transaction that satisfies the given transaction outputs // result must be freed using TransactionFree() BRTransaction *BRWalletCreateTxForOutputs(BRWallet *wallet, const BRTxOutput outputs[], size_t outCount) { diff --git a/core/BRWallet.h b/core/BRWallet.h index fd52792..d46c959 100755 --- a/core/BRWallet.h +++ b/core/BRWallet.h @@ -98,10 +98,10 @@ size_t BRWalletTxUnconfirmedBefore(BRWallet *wallet, BRTransaction **transaction // current wallet balance, not including transactions known to be invalid uint64_t BRWalletBalance(BRWallet *wallet); -// total amount spent from the wallet (exluding change) +// total amount spent from the wallet (excluding change) uint64_t BRWalletTotalSent(BRWallet *wallet); -// total amount received by the wallet (exluding change) +// total amount received by the wallet (excluding change) uint64_t BRWalletTotalReceived(BRWallet *wallet); // writes unspent outputs to utxos and returns the number of outputs written, or number available if utxos is NULL @@ -109,12 +109,18 @@ size_t BRWalletUTXOs(BRWallet *wallet, UTXO *utxos, size_t utxosCount); // fee-per-kb of transaction size to use when creating a transaction uint64_t BRWalletFeePerKb(BRWallet *wallet); + void BRWalletSetFeePerKb(BRWallet *wallet, uint64_t feePerKb); // returns an unsigned transaction that sends the specified amount from the wallet to the given address // result must be freed using TransactionFree() BRTransaction *BRWalletCreateTransaction(BRWallet *wallet, uint64_t amount, const char *addr); +// this method is used in sweeping assets, fees must be added from current wallet +// adds one output to given transaction for fees to a constructed transaction +// in case of insufficient fees, transaction is freed by calling TransactionFree() +void BRWalletAddFeeToTransaction(BRWallet *wallet, BRTransaction *transaction); + // // // returns an unsigned transaction that sends the specified amount from the wallet to the given address @@ -203,7 +209,7 @@ uint64_t BRWalletAmountReceivedFromTx(BRWallet *wallet, const BRTransaction *tx) // writes the assets contained in the transaction and return the asset object count. size_t BRWalletAssetsReceivedFromTx(BRWallet *wallet, const BRTransaction *tx, BRAsset *asset, size_t asstCount); -// returns the amount sent from the wallet by the trasaction (total wallet outputs consumed, change and fee included) +// returns the amount sent from the wallet by the transaction (total wallet outputs consumed, change and fee included) uint64_t BRWalletAmountSentByTx(BRWallet *wallet, const BRTransaction *tx); // returns the fee for the given transaction if all its inputs are from wallet transactions, UINT64_MAX otherwise