Skip to content

Commit

Permalink
Release source code for 44.3
Browse files Browse the repository at this point in the history
  • Loading branch information
acrespo committed Mar 17, 2021
1 parent a506d13 commit 486180a
Show file tree
Hide file tree
Showing 22 changed files with 138 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ enum Bucket {
FREQUENT,
WORKING_SET,
ACTIVE,
UNKNOWN
UNKNOWN,
UNAVAILABLE,
}

Bucket current();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ public class NotificationProcessor {
private final OperationMetadataMapper operationMapper;
private final FulfillIncomingSwapAction fulfillIncomingSwap;

private final Map<String, NotificationHandler> handlers =
new HashMap<>();
private final Map<String, NotificationHandler> handlers = new HashMap<>();

/**
* Constructor.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ public void dangerouslyDestroyUnrecoverableWallet() {
destroyWallet();
}

/**
* Wipe all user associated data from the app, prior to a signup/login.
*/
public void destroyWalletToStartClean() {
destroyWallet();
}

/**
* Wipe all user associated data from the app.
* As the name suggests, this method performs no checks and dangerously destroy all user data in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.muun.apollo.data.net.HoustonClient
import io.muun.apollo.data.preferences.KeysRepository
import io.muun.apollo.data.preferences.UserRepository
import io.muun.apollo.domain.action.CurrencyActions
import io.muun.apollo.domain.action.LogoutActions
import io.muun.apollo.domain.action.base.BaseAsyncAction0
import io.muun.apollo.domain.action.fcm.GetFcmTokenAction
import io.muun.apollo.domain.action.keys.CreateBasePrivateKeyAction
Expand All @@ -20,6 +21,7 @@ class CreateFirstSessionAction @Inject constructor(
private val userRepository: UserRepository,
private val keysRepository: KeysRepository,
private val currencyActions: CurrencyActions,
private val logoutActions: LogoutActions,
private val getFcmToken: GetFcmTokenAction,
private val createBasePrivateKey: CreateBasePrivateKeyAction

Expand All @@ -30,6 +32,7 @@ class CreateFirstSessionAction @Inject constructor(
*/
override fun action(): Observable<CreateFirstSessionOk> =
Observable.defer {
logoutActions.destroyWalletToStartClean()
getFcmToken.action().flatMap { setUpUser(it) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.muun.apollo.domain.action.session
import io.muun.apollo.data.external.Globals
import io.muun.apollo.data.logging.LoggingContext
import io.muun.apollo.data.net.HoustonClient
import io.muun.apollo.domain.action.LogoutActions
import io.muun.apollo.domain.action.base.BaseAsyncAction1
import io.muun.apollo.domain.action.fcm.GetFcmTokenAction
import io.muun.common.model.CreateSessionOk
Expand All @@ -14,7 +15,8 @@ import javax.validation.constraints.NotNull
@Singleton
class CreateLoginSessionAction @Inject constructor(
private val houstonClient: HoustonClient,
private val getFcmToken: GetFcmTokenAction
private val getFcmToken: GetFcmTokenAction,
private val logoutActions: LogoutActions,

): BaseAsyncAction1<String, CreateSessionOk>() {

Expand All @@ -24,8 +26,11 @@ class CreateLoginSessionAction @Inject constructor(
/**
* Creates a new session to log into Houston, associated with a given email.
*/
private fun createSession(@NotNull email: String) =
getFcmToken.action()
private fun createSession(@NotNull email: String): Observable<CreateSessionOk> {

logoutActions.destroyWalletToStartClean()

return getFcmToken.action()
.flatMap { fcmToken ->
houstonClient.createLoginSession(
Globals.INSTANCE.oldBuildType,
Expand All @@ -35,4 +40,5 @@ class CreateLoginSessionAction @Inject constructor(
)
}
.doOnNext { LoggingContext.configure(email, "NotLoggedYet") }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.muun.apollo.data.preferences.UserPreferencesRepository
import io.muun.apollo.data.preferences.UserRepository
import io.muun.apollo.domain.ApiMigrationsManager
import io.muun.apollo.domain.action.ContactActions
import io.muun.apollo.domain.action.LogoutActions
import io.muun.apollo.domain.action.OperationActions
import io.muun.apollo.domain.action.SigninActions
import io.muun.apollo.domain.action.base.BaseAsyncAction3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public BitcoinAmount(
public BitcoinAmount add(BitcoinAmount other) {
// TODO we should NOT be adding MonetaryAmounts, instead recalculating with the implied
// exchange rate using only satoshis.

if (other == null) {
return this;
}

return new BitcoinAmount(
inSatoshis + other.inSatoshis,
inInputCurrency.add(other.inInputCurrency),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ class PaymentAnalysis(
/** The transaction fee for the PaymentRequest, null if `canPayWithoutFee` is false. */
val fee: BitcoinAmount?,

/** The total money to be spent, null if `canPayWithSelectedFee` is false. */
/**
* The total money to be spent, null if `canPayWithSelectedFee` is false.
* UPDATE: This is total BS. Sometimes canPayWithSelectedFee is false and total is not null.
* E.g for UseAllFunds/TFFA this can happen.
*/
val total: BitcoinAmount?,

/** Whether the amount could itself be paid, ignoring fees. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,15 @@ class PaymentAnalyzer(private val payCtx: PaymentContext,
totalInSatoshis = null,
outputAmountInSatoshis = payReq.swap?.fundingOutput?.outputAmountInSatoshis,
swapFees = payReq.swap?.fees,
canPayWithoutFee = false,
canPayWithoutFee = originalAmountInSatoshis < totalBalanceInSatoshis,
canPayWithSelectedFee = false,
canPayWithMinimumFee = false
)
}

private fun analyzeFeeFromAmount(): PaymentAnalysis {
checkNotNull(payReq.feeInSatoshisPerByte)
check(payReq.takeFeeFromAmount)

// TODO UseAllFunds shouldn't need amount, take userBalance from payCtx
val totalInSatoshis = originalAmountInSatoshis
Expand Down Expand Up @@ -145,6 +146,7 @@ class PaymentAnalyzer(private val payCtx: PaymentContext,
checkNotNull(payReq.swap)
checkNotNull(payReq.swap.bestRouteFees)
checkNotNull(payReq.swap.fundingOutputPolicies)
check(payReq.takeFeeFromAmount)

var (feeInSats, offchainAmountInSats, params, feeRate) = computeTffaParamsFor(payReq.swap, 0)

Expand Down Expand Up @@ -405,17 +407,48 @@ class PaymentAnalyzer(private val payCtx: PaymentContext,
canPayWithSelectedFee: Boolean,
canPayWithMinimumFee: Boolean): PaymentAnalysis {

val amount = convertToBitcoinAmount(amountInSatoshis)
val sweepFee = convertToNullableBitcoinAmount(swapFees?.sweepInSats)
val lightningFee = convertToNullableBitcoinAmount(swapFees?.lightningInSats)
val fee = convertToNullableBitcoinAmount(feeInSatoshis)


// Ok, so here's how it goes. Sometimes we don't care to calculate the total, as the
// payment is invalid/can't be paid. (Most of) Those times, totalInSatoshis is null, so
// we're fine leaving total null (and avoiding the precondition check).
var total: BitcoinAmount? = null

if (totalInSatoshis != null) {

// Avoiding precondition check, and keep returning same value as before, for TFFA edge
// case where we return a non-null total (e.g total == amount) when
// canPayWithSelectedFee is false.
// TODO: fix this edge case
if (payReq.takeFeeFromAmount && !canPayWithSelectedFee) {
total = convertToBitcoinAmount(totalInSatoshis)

} else {

// Doing math with converted amounts to avoid showing rounding errors in UI.
total = amount
.add(sweepFee)
.add(lightningFee)
.add(fee)

Preconditions.checkArgument(totalInSatoshis == total.inSatoshis)
}
}

return PaymentAnalysis(
updatedPayReq ?: payReq,
totalBalance = convertToBitcoinAmount(totalBalanceInSatoshis),

amount = convertToBitcoinAmount(amountInSatoshis),
amount = amount,
outputAmount = convertToBitcoinAmount(outputAmountInSatoshis ?: amountInSatoshis),
sweepFee = convertToNullableBitcoinAmount(swapFees?.sweepInSats),
lightningFee = convertToNullableBitcoinAmount(swapFees?.lightningInSats),
fee = convertToNullableBitcoinAmount(feeInSatoshis),
total = convertToNullableBitcoinAmount(totalInSatoshis),

sweepFee = sweepFee,
lightningFee = lightningFee,
fee = fee,
total = total,
canPayWithoutFee = canPayWithoutFee,
canPayWithSelectedFee = canPayWithSelectedFee,
canPayWithMinimumFee = canPayWithMinimumFee,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class PaymentContext(
.withAmount(allFunds)
.withTakeFeeFromAmount(true)

if (payReq.swap != null) {
if (payReq.swap?.bestRouteFees == null) {
simulatedUseAllFundsPayReq = simulatedUseAllFundsPayReq
.withSwapAmount(userBalance)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,15 @@ class LogoutOptionsSelector @Inject constructor(
fun get(): LogoutOptions =
watch().toBlocking().first()

/**
* We decide if it's ok to go ahead and delete wallet aka clear local storage.
*/
fun canDeleteWallet(): Boolean =
if (userSel.getOptional().isPresent) {
get().canDeleteWallet()
} else {
// If we don't have enough data to decide we'll asume its some early or inconsistent
// state and we default to false
false
}
}
4 changes: 2 additions & 2 deletions android/apolloui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ android {
applicationId "io.muun.apollo"
minSdkVersion 19
targetSdkVersion 29
versionCode 402
versionName "44.2"
versionCode 403
versionName "44.3"

// Needed to make sure these classes are available in the main DEX file for API 19
// See: https://spin.atomicobject.com/2018/07/16/support-kitkat-multidex/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@ internal class AppStandbyBucketProviderImpl(val context: Context) : AppStandbyBu

override fun current(): Bucket {

val bucket = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val stats = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
stats.appStandbyBucket
} else {
0 // They start at 10 with ACTIVE and only go up from there so this will be UNKNOWN
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
return Bucket.UNAVAILABLE
}

return when (bucket) {
val stats = context.getSystemService(Context.USAGE_STATS_SERVICE) as? UsageStatsManager
if (stats == null) {
// Report a special bucket if we have no access
return Bucket.UNAVAILABLE
}

return when (stats.appStandbyBucket) {
UsageStatsManager.STANDBY_BUCKET_ACTIVE -> Bucket.ACTIVE
UsageStatsManager.STANDBY_BUCKET_WORKING_SET -> Bucket.WORKING_SET
UsageStatsManager.STANDBY_BUCKET_FREQUENT -> Bucket.FREQUENT
UsageStatsManager.STANDBY_BUCKET_RARE -> Bucket.RARE
UsageStatsManager.STANDBY_BUCKET_WORKING_SET -> Bucket.WORKING_SET
else -> Bucket.UNKNOWN
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public void navigateToRequestUpdate(@NotNull Context context) {
* @param context an {Activity} context.
*/
public void navigateToRequestRestart(@NotNull Context context) {
logoutActions.destroyRecoverableWallet(); // If user canLogout, wipe Local Storage early.
navigateToSingleAction(context, SingleActionActivity.ActionType.REQUEST_RESTART, true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ protected boolean maybeHandleFatalError(Throwable error) {
* needing anything from the local data (which may or may not be available).
*/
protected boolean canLogout() {
return logoutOptionsSel.get().canDeleteWallet();
return logoutOptionsSel.canDeleteWallet();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ class HomeFragment : SingleFragment<HomePresenter>(), HomeView {

}

class GestureListener(val chevron: View, val context: Context, val down: Boolean):
GestureDetector.SimpleOnGestureListener() {
class GestureListener(private val chevron: View, context: Context, private val down: Boolean):
GestureDetector.SimpleOnGestureListener() {

private val minVelocity = ViewConfiguration.get(context).scaledMinimumFlingVelocity
private val minTravelDistance = ViewConfiguration.get(context).scaledTouchSlop
Expand Down Expand Up @@ -178,14 +178,12 @@ class HomeFragment : SingleFragment<HomePresenter>(), HomeView {

balanceView.setBalance(homeBalanceState)

if (utxoSetState != homeBalanceState.utxoSetState) {
when (homeBalanceState.utxoSetState) {
UtxoSetStateSelector.UtxoSetState.PENDING -> chevron.setAnimation(R.raw.lm_chevron_pending)
UtxoSetStateSelector.UtxoSetState.RBF -> chevron.setAnimation(R.raw.lm_chevron_rbf)
UtxoSetStateSelector.UtxoSetState.CONFIRMED -> chevron.setAnimation(R.raw.lm_chevron_regular)
}
utxoSetState = homeBalanceState.utxoSetState
when (homeBalanceState.utxoSetState) {
UtxoSetStateSelector.UtxoSetState.PENDING -> chevron.setAnimation(R.raw.lm_chevron_pending)
UtxoSetStateSelector.UtxoSetState.RBF -> chevron.setAnimation(R.raw.lm_chevron_rbf)
UtxoSetStateSelector.UtxoSetState.CONFIRMED -> chevron.setAnimation(R.raw.lm_chevron_regular)
}
utxoSetState = homeBalanceState.utxoSetState
}

override fun setNewOp(newOp: Operation, mode: CurrencyDisplayMode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import io.muun.common.Optional;
import io.muun.common.Rules;
import io.muun.common.exception.MissingCaseError;
import io.muun.common.utils.Preconditions;

import android.os.Bundle;
import android.view.View;
Expand Down Expand Up @@ -136,9 +135,8 @@ public void setPaymentContextForError(PaymentContext payCtx,

final MonetaryAmount minBalance;

if (payReq.getSwap() != null && analysis.getFee() != null) {
if (payReq.getSwap() != null && analysis.getTotal() != null) {
// We could compute the fee (and thus, the total amount too) but we can't pay for it
Preconditions.checkNotNull(analysis.getTotal());
minBalance = analysis.getTotal().inInputCurrency;

} else if (minFeeAnalysis.getTotal() != null) {
Expand Down
Loading

0 comments on commit 486180a

Please sign in to comment.