Skip to content

Commit b050c13

Browse files
committed
Litecoin: adding fee confirmation dialog
Will alert the user when a higher fee is about to be used
1 parent 9f63f57 commit b050c13

File tree

3 files changed

+139
-39
lines changed

3 files changed

+139
-39
lines changed

wallet/src/de/schildbach/wallet/Constants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
package de.schildbach.wallet;
1919

2020
import java.io.File;
21+
import java.math.BigDecimal;
22+
import java.math.BigInteger;
2123
import java.nio.charset.Charset;
2224

2325
import android.os.Environment;
@@ -77,6 +79,10 @@ public class Constants
7779
public static final int ADDRESS_FORMAT_GROUP_SIZE = 4;
7880
public static final int ADDRESS_FORMAT_LINE_SIZE = 12;
7981

82+
public static final BigInteger CENT = new BigInteger("1000000", 10);
83+
public static final BigInteger MIN_TX_FEE = CENT.divide(new BigInteger("10"));
84+
public static final BigInteger TX_FEE_PER_KB = CENT.divide(new BigInteger("10"));
85+
8086
public static final int BTC_MAX_PRECISION = 8;
8187
public static final int MBTC_MAX_PRECISION = 5;
8288
public static final int LOCAL_PRECISION = 4;

wallet/src/de/schildbach/wallet/ui/SendCoinsFragment.java

Lines changed: 111 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@
1717

1818
package de.schildbach.wallet.ui;
1919

20+
import java.math.BigDecimal;
2021
import java.math.BigInteger;
2122

2223
import javax.annotation.CheckForNull;
2324
import javax.annotation.Nonnull;
2425
import javax.annotation.Nullable;
2526

27+
import android.app.AlertDialog;
28+
import android.util.Log;
29+
import android.widget.Toast;
30+
import com.google.bitcoin.core.InsufficientMoneyException;
31+
import com.google.bitcoin.core.VerificationException;
32+
import org.litecoin.LitecoinWallet;
2633
import org.slf4j.Logger;
2734
import org.slf4j.LoggerFactory;
2835

@@ -845,52 +852,111 @@ private void handleGo()
845852
sendRequest.changeAddress = WalletUtils.pickOldestKey(wallet).toAddress(Constants.NETWORK_PARAMETERS);
846853
sendRequest.emptyWallet = amount.equals(wallet.getBalance(BalanceType.AVAILABLE));
847854

