From af5076ce7d8b2842f75d082f491e0ef580331ab0 Mon Sep 17 00:00:00 2001 From: pokkst Date: Thu, 22 Sep 2022 06:07:39 -0500 Subject: [PATCH] Sweep selected outputs --- app/src/main/cpp/monerujo.cpp | 39 +++++++++++++++---- .../java/net/mynero/wallet/data/TxData.java | 15 ++++++- .../dialog/ReceiveBottomSheetDialog.java | 4 +- .../net/mynero/wallet/model/CoinsInfo.java | 14 ++++++- .../java/net/mynero/wallet/model/Wallet.java | 20 +++++----- .../wallet/service/MoneroHandlerThread.java | 7 +++- external-libs/include/wallet2_api.h | 6 ++- 7 files changed, 80 insertions(+), 25 deletions(-) diff --git a/app/src/main/cpp/monerujo.cpp b/app/src/main/cpp/monerujo.cpp index b94a6d7..5c5e0e8 100644 --- a/app/src/main/cpp/monerujo.cpp +++ b/app/src/main/cpp/monerujo.cpp @@ -230,6 +230,25 @@ std::vector java2cpp(JNIEnv *env, jobject arrayList) { return result; } +std::set java2cpp_set(JNIEnv *env, jobject arrayList) { + + jmethodID java_util_ArrayList_size = env->GetMethodID(class_ArrayList, "size", "()I"); + jmethodID java_util_ArrayList_get = env->GetMethodID(class_ArrayList, "get", + "(I)Ljava/lang/Object;"); + + jint len = env->CallIntMethod(arrayList, java_util_ArrayList_size); + std::set result; + for (jint i = 0; i < len; i++) { + jstring element = static_cast(env->CallObjectMethod(arrayList, + java_util_ArrayList_get, i)); + const char *pchars = env->GetStringUTFChars(element, nullptr); + result.emplace(pchars); + env->ReleaseStringUTFChars(element, pchars); + env->DeleteLocalRef(element); + } + return result; +} + jobject cpp2java(JNIEnv *env, const std::vector &vector) { jmethodID java_util_ArrayList_ = env->GetMethodID(class_ArrayList, "", "(I)V"); @@ -961,8 +980,8 @@ Java_net_mynero_wallet_model_Wallet_createTransactionJ(JNIEnv *env, jobject inst jstring dst_addr, jstring payment_id, jlong amount, jint mixin_count, jint priority, - jint accountIndex) { - + jint accountIndex, jobject key_images) { + const std::set _key_images = java2cpp_set(env, key_images); const char *_dst_addr = env->GetStringUTFChars(dst_addr, nullptr); const char *_payment_id = env->GetStringUTFChars(payment_id, nullptr); Monero::PendingTransaction::Priority _priority = @@ -972,7 +991,7 @@ Java_net_mynero_wallet_model_Wallet_createTransactionJ(JNIEnv *env, jobject inst Monero::PendingTransaction *tx = wallet->createTransaction(_dst_addr, _payment_id, amount, (uint32_t) mixin_count, _priority, - (uint32_t) accountIndex); + (uint32_t) accountIndex, {}, _key_images); env->ReleaseStringUTFChars(dst_addr, _dst_addr); env->ReleaseStringUTFChars(payment_id, _payment_id); @@ -1013,8 +1032,8 @@ Java_net_mynero_wallet_model_Wallet_createSweepTransaction(JNIEnv *env, jobject jstring dst_addr, jstring payment_id, jint mixin_count, jint priority, - jint accountIndex) { - + jint accountIndex, jobject key_images) { + const std::set _key_images = java2cpp_set(env, key_images); const char *_dst_addr = env->GetStringUTFChars(dst_addr, nullptr); const char *_payment_id = env->GetStringUTFChars(payment_id, nullptr); Monero::PendingTransaction::Priority _priority = @@ -1026,7 +1045,7 @@ Java_net_mynero_wallet_model_Wallet_createSweepTransaction(JNIEnv *env, jobject Monero::PendingTransaction *tx = wallet->createTransaction(_dst_addr, _payment_id, empty, (uint32_t) mixin_count, _priority, - (uint32_t) accountIndex); + (uint32_t) accountIndex, {}, _key_images); env->ReleaseStringUTFChars(dst_addr, _dst_addr); env->ReleaseStringUTFChars(payment_id, _payment_id); @@ -1064,9 +1083,13 @@ Java_net_mynero_wallet_model_Wallet_getCoinsJ(JNIEnv *env, jobject instance) { jobject newCoinsInfo(JNIEnv *env, Monero::CoinsInfo *info) { jmethodID c = env->GetMethodID(class_CoinsInfo, "", - "(J)V"); + "(JZLjava/lang/String;)V"); + jstring _key_image = env->NewStringUTF(info->keyImage().c_str()); jobject result = env->NewObject(class_CoinsInfo, c, - static_cast (info->globalOutputIndex())); + static_cast (info->globalOutputIndex()), + info->spent(), + _key_image); + env->DeleteLocalRef(_key_image); return result; } diff --git a/app/src/main/java/net/mynero/wallet/data/TxData.java b/app/src/main/java/net/mynero/wallet/data/TxData.java index 2428c8d..bbd2386 100644 --- a/app/src/main/java/net/mynero/wallet/data/TxData.java +++ b/app/src/main/java/net/mynero/wallet/data/TxData.java @@ -23,6 +23,9 @@ import net.mynero.wallet.model.PendingTransaction; import net.mynero.wallet.model.Wallet; import net.mynero.wallet.util.Helper; +import java.util.ArrayList; +import java.util.List; + // https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents public class TxData implements Parcelable { @@ -41,6 +44,7 @@ public class TxData implements Parcelable { private int mixin; private PendingTransaction.Priority priority; private UserNotes userNotes; + private ArrayList preferredInputs; public TxData() { } @@ -50,16 +54,19 @@ public class TxData implements Parcelable { this.amount = txData.amount; this.mixin = txData.mixin; this.priority = txData.priority; + this.preferredInputs = txData.preferredInputs; } public TxData(String dstAddr, long amount, int mixin, - PendingTransaction.Priority priority) { + PendingTransaction.Priority priority, + ArrayList preferredInputs) { this.dstAddr = dstAddr; this.amount = amount; this.mixin = mixin; this.priority = priority; + this.preferredInputs = preferredInputs; } protected TxData(Parcel in) { @@ -67,7 +74,7 @@ public class TxData implements Parcelable { amount = in.readLong(); mixin = in.readInt(); priority = PendingTransaction.Priority.fromInteger(in.readInt()); - + in.readStringList(preferredInputs); } public String getDestinationAddress() { @@ -94,6 +101,10 @@ public class TxData implements Parcelable { return 1.0 * amount / Helper.ONE_XMR; } + public ArrayList getPreferredInputs() { + return preferredInputs; + } + public int getMixin() { return mixin; } diff --git a/app/src/main/java/net/mynero/wallet/fragment/dialog/ReceiveBottomSheetDialog.java b/app/src/main/java/net/mynero/wallet/fragment/dialog/ReceiveBottomSheetDialog.java index f3b484d..ffcdd72 100644 --- a/app/src/main/java/net/mynero/wallet/fragment/dialog/ReceiveBottomSheetDialog.java +++ b/app/src/main/java/net/mynero/wallet/fragment/dialog/ReceiveBottomSheetDialog.java @@ -56,7 +56,9 @@ public class ReceiveBottomSheetDialog extends BottomSheetDialogFragment { List coins = WalletManager.getInstance().getWallet().getCoins().getAll(); System.out.println("COINS::"); for(CoinsInfo coinsInfo : coins) { - System.out.println(coinsInfo.getGlobalOutputIndex()); + if(!coinsInfo.isSpent()) { + System.out.println(coinsInfo.getKeyImage()); + } } } diff --git a/app/src/main/java/net/mynero/wallet/model/CoinsInfo.java b/app/src/main/java/net/mynero/wallet/model/CoinsInfo.java index 32e3de5..259ed47 100644 --- a/app/src/main/java/net/mynero/wallet/model/CoinsInfo.java +++ b/app/src/main/java/net/mynero/wallet/model/CoinsInfo.java @@ -30,9 +30,13 @@ public class CoinsInfo implements Parcelable { } long globalOutputIndex; + boolean spent; + String keyImage; - public CoinsInfo(long globalOutputIndex) { + public CoinsInfo(long globalOutputIndex, boolean spent, String keyImage) { this.globalOutputIndex = globalOutputIndex; + this.spent = spent; + this.keyImage = keyImage; } protected CoinsInfo(Parcel in) { @@ -55,6 +59,14 @@ public class CoinsInfo implements Parcelable { return globalOutputIndex; } + public boolean isSpent() { + return spent; + } + + public String getKeyImage() { + return keyImage; + } + @Override public int describeContents() { return 0; diff --git a/app/src/main/java/net/mynero/wallet/model/Wallet.java b/app/src/main/java/net/mynero/wallet/model/Wallet.java index 1114657..1cd1779 100644 --- a/app/src/main/java/net/mynero/wallet/model/Wallet.java +++ b/app/src/main/java/net/mynero/wallet/model/Wallet.java @@ -24,6 +24,7 @@ import net.mynero.wallet.data.TxData; import java.io.File; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; @@ -276,32 +277,31 @@ public class Wallet { return createTransaction( txData.getDestinationAddress(), txData.getAmount(), - txData.getMixin(), - txData.getPriority()); + txData.getPriority(), + txData.getPreferredInputs()); } public PendingTransaction createTransaction(String dst_addr, - long amount, int mixin_count, - PendingTransaction.Priority priority) { + long amount, PendingTransaction.Priority priority, ArrayList key_images) { disposePendingTransaction(); int _priority = priority.getValue(); long txHandle = (amount == SWEEP_ALL ? - createSweepTransaction(dst_addr, "", mixin_count, _priority, - accountIndex) : - createTransactionJ(dst_addr, "", amount, mixin_count, _priority, - accountIndex)); + createSweepTransaction(dst_addr, "", 0, _priority, + accountIndex, key_images) : + createTransactionJ(dst_addr, "", amount, 0, _priority, + accountIndex, key_images)); pendingTransaction = new PendingTransaction(txHandle); return pendingTransaction; } private native long createTransactionJ(String dst_addr, String payment_id, long amount, int mixin_count, - int priority, int accountIndex); + int priority, int accountIndex, ArrayList key_images); private native long createSweepTransaction(String dst_addr, String payment_id, int mixin_count, - int priority, int accountIndex); + int priority, int accountIndex, ArrayList key_images); private native long createTransactionSingleJ(String key_image, String dst_addr, int priority); diff --git a/app/src/main/java/net/mynero/wallet/service/MoneroHandlerThread.java b/app/src/main/java/net/mynero/wallet/service/MoneroHandlerThread.java index 1780e55..04bc870 100644 --- a/app/src/main/java/net/mynero/wallet/service/MoneroHandlerThread.java +++ b/app/src/main/java/net/mynero/wallet/service/MoneroHandlerThread.java @@ -28,6 +28,9 @@ import net.mynero.wallet.model.WalletListener; import net.mynero.wallet.model.WalletManager; import net.mynero.wallet.util.Constants; +import java.util.ArrayList; +import java.util.List; + /** * Handy class for starting a new thread that has a looper. The looper can then be @@ -121,7 +124,9 @@ public class MoneroHandlerThread extends Thread implements WalletListener { public PendingTransaction createTx(String address, String amountStr, boolean sendAll, PendingTransaction.Priority feePriority) { long amount = sendAll ? SWEEP_ALL : Wallet.getAmountFromString(amountStr); - return wallet.createTransaction(new TxData(address, amount, 0, feePriority)); + ArrayList preferredInputs = new ArrayList<>(); + preferredInputs.add(""); + return wallet.createTransaction(new TxData(address, amount, 0, feePriority, preferredInputs)); } public boolean sendTx(PendingTransaction pendingTx) { diff --git a/external-libs/include/wallet2_api.h b/external-libs/include/wallet2_api.h index 8d634b3..291f214 100644 --- a/external-libs/include/wallet2_api.h +++ b/external-libs/include/wallet2_api.h @@ -886,7 +886,8 @@ struct Wallet optional> amount, uint32_t mixin_count, PendingTransaction::Priority = PendingTransaction::Priority_Low, uint32_t subaddr_account = 0, - std::set subaddr_indices = {}) = 0; + std::set subaddr_indices = {}, + const std::set &preferred_inputs = {}) = 0; /*! * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored @@ -905,7 +906,8 @@ struct Wallet optional amount, uint32_t mixin_count, PendingTransaction::Priority = PendingTransaction::Priority_Low, uint32_t subaddr_account = 0, - std::set subaddr_indices = {}) = 0; + std::set subaddr_indices = {}, + const std::set &preferred_inputs = {}) = 0; /*! * \brief createTransactionSingle creates transaction with single input