mirror of
https://codeberg.org/anoncontributorxmr/mysu.git
synced 2024-11-25 08:52:28 +00:00
EXPERIMENTAL: Playing around with the idea of letting users attach a donation "per tx" (read comment in MoneroHandlerThread.java for why this is in quotes) to support MyNero development when they spend coins.
This commit is contained in:
parent
4059e28d3f
commit
fd84f11848
5 changed files with 131 additions and 2 deletions
|
@ -233,6 +233,24 @@ std::vector<std::string> java2cpp(JNIEnv *env, jobject arrayList) {
|
|||
return result;
|
||||
}
|
||||
|
||||
jlong getElement(JNIEnv *env, jlongArray arr_j, int element) {
|
||||
jlong result;
|
||||
env->GetLongArrayRegion(arr_j, element,1, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::uint64_t> java2cpp_long(JNIEnv *env, jlongArray longArray) {
|
||||
jint len = env->GetArrayLength(longArray);
|
||||
std::vector<std::uint64_t> result;
|
||||
result.reserve(len);
|
||||
for (jint i = 0; i < len; i++) {
|
||||
jlong amount = getElement(env, longArray, i);
|
||||
result.emplace_back(amount);
|
||||
env->ReleaseLongArrayElements(longArray, reinterpret_cast<jlong *>(amount), i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<std::string> java2cpp_set(JNIEnv *env, jobject arrayList) {
|
||||
|
||||
jmethodID java_util_ArrayList_size = env->GetMethodID(class_ArrayList, "size", "()I");
|
||||
|
@ -1029,6 +1047,29 @@ Java_net_mynero_wallet_model_Wallet_createTransactionJ(JNIEnv *env, jobject inst
|
|||
return reinterpret_cast<jlong>(tx);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_net_mynero_wallet_model_Wallet_createTransactionMultDestJ(JNIEnv *env, jobject instance,
|
||||
jobject dst_addrs, jstring payment_id,
|
||||
jlongArray amounts, jint mixin_count,
|
||||
jint priority,
|
||||
jint accountIndex, jobject key_images) {
|
||||
const std::set<std::string> _key_images = java2cpp_set(env, key_images);
|
||||
const std::vector<std::string> _dst_addrs = java2cpp(env, dst_addrs);
|
||||
const std::vector<std::uint64_t> _dst_amounts = java2cpp_long(env, amounts);
|
||||
const char *_payment_id = env->GetStringUTFChars(payment_id, nullptr);
|
||||
Monero::PendingTransaction::Priority _priority =
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority);
|
||||
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
|
||||
|
||||
Monero::PendingTransaction *tx = wallet->createTransactionMultDest(_dst_addrs, _payment_id,
|
||||
_dst_amounts, (uint32_t) mixin_count,
|
||||
_priority,
|
||||
(uint32_t) accountIndex, {}, _key_images);
|
||||
|
||||
env->ReleaseStringUTFChars(payment_id, _payment_id);
|
||||
return reinterpret_cast<jlong>(tx);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_net_mynero_wallet_model_Wallet_estimateTransactionFee(JNIEnv *env, jobject instance,
|
||||
jobject destinations, jint priority) {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package net.mynero.wallet.model;
|
||||
|
||||
import net.mynero.wallet.service.PrefService;
|
||||
import net.mynero.wallet.util.Constants;
|
||||
|
||||
public class TransactionOutput {
|
||||
private final String destination;
|
||||
private final long amount;
|
||||
|
||||
public TransactionOutput(String destination, long amount) {
|
||||
this.destination = destination;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public long getAmount() {
|
||||
return amount;
|
||||
}
|
||||
}
|
|
@ -288,6 +288,14 @@ public class Wallet {
|
|||
txData.getPreferredInputs());
|
||||
}
|
||||
|
||||
public PendingTransaction createSweepTransaction(String dst_addr, PendingTransaction.Priority priority, ArrayList<String> key_images) {
|
||||
disposePendingTransaction();
|
||||
int _priority = priority.getValue();
|
||||
long txHandle = createSweepTransaction(dst_addr, "", 0, _priority, accountIndex, key_images);
|
||||
pendingTransaction = new PendingTransaction(txHandle);
|
||||
return pendingTransaction;
|
||||
}
|
||||
|
||||
public PendingTransaction createTransaction(String dst_addr,
|
||||
long amount, PendingTransaction.Priority priority, ArrayList<String> key_images) {
|
||||
disposePendingTransaction();
|
||||
|
@ -302,6 +310,26 @@ public class Wallet {
|
|||
return pendingTransaction;
|
||||
}
|
||||
|
||||
public PendingTransaction createTransactionMultDest(ArrayList<TransactionOutput> outputs, PendingTransaction.Priority priority, ArrayList<String> key_images) {
|
||||
disposePendingTransaction();
|
||||
int _priority = priority.getValue();
|
||||
ArrayList<String> destinations = new ArrayList<>();
|
||||
long[] amounts = new long[outputs.size()];
|
||||
for(int i = 0; i < outputs.size(); i++) {
|
||||
TransactionOutput output = outputs.get(i);
|
||||
destinations.add(output.getDestination());
|
||||
amounts[i] = output.getAmount();
|
||||
}
|
||||
long txHandle = createTransactionMultDestJ(destinations, "", amounts, 0, _priority,
|
||||
accountIndex, key_images);
|
||||
pendingTransaction = new PendingTransaction(txHandle);
|
||||
return pendingTransaction;
|
||||
}
|
||||
|
||||
private native long createTransactionMultDestJ(ArrayList<String> dst_addrs, String payment_id,
|
||||
long[] amount, int mixin_count,
|
||||
int priority, int accountIndex, ArrayList<String> key_images);
|
||||
|
||||
private native long createTransactionJ(String dst_addr, String payment_id,
|
||||
long amount, int mixin_count,
|
||||
int priority, int accountIndex, ArrayList<String> key_images);
|
||||
|
|
|
@ -22,11 +22,13 @@ import net.mynero.wallet.data.Node;
|
|||
import net.mynero.wallet.data.TxData;
|
||||
import net.mynero.wallet.model.CoinsInfo;
|
||||
import net.mynero.wallet.model.PendingTransaction;
|
||||
import net.mynero.wallet.model.TransactionOutput;
|
||||
import net.mynero.wallet.model.Wallet;
|
||||
import net.mynero.wallet.model.WalletListener;
|
||||
import net.mynero.wallet.model.WalletManager;
|
||||
import net.mynero.wallet.util.Constants;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
|
@ -128,7 +130,7 @@ public class MoneroHandlerThread extends Thread implements WalletListener {
|
|||
}
|
||||
|
||||
public PendingTransaction createTx(String address, String amountStr, boolean sendAll, PendingTransaction.Priority feePriority, ArrayList<String> selectedUtxos) throws Exception {
|
||||
long amount = sendAll ? Wallet.SWEEP_ALL : Wallet.getAmountFromString(amountStr);
|
||||
long amount = Wallet.getAmountFromString(amountStr);
|
||||
ArrayList<String> preferredInputs;
|
||||
if (selectedUtxos.isEmpty()) {
|
||||
// no inputs manually selected, we are sending from home screen most likely, or user somehow broke the app
|
||||
|
@ -137,7 +139,36 @@ public class MoneroHandlerThread extends Thread implements WalletListener {
|
|||
preferredInputs = selectedUtxos;
|
||||
checkSelectedAmounts(selectedUtxos, amount, sendAll);
|
||||
}
|
||||
return wallet.createTransaction(new TxData(address, amount, 0, feePriority, preferredInputs));
|
||||
|
||||
if(sendAll) {
|
||||
return wallet.createSweepTransaction(address, feePriority, preferredInputs);
|
||||
}
|
||||
|
||||
boolean donatePerTx = PrefService.getInstance().getBoolean(Constants.PREF_DONATE_PER_TX, false);
|
||||
ArrayList<TransactionOutput> outputs = new ArrayList<>();
|
||||
outputs.add(new TransactionOutput(address, amount));
|
||||
if(donatePerTx) {
|
||||
float randomDonatePct = getRandomDonateAmount(0.0075f, 0.015f); // occasionally attaches a 0.75% to 1.5% fee. It is random so that not even I know how much exactly you are sending.
|
||||
/*
|
||||
It's also not entirely "per tx". It won't always attach it so as to not have a consistent fingerprint on-chain. When it does attach a donation,
|
||||
it will periodically split it up into 2 outputs instead of 1.
|
||||
*/
|
||||
int attachDonationRoll = new SecureRandom().nextInt(100);
|
||||
if(attachDonationRoll > 75) {
|
||||
int splitDonationRoll = new SecureRandom().nextInt(100);
|
||||
long donateAmount = (long) (amount*randomDonatePct);
|
||||
if(splitDonationRoll > 50) {
|
||||
// split
|
||||
long splitAmount = donateAmount / 2;
|
||||
outputs.add(new TransactionOutput(Constants.DONATE_ADDRESS, splitAmount));
|
||||
outputs.add(new TransactionOutput(Constants.DONATE_ADDRESS, splitAmount));
|
||||
} else {
|
||||
outputs.add(new TransactionOutput(Constants.DONATE_ADDRESS, donateAmount));
|
||||
}
|
||||
checkSelectedAmounts(selectedUtxos, amount+donateAmount, false); // check that the selected UTXOs satisfy the new amount total
|
||||
}
|
||||
}
|
||||
return wallet.createTransactionMultDest(outputs, feePriority, preferredInputs);
|
||||
}
|
||||
|
||||
private void checkSelectedAmounts(ArrayList<String> selectedUtxos, long amount, boolean sendAll) throws Exception {
|
||||
|
@ -163,6 +194,12 @@ public class MoneroHandlerThread extends Thread implements WalletListener {
|
|||
return height % interval == 0;
|
||||
}
|
||||
|
||||
private float getRandomDonateAmount(float min, float max) {
|
||||
SecureRandom rand = new SecureRandom();
|
||||
return rand.nextFloat() * (max - min) + min;
|
||||
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onRefresh(long height);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ public class Constants {
|
|||
public static final String PREF_USES_OFFSET = "pref_uses_offset";
|
||||
public static final String PREF_STREET_MODE = "pref_street_mode";
|
||||
public static final String PREF_MONEROCHAN = "pref_monerochan";
|
||||
public static final String PREF_DONATE_PER_TX = "pref_donate_per_tx";
|
||||
|
||||
public static final String URI_PREFIX = "monero:";
|
||||
public static final String URI_ARG_AMOUNT = "tx_amount";
|
||||
|
|
Loading…
Reference in a new issue