848-
new SendCoinsOfflineTask(wallet, backgroundHandler)
849-
{
850-
@Override
851-
protected void onSuccess(final Transaction transaction)
852-
{
853-
sentTransaction = transaction;
855+
// Multi-part transaction creation to properly calculate fee
856+
// Complete the transaction in order to get the final size
857+
try {
858+
wallet.completeTx(sendRequest);
859+
} catch (InsufficientMoneyException e) {
860+
Log.i("wallet_ltc", "Insufficient funds when completing tx");
861+
Toast
862+
.makeText(getActivity(), "Insufficient funds. Please lower the amount and try again.", Toast.LENGTH_LONG)
863+
.show();
864+
return;
865+
}
866+
// Get the size of the transaction
867+
/*
868+
Log.d("Litecoin", "Transaction size is " + sendRequest.tx.getLength());
869+
BigInteger nTransactionFee = Constants.MIN_TX_FEE;
870+
BigInteger nFeePerKB = Constants.TX_FEE_PER_KB;
871+
BigInteger nSizeFee = nFeePerKB.multiply(new BigInteger(Integer.toString(sendRequest.tx.getLength() / 1000)));
872+
BigInteger nPayFee = nTransactionFee.add(nSizeFee);
873+
*/
874+
875+
if(sendRequest.fee.compareTo(Constants.MIN_TX_FEE) > 0)
876+
{
877+
Log.i("LitecoinSendCoins", "Higher fee: " +
878+
sendRequest.fee.toString() + " < " + sendRequest.fee.toString());
879+
880+
new AlertDialog.Builder(SendCoinsFragment.this.getActivity())
881+
.setMessage("Transaction requires fee of " +
882+
new BigDecimal(sendRequest.fee).divide(new BigDecimal("100000000")) + ". Continue?")
883+
.setTitle("Extra fee needed")
884+
.setCancelable(true)
885+
.setNeutralButton(android.R.string.cancel,
886+
new DialogInterface.OnClickListener() {
887+
public void onClick(DialogInterface dialog, int whichButton) {
888+
startActivity(new Intent(getActivity(), WalletActivity.class));
889+
getActivity().finish();
890+
}
891+
})
892+
.setPositiveButton(android.R.string.ok,
893+
new DialogInterface.OnClickListener() {
894+
public void onClick(DialogInterface dialogInterface, int i) {
895+
// Fees are agreeable
896+
// Process the transaction
897+
// Send Asynchronously
898+
new NormalSendCoinsOfflineTask(wallet, backgroundHandler).commitRequest(sendRequest);
899+
}
900+
})
901+
.show();
902+
} else {
903+
// No fee recalculation necessary
904+
// Process the transaction
905+
// Send Asynchronously
906+
new NormalSendCoinsOfflineTask(wallet, backgroundHandler).commitRequest(sendRequest);
907+
}
854908

855-
state = State.SENDING;
856-
updateView();
909+
}
857910

858-
sentTransaction.getConfidence().addEventListener(sentTransactionConfidenceListener);
911+
class NormalSendCoinsOfflineTask extends SendCoinsOfflineTask {
859912

860-
if (bluetoothAdapter != null && bluetoothAdapter.isEnabled() && bluetoothMac != null && bluetoothEnableView.isChecked())
861-
{
862-
new SendBluetoothTask(bluetoothAdapter, backgroundHandler)
863-
{
864-
@Override
865-
protected void onResult(final boolean ack)
866-
{
867-
bluetoothAck = ack;
913+
public NormalSendCoinsOfflineTask(@Nonnull Wallet wallet, @Nonnull Handler backgroundHandler) {
914+
super(wallet, backgroundHandler);
915+
}
868916

869-
if (state == State.SENDING)
870-
state = State.SENT;
917+
@Override
918+
protected void onSuccess(@Nonnull final Transaction transaction)
919+
{
920+
sentTransaction = transaction;
871921

872-
updateView();
873-
}
874-
}.send(bluetoothMac, transaction); // send asynchronously
875-
}
922+
state = State.SENDING;
923+
updateView();
876924

877-
application.broadcastTransaction(sentTransaction);
925+
sentTransaction.getConfidence().addEventListener(sentTransactionConfidenceListener);
878926

879-
final Intent result = new Intent();
880-
BitcoinIntegration.transactionHashToResult(result, sentTransaction.getHashAsString());
881-
activity.setResult(Activity.RESULT_OK, result);
882-
}
927+
if (bluetoothAdapter != null && bluetoothAdapter.isEnabled() && bluetoothMac != null && bluetoothEnableView.isChecked())
928+
{
929+
new SendBluetoothTask(bluetoothAdapter, backgroundHandler)
930+
{
931+
@Override
932+
protected void onResult(final boolean ack)
933+
{
934+
bluetoothAck = ack;
883935

884-
@Override
885-
protected void onFailure()
886-
{
887-
state = State.FAILED;
888-
updateView();
936+
if (state == State.SENDING)
937+
state = State.SENT;
889938

890-
activity.longToast(R.string.send_coins_error_msg);
891-
}
892-
}.sendCoinsOffline(sendRequest); // send asynchronously
893-
}
939+
updateView();
940+
}
941+
}.send(bluetoothMac, transaction); // send asynchronously
942+
}
943+
944+
application.broadcastTransaction(sentTransaction);
945+
946+
final Intent result = new Intent();
947+
BitcoinIntegration.transactionHashToResult(result, sentTransaction.getHashAsString());
948+
activity.setResult(Activity.RESULT_OK, result);
949+
}
950+
951+
@Override
952+
protected void onFailure()
953+
{
954+
state = State.FAILED;
955+
updateView();
956+
957+
activity.longToast(R.string.send_coins_error_msg);
958+
}
959+
}
894960

895961
private void handleScan()
896962
{
@@ -940,8 +1006,14 @@ public CharSequence convertToString(final Cursor cursor)
9401006
@Override
9411007
public Cursor runQueryOnBackgroundThread(final CharSequence constraint)
9421008
{
943-
final Cursor cursor = activity.managedQuery(AddressBookProvider.contentUri(activity.getPackageName()), null,
944-
AddressBookProvider.SELECTION_QUERY, new String[] { constraint.toString() }, null);
1009+
final Cursor cursor;
1010+
try {
1011+
cursor = activity.managedQuery(AddressBookProvider.contentUri(activity.getPackageName()),
1012+
null, AddressBookProvider.SELECTION_QUERY, new String[] { constraint.toString() }, null);
1013+
} catch(NullPointerException e) {
1014+
Log.i("wallet_ltc", "NULL Pointer exception when doing address book completion");
1015+
return null;
1016+
}
9451017
return cursor;
9461018
}
9471019
}

wallet/src/de/schildbach/wallet/ui/SendCoinsOfflineTask.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,28 @@ public void run()
7373
});
7474
}
7575

76+
public final void commitRequest(@Nonnull final SendRequest sendRequest)
77+
{
78+
backgroundHandler.post(new Runnable()
79+
{
80+
@Override
81+
public void run()
82+
{
83+
final Transaction transaction; // can take long
84+
wallet.commitTx(sendRequest.tx);
85+
86+
callbackHandler.post(new Runnable()
87+
{
88+
@Override
89+
public void run()
90+
{
91+
onSuccess(sendRequest.tx);
92+
}
93+
});
94+
}
95+
});
96+
}
97+
7698
protected abstract void onSuccess(@Nonnull Transaction transaction);
7799

78100
protected abstract void onFailure();

0 commit comments

Comments
 (0)