Verified Commit 4a00874d authored by Sarath's avatar Sarath
Browse files

Improved Fee breakdown for whirlpool

parent c458ec36
......@@ -65,6 +65,7 @@ import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java8.util.Optional;
import kotlin.Unit;
import static android.graphics.Typeface.BOLD;
......@@ -152,6 +153,13 @@ public class NewPoolActivity extends AppCompatActivity {
enableConfirmButton(selectedPoolViewModel != null);
});
reviewPoolFragment.setLoadingListener((aBoolean, e) -> {
if(e==null){
enableBroadcastButton(!aBoolean);
}
return Unit.INSTANCE;
});
confirmButton.setOnClickListener(view -> {
switch (newPoolViewPager.getCurrentItem()) {
case 0: {
......@@ -171,7 +179,7 @@ public class NewPoolActivity extends AppCompatActivity {
newPoolViewPager.setCurrentItem(2);
confirmButton.setText(getString(R.string.begin_cycle));
confirmButton.setBackgroundResource(R.drawable.button_green);
reviewPoolFragment.setTx0(tx0);
reviewPoolFragment.setTx0(tx0,tx0FeeTarget,selectedPoolViewModel);
break;
}
case 2: {
......@@ -494,6 +502,15 @@ public class NewPoolActivity extends AppCompatActivity {
confirmButton.setBackgroundResource(R.drawable.disabled_grey_button);
}
}
private void enableBroadcastButton(boolean enable) {
if (enable) {
confirmButton.setEnabled(true);
confirmButton.setBackgroundResource(R.drawable.button_green);
} else {
confirmButton.setEnabled(false);
confirmButton.setBackgroundResource(R.drawable.disabled_grey_button);
}
}
class NewPoolStepsPager extends FragmentPagerAdapter {
......
package com.samourai.wallet.whirlpool.newPool.fragments;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.samourai.wallet.R;
import com.samourai.wallet.whirlpool.WhirlpoolTx0;
import com.samourai.wallet.widgets.EntropyBar;
import java.text.DecimalFormat;
public class ReviewPoolFragment extends Fragment {
private static final String TAG = "SelectPoolFragment";
private EntropyBar entropyBar;
private TextView deterMinisticLinksPerTx,
totalTxs,
poolAmount,
combinationPerTxs,
poolTotalFees,
minerFees,
totalPoolAmount,
amountToCycle,
uncycledAmount,
poolFees,
entropyPerTxs;
private ProgressBar progressBar;
public ReviewPoolFragment() {
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
entropyBar = view.findViewById(R.id.pool_review_entropy_bar);
entropyPerTxs = view.findViewById(R.id.pool_review_entropy_txt);
deterMinisticLinksPerTx = view.findViewById(R.id.pool_review_deterministic_links_per_tx);
totalTxs = view.findViewById(R.id.pool_review_total_txes);
poolAmount = view.findViewById(R.id.pool_review_amount);
poolFees = view.findViewById(R.id.pool_review_pool_fee);
minerFees = view.findViewById(R.id.pool_review_miner_fee);
uncycledAmount = view.findViewById(R.id.pool_review_uncycled_amount);
amountToCycle = view.findViewById(R.id.pool_review_amount_to_cycle);
poolTotalFees = view.findViewById(R.id.pool_review_total_fees);
combinationPerTxs = view.findViewById(R.id.pool_review_combination_per_tx);
totalPoolAmount = view.findViewById(R.id.pool_review_total_pool_amount);
progressBar = view.findViewById(R.id.pool_review_progress);
entropyBar.setMaxBars(4);
entropyBar.setRange(4);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_whirlpool_review, container, false);
}
public void showProgress(boolean show) {
progressBar.setVisibility(show ? View.VISIBLE : View.GONE);
}
public void setTx0(WhirlpoolTx0 tx0) {
totalPoolAmount.setText(new DecimalFormat("0.########").format(tx0.getAmountSelected() / 1e8));
poolAmount.setText(new DecimalFormat("0.########").format(tx0.getPool() / 1e8));
poolFees.setText(new DecimalFormat("0.########").format(tx0.getFeeSamourai() / 1e8));
minerFees.setText(new DecimalFormat("0.########").format(tx0.getFee() / 1e8));
amountToCycle.setText(new DecimalFormat("0.########").format(tx0.getAmountAfterWhirlpoolFee() / 1e8));
poolTotalFees.setText(new DecimalFormat("0.########").format((tx0.getFeeSamourai() + tx0.getFee()) / 1e8));
uncycledAmount.setText(new DecimalFormat("0.########").format((tx0.getChange() / 1e8)));
totalTxs.setText(String.valueOf(tx0.getPremixRequested()));
}
}
package com.samourai.wallet.whirlpool.newPool.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.transition.AutoTransition
import androidx.transition.Fade
import androidx.transition.TransitionManager
import com.samourai.wallet.R
import com.samourai.wallet.api.backend.beans.UnspentResponse.UnspentOutput
import com.samourai.wallet.api.backend.beans.UnspentResponse.UnspentOutput.Xpub
import com.samourai.wallet.send.SendFactory
import com.samourai.wallet.util.FormatsUtil
import com.samourai.wallet.whirlpool.WhirlpoolTx0
import com.samourai.wallet.widgets.EntropyBar
import com.samourai.whirlpool.client.tx0.Tx0Preview
import com.samourai.whirlpool.client.tx0.UnspentOutputWithKey
import com.samourai.whirlpool.client.wallet.AndroidWhirlpoolWalletService
import com.samourai.whirlpool.client.wallet.beans.Tx0FeeTarget
import com.samourai.whirlpool.client.wallet.beans.WhirlpoolAccount
import com.samourai.whirlpool.client.whirlpool.beans.Pool
import kotlinx.android.synthetic.main.fragment_whirlpool_review.*
import kotlinx.coroutines.*
import org.bouncycastle.util.encoders.Hex
import java.util.*
class ReviewPoolFragment : Fragment() {
private val coroutineContext = CoroutineScope(Dispatchers.IO)
private val account = 0
private var tx0: WhirlpoolTx0? = null;
private var tx0FeeTarget: Tx0FeeTarget? = null
private var pool: Pool? = null
private var onLoading: (Boolean, Exception?) -> Unit = { _: Boolean, _: Exception? -> }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
entropyBar?.setMaxBars(4)
entropyBar?.setRange(4)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_whirlpool_review, container, false)
}
fun showProgress(show: Boolean) {
progressBar!!.visibility = if (show) View.VISIBLE else View.GONE
}
fun setLoadingListener(listener: (Boolean, Exception?) -> Unit) {
this.onLoading = listener
}
fun setTx0(tx0: WhirlpoolTx0, tx0FeeTarget: Tx0FeeTarget?, pool: Pool?) {
this.pool = pool
this.tx0 = tx0;
this.tx0FeeTarget = tx0FeeTarget
makeTxoPreview(tx0)
minerFees.text = ""
feePerUtxo.text = ""
poolFees.text = ""
poolTotalFees.text = ""
poolAmount.text = getBTCDisplayAmount(tx0.pool)
totalUtxoCreated.text = "${tx0.premixRequested}";
}
private fun makeTxoPreview(tx0: WhirlpoolTx0) {
showLoadingProgress(true)
onLoading.invoke(true, null)
val whirlpoolWallet = AndroidWhirlpoolWalletService.getInstance(context).whirlpoolWalletOrNull
val spendFroms: MutableCollection<UnspentOutputWithKey> = ArrayList()
for (outPoint in tx0.outpoints) {
val unspentOutput = UnspentOutput()
unspentOutput.addr = outPoint.address
unspentOutput.script = Hex.toHexString(outPoint.scriptBytes)
unspentOutput.confirmations = outPoint.confirmations
unspentOutput.tx_hash = outPoint.txHash.toString()
unspentOutput.tx_output_n = outPoint.txOutputN
unspentOutput.value = outPoint.value.value
unspentOutput.xpub = Xpub()
unspentOutput.xpub.path = "M/0/0"
val eckey = SendFactory.getPrivKey(outPoint.address, account)
val spendFrom = UnspentOutputWithKey(unspentOutput, eckey.privKeyBytes)
spendFroms.add(spendFrom)
}
coroutineContext.launch(Dispatchers.IO) {
val tx0Config = whirlpoolWallet.tx0Config
tx0Config.changeWallet = WhirlpoolAccount.DEPOSIT
try {
val poolSelected: Pool = whirlpoolWallet.poolSupplier.findPoolById(pool?.poolId)
val tx0Preview = whirlpoolWallet.tx0Preview(poolSelected, spendFroms, tx0Config, tx0FeeTarget)
withContext(Dispatchers.Main) {
showLoadingProgress(false)
setFees(tx0Preview);
onLoading.invoke(false, null);
}
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
onLoading.invoke(false, e);
showLoadingProgress(false)
}
}
}
}
private fun showLoadingProgress(loading: Boolean) {
if (loading) {
loadingFeeDetails.show()
} else {
loadingFeeDetails.hide()
}
}
private fun setFees(tx0Preview: Tx0Preview?) {
tx0Preview?.let {
TransitionManager.beginDelayedTransition(reviewLayout, Fade())
val embeddedFees = tx0Preview.premixValue.minus(tx0!!.pool);
val embeddedTotalFees = (embeddedFees * it.nbPremix)
minerFees.text = getBTCDisplayAmount(it.minerFee);
val totalFees =embeddedTotalFees + tx0Preview.feeValue + tx0Preview.minerFee;
poolTotalFees.text = getBTCDisplayAmount(totalFees);
poolFees.text = getBTCDisplayAmount(tx0Preview.feeValue)
if (it.feeDiscountPercent != 0) {
val scodeMessage = "SCODE Applied, ${it.feeDiscountPercent}% Discount"
discountText.text = scodeMessage
}
this.tx0?.let { tx0 ->
totalPoolAmount.text = "${getBTCDisplayAmount(tx0.amountSelected)}"
amountToCycle.text = getBTCDisplayAmount((tx0.amountSelected - totalFees ) - tx0Preview.changeValue )
}
uncycledAmount?.text = getBTCDisplayAmount((tx0Preview.changeValue));
feePerUtxo.text = getBTCDisplayAmount(embeddedTotalFees);
}
}
override fun onDestroy() {
coroutineContext.cancel()
super.onDestroy()
}
companion object {
private const val TAG = "SelectPoolFragment"
}
private fun getBTCDisplayAmount(value: Long): String? {
return "${FormatsUtil.getBTCDecimalFormat(value)} BTC"
}
}
\ No newline at end of file
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:id="@+id/reviewLayout"
android:layout_height="wrap_content"
tools:context="com.samourai.wallet.whirlpool.newPool.fragments.ReviewPoolFragment">
<TextView
......@@ -15,19 +23,19 @@
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/pool_review_amount"
app:layout_constraintEnd_toStartOf="@+id/poolAmount"
app:layout_constraintHorizontal_bias="0.03"
app:layout_constraintStart_toStartOf="@+id/guideline12"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/pool_review_amount"
android:id="@+id/poolAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:text="0.05 BTC Pool"
tools:text="0.05 BTC Pool"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/textView51"
......@@ -40,7 +48,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="UTXO's CREATED"
android:text="UTXO's Created"
android:textColor="#858586"
android:typeface="monospace"
app:layout_constraintEnd_toEndOf="parent"
......@@ -49,14 +57,14 @@
app:layout_constraintTop_toBottomOf="@+id/textView51" />
<TextView
android:id="@+id/pool_review_total_txes"
android:id="@+id/totalUtxoCreated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="15"
android:textColor="#858586"
app:layout_constraintBottom_toBottomOf="@+id/textView53"
app:layout_constraintEnd_toEndOf="@+id/pool_review_amount"
app:layout_constraintEnd_toEndOf="@+id/poolAmount"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView53"
app:layout_constraintTop_toTopOf="@+id/textView53" />
......@@ -65,25 +73,25 @@
android:id="@+id/textView55"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:fontFamily="monospace"
android:text="DETERMINISTIC LINKS "
android:text="Deterministic Links "
android:textColor="#858586"
app:layout_constraintEnd_toEndOf="@+id/pool_review_total_txes"
app:layout_constraintEnd_toEndOf="@+id/totalUtxoCreated"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textView53"
app:layout_constraintTop_toBottomOf="@+id/textView53" />
<TextView
android:id="@+id/pool_review_deterministic_links_per_tx"
android:id="@+id/deterMinisticLinksPerTx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="0"
android:textColor="#858586"
app:layout_constraintBottom_toBottomOf="@+id/textView55"
app:layout_constraintEnd_toEndOf="@+id/pool_review_total_txes"
app:layout_constraintEnd_toEndOf="@+id/totalUtxoCreated"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView55"
app:layout_constraintTop_toTopOf="@+id/textView55" />
......@@ -92,9 +100,9 @@
android:id="@+id/textView57"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="COMBINATIONS "
android:text="Combinations "
android:textColor="#858586"
android:typeface="monospace"
app:layout_constraintEnd_toEndOf="parent"
......@@ -103,14 +111,14 @@
app:layout_constraintTop_toBottomOf="@+id/textView55" />
<TextView
android:id="@+id/pool_review_combination_per_tx"
android:id="@+id/combinationPerTxs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="10,546"
android:textColor="#858586"
app:layout_constraintBottom_toBottomOf="@+id/textView57"
app:layout_constraintEnd_toEndOf="@+id/pool_review_deterministic_links_per_tx"
app:layout_constraintEnd_toEndOf="@+id/deterMinisticLinksPerTx"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView57"
app:layout_constraintTop_toTopOf="@+id/textView57" />
......@@ -119,9 +127,9 @@
android:id="@+id/textView59"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="ENTROPY "
android:text="Entropy "
android:textAllCaps="false"
android:textColor="#858586"
android:typeface="monospace"
......@@ -131,12 +139,12 @@
app:layout_constraintTop_toBottomOf="@+id/textView57" />
<com.samourai.wallet.widgets.EntropyBar
android:id="@+id/pool_review_entropy_bar"
android:id="@+id/entropyBar"
android:layout_width="24dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/textView59"
app:layout_constraintEnd_toEndOf="@+id/pool_review_combination_per_tx"
app:layout_constraintEnd_toEndOf="@+id/combinationPerTxs"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView59"
app:layout_constraintTop_toTopOf="@+id/textView59" />
......@@ -165,41 +173,32 @@
app:layout_constraintStart_toStartOf="@+id/guideline12"
app:layout_constraintTop_toBottomOf="@+id/textView59" />
<View
android:id="@+id/view9"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginTop="24dp"
android:background="#A1CFCFCF"
app:layout_constraintEnd_toStartOf="@+id/guideline13"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/guideline12"
app:layout_constraintTop_toBottomOf="@+id/textView64" />
<TextView
android:id="@+id/textView60"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="Fees"
android:text="Total Fees"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/guideline13"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textView51"
app:layout_constraintTop_toBottomOf="@+id/view8" />
app:layout_constraintTop_toBottomOf="@+id/textView68" />
<TextView
android:id="@+id/pool_review_total_fees"
android:id="@+id/poolTotalFees"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0.00259855 BTC"
tools:text="0.00259855 BTC"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/textView60"
app:layout_constraintEnd_toEndOf="@+id/pool_review_amount"
app:layout_constraintEnd_toEndOf="@+id/poolAmount"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView60"
app:layout_constraintTop_toTopOf="@+id/textView60" />
......@@ -210,48 +209,98 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="POOL FEE"
android:text="Pool Fee"
android:textColor="#858586"
app:layout_constraintEnd_toStartOf="@+id/guideline13"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textView60"
app:layout_constraintTop_toBottomOf="@+id/textView60" />
app:layout_constraintTop_toBottomOf="@+id/view8" />
<TextView
android:id="@+id/textView81"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="Total premix fee"
android:textColor="#858586"
app:layout_constraintEnd_toStartOf="@+id/guideline13"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textView60"
app:layout_constraintTop_toBottomOf="@+id/textView62" />
<TextView
android:id="@+id/pool_review_pool_fee"
android:id="@+id/poolFees"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="0.0025 BTC"
android:textColor="#858586"
android:maxLines="3"
android:gravity="end"
android:textAlignment="textEnd"
app:layout_constraintBottom_toBottomOf="@+id/textView62"
app:layout_constraintEnd_toEndOf="@+id/pool_review_total_fees"
app:layout_constraintEnd_toEndOf="@+id/poolTotalFees"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView62"
app:layout_constraintTop_toTopOf="@+id/textView62" />
app:layout_constraintTop_toTopOf="@+id/textView62"
tools:text="0.0025 BTC" />
<TextView
android:id="@+id/feePerUtxo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textColor="#858586"
android:tooltipText="Per utxo embeded fees"
app:layout_constraintBottom_toBottomOf="@+id/textView81"
app:layout_constraintEnd_toEndOf="@+id/poolTotalFees"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView62"
app:layout_constraintTop_toTopOf="@+id/textView81"
app:layout_constraintVertical_bias="1.0"
tools:text="0.0025 BTC" />
<TextView
android:id="@+id/textView64"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="MINER FEE"
android:layout_marginTop="16dp"
android:text="Miner Fee"
android:textColor="#858586"
app:layout_constraintStart_toStartOf="@+id/textView62"
app:layout_constraintTop_toBottomOf="@+id/textView62" />
app:layout_constraintTop_toBottomOf="@+id/textView81" />
<com.google.android.material.progressindicator.ProgressIndicator
android:id="@+id/loadingFeeDetails"
style="@style/Widget.MaterialComponents.ProgressIndicator.Circular.Indeterminate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:indeterminate="true"
app:circularInset="8dp"
app:circularRadius="8dp"
app:indicatorColor="?attr/colorAccent"
app:indicatorSize="2dp"
app:layout_constraintBottom_toBottomOf="@+id/textView66"
app:layout_constraintEnd_toStartOf="@+id/guideline13"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView64"
app:layout_constraintTop_toBottomOf="@+id/view8" />
<TextView
android:id="@+id/pool_review_miner_fee"