diff options
author | ms <ms@taler.net> | 2023-03-20 15:44:19 +0100 |
---|---|---|
committer | ms <ms@taler.net> | 2023-03-20 15:44:19 +0100 |
commit | 5276f88d7f268f3fa14fb22f5731af2087c24c92 (patch) | |
tree | a9bd269af3d57634c8f3fc32ff6a27989b317342 /sandbox/src/main/kotlin/tech/libeufin | |
parent | 265a823964fe6aaa7348cebdea674743fe449872 (diff) | |
download | libeufin-5276f88d7f268f3fa14fb22f5731af2087c24c92.tar.gz libeufin-5276f88d7f268f3fa14fb22f5731af2087c24c92.tar.bz2 libeufin-5276f88d7f268f3fa14fb22f5731af2087c24c92.zip |
cash-out estimation endpoint
Diffstat (limited to 'sandbox/src/main/kotlin/tech/libeufin')
-rw-r--r-- | sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt index 8ddbab47..4fd041ee 100644 --- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt +++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt @@ -6,8 +6,6 @@ import io.ktor.http.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import org.jetbrains.exposed.sql.deleteAll -import org.jetbrains.exposed.sql.lowerCase import org.jetbrains.exposed.sql.transactions.transaction import tech.libeufin.sandbox.CashoutOperationsTable.uuid import tech.libeufin.util.* @@ -19,6 +17,18 @@ import java.util.concurrent.TimeUnit import kotlin.text.toByteArray // CIRCUIT API TYPES +/** + * This type is used by clients to ask the bank a cash-out + * estimate to show to the customer before they confirm the + * cash-out creation. + */ +data class CircuitCashoutEstimateRequest( + /** + * This is the amount that the customer will get deducted + * from their regio bank account to fuel the cash-out operation. + */ + val amount_debit: String +) data class CircuitCashoutRequest( val subject: String?, val amount_debit: String, // As specified by the user via the SPA. @@ -135,6 +145,18 @@ fun generateCashoutSubject( " to ${amountCredit.currency}:${amountCredit.amount}" } +/* Takes one amount value as input, applies cash-out rates +* and fees to it, and returns the result. Typically, the input +* comes from a regional currency amount and the output will be +* the fiat currency amount that the customer will get in their +* fiat bank account. */ +fun applyCashoutRatioAndFee( + regioAmount: BigDecimal, + ratiosAndFees: RatioAndFees +): BigDecimal = + (regioAmount * ratiosAndFees.sell_at_ratio.toBigDecimal()) - + ratiosAndFees.sell_out_fee.toBigDecimal() + /** * NOTE: future versions take the supported TAN method from * the configuration, or options passed when starting the bank. @@ -355,6 +377,20 @@ fun circuitApi(circuitRoute: Route) { call.respond(node) return@get } + circuitRoute.get("/cashouts/estimates") { + call.request.basicAuth() + val maybeAmountDebit: String? = call.request.queryParameters["amount_debit"] + if (maybeAmountDebit == null) throw badRequest("Missing 'amount_debit' URI parameter.") + val amountDebit = parseAmount(maybeAmountDebit) + val demobank = ensureDemobank(call) + if (amountDebit.currency != demobank.config.currency) + throw badRequest("POSTed debit amount has wrong currency (${amountDebit.currency}). Give '${demobank.config.currency}' instead.") + val amountDebitValue = try { + amountDebit.amount.toBigDecimal() + } catch (e: Exception) { throw badRequest("POSTed debit amount has invalid number.") } + val estimate = applyCashoutRatioAndFee(amountDebitValue, ratiosAndFees) + call.respond(object { val amount_credit = "$FIAT_CURRENCY:$estimate" }) + } // Create a cash-out operation. circuitRoute.post("/cashouts") { val user = call.request.basicAuth() @@ -401,10 +437,8 @@ fun circuitApi(circuitRoute: Route) { if ((tanChannel == SupportedTanChannels.SMS.name) && (customer.phone == null)) throw conflict("Phone number not found for '$user'. Can't send the TAN") // check rates correctness - val sellRatio = BigDecimal(ratiosAndFees.sell_at_ratio.toString()) - val sellFee = BigDecimal(ratiosAndFees.sell_out_fee.toString()) val amountDebitAsNumber = BigDecimal(amountDebit.amount) - val expectedAmountCredit = (amountDebitAsNumber * sellRatio) - sellFee + val expectedAmountCredit = applyCashoutRatioAndFee(amountDebitAsNumber, ratiosAndFees) val commonRounding = MathContext(2) // ensures both amounts end with ".XY" val amountCreditAsNumber = BigDecimal(amountCredit.amount) if (expectedAmountCredit.round(commonRounding) != amountCreditAsNumber.round(commonRounding)) { |