-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e1d54be
commit 721b5b5
Showing
7 changed files
with
207 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 0 additions & 63 deletions
63
app/src/main/java/org/p2p/wallet/send/model/NewSendButtonStateMinSolValidator.kt
This file was deleted.
Oops, something went wrong.
81 changes: 81 additions & 0 deletions
81
app/src/main/java/org/p2p/wallet/send/model/SendButtonStateMinSolValidator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package org.p2p.wallet.send.model | ||
|
||
import timber.log.Timber | ||
import java.math.BigInteger | ||
import org.p2p.core.token.Token | ||
import org.p2p.core.utils.isZero | ||
|
||
sealed interface SendSolValidation { | ||
object AmountIsValid : SendSolValidation | ||
object EmptyRecipientMinAmountInvalid : SendSolValidation | ||
object SenderNotZeroed : SendSolValidation | ||
object SenderNoRentExemptAmountLeft : SendSolValidation | ||
} | ||
|
||
/** | ||
* One place to keep all the logic regarding min SOL validation | ||
*/ | ||
class SendButtonStateMinSolValidator( | ||
private val tokenToSend: Token.Active, | ||
private val minRentExemption: BigInteger, | ||
private val recipient: SearchResult | ||
) { | ||
|
||
/** | ||
* This case is only for sending SOL | ||
* | ||
* 1. The recipient should receive at least [minRentExemption] SOL balance if the recipient's current balance is 0 | ||
* 2. The recipient should have at least [minRentExemption] after the transaction | ||
* | ||
* 1. The sender is allowed to sent exactly the whole balance. | ||
* 2. It's allowed for the sender to have a SOL balance 0 or at least [minRentExemption] | ||
* */ | ||
fun validateAmount(inputAmount: BigInteger): SendSolValidation { | ||
if (!tokenToSend.isSOL) return SendSolValidation.AmountIsValid | ||
|
||
val isRecipientEmpty = recipient is SearchResult.AddressFound && recipient.isEmptyBalance | ||
val balanceRemaining = tokenToSend.totalInLamports - inputAmount | ||
val isSendingAllSol = balanceRemaining.isZero() | ||
val isRentExemptionRemaining = balanceRemaining >= minRentExemption | ||
val sendingMoreThanMinRent = inputAmount >= minRentExemption | ||
|
||
Timber.i( | ||
buildString { | ||
appendLine("$minRentExemption") | ||
appendLine("-----") | ||
appendLine("isRecipientEmpty = $isRecipientEmpty") | ||
appendLine("balanceRemaining = $balanceRemaining") | ||
appendLine("isSendingAllSol = $isSendingAllSol") | ||
appendLine("isRentExemptionRemaining = $isRentExemptionRemaining") | ||
appendLine("sendingMoreThanMinRent = $sendingMoreThanMinRent") | ||
} | ||
) | ||
|
||
val isSolAmountCanBeSent = isSendingAllSol || isRentExemptionRemaining | ||
|
||
if (isRecipientEmpty) { | ||
if (!sendingMoreThanMinRent) { | ||
return SendSolValidation.EmptyRecipientMinAmountInvalid | ||
} | ||
if (isSendingAllSol) { | ||
return SendSolValidation.AmountIsValid | ||
} | ||
|
||
if (!isRentExemptionRemaining && !isSendingAllSol) { | ||
return SendSolValidation.SenderNoRentExemptAmountLeft | ||
} | ||
if (!isSendingAllSol && !isRentExemptionRemaining) { | ||
return SendSolValidation.SenderNoRentExemptAmountLeft | ||
} | ||
} | ||
|
||
if (isSendingAllSol) { | ||
return SendSolValidation.AmountIsValid | ||
} | ||
// if we are not sending all SOL but leave some dust that less than rent | ||
if (!isRentExemptionRemaining) { | ||
return SendSolValidation.SenderNoRentExemptAmountLeft | ||
} | ||
return SendSolValidation.AmountIsValid | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
app/src/test/java/org/p2p/wallet/send/model/SendButtonStateMinSolValidatorTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package org.p2p.wallet.send.model | ||
|
||
import assertk.assertions.isInstanceOf | ||
import io.mockk.every | ||
import io.mockk.mockk | ||
import org.junit.Test | ||
import java.math.BigInteger | ||
import org.p2p.core.token.Token | ||
import org.p2p.core.utils.fromLamports | ||
import org.p2p.wallet.utils.assertThat | ||
|
||
class SendButtonStateMinSolValidatorTest { | ||
|
||
private lateinit var solValidator: SendButtonStateMinSolValidator | ||
|
||
private val emptyRecipient = mockk<SearchResult.AddressFound> { | ||
every { isEmptyBalance }.returns(true) | ||
} | ||
|
||
private val nonEmptyRecipient = mockk<SearchResult.AddressFound> { | ||
every { isEmptyBalance }.returns(false) | ||
} | ||
|
||
@Test | ||
fun `GIVEN empty recipient THEN validator cases work`() { | ||
// entering amount that less than minRentExemption | ||
val minRentExemption = BigInteger("890000") | ||
// "0.015000000" | ||
val solAmount = BigInteger.valueOf(15_000_000) | ||
|
||
solValidator = SendButtonStateMinSolValidator( | ||
tokenToSend = createCustomSol(solAmount), | ||
minRentExemption = minRentExemption, | ||
recipient = emptyRecipient | ||
) | ||
|
||
// enter less than min rent | ||
var input = BigInteger.valueOf(880_000) | ||
var result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.EmptyRecipientMinAmountInvalid::class) | ||
|
||
// enter more == min rent | ||
input = "890000".toBigInteger() | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.AmountIsValid::class) | ||
|
||
// enter more than min rent | ||
input = "890001".toBigInteger() | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.AmountIsValid::class) | ||
|
||
// enter full amount | ||
input = solAmount | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.AmountIsValid::class) | ||
|
||
// enter amount but mint rent is not left | ||
input = BigInteger.valueOf(14_999_000) | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.SenderNoRentExemptAmountLeft::class) | ||
} | ||
|
||
@Test | ||
fun `GIVEN non-empty recipient THEN validator cases work`() { | ||
val minRentExemption = BigInteger.valueOf(890_000) | ||
// "0.015000000" | ||
val solAmount = BigInteger.valueOf(15_000_000) | ||
|
||
solValidator = SendButtonStateMinSolValidator( | ||
tokenToSend = createCustomSol(solAmount), | ||
minRentExemption = minRentExemption, | ||
recipient = nonEmptyRecipient | ||
) | ||
|
||
// enter less than min rent | ||
var input = BigInteger.valueOf(880_000) | ||
var result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.AmountIsValid::class) | ||
|
||
// enter equals min rent | ||
input = "890000".toBigInteger() | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.AmountIsValid::class) | ||
|
||
// enter more than min rent | ||
input = "890001".toBigInteger() | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.AmountIsValid::class) | ||
|
||
// enter full amount | ||
input = solAmount | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.AmountIsValid::class) | ||
|
||
// enter amount but mint rent is not left | ||
input = BigInteger.valueOf(14_999_000) | ||
result = solValidator.validateAmount(input) | ||
result.assertThat() | ||
.isInstanceOf(SendSolValidation.SenderNoRentExemptAmountLeft::class) | ||
} | ||
|
||
private fun createCustomSol(solAmount: BigInteger): Token.Active = mockk { | ||
every { isSOL }.returns(true) | ||
every { totalInLamports }.returns(solAmount) | ||
every { total }.returns(solAmount.fromLamports(9)) | ||
} | ||
} |