commit e4c46845b3314239f4cd354e15d4b7207830fd28
parent 736c3998648ad249577f8930b616e1f27647f938
Author: Antoine A <>
Date: Mon, 27 Nov 2023 17:37:09 +0000
Check exchange account when conversion is enabled
Diffstat:
4 files changed, 59 insertions(+), 57 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -228,7 +228,7 @@ fun Application.corebankWebApp(db: Database, ctx: BankConfig) {
bankIntegrationApi(db, ctx)
wireGatewayApi(db, ctx)
revenueApi(db)
- ctx.spaPath?.let {
+ ctx.spaPath?.let {
staticFiles("/", File(it))
}
}
@@ -332,31 +332,39 @@ class ServeBank : CliktCommand("Run libeufin-bank HTTP server", name = "serve")
val dbCfg = cfg.loadDbConfig()
val serverCfg = cfg.loadServerConfig()
if (serverCfg.method.lowercase() != "tcp") {
- logger.info("Can only serve libeufin-bank via TCP")
+ logger.error("Can only serve libeufin-bank via TCP")
exitProcess(1)
}
val db = Database(dbCfg.dbConnStr, ctx.regionalCurrency, ctx.fiatCurrency)
runBlocking {
if (ctx.allowConversion) {
- // TODO check exchange account
- logger.info("ensure conversion is enabled")
+ logger.info("Ensure exchange account exists")
+ val info = db.account.bankInfo("exchange")
+ if (info == null) {
+ logger.error("Exchange account missing: an exchange account named 'exchange' is required for conversion to be enabled")
+ exitProcess(1)
+ } else if (!info.isTalerExchange) {
+ logger.error("Account is not an exchange: an exchange account named 'exchange' is required for conversion to be enabled")
+ exitProcess(1)
+ }
+ logger.info("Ensure conversion is enabled")
val sqlProcedures = File("${dbCfg.sqlDir}/libeufin-conversion-setup.sql")
if (!sqlProcedures.exists()) {
- logger.info("Missing libeufin-conversion-setup.sql file")
+ logger.error("Missing libeufin-conversion-setup.sql file")
exitProcess(1)
}
- pgDataSource(dbCfg.dbConnStr).pgConnection().execSQLUpdate(sqlProcedures.readText())
+ db.conn { it.execSQLUpdate(sqlProcedures.readText()) }
} else {
- logger.info("ensure conversion is disabled")
+ logger.info("Ensure conversion is disabled")
val sqlProcedures = File("${dbCfg.sqlDir}/libeufin-conversion-drop.sql")
if (!sqlProcedures.exists()) {
- logger.info("Missing libeufin-conversion-drop.sql file")
+ logger.error("Missing libeufin-conversion-drop.sql file")
exitProcess(1)
}
- pgDataSource(dbCfg.dbConnStr).pgConnection().execSQLUpdate(sqlProcedures.readText())
+ db.conn { it.execSQLUpdate(sqlProcedures.readText()) }
// Remove conversion info from the database ?
}
- }
+ }
embeddedServer(Netty, port = serverCfg.port) {
corebankWebApp(db, ctx)
}.start(wait = true)
@@ -433,14 +441,14 @@ class BankConfigGet : CliktCommand("Lookup config value", name = "get") {
if (isPath) {
val res = config.lookupPath(sectionName, optionName)
if (res == null) {
- logger.info("value not found in config")
+ logger.error("value not found in config")
exitProcess(2)
}
println(res)
} else {
val res = config.lookupString(sectionName, optionName)
if (res == null) {
- logger.info("value not found in config")
+ logger.error("value not found in config")
exitProcess(2)
}
println(res)
diff --git a/contrib/libeufin-bank.conf b/contrib/libeufin-bank.conf
@@ -3,15 +3,13 @@
# Internal currency of the libeufin-bank
CURRENCY = KUDOS
-# Debt limit for newly created customer accounts
+# Default debt limit for newly created customer accounts
DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:200
-# Debt limit of the admin. Typically higher,
-# since sign-up bonuses are deducted from the
-# admin account.
-DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:2000
+# Default debt limit of the admin. Typically higher, since sign-up bonuses and cashin are deducted from the admin account.
+DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:20000000
-# Value of the registration bonus for new users.
+# Value of the registration bonus for new users. Default is "CURRENCY:0"
REGISTRATION_BONUS = KUDOS:100
# Allow account registration by anyone.
@@ -20,8 +18,14 @@ ALLOW_REGISTRATION = yes
# Allow an account to delete itself
ALLOW_ACCOUNT_DELETION = yes
-# Exchange that is suggested to wallets when withdrawing.
-SUGGESTED_WITHDRAWAL_EXCHANGE = https://exchange.demo.taler.net/
+# Enable regional currency conversion
+ALLOW_CONVERSION = no
+
+# Path to TAN challenge transmission script via sms. If not specified, this TAN channel wil be unuspported.
+TAN_SMS =
+
+# Path to TAN challenge transmission script via email. If not specified, this TAN channel wil be unuspported.
+TAN_EMAIL =
# Where "libeufin-bank serve" serves its API
SERVE = tcp
@@ -37,14 +41,8 @@ SPA = $DATADIR/spa/
# or something similar?
SPA_CAPTCHA_URL = https://bank.demo.taler.net/webui/#/operation/{woid}
-# Enable regional currency conversion
-ALLOW_CONVERSION = no
-
-# Path to the script TAN challenge transmission via sms
-TAN_SMS =
-
-# Path to the script TAN challenge transmission via email
-TAN_EMAIL =
+# Exchange that is suggested to wallets when withdrawing.
+SUGGESTED_WITHDRAWAL_EXCHANGE = https://exchange.demo.taler.net/
[libeufin-bankdb-postgres]
# Where are the SQL files to setup our tables?
diff --git a/integration/test/IntegrationTest.kt b/integration/test/IntegrationTest.kt
@@ -47,16 +47,10 @@ fun CliktCommand.run(cmd: String) {
println(result.output)
}
-suspend fun HttpResponse.assertStatus(status: HttpStatusCode): HttpResponse {
- assertEquals(status, this.status);
- return this
+fun HttpResponse.assertNoContent() {
+ assertEquals(HttpStatusCode.NoContent, this.status)
}
-suspend fun HttpResponse.assertCreated(): HttpResponse
- = assertStatus(HttpStatusCode.Created)
-suspend fun HttpResponse.assertNoContent(): HttpResponse
- = assertStatus(HttpStatusCode.NoContent)
-
fun randBytes(lenght: Int): ByteArray {
val bytes = ByteArray(lenght)
kotlin.random.Random.nextBytes(bytes)
@@ -71,9 +65,7 @@ class IntegrationTest {
val bankCmd = LibeufinBankCommand();
bankCmd.run("dbinit -c ../bank/conf/test.conf -r")
bankCmd.run("passwd admin password -c ../bank/conf/test.conf")
- kotlin.concurrent.thread(isDaemon = true) {
- bankCmd.run("serve -c ../bank/conf/test.conf")
- }
+
runBlocking {
val client = HttpClient(CIO) {
@@ -82,10 +74,28 @@ class IntegrationTest {
constantDelay(200, 100)
}
}
+
val nexusDb = NexusDb("postgresql:///libeufincheck")
+ val bankDb = BankDb("postgresql:///libeufincheck", "KUDOS", "EUR")
+
+ bankDb.account.create(
+ login = "exchange",
+ password = "password",
+ name = "Mr Money",
+ internalPaytoUri = IbanPayTo(genIbanPaytoUri()),
+ isPublic = false,
+ isTalerExchange = true,
+ maxDebt = BankAmount("KUDOS:0"),
+ bonus = BankAmount("KUDOS:0")
+ )
+
val userPayTo = IbanPayTo(genIbanPaytoUri())
val fiatPayTo = IbanPayTo(genIbanPaytoUri())
+ kotlin.concurrent.thread(isDaemon = true) {
+ bankCmd.run("serve -c ../bank/conf/test.conf")
+ }
+
// Create user
client.post("http://0.0.0.0:8080/accounts") {
json {
@@ -100,16 +110,6 @@ class IntegrationTest {
}
}.assertOkJson<RegisterAccountResponse>()
- // Create exchange
- client.post("http://0.0.0.0:8080/accounts") {
- json {
- "username" to "exchange"
- "password" to "password"
- "name" to "Mr Money"
- "is_taler_exchange" to true
- }
- }.assertOkJson<RegisterAccountResponse>()
-
// Set conversion rates
client.post("http://0.0.0.0:8080/conversion-info/conversion-rate") {
basicAuth("admin", "password")
diff --git a/util/src/main/kotlin/DB.kt b/util/src/main/kotlin/DB.kt
@@ -234,19 +234,15 @@ fun initializeDatabaseTables(cfg: DatabaseConfig, sqlFilePrefix: String) {
fun resetDatabaseTables(cfg: DatabaseConfig, sqlFilePrefix: String) {
logger.info("reset DB, sqldir ${cfg.sqlDir}, dbConnStr ${cfg.dbConnStr}")
pgDataSource(cfg.dbConnStr).pgConnection().use { conn ->
- val count = conn.prepareStatement("SELECT count(*) FROM information_schema.schemata WHERE schema_name='_v'").oneOrNull {
- it.getInt(1)
- } ?: 0
- if (count == 0) {
+ val isInitialized = conn.prepareStatement("SELECT EXISTS(SELECT 1 FROM information_schema.schemata WHERE schema_name='_v')").oneOrNull {
+ it.getBoolean(1)
+ }!!
+ if (!isInitialized) {
logger.info("versioning schema not present, not running drop sql")
return
}
val sqlDrop = File("${cfg.sqlDir}/$sqlFilePrefix-drop.sql").readText()
- try {
conn.execSQLUpdate(sqlDrop) // TODO can fail ?
- } catch (e: Exception) {
-
- }
}
}
\ No newline at end of file