Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fees to Tx from wallets fund when sweeping assets #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 72 additions & 1 deletion core/BRWallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)
{
Expand Down
12 changes: 9 additions & 3 deletions core/BRWallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,23 +98,29 @@ 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
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
Expand Down Expand Up @@ -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
Expand Down