libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 4acefbd1c6bcf1313be312851abe5a4ecf3f178f
parent cc9fcded04ca7b288a568644ba1edd90c6421159
Author: MS <ms@taler.net>
Date:   Fri, 13 Jan 2023 14:33:45 +0100

Fix debit check on withdrawals.

Diffstat:
Mnexus/src/test/kotlin/SandboxAccessApiTest.kt | 32++++++++++++++++++++++++++++++++
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt | 21++++-----------------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt | 1+
3 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/nexus/src/test/kotlin/SandboxAccessApiTest.kt b/nexus/src/test/kotlin/SandboxAccessApiTest.kt @@ -60,6 +60,38 @@ class SandboxAccessApiTest { } } } + @Test + fun withdrawWithHighBalance() { + withTestDatabase { + prepSandboxDb() + /** + * A problem appeared (Sandbox responding "insufficient funds") + * when B - A > T, where B is the balance, A the potential amount + * to withdraw and T is the debit threshold for the user. T is + * 1000 here, therefore setting B as 2000 and A as 1 should get + * this case tested. + */ + wireTransfer( + "admin", + "foo", + "default", + "bring balance to high amount", + "TESTKUDOS:2000" + ) + testApplication { + this.application(sandboxApp) + runBlocking { + // Normal, successful withdrawal. + client.post("/demobanks/default/access-api/accounts/foo/withdrawals") { + expectSuccess = true + setBody("{\"amount\": \"TESTKUDOS:1\"}") + contentType(ContentType.Application.Json) + basicAuth("foo", "foo") + } + } + } + } + } // Check successful and failing case due to insufficient funds. @Test fun debitWithdraw() { diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt @@ -1301,23 +1301,10 @@ val sandboxApp: Application.() -> Unit = { val amount = parseAmount(req.amount) if (amount.currency != demobank.currency) throw badRequest("Currency ${amount.currency} differs from Demobank's: ${demobank.currency}") - /** - * Check for debit threshold. That's however also later checked - * after the /confirm call. Username == null case is handled above. - */ - val pendingBalance = getBalance(username!!, withPending = true) - val maxDebt = if (username == "admin") { - demobank.bankDebtLimit - } else demobank.usersDebtLimit - val amountAsNumber = BigDecimal(amount.amount) - if ((pendingBalance - amountAsNumber).abs() > BigDecimal.valueOf(maxDebt.toLong())) { - logger.info("User $username would surpass user debit " + - "threshold of ${demobank.usersDebtLimit}. Rollback Taler withdrawal" - ) - throw SandboxError( - HttpStatusCode.Forbidden, - "Insufficient funds." - ) + // Check funds are sufficient. + if (maybeDebit(maybeOwnedAccount.label, BigDecimal(amount.amount))) { + logger.error("Account ${maybeOwnedAccount.label} would surpass debit threshold. Not withdrawing") + throw SandboxError(HttpStatusCode.PreconditionFailed, "Insufficient funds") } val wo: TalerWithdrawalEntity = transaction { TalerWithdrawalEntity.new { diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt @@ -127,6 +127,7 @@ fun wireTransfer( pmtInfId: String? = null ): String { val parsedAmount = parseAmount(amount) + // Potential amount to transfer. val amountAsNumber = BigDecimal(parsedAmount.amount) if (amountAsNumber == BigDecimal.ZERO) throw badRequest("Wire transfers of zero not possible.")