From 43b096f98226f9a52c75ea49c07ef63ce5bdf890 Mon Sep 17 00:00:00 2001 From: tyleroooo Date: Tue, 15 Oct 2024 12:45:07 -0400 Subject: [PATCH] fix: help users not leave dust in the vault (#709) --- build.gradle.kts | 2 +- .../vault/VaultDepositWithdrawForm.kt | 24 ++--- .../functional/vault/VaultFormTests.kt | 88 +++++++++++++++++++ v4_abacus.podspec | 2 +- 4 files changed, 103 insertions(+), 13 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 799e48df6..b8405a825 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ allprojects { } group = "exchange.dydx.abacus" -version = "1.12.24" +version = "1.12.25" repositories { google() diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/VaultDepositWithdrawForm.kt b/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/VaultDepositWithdrawForm.kt index 822510a9d..901465672 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/VaultDepositWithdrawForm.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/VaultDepositWithdrawForm.kt @@ -17,7 +17,6 @@ import kollections.toIList import kotlinx.serialization.Serializable import kotlin.js.JsExport import kotlin.math.abs -import kotlin.math.floor @JsExport @Serializable @@ -245,7 +244,17 @@ object VaultDepositWithdrawFormValidator { if (shareValue == 0.0) { return 0.0 } - return (amount / shareValue).toLong().toDouble() + + val amountToUse = if (vaultAccount?.withdrawableUsdc != null && + vaultAccount.withdrawableUsdc - amount >= 0 && + vaultAccount.withdrawableUsdc - amount <= 0.01 + ) { + vaultAccount.withdrawableUsdc + } else { + amount + } + + return (amountToUse / shareValue).toLong().toDouble() } fun validateVaultForm( @@ -260,15 +269,8 @@ object VaultDepositWithdrawFormValidator { var submissionData: VaultDepositWithdrawSubmissionData? = null // Calculate post-operation values and slippage - val amount = formData.amount ?: 0.0 - - val shareValue = vaultAccount?.shareValue - val sharesToAttemptWithdraw = if (amount > 0 && shareValue != null && shareValue > 0) { - // shares must be whole numbers - floor(amount / shareValue) - } else { - null - } + val sharesToAttemptWithdraw = calculateSharesToWithdraw(vaultAccount, formData.amount ?: 0.0) + val amount = sharesToAttemptWithdraw * (vaultAccount?.shareValue ?: 0.0) val withdrawnAmountIncludingSlippage = slippageResponse?.expectedQuoteQuantums?.let { it / 1_000_000.0 } val postOpVaultBalance = when (formData.action) { diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultFormTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultFormTests.kt index 25e481928..4577094e5 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultFormTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultFormTests.kt @@ -38,6 +38,94 @@ class VaultFormTests { ) } + @Test + fun testShareCalculationCloseToZero() { + assertEquals( + VaultDepositWithdrawFormValidator.calculateSharesToWithdraw( + vaultAccount = makeVaultAccount( + balanceUsdc = 600.0, + balanceShares = 600000.0, + withdrawableUsdc = 500.0, + ), + amount = 500.0, + ), + 500000.0, + ) + + assertEquals( + VaultDepositWithdrawFormValidator.calculateSharesToWithdraw( + vaultAccount = makeVaultAccount( + balanceUsdc = 600.0, + balanceShares = 600000.0, + withdrawableUsdc = 500.0, + ), + amount = 499.02, + ), + 499020.0, + ) + + assertEquals( + VaultDepositWithdrawFormValidator.calculateSharesToWithdraw( + vaultAccount = makeVaultAccount( + balanceUsdc = 600.0, + balanceShares = 600000.0, + withdrawableUsdc = 500.0, + ), + amount = 499.07, + ), + 499070.0, + ) + + assertEquals( + VaultDepositWithdrawFormValidator.calculateSharesToWithdraw( + vaultAccount = makeVaultAccount( + balanceUsdc = 600.0, + balanceShares = 600000.0, + withdrawableUsdc = 500.0, + ), + amount = 499.02, + ), + 499020.0, + ) + + assertEquals( + VaultDepositWithdrawFormValidator.calculateSharesToWithdraw( + vaultAccount = makeVaultAccount( + balanceUsdc = 600.0, + balanceShares = 600000.0, + withdrawableUsdc = 500.0, + ), + amount = 499.989, + ), + // actually off by one because of double precision + cast to long + 499988.0, + ) + + assertEquals( + VaultDepositWithdrawFormValidator.calculateSharesToWithdraw( + vaultAccount = makeVaultAccount( + balanceUsdc = 600.0, + balanceShares = 600000.0, + withdrawableUsdc = 500.0, + ), + amount = 499.99, + ), + 500000.0, + ) + + assertEquals( + VaultDepositWithdrawFormValidator.calculateSharesToWithdraw( + vaultAccount = makeVaultAccount( + balanceUsdc = 600.0, + balanceShares = 600000.0, + withdrawableUsdc = 500.0, + ), + amount = 499.992, + ), + 500000.0, + ) + } + @Test fun testDepositValidation() { val result = VaultDepositWithdrawFormValidator.validateVaultForm( diff --git a/v4_abacus.podspec b/v4_abacus.podspec index 94d2ddbf0..1651704e4 100644 --- a/v4_abacus.podspec +++ b/v4_abacus.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'v4_abacus' - spec.version = '1.12.24' + spec.version = '1.12.25' spec.homepage = 'https://github.com/dydxprotocol/v4-abacus' spec.source = { :http=> ''} spec.authors = ''