libeufin

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

commit 5aab7b614273c085d8554b80908ba895a318ce01
parent 587d1ed27e43e95e0ae9ff0b91b6d21824035b04
Author: Antoine A <>
Date:   Fri, 29 May 2026 13:59:55 +0200

common: update prepared transfer API

Diffstat:
MCargo.lock | 50++++++++++++++++++++++----------------------------
MMakefile | 6++++++
Mlibeufin-bank/src/api/cashout.rs | 6++----
Mlibeufin-bank/src/api/prepared.rs | 42+++++++++++++++++++++++-------------------
Mlibeufin-bank/src/api/revenue.rs | 7++++---
Mlibeufin-bank/src/api/tx.rs | 6++++--
Mlibeufin-bank/src/api/wire.rs | 22++++++++++++++++------
Mlibeufin-bank/src/db/prepared.rs | 14++++++++------
Mlibeufin-nexus/src/api.rs | 68++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mlibeufin-nexus/src/bench.rs | 37+++++++++++++++++++------------------
Mlibeufin-nexus/src/lib.rs | 4++--
Mlibeufin-nexus/src/manual.rs | 2+-
Mlibeufin-nexus/src/test.rs | 27++++++++++++---------------
Mtestbench/Cargo.toml | 2+-
14 files changed, 170 insertions(+), 123 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -382,14 +382,14 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex 1.3.0", + "shlex", ] [[package]] @@ -1589,9 +1589,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.27" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "392c70591e8749fe235ddaf513e6f58b26bce3dcc16524cecc8936f75afa161e" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "log", @@ -1603,9 +1603,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.27" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b605b0c050d845fc355bb11eb3f9a8deddc218ea60c76e61aa1f2adfb2c96a" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", @@ -1801,7 +1801,7 @@ dependencies = [ "regex", "serde", "serde_json", - "shlex 2.0.1", + "shlex", "sqlx", "taler-api", "taler-build", @@ -1996,9 +1996,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", @@ -2507,9 +2507,9 @@ dependencies = [ [[package]] name = "reedline" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2066729dce9fecd28d1c6850a159ee68719130f149b22467c362353e16994e90" +checksum = "201e8e0160cbe7bb5eb2caccf281e178e77fac95115ab31a2c29edc5593603c8" dependencies = [ "chrono", "crossterm", @@ -2957,12 +2957,6 @@ checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" [[package]] name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "shlex" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" @@ -3047,9 +3041,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -3388,7 +3382,7 @@ dependencies = [ [[package]] name = "taler-api" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#664cd180f65c314bae731743dbd481e4314a8ed7" +source = "git+git://git.taler.net/taler-rust.git/#9df4ad89b8a4c8acbd06b0ebce398449ba4364df" dependencies = [ "aws-lc-rs", "axum", @@ -3415,12 +3409,12 @@ dependencies = [ [[package]] name = "taler-build" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#664cd180f65c314bae731743dbd481e4314a8ed7" +source = "git+git://git.taler.net/taler-rust.git/#9df4ad89b8a4c8acbd06b0ebce398449ba4364df" [[package]] name = "taler-common" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#664cd180f65c314bae731743dbd481e4314a8ed7" +source = "git+git://git.taler.net/taler-rust.git/#9df4ad89b8a4c8acbd06b0ebce398449ba4364df" dependencies = [ "anyhow", "aws-lc-rs", @@ -3449,7 +3443,7 @@ dependencies = [ [[package]] name = "taler-macros" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#664cd180f65c314bae731743dbd481e4314a8ed7" +source = "git+git://git.taler.net/taler-rust.git/#9df4ad89b8a4c8acbd06b0ebce398449ba4364df" dependencies = [ "proc-macro2", "quote", @@ -3459,7 +3453,7 @@ dependencies = [ [[package]] name = "taler-test-utils" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#664cd180f65c314bae731743dbd481e4314a8ed7" +source = "git+git://git.taler.net/taler-rust.git/#9df4ad89b8a4c8acbd06b0ebce398449ba4364df" dependencies = [ "aws-lc-rs", "axum", @@ -3503,7 +3497,7 @@ dependencies = [ "libeufin-nexus", "owo-colors", "reedline", - "shlex 2.0.1", + "shlex", "taler-common", "tokio", "tracing", @@ -3935,9 +3929,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" dependencies = [ "getrandom 0.4.2", "js-sys", diff --git a/Makefile b/Makefile @@ -57,3 +57,8 @@ deb: .PHONY: ci ci: contrib/ci/run-all-jobs.sh + + +.PHONY: fmt +fmt: + rustfmt-unstable --apply +\ No newline at end of file diff --git a/libeufin-bank/src/api/cashout.rs b/libeufin-bank/src/api/cashout.rs @@ -414,16 +414,14 @@ pub mod test { let router = ctx.admin_router().await; let c = &ctx; routine_pagination::<Cashouts>( - &router, - "/accounts/customer/cashouts", + &router.suffix("/accounts/customer/cashouts"), tasks!({ c.cashout("0.1").await; }), ) .await; routine_pagination::<Cashouts>( - &router, - "/cashouts", + &router.suffix("/cashouts"), tasks!({ c.cashout("0.1").await; }), diff --git a/libeufin-bank/src/api/prepared.rs b/libeufin-bank/src/api/prepared.rs @@ -25,13 +25,12 @@ use axum::{ response::NoContent, routing::{get, post}, }; -use compact_str::CompactString; use jiff::Timestamp; use taler_api::{ api::{Validation, prepared::simple_subject}, constants::PREPARED_TRANSFER_API_VERSION, error::failure_code, - extract::{Path, Req}, + extract::Req, }; use taler_common::{ api::prepared::{ @@ -45,12 +44,13 @@ use taler_common::{ use crate::{ api::{BankState, IMPLEMENTATION}, db::prepared::{RegistrationResult, register, unregister}, + payto::BankPayto, }; pub fn prepared_api() -> Router<Arc<BankState>> { Router::new() .route( - "/accounts/{username}/taler-prepared-transfer/config", + "/taler-prepared-transfer/config", get(async |State(state): State<Arc<BankState>>| { Json(PreparedTransferConfig { name: (), @@ -62,15 +62,14 @@ pub fn prepared_api() -> Router<Arc<BankState>> { }), ) .route( - "/accounts/{username}/taler-prepared-transfer/registration", + "/taler-prepared-transfer/registration", post( - async |Path(username): Path<CompactString>, - State(state): State<Arc<BankState>>, - Req(req): Req<RegistrationRequest>| { + async |State(state): State<Arc<BankState>>, Req(req): Req<RegistrationRequest>| { req.check(&state.cfg.regional_currency)?; + let creditor = BankPayto::try_from(&req.credit_account)?; match register( &state.db, - &username, + &creditor, req.r#type, &req.account_pub, &req.authorization_pub, @@ -95,8 +94,8 @@ pub fn prepared_api() -> Router<Arc<BankState>> { expiration: TalerTimestamp::Never, })) } - RegistrationResult::UnknownAccount => { - Err(failure_code(ErrorCode::BANK_UNKNOWN_ACCOUNT)) + RegistrationResult::UnknownCreditor => { + Err(failure_code(ErrorCode::BANK_UNKNOWN_CREDITOR)) } RegistrationResult::NotExchange => { Err(failure_code(ErrorCode::BANK_ACCOUNT_IS_NOT_EXCHANGE)) @@ -109,7 +108,7 @@ pub fn prepared_api() -> Router<Arc<BankState>> { ), ) .route( - "/accounts/{username}/taler-prepared-transfer/unregistration", + "/taler-prepared-transfer/unregistration", post( async |State(state): State<Arc<BankState>>, Req(req): Req<Unregistration>| { req.check(&state.cfg.regional_currency)?; @@ -144,6 +143,7 @@ mod test { let key_pair1 = Ed25519KeyPair::generate().unwrap(); let auth_pub1 = EddsaPublicKey::try_from(key_pair1.public_key().as_ref()).unwrap(); let req = json!({ + "credit_account": ctx.exchange_payto, "credit_amount": "KUDOS:120", "type": "reserve", "alg": "EdDSA", @@ -152,19 +152,23 @@ mod test { "authorization_sig": eddsa_sign(&key_pair1, auth_pub1.as_ref()), "recurrent": false }); - ctx.post("/accounts/merchant/taler-prepared-transfer/registration") - .json(&req) + ctx.post("/taler-prepared-transfer/registration") + .json(json!(req + { "credit_account": ctx.customer_payto })) .await .assert_error(ErrorCode::BANK_ACCOUNT_IS_NOT_EXCHANGE); - ctx.post("/accounts/unknown/taler-prepared-transfer/registration") - .json(&req) + ctx.post("/taler-prepared-transfer/registration") + .json(json!(req + { "credit_account": ctx.unknown_payto })) .await - .assert_error(ErrorCode::BANK_UNKNOWN_ACCOUNT); + .assert_error(ErrorCode::BANK_UNKNOWN_CREDITOR); ctx.set_max_debt("customer", "1000").await; + let admin = ctx.admin_router().await; registration_routine( - &ctx.admin_router().await.prefix("/accounts/exchange"), + &admin.prefix("/accounts/exchange/taler-wire-gateway"), + &admin.prefix("/taler-prepared-transfer"), &ctx.customer_payto.as_uri(), + &ctx.exchange_payto.as_uri(), + &ctx.unknown_payto.as_uri(), async || { sqlx::query( " @@ -208,7 +212,7 @@ mod test { /* * * // Non recurrent no URI - client.post("/accounts/exchange/taler-prepared-transfer/registration") { + client.post("/taler-prepared-transfer/registration") { json(valid_req) { "type" to "reserve" } @@ -221,7 +225,7 @@ mod test { assertBalance("exchange", "+KUDOS:1") } * // Withdrawal is aborted on completion - client.post("/accounts/exchange/taler-prepared-transfer/registration") { + client.post("/taler-prepared-transfer/registration") { json(valid_req) { "type" to "kyc" } diff --git a/libeufin-bank/src/api/revenue.rs b/libeufin-bank/src/api/revenue.rs @@ -83,7 +83,6 @@ pub fn revenue_api() -> Router<Arc<BankState>> { #[cfg(test)] mod test { - use taler_common::types::payto::PaytoImpl as _; use taler_test_utils::{routine::revenue_routine, server::TestServer, tasks}; use crate::api::test::bank_setup; @@ -92,9 +91,11 @@ mod test { async fn revenue() { let ctx = bank_setup().await; ctx.set_max_debt("customer", "1000").await; + let admin = ctx.admin_router().await; revenue_routine( - &ctx.admin_router().await.prefix("/accounts/exchange"), - &ctx.customer_payto.as_full_uri("Customer"), + &admin.prefix("/accounts/exchange/taler-wire-gateway"), + &admin.prefix("/accounts/exchange/taler-revenue"), + &ctx.customer_payto.as_uri(), true, tasks!(), tasks!(), diff --git a/libeufin-bank/src/api/tx.rs b/libeufin-bank/src/api/tx.rs @@ -210,6 +210,7 @@ pub mod test { use taler_test_utils::{ json, routine::{Page, routine_history}, + server::TestServer, tasks, }; @@ -529,8 +530,9 @@ pub mod test { ctx.fill_cashout_info("customer").await; routine_history::<BankAccountTransactionsResponse>( - &ctx.admin_router().await, - "/accounts/customer/transactions", + &ctx.admin_router() + .await + .suffix("/accounts/customer/transactions"), tasks!( // Incoming { ctx.tx("merchant", "0.1", "customer").await }, diff --git a/libeufin-bank/src/api/wire.rs b/libeufin-bank/src/api/wire.rs @@ -403,7 +403,7 @@ pub mod test { }, db::IncomingType, error_code::ErrorCode, - types::{amount::amount, payto::PaytoImpl}, + types::amount::amount, }; use taler_test_utils::{ json, @@ -454,7 +454,9 @@ pub mod test { ctx.set_max_debt("exchange", "1000").await; transfer_routine( - &ctx.admin_router().await.prefix("/accounts/exchange"), + &ctx.admin_router() + .await + .prefix("/accounts/exchange/taler-wire-gateway"), TransferState::success, &ctx.customer_payto.as_uri(), ) @@ -558,7 +560,9 @@ pub mod test { .await; ctx.set_max_debt("exchange", "1000").await; out_history_routine( - &ctx.admin_router().await.prefix("/accounts/exchange"), + &ctx.admin_router() + .await + .prefix("/accounts/exchange/taler-wire-gateway"), tasks!( // Transactions using clean add incoming logic { ctx.transfer("10", &ctx.customer_payto, None).await }, @@ -605,9 +609,12 @@ pub mod test { .await; ctx.set_max_debt("customer", "1000").await; ctx.set_max_debt("merchant", "1000").await; + let admin = ctx.admin_router().await; in_history_routine( - &ctx.admin_router().await.prefix("/accounts/exchange"), + &admin.prefix("/accounts/exchange/taler-wire-gateway"), + &admin.prefix("/taler-prepared-transfer"), &ctx.customer_payto.as_uri(), + &ctx.exchange_payto.as_uri(), false, tasks!( // Reserve transactions using raw bank transaction logic @@ -689,9 +696,12 @@ pub mod test { } } ctx.set_max_debt("customer", "1000").await; + let admin = ctx.admin_router().await; admin_add_incoming_routine( - &ctx.admin_router().await.prefix("/accounts/exchange"), - &ctx.customer_payto.as_full_uri("Customer"), + &admin.prefix("/accounts/exchange/taler-wire-gateway"), + &admin.prefix("/taler-prepared-transfer"), + &ctx.customer_payto.as_uri(), + &ctx.exchange_payto.as_uri(), true, ) .await; diff --git a/libeufin-bank/src/db/prepared.rs b/libeufin-bank/src/db/prepared.rs @@ -32,10 +32,12 @@ use taler_common::{ }; use uuid::Uuid; +use crate::payto::BankPayto; + /** Result of prepared transfer registration */ pub enum RegistrationResult { Success(Option<Uuid>), - UnknownAccount, + UnknownCreditor, NotExchange, ReservePubReuse, } @@ -43,7 +45,7 @@ pub enum RegistrationResult { /** Register a prepared transfer */ pub async fn register( db: &PgPool, - username: &str, + creditor: &BankPayto, ty: TransferType, account_pub: &EddsaPublicKey, auth_pub: &EddsaPublicKey, @@ -56,11 +58,11 @@ pub async fn register( serialized!( sqlx::query( " - SELECT out_unknown_account, out_not_exchange, out_reserve_pub_reuse, out_withdrawal_uuid + SELECT out_unknown_creditor, out_not_exchange, out_reserve_pub_reuse, out_withdrawal_uuid FROM register_prepared_transfers($1,$2::taler_incoming_type,$3,$4,$5,$6,$7,$8,$9) " ) - .bind(username) + .bind(creditor.canonical()) .bind(ty.as_ref()) .bind(account_pub) .bind(auth_pub) @@ -70,8 +72,8 @@ pub async fn register( .bind_timestamp(timestamp) .bind(format!("Taler prepared MAP:{auth_pub}")) .try_map(|r: PgRow| { - Ok(if r.try_get_flag("out_unknown_account")? { - RegistrationResult::UnknownAccount + Ok(if r.try_get_flag("out_unknown_creditor")? { + RegistrationResult::UnknownCreditor } else if r.try_get_flag("out_not_exchange")? { RegistrationResult::NotExchange } else if r.try_get_flag("out_reserve_pub_reuse")? { diff --git a/libeufin-nexus/src/api.rs b/libeufin-nexus/src/api.rs @@ -50,7 +50,7 @@ use taler_common::{ error_code::ErrorCode, types::{ amount::{Amount, Currency}, - payto::{FullIbanPayto, PaytoURI}, + payto::{FullIbanPayto, IbanPayto, PaytoURI}, timestamp::TalerTimestamp, }, }; @@ -69,14 +69,14 @@ use crate::db::{ pub struct NexusApi { pub pool: sqlx::PgPool, pub currency: Currency, - pub payto: PaytoURI, + pub payto: FullIbanPayto, pub in_channel: Sender<i64>, pub taler_in_channel: Sender<i64>, pub taler_out_channel: Sender<i64>, } impl NexusApi { - pub async fn start(pool: sqlx::PgPool, payto: PaytoURI, currency: Currency) -> Self { + pub async fn start(pool: sqlx::PgPool, payto: FullIbanPayto, currency: Currency) -> Self { let in_channel = Sender::new(0); let taler_in_channel = Sender::new(0); let taler_out_channel = Sender::new(0); @@ -176,7 +176,7 @@ impl WireGateway for NexusApi { ) -> ApiResult<TransferList> { Ok(TransferList { transfers: transfer_page(&self.pool, &self.currency, &page, &status).await?, - debit_account: self.payto.clone(), + debit_account: self.payto.as_uri(), }) } @@ -190,7 +190,7 @@ impl WireGateway for NexusApi { self.taler_out_channel.subscribe() }) .await?, - debit_account: self.payto.clone(), + debit_account: self.payto.as_uri(), }) } @@ -200,7 +200,7 @@ impl WireGateway for NexusApi { self.taler_in_channel.subscribe() }) .await?, - credit_account: self.payto.clone(), + credit_account: self.payto.as_uri(), }) } @@ -249,7 +249,7 @@ impl Revenue for NexusApi { self.in_channel.subscribe() }) .await?, - credit_account: self.payto.clone(), + credit_account: self.payto.as_uri(), }) } } @@ -260,6 +260,10 @@ impl PreparedTransfer for NexusApi { } async fn registration(&self, req: RegistrationRequest) -> ApiResult<RegistrationResponse> { + let creditor = IbanPayto::try_from(&req.credit_account)?; + if *creditor != *self.payto { + return Err(failure_code(ErrorCode::BANK_UNKNOWN_CREDITOR)); + } let reference_number = subject_fmt_qr_bill(req.authorization_pub.as_ref()); match transfer_register( &self.pool, @@ -306,13 +310,13 @@ pub mod test { use taler_common::api::{ prepared::PreparedTransferConfig, revenue::RevenueConfig, - wire::{OutgoingHistory, TransferState, WireConfig}, + wire::{TransferState, WireConfig}, }; use taler_test_utils::{ Router, db::db_test_setup, routine::{ - admin_add_incoming_routine, registration_routine, revenue_routine, routine_pagination, + admin_add_incoming_routine, out_history_routine, registration_routine, revenue_routine, transfer_routine, }, server::TestServer as _, @@ -323,12 +327,12 @@ pub mod test { CONFIG_SOURCE, api::NexusApi, db::{payment::register_out_tx, test::check_in}, - test::{ACCOUNT, CURR, gen_out_pay}, + test::{CLIENT, CURR, EXCHANGE, UNKNOWN, gen_out_pay}, }; pub async fn api_setup() -> (Router, PgPool) { let (_, pool) = db_test_setup(CONFIG_SOURCE).await; - let api = Arc::new(NexusApi::start(pool.clone(), ACCOUNT.clone(), CURR).await); + let api = Arc::new(NexusApi::start(pool.clone(), EXCHANGE.clone(), CURR).await); let server = Router::new() .wire_gateway(api.clone(), AuthMethod::None) .prepared_transfer(api.clone()) @@ -358,7 +362,12 @@ pub mod test { #[tokio::test] async fn transfer() { let (server, _) = api_setup().await; - transfer_routine(&server, TransferState::pending, &ACCOUNT).await; + transfer_routine( + &server.prefix("/taler-wire-gateway"), + TransferState::pending, + &EXCHANGE.as_uri(), + ) + .await; // TODO /*db.initiated.batchSubmissionSuccess(1, Instant.now(), "ORDER1") db.initiated.batchSubmissionFailure(2, Instant.now(), "Failure") @@ -374,9 +383,8 @@ pub mod test { #[tokio::test] async fn outgoing_history() { let (server, pool) = api_setup().await; - routine_pagination::<OutgoingHistory>( - &server, - "/taler-wire-gateway/history/outgoing", + out_history_routine( + &server.prefix("/taler-wire-gateway"), tasks!({ register_out_tx( &pool, @@ -386,6 +394,7 @@ pub mod test { .await .unwrap(); }), + tasks!(), ) .await; } @@ -393,18 +402,41 @@ pub mod test { #[tokio::test] async fn admin_add_incoming() { let (server, _) = api_setup().await; - admin_add_incoming_routine(&server, &ACCOUNT, true).await; + admin_add_incoming_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &CLIENT.as_uri(), + &EXCHANGE.as_uri(), + true, + ) + .await; } #[tokio::test] async fn revenue() { let (server, _) = api_setup().await; - revenue_routine(&server, &ACCOUNT, true, tasks!(), tasks!()).await; + revenue_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-revenue"), + &CLIENT.as_uri(), + true, + tasks!(), + tasks!(), + ) + .await; } #[tokio::test] async fn registration() { let (server, pool) = api_setup().await; - registration_routine(&server, &ACCOUNT, || check_in(&pool)).await; + registration_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &CLIENT.as_uri(), + &EXCHANGE.as_uri(), + &UNKNOWN, + || check_in(&pool), + ) + .await; } } diff --git a/libeufin-nexus/src/bench.rs b/libeufin-nexus/src/bench.rs @@ -37,7 +37,7 @@ mod test { use crate::{ api::test::api_setup, test::{ - ACCOUNT, incomplete_out, malformed_completeted_in, malformed_in, + CLIENT, EXCHANGE, incomplete_out, malformed_completeted_in, malformed_in, malformed_incomplete_in, malformed_out, prepared_completeted_in, prepared_in, prepared_incomplete_in, talerable_completeted_in, talerable_in, talerable_incomplete_in, talerable_out, @@ -58,37 +58,37 @@ mod test { }) .collect(); let mut b = Bench::new(&db, iter, amount); + let uri = CLIENT.as_uri(); b.table("incoming_transactions(amount, subject, execution_time, debit_payto, uetr, tx_id, acct_svcr_ref)", |f, i| { let subject = if i % 4 == 0 { CompactString::const_new("\\N")} else {format_compact!("subject {i}")}; - let debtor = ACCOUNT.as_ref().as_str() ; if i % 3 == 0 { - writeln!(f, "(20,0)\t{subject}\t0\t{debtor}\t{}\t\\N\t\\N", uuid::Uuid::new_v4())?; - writeln!(f, "(21,0)\t{subject}\t0\t{debtor}\t\\N\tTX_ID{}\t\\N", i*2)?; - writeln!(f, "(22,0)\t{subject}\t0\t{debtor}\t\\N\t\\N\tREF{}", i*2) + writeln!(f, "(20,0)\t{subject}\t0\t{uri}\t{}\t\\N\t\\N", uuid::Uuid::new_v4())?; + writeln!(f, "(21,0)\t{subject}\t0\t{uri}\t\\N\tTX_ID{}\t\\N", i*2)?; + writeln!(f, "(22,0)\t{subject}\t0\t{uri}\t\\N\t\\N\tREF{}", i*2) } else if i%3 == 1 { - writeln!(f, "(30,0)\t{subject}\t0\t{debtor}\t{}\tTX_ID{}\t\\N", uuid::Uuid::new_v4(), i*2)?; - writeln!(f, "(31,0)\t{subject}\t0\t{debtor}\t\\N\tTX_ID{}\tREF{}", i*2+1, i*2)?; - writeln!(f, "(32,0)\t{subject}\t0\t{debtor}\t{}\t\\N\tREF{}", uuid::Uuid::new_v4(), i*2+1) + writeln!(f, "(30,0)\t{subject}\t0\t{uri}\t{}\tTX_ID{}\t\\N", uuid::Uuid::new_v4(), i*2)?; + writeln!(f, "(31,0)\t{subject}\t0\t{uri}\t\\N\tTX_ID{}\tREF{}", i*2+1, i*2)?; + writeln!(f, "(32,0)\t{subject}\t0\t{uri}\t{}\t\\N\tREF{}", uuid::Uuid::new_v4(), i*2+1) } else { - writeln!(f, "(40,0)\t{subject}\t0\t{debtor}\t{}\tTX_ID{}\tREF{}", uuid::Uuid::new_v4(), i*2, i*2)?; - writeln!(f, "(40,0)\t{subject}\t0\t{debtor}\t{}\tTX_ID{}\tREF{}", uuid::Uuid::new_v4(), i*2+1, i*2+1) + writeln!(f, "(40,0)\t{subject}\t0\t{uri}\t{}\tTX_ID{}\tREF{}", uuid::Uuid::new_v4(), i*2, i*2)?; + writeln!(f, "(40,0)\t{subject}\t0\t{uri}\t{}\tTX_ID{}\tREF{}", uuid::Uuid::new_v4(), i*2+1, i*2+1) } }).await; b.table("outgoing_transactions(amount, subject, execution_time, credit_payto, end_to_end_id, acct_svcr_ref)", |f, i| { let subject = if i % 4 == 0 { CompactString::const_new("\\N")} else {format_compact!("subject {i}")}; - let creditor =ACCOUNT.as_ref().as_str(); + if i % 2 == 0 { - writeln!(f, "(40,0)\t{subject}\t0\t{creditor}\t\\N\tREF{}", i*2)?; - writeln!(f, "(41,0)\t{subject}\t0\t{creditor}\tE2E_ID{}\t\\N", i*2) + writeln!(f, "(40,0)\t{subject}\t0\t{uri}\t\\N\tREF{}", i*2)?; + writeln!(f, "(41,0)\t{subject}\t0\t{uri}\tE2E_ID{}\t\\N", i*2) } else { - writeln!(f, "(40,0)\t{subject}\t0\t{creditor}\tE2E_ID{}\tREF{}", i*2, i*2)?; - writeln!(f, "(41,0)\t{subject}\t0\t{creditor}\tE2E_ID{}\tREF{}", i*2+1, i*2+1) + writeln!(f, "(40,0)\t{subject}\t0\t{uri}\tE2E_ID{}\tREF{}", i*2, i*2)?; + writeln!(f, "(41,0)\t{subject}\t0\t{uri}\tE2E_ID{}\tREF{}", i*2+1, i*2+1) } }).await; b.table("initiated_outgoing_transactions(amount, subject, initiation_time, credit_payto, outgoing_transaction_id, end_to_end_id)", |f, i| { - writeln!(f, "(42,0)\tsubject\t0\t{}\t{}\tE2E_ID{i}", &*ACCOUNT , i*2) + writeln!(f, "(42,0)\tsubject\t0\t{uri}\t{}\tE2E_ID{i}", i*2) }).await; b.table("prepared_transfers(type, account_pub, authorization_pub, authorization_sig, recurrent, reference_number, registered_at, incoming_transaction_id)", |f, i| { let ty = if i%2==0 {"reserve"} else {"kyc"}; @@ -192,7 +192,7 @@ mod test { "amount": "KUDOS:0.0001", "exchange_base_url": "http://exchange.example.com/", "wtid": ShortHashCode::rand(), - "credit_account": &*ACCOUNT + "credit_account": *CLIENT })) .await .assert_ok() @@ -225,7 +225,7 @@ mod test { .json(json!({ "amount": "KUDOS:0.0001", "reserve_pub": EddsaPublicKey::rand(), - "debit_account": &*ACCOUNT + "debit_account": *CLIENT })) .await .assert_ok() @@ -253,6 +253,7 @@ mod test { server .post("/taler-prepared-transfer/registration") .json(json!({ + "credit_account": *EXCHANGE, "credit_amount": "KUDOS:55", "type": "reserve", "alg": "EdDSA", diff --git a/libeufin-nexus/src/lib.rs b/libeufin-nexus/src/lib.rs @@ -569,8 +569,8 @@ pub async fn run(cfg: Config, cmd: Cmd) -> anyhow::Result<()> { } else { let pool = pool(&cfg.cfg).await?; - let payto = cfg.ebics()?.account.as_uri(); - let api = Arc::new(NexusApi::start(pool, payto, cfg.currency).await); + let payto = &cfg.ebics()?.account; + let api = Arc::new(NexusApi::start(pool, payto.clone(), cfg.currency).await); let mut server = Router::new(); if let Some(it) = cfg.wire_cfg { server = server diff --git a/libeufin-nexus/src/manual.rs b/libeufin-nexus/src/manual.rs @@ -44,6 +44,7 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, EnumMeta)] #[enum_meta(Str)] +#[allow(non_camel_case_types)] pub enum Kind { batch, tx, @@ -56,7 +57,6 @@ pub enum ManualCmd { Export { out: CompactString }, /// Import EBICS camt files Import { sources: Vec<CompactString> }, - /// Change batches or transactions status Status { kind: Kind, id: CompactString, diff --git a/libeufin-nexus/src/test.rs b/libeufin-nexus/src/test.rs @@ -30,7 +30,7 @@ use taler_common::{ types::{ amount::{Amount, Currency}, base32::Base32, - payto::{FullIbanPayto, IbanPayto, PaytoURI, payto}, + payto::{FullIbanPayto, PaytoURI, payto}, }, }; @@ -46,8 +46,14 @@ use crate::{ }; pub const CURR: Currency = Currency::KUDOS; -pub static ACCOUNT: LazyLock<PaytoURI> = - LazyLock::new(|| payto("payto://iban/CH4189144589712575493?receiver-name=Test")); +pub static EXCHANGE: LazyLock<FullIbanPayto> = LazyLock::new(|| { + FullIbanPayto::from_str("payto://iban/CH4189144589712575493?receiver-name=Exchange").unwrap() +}); +pub static CLIENT: LazyLock<FullIbanPayto> = LazyLock::new(|| { + FullIbanPayto::from_str("payto://iban/DE84500105177118117964?receiver-name=John+Smith").unwrap() +}); +pub static UNKNOWN: LazyLock<PaytoURI> = + LazyLock::new(|| payto("payto://iban/HU60162006491000639900000000?receiver-name=Unknown")); /** Generates an outgoing payment, given its subject */ pub fn gen_out_pay(subject: impl Into<String>) -> OutTx { @@ -59,11 +65,7 @@ pub fn gen_out_pay(subject: impl Into<String>) -> OutTx { }, amount: Amount::new(&CURR, 44, 0), debit_fee: Amount::zero(&CURR), - creditor: Some( - IbanPayto::from_str("payto://iban/CH4189144589712575493?receiver-name=Test") - .unwrap() - .as_uri(), - ), + creditor: Some(EXCHANGE.as_uri()), subject: Some(subject.into()), execution_time: Timestamp::now(), } @@ -77,8 +79,7 @@ pub fn gen_init_pay( Initiated { id: 0, amount: Amount::new(&CURR, 44, 0), - creditor: FullIbanPayto::from_str("payto://iban/CH4189144589712575493?receiver-name=Test") - .unwrap(), + creditor: EXCHANGE.clone(), subject: subject.into(), initiation_time: Timestamp::now(), e2e_id: end_to_end_id.into(), @@ -91,11 +92,7 @@ pub fn gen_in_pay(subject: impl Display) -> InTx { id: InId::new(None, Some(rand_ebics_id()), None), amount: Amount::new(&CURR, 44, 0), credit_fee: Amount::zero(&CURR), - debtor: Some( - IbanPayto::from_str("payto://iban/DE84500105177118117964?receiver-name=John+Smith") - .unwrap() - .as_uri(), - ), + debtor: Some(CLIENT.as_uri()), subject: Some(subject.to_string()), execution_time: Timestamp::now(), } diff --git a/testbench/Cargo.toml b/testbench/Cargo.toml @@ -16,7 +16,7 @@ clap.workspace = true taler-common.workspace = true libeufin-nexus = { path = "../libeufin-nexus"} libeufin-ebics = { path = "../libeufin-ebics"} -reedline = "0.47" +reedline = "0.48" shlex = "2.0" owo-colors = "4.3" tracing-subscriber = "0.3"