@@ -463,6 +463,7 @@ class SpeedHandler @Inject constructor(
463463 selectable = isSelectable(
464464 speedOption,
465465 amount,
466+ currentBalance,
466467 Bitcoins (amountFreeTierMin),
467468 Bitcoins (minimum),
468469 Bitcoins (amountFreeTierMin),
@@ -472,51 +473,55 @@ class SpeedHandler @Inject constructor(
472473 } else {
473474 speedOption.copy(selectable = false )
474475 }
475- else ->
476- if (currentBalance.units < amountFreeTierMin) {
477- val minAmount = Bitcoins (minimum)
478- val maxAmount = currentBalance - speedOption.totalFee
479- speedOption.copy(
480- minimumAmount = minAmount,
481- maximumAmount = maxAmount,
482- selectable = isSelectable(
483- speedOption,
484- amount,
485- Bitcoins (amountFreeTierMin),
486- Bitcoins (minimum),
487- minAmount,
488- maxAmount
489- )
490- )
476+ else -> {
477+ val minAmount = Bitcoins (minimum)
478+ val maxAmount = currentBalance - speedOption.totalFee
479+ // For Rush, if the fee pushes maxAmount below minAmount but the balance exceeds
480+ // the minimum, the fee will be reduced at selection time. Reflect that here so the
481+ // global min/max check in getHurdles doesn't reject the withdrawal.
482+ val effectiveMaxAmount = if (
483+ speedOption.speed == RUSH &&
484+ maxAmount < minAmount &&
485+ currentBalance > minAmount
486+ ) {
487+ minAmount
491488 } else {
492- val minAmount = Bitcoins (minimum)
493- val maxAmount = currentBalance - speedOption.totalFee
494- speedOption.copy(
495- minimumAmount = minAmount,
496- maximumAmount = maxAmount,
497- selectable = isSelectable(
498- speedOption,
499- amount,
500- Bitcoins (amountFreeTierMin),
501- Bitcoins (minimum),
502- minAmount,
503- maxAmount
504- )
505- )
489+ maxAmount
506490 }
491+ speedOption.copy(
492+ minimumAmount = minAmount,
493+ maximumAmount = effectiveMaxAmount,
494+ selectable = isSelectable(
495+ speedOption,
496+ amount,
497+ currentBalance,
498+ Bitcoins (amountFreeTierMin),
499+ Bitcoins (minimum),
500+ minAmount,
501+ effectiveMaxAmount
502+ )
503+ )
504+ }
507505 }
508506 }
509507
510508 @Suppress(" LongParameterList" )
511509 fun isSelectable (
512510 speedOption : WithdrawalSpeedOption ,
513511 amount : Bitcoins ,
512+ currentBalance : Bitcoins ,
514513 amountFreeTierMin : Bitcoins ,
515514 minimumAmount : Bitcoins ,
516515 calculatedMinAmount : Bitcoins ,
517516 calculatedMaxAmount : Bitcoins ,
518517 ): Boolean? = when (speedOption.speed) {
519518 STANDARD -> amount >= amountFreeTierMin
519+ RUSH -> {
520+ // Rush is selectable if the customer's balance exceeds the minimum withdrawal amount,
521+ // even if fees would normally push maxAmount below minAmount. In that case, the fee
522+ // will be reduced at selection time so the withdrawal amount is exactly the minimum.
523+ amount >= minimumAmount && currentBalance > minimumAmount
524+ }
520525 else -> {
521526 amount >= minimumAmount && calculatedMaxAmount >= calculatedMinAmount
522527 }
@@ -537,17 +542,32 @@ class SpeedHandler @Inject constructor(
537542 val selectedSpeed = response.selectedSpeed
538543 ? : raise(ParameterIsRequired (value.customerId, " selectedSpeed" ))
539544
545+ val storedOption =
546+ withdrawalStore.findSpeedOptionByWithdrawalTokenAndSpeed(value.id, selectedSpeed).bind()
547+ ? : raise(
548+ IllegalStateException (
549+ " No speed option for speed $selectedSpeed for withdrawal ${value.id} "
550+ )
551+ )
552+
553+ // For Rush speed, if the normal fee would push the withdrawal amount below the minimum,
554+ // reduce the fee so the customer can withdraw exactly the minimum amount.
555+ val effectiveOption = if (
556+ storedOption.speed == RUSH &&
557+ balance - storedOption.totalFee < Bitcoins (minimum) &&
558+ balance > Bitcoins (minimum)
559+ ) {
560+ val reducedFee = balance - Bitcoins (minimum)
561+ storedOption.copy(
562+ totalFee = reducedFee,
563+ totalFeeFiatEquivalent = bitcoinsToUsd(reducedFee, exchangeRate),
564+ )
565+ } else {
566+ storedOption
567+ }
568+
540569 val option =
541- addAmountsAndSelectability(
542- withdrawalStore.findSpeedOptionByWithdrawalTokenAndSpeed(value.id, selectedSpeed).bind()
543- ? : raise(
544- IllegalStateException (
545- " No speed option for speed $selectedSpeed for withdrawal ${value.id} "
546- )
547- ),
548- balance,
549- amount
550- ).map {
570+ addAmountsAndSelectability(effectiveOption, balance, amount).map {
551571 addAdjustedAmount(it, amount, exchangeRate).bind()
552572 }.bind()
553573
0 commit comments