fake_wallet.rs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362
  1. //! Fake Wallet Integration Tests
  2. //!
  3. //! This file contains tests for the fake wallet backend functionality.
  4. //! The fake wallet simulates Lightning Network behavior for testing purposes,
  5. //! allowing verification of mint behavior in various payment scenarios without
  6. //! requiring a real Lightning node.
  7. //!
  8. //! Test Scenarios:
  9. //! - Pending payment states and proof handling
  10. //! - Payment failure cases and proof state management
  11. //! - Change output verification in melt operations
  12. //! - Witness signature validation
  13. //! - Cross-unit transaction validation
  14. //! - Overflow and balance validation
  15. //! - Duplicate proof detection
  16. use std::sync::Arc;
  17. use bip39::Mnemonic;
  18. use cashu::Amount;
  19. use cdk::amount::SplitTarget;
  20. use cdk::nuts::nut00::ProofsMethods;
  21. use cdk::nuts::{
  22. CurrencyUnit, MeltQuoteState, MeltRequest, MintRequest, PreMintSecrets, Proofs, SecretKey,
  23. State, SwapRequest,
  24. };
  25. use cdk::wallet::types::TransactionDirection;
  26. use cdk::wallet::{HttpClient, MintConnector, Wallet};
  27. use cdk::StreamExt;
  28. use cdk_fake_wallet::{create_fake_invoice, FakeInvoiceDescription};
  29. use cdk_integration_tests::attempt_to_swap_pending;
  30. use cdk_sqlite::wallet::memory;
  31. const MINT_URL: &str = "http://127.0.0.1:8086";
  32. /// Tests that when both pay and check return pending status, input proofs should remain pending
  33. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  34. async fn test_fake_tokens_pending() {
  35. let wallet = Wallet::new(
  36. MINT_URL,
  37. CurrencyUnit::Sat,
  38. Arc::new(memory::empty().await.unwrap()),
  39. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  40. None,
  41. )
  42. .expect("failed to create new wallet");
  43. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  44. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  45. let _proofs = proof_streams
  46. .next()
  47. .await
  48. .expect("payment")
  49. .expect("no error");
  50. let fake_description = FakeInvoiceDescription {
  51. pay_invoice_state: MeltQuoteState::Pending,
  52. check_payment_state: MeltQuoteState::Pending,
  53. pay_err: false,
  54. check_err: false,
  55. };
  56. let invoice = create_fake_invoice(1000, serde_json::to_string(&fake_description).unwrap());
  57. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  58. let melt = wallet.melt(&melt_quote.id).await;
  59. assert!(melt.is_err());
  60. attempt_to_swap_pending(&wallet).await.unwrap();
  61. }
  62. /// Tests that if the pay error fails and the check returns unknown or failed,
  63. /// the input proofs should be unset as spending (returned to unspent state)
  64. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  65. async fn test_fake_melt_payment_fail() {
  66. let wallet = Wallet::new(
  67. MINT_URL,
  68. CurrencyUnit::Sat,
  69. Arc::new(memory::empty().await.unwrap()),
  70. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  71. None,
  72. )
  73. .expect("Failed to create new wallet");
  74. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  75. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  76. let _proofs = proof_streams
  77. .next()
  78. .await
  79. .expect("payment")
  80. .expect("no error");
  81. let fake_description = FakeInvoiceDescription {
  82. pay_invoice_state: MeltQuoteState::Unknown,
  83. check_payment_state: MeltQuoteState::Unknown,
  84. pay_err: true,
  85. check_err: false,
  86. };
  87. let invoice = create_fake_invoice(1000, serde_json::to_string(&fake_description).unwrap());
  88. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  89. // The melt should error at the payment invoice command
  90. let melt = wallet.melt(&melt_quote.id).await;
  91. assert!(melt.is_err());
  92. let fake_description = FakeInvoiceDescription {
  93. pay_invoice_state: MeltQuoteState::Failed,
  94. check_payment_state: MeltQuoteState::Failed,
  95. pay_err: true,
  96. check_err: false,
  97. };
  98. let invoice = create_fake_invoice(1000, serde_json::to_string(&fake_description).unwrap());
  99. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  100. // The melt should error at the payment invoice command
  101. let melt = wallet.melt(&melt_quote.id).await;
  102. assert!(melt.is_err());
  103. // The mint should have unset proofs from pending since payment failed
  104. let all_proof = wallet.get_unspent_proofs().await.unwrap();
  105. let states = wallet.check_proofs_spent(all_proof).await.unwrap();
  106. for state in states {
  107. assert!(state.state == State::Unspent);
  108. }
  109. let wallet_bal = wallet.total_balance().await.unwrap();
  110. assert_eq!(wallet_bal, 100.into());
  111. }
  112. /// Tests that when both the pay_invoice and check_invoice both fail,
  113. /// the proofs should remain in pending state
  114. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  115. async fn test_fake_melt_payment_fail_and_check() {
  116. let wallet = Wallet::new(
  117. MINT_URL,
  118. CurrencyUnit::Sat,
  119. Arc::new(memory::empty().await.unwrap()),
  120. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  121. None,
  122. )
  123. .expect("Failed to create new wallet");
  124. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  125. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  126. let _proofs = proof_streams
  127. .next()
  128. .await
  129. .expect("payment")
  130. .expect("no error");
  131. let fake_description = FakeInvoiceDescription {
  132. pay_invoice_state: MeltQuoteState::Unknown,
  133. check_payment_state: MeltQuoteState::Unknown,
  134. pay_err: true,
  135. check_err: true,
  136. };
  137. let invoice = create_fake_invoice(7000, serde_json::to_string(&fake_description).unwrap());
  138. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  139. // The melt should error at the payment invoice command
  140. let melt = wallet.melt(&melt_quote.id).await;
  141. assert!(melt.is_err());
  142. let pending = wallet
  143. .localstore
  144. .get_proofs(None, None, Some(vec![State::Pending]), None)
  145. .await
  146. .unwrap();
  147. assert!(!pending.is_empty());
  148. }
  149. /// Tests that when the ln backend returns a failed status but does not error,
  150. /// the mint should do a second check, then remove proofs from pending state
  151. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  152. async fn test_fake_melt_payment_return_fail_status() {
  153. let wallet = Wallet::new(
  154. MINT_URL,
  155. CurrencyUnit::Sat,
  156. Arc::new(memory::empty().await.unwrap()),
  157. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  158. None,
  159. )
  160. .expect("Failed to create new wallet");
  161. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  162. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  163. let _proofs = proof_streams
  164. .next()
  165. .await
  166. .expect("payment")
  167. .expect("no error");
  168. let fake_description = FakeInvoiceDescription {
  169. pay_invoice_state: MeltQuoteState::Failed,
  170. check_payment_state: MeltQuoteState::Failed,
  171. pay_err: false,
  172. check_err: false,
  173. };
  174. let invoice = create_fake_invoice(7000, serde_json::to_string(&fake_description).unwrap());
  175. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  176. // The melt should error at the payment invoice command
  177. let melt = wallet.melt(&melt_quote.id).await;
  178. assert!(melt.is_err());
  179. let fake_description = FakeInvoiceDescription {
  180. pay_invoice_state: MeltQuoteState::Unknown,
  181. check_payment_state: MeltQuoteState::Unknown,
  182. pay_err: false,
  183. check_err: false,
  184. };
  185. let invoice = create_fake_invoice(7000, serde_json::to_string(&fake_description).unwrap());
  186. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  187. // The melt should error at the payment invoice command
  188. let melt = wallet.melt(&melt_quote.id).await;
  189. assert!(melt.is_err());
  190. let pending = wallet
  191. .localstore
  192. .get_proofs(None, None, Some(vec![State::Pending]), None)
  193. .await
  194. .unwrap();
  195. assert!(pending.is_empty());
  196. }
  197. /// Tests that when the ln backend returns an error with unknown status,
  198. /// the mint should do a second check, then remove proofs from pending state
  199. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  200. async fn test_fake_melt_payment_error_unknown() {
  201. let wallet = Wallet::new(
  202. MINT_URL,
  203. CurrencyUnit::Sat,
  204. Arc::new(memory::empty().await.unwrap()),
  205. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  206. None,
  207. )
  208. .unwrap();
  209. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  210. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  211. let _proofs = proof_streams
  212. .next()
  213. .await
  214. .expect("payment")
  215. .expect("no error");
  216. let fake_description = FakeInvoiceDescription {
  217. pay_invoice_state: MeltQuoteState::Failed,
  218. check_payment_state: MeltQuoteState::Unknown,
  219. pay_err: true,
  220. check_err: false,
  221. };
  222. let invoice = create_fake_invoice(7000, serde_json::to_string(&fake_description).unwrap());
  223. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  224. // The melt should error at the payment invoice command
  225. let melt = wallet.melt(&melt_quote.id).await;
  226. assert_eq!(melt.unwrap_err().to_string(), "Payment failed");
  227. let fake_description = FakeInvoiceDescription {
  228. pay_invoice_state: MeltQuoteState::Unknown,
  229. check_payment_state: MeltQuoteState::Unknown,
  230. pay_err: true,
  231. check_err: false,
  232. };
  233. let invoice = create_fake_invoice(7000, serde_json::to_string(&fake_description).unwrap());
  234. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  235. // The melt should error at the payment invoice command
  236. let melt = wallet.melt(&melt_quote.id).await;
  237. assert_eq!(melt.unwrap_err().to_string(), "Payment failed");
  238. let pending = wallet
  239. .localstore
  240. .get_proofs(None, None, Some(vec![State::Pending]), None)
  241. .await
  242. .unwrap();
  243. assert!(pending.is_empty());
  244. }
  245. /// Tests that when the ln backend returns an error but the second check returns paid,
  246. /// proofs should remain in pending state
  247. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  248. async fn test_fake_melt_payment_err_paid() {
  249. let wallet = Wallet::new(
  250. MINT_URL,
  251. CurrencyUnit::Sat,
  252. Arc::new(memory::empty().await.unwrap()),
  253. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  254. None,
  255. )
  256. .expect("Failed to create new wallet");
  257. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  258. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  259. let _proofs = proof_streams
  260. .next()
  261. .await
  262. .expect("payment")
  263. .expect("no error");
  264. let fake_description = FakeInvoiceDescription {
  265. pay_invoice_state: MeltQuoteState::Failed,
  266. check_payment_state: MeltQuoteState::Paid,
  267. pay_err: true,
  268. check_err: false,
  269. };
  270. let invoice = create_fake_invoice(7000, serde_json::to_string(&fake_description).unwrap());
  271. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  272. // The melt should error at the payment invoice command
  273. let melt = wallet.melt(&melt_quote.id).await;
  274. assert!(melt.is_err());
  275. attempt_to_swap_pending(&wallet).await.unwrap();
  276. }
  277. /// Tests that change outputs in a melt quote are correctly handled
  278. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  279. async fn test_fake_melt_change_in_quote() {
  280. let wallet = Wallet::new(
  281. MINT_URL,
  282. CurrencyUnit::Sat,
  283. Arc::new(memory::empty().await.unwrap()),
  284. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  285. None,
  286. )
  287. .expect("Failed to create new wallet");
  288. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  289. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  290. let _proofs = proof_streams
  291. .next()
  292. .await
  293. .expect("payment")
  294. .expect("no error");
  295. let transaction = wallet
  296. .list_transactions(Some(TransactionDirection::Incoming))
  297. .await
  298. .unwrap()
  299. .pop()
  300. .expect("No transaction found");
  301. assert_eq!(wallet.mint_url, transaction.mint_url);
  302. assert_eq!(TransactionDirection::Incoming, transaction.direction);
  303. assert_eq!(Amount::from(100), transaction.amount);
  304. assert_eq!(Amount::from(0), transaction.fee);
  305. assert_eq!(CurrencyUnit::Sat, transaction.unit);
  306. let fake_description = FakeInvoiceDescription::default();
  307. let invoice = create_fake_invoice(9000, serde_json::to_string(&fake_description).unwrap());
  308. let proofs = wallet.get_unspent_proofs().await.unwrap();
  309. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  310. let keyset = wallet.fetch_active_keyset().await.unwrap();
  311. let premint_secrets = PreMintSecrets::random(
  312. keyset.id,
  313. 100.into(),
  314. &SplitTarget::default(),
  315. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  316. )
  317. .unwrap();
  318. let client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  319. let melt_request = MeltRequest::new(
  320. melt_quote.id.clone(),
  321. proofs.clone(),
  322. Some(premint_secrets.blinded_messages()),
  323. );
  324. let melt_response = client.post_melt(melt_request).await.unwrap();
  325. assert!(melt_response.change.is_some());
  326. let check = wallet.melt_quote_status(&melt_quote.id).await.unwrap();
  327. let mut melt_change = melt_response.change.unwrap();
  328. melt_change.sort_by(|a, b| a.amount.cmp(&b.amount));
  329. let mut check = check.change.unwrap();
  330. check.sort_by(|a, b| a.amount.cmp(&b.amount));
  331. assert_eq!(melt_change, check);
  332. }
  333. /// Tests minting tokens with a valid witness signature
  334. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  335. async fn test_fake_mint_with_witness() {
  336. let wallet = Wallet::new(
  337. MINT_URL,
  338. CurrencyUnit::Sat,
  339. Arc::new(memory::empty().await.unwrap()),
  340. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  341. None,
  342. )
  343. .expect("failed to create new wallet");
  344. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  345. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  346. let proofs = proof_streams
  347. .next()
  348. .await
  349. .expect("payment")
  350. .expect("no error");
  351. let mint_amount = proofs.total_amount().unwrap();
  352. assert!(mint_amount == 100.into());
  353. }
  354. /// Tests that minting without a witness signature fails with the correct error
  355. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  356. async fn test_fake_mint_without_witness() {
  357. let wallet = Wallet::new(
  358. MINT_URL,
  359. CurrencyUnit::Sat,
  360. Arc::new(memory::empty().await.unwrap()),
  361. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  362. None,
  363. )
  364. .expect("failed to create new wallet");
  365. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  366. let mut payment_streams = wallet.payment_stream(&mint_quote);
  367. payment_streams
  368. .next()
  369. .await
  370. .expect("payment")
  371. .expect("no error");
  372. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  373. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  374. let premint_secrets = PreMintSecrets::random(
  375. active_keyset_id,
  376. 100.into(),
  377. &SplitTarget::default(),
  378. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  379. )
  380. .unwrap();
  381. let request = MintRequest {
  382. quote: mint_quote.id,
  383. outputs: premint_secrets.blinded_messages(),
  384. signature: None,
  385. };
  386. let response = http_client.post_mint(request.clone()).await;
  387. match response {
  388. Err(cdk::error::Error::SignatureMissingOrInvalid) => {} //pass
  389. Err(err) => panic!("Wrong mint response for minting without witness: {}", err),
  390. Ok(_) => panic!("Minting should not have succeed without a witness"),
  391. }
  392. }
  393. /// Tests that minting with an incorrect witness signature fails with the correct error
  394. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  395. async fn test_fake_mint_with_wrong_witness() {
  396. let wallet = Wallet::new(
  397. MINT_URL,
  398. CurrencyUnit::Sat,
  399. Arc::new(memory::empty().await.unwrap()),
  400. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  401. None,
  402. )
  403. .expect("failed to create new wallet");
  404. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  405. let mut payment_streams = wallet.payment_stream(&mint_quote);
  406. payment_streams
  407. .next()
  408. .await
  409. .expect("payment")
  410. .expect("no error");
  411. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  412. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  413. let premint_secrets = PreMintSecrets::random(
  414. active_keyset_id,
  415. 100.into(),
  416. &SplitTarget::default(),
  417. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  418. )
  419. .unwrap();
  420. let mut request = MintRequest {
  421. quote: mint_quote.id,
  422. outputs: premint_secrets.blinded_messages(),
  423. signature: None,
  424. };
  425. let secret_key = SecretKey::generate();
  426. request
  427. .sign(secret_key)
  428. .expect("failed to sign the mint request");
  429. let response = http_client.post_mint(request.clone()).await;
  430. match response {
  431. Err(cdk::error::Error::SignatureMissingOrInvalid) => {} //pass
  432. Err(err) => panic!("Wrong mint response for minting without witness: {}", err),
  433. Ok(_) => panic!("Minting should not have succeed without a witness"),
  434. }
  435. }
  436. /// Tests that attempting to mint more tokens than allowed by the quote fails
  437. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  438. async fn test_fake_mint_inflated() {
  439. let wallet = Wallet::new(
  440. MINT_URL,
  441. CurrencyUnit::Sat,
  442. Arc::new(memory::empty().await.unwrap()),
  443. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  444. None,
  445. )
  446. .expect("failed to create new wallet");
  447. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  448. let mut payment_streams = wallet.payment_stream(&mint_quote);
  449. payment_streams
  450. .next()
  451. .await
  452. .expect("payment")
  453. .expect("no error");
  454. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  455. let pre_mint = PreMintSecrets::random(
  456. active_keyset_id,
  457. 500.into(),
  458. &SplitTarget::None,
  459. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  460. )
  461. .unwrap();
  462. let quote_info = wallet
  463. .localstore
  464. .get_mint_quote(&mint_quote.id)
  465. .await
  466. .unwrap()
  467. .expect("there is a quote");
  468. let mut mint_request = MintRequest {
  469. quote: mint_quote.id,
  470. outputs: pre_mint.blinded_messages(),
  471. signature: None,
  472. };
  473. if let Some(secret_key) = quote_info.secret_key {
  474. mint_request
  475. .sign(secret_key)
  476. .expect("failed to sign the mint request");
  477. }
  478. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  479. let response = http_client.post_mint(mint_request.clone()).await;
  480. match response {
  481. Err(err) => match err {
  482. cdk::Error::TransactionUnbalanced(_, _, _) => (),
  483. err => {
  484. panic!("Wrong mint error returned: {}", err);
  485. }
  486. },
  487. Ok(_) => {
  488. panic!("Should not have allowed second payment");
  489. }
  490. }
  491. }
  492. /// Tests that attempting to mint with multiple currency units in the same request fails
  493. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  494. async fn test_fake_mint_multiple_units() {
  495. let wallet = Wallet::new(
  496. MINT_URL,
  497. CurrencyUnit::Sat,
  498. Arc::new(memory::empty().await.unwrap()),
  499. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  500. None,
  501. )
  502. .expect("failed to create new wallet");
  503. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  504. let mut payment_streams = wallet.payment_stream(&mint_quote);
  505. payment_streams
  506. .next()
  507. .await
  508. .expect("payment")
  509. .expect("no error");
  510. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  511. let pre_mint = PreMintSecrets::random(
  512. active_keyset_id,
  513. 50.into(),
  514. &SplitTarget::None,
  515. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  516. )
  517. .unwrap();
  518. let wallet_usd = Wallet::new(
  519. MINT_URL,
  520. CurrencyUnit::Usd,
  521. Arc::new(memory::empty().await.unwrap()),
  522. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  523. None,
  524. )
  525. .expect("failed to create new wallet");
  526. let active_keyset_id = wallet_usd.fetch_active_keyset().await.unwrap().id;
  527. let usd_pre_mint = PreMintSecrets::random(
  528. active_keyset_id,
  529. 50.into(),
  530. &SplitTarget::None,
  531. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  532. )
  533. .unwrap();
  534. let quote_info = wallet
  535. .localstore
  536. .get_mint_quote(&mint_quote.id)
  537. .await
  538. .unwrap()
  539. .expect("there is a quote");
  540. let mut sat_outputs = pre_mint.blinded_messages();
  541. let mut usd_outputs = usd_pre_mint.blinded_messages();
  542. sat_outputs.append(&mut usd_outputs);
  543. let mut mint_request = MintRequest {
  544. quote: mint_quote.id,
  545. outputs: sat_outputs,
  546. signature: None,
  547. };
  548. if let Some(secret_key) = quote_info.secret_key {
  549. mint_request
  550. .sign(secret_key)
  551. .expect("failed to sign the mint request");
  552. }
  553. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  554. let response = http_client.post_mint(mint_request.clone()).await;
  555. match response {
  556. Err(err) => match err {
  557. cdk::Error::MultipleUnits => (),
  558. err => {
  559. panic!("Wrong mint error returned: {}", err);
  560. }
  561. },
  562. Ok(_) => {
  563. panic!("Should not have allowed to mint with multiple units");
  564. }
  565. }
  566. }
  567. /// Tests that attempting to swap tokens with multiple currency units fails
  568. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  569. async fn test_fake_mint_multiple_unit_swap() {
  570. let wallet = Wallet::new(
  571. MINT_URL,
  572. CurrencyUnit::Sat,
  573. Arc::new(memory::empty().await.unwrap()),
  574. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  575. None,
  576. )
  577. .expect("failed to create new wallet");
  578. wallet.refresh_keysets().await.unwrap();
  579. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  580. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  581. let proofs = proof_streams
  582. .next()
  583. .await
  584. .expect("payment")
  585. .expect("no error");
  586. let wallet_usd = Wallet::new(
  587. MINT_URL,
  588. CurrencyUnit::Usd,
  589. Arc::new(memory::empty().await.unwrap()),
  590. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  591. None,
  592. )
  593. .expect("failed to create usd wallet");
  594. wallet_usd.refresh_keysets().await.unwrap();
  595. let mint_quote = wallet_usd.mint_quote(100.into(), None).await.unwrap();
  596. let mut proof_streams =
  597. wallet_usd.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  598. let usd_proofs = proof_streams
  599. .next()
  600. .await
  601. .expect("payment")
  602. .expect("no error");
  603. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  604. {
  605. let inputs: Proofs = vec![
  606. proofs.first().expect("There is a proof").clone(),
  607. usd_proofs.first().expect("There is a proof").clone(),
  608. ];
  609. let pre_mint = PreMintSecrets::random(
  610. active_keyset_id,
  611. inputs.total_amount().unwrap(),
  612. &SplitTarget::None,
  613. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  614. )
  615. .unwrap();
  616. let swap_request = SwapRequest::new(inputs, pre_mint.blinded_messages());
  617. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  618. let response = http_client.post_swap(swap_request.clone()).await;
  619. match response {
  620. Err(err) => match err {
  621. cdk::Error::MultipleUnits => (),
  622. err => {
  623. panic!("Wrong mint error returned: {}", err);
  624. }
  625. },
  626. Ok(_) => {
  627. panic!("Should not have allowed to mint with multiple units");
  628. }
  629. }
  630. }
  631. {
  632. let usd_active_keyset_id = wallet_usd.fetch_active_keyset().await.unwrap().id;
  633. let inputs: Proofs = proofs.into_iter().take(2).collect();
  634. let total_inputs = inputs.total_amount().unwrap();
  635. let half = total_inputs / 2.into();
  636. let usd_pre_mint = PreMintSecrets::random(
  637. usd_active_keyset_id,
  638. half,
  639. &SplitTarget::None,
  640. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  641. )
  642. .unwrap();
  643. let pre_mint = PreMintSecrets::random(
  644. active_keyset_id,
  645. total_inputs - half,
  646. &SplitTarget::None,
  647. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  648. )
  649. .unwrap();
  650. let mut usd_outputs = usd_pre_mint.blinded_messages();
  651. let mut sat_outputs = pre_mint.blinded_messages();
  652. usd_outputs.append(&mut sat_outputs);
  653. let swap_request = SwapRequest::new(inputs, usd_outputs);
  654. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  655. let response = http_client.post_swap(swap_request.clone()).await;
  656. match response {
  657. Err(err) => match err {
  658. cdk::Error::MultipleUnits => (),
  659. err => {
  660. panic!("Wrong mint error returned: {}", err);
  661. }
  662. },
  663. Ok(_) => {
  664. panic!("Should not have allowed to mint with multiple units");
  665. }
  666. }
  667. }
  668. }
  669. /// Tests that attempting to melt tokens with multiple currency units fails
  670. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  671. async fn test_fake_mint_multiple_unit_melt() {
  672. let wallet = Wallet::new(
  673. MINT_URL,
  674. CurrencyUnit::Sat,
  675. Arc::new(memory::empty().await.unwrap()),
  676. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  677. None,
  678. )
  679. .expect("failed to create new wallet");
  680. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  681. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  682. let proofs = proof_streams
  683. .next()
  684. .await
  685. .expect("payment")
  686. .expect("no error");
  687. println!("Minted sat");
  688. let wallet_usd = Wallet::new(
  689. MINT_URL,
  690. CurrencyUnit::Usd,
  691. Arc::new(memory::empty().await.unwrap()),
  692. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  693. None,
  694. )
  695. .expect("failed to create new wallet");
  696. let mint_quote = wallet_usd.mint_quote(100.into(), None).await.unwrap();
  697. println!("Minted quote usd");
  698. let mut proof_streams =
  699. wallet_usd.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  700. let usd_proofs = proof_streams
  701. .next()
  702. .await
  703. .expect("payment")
  704. .expect("no error");
  705. {
  706. let inputs: Proofs = vec![
  707. proofs.first().expect("There is a proof").clone(),
  708. usd_proofs.first().expect("There is a proof").clone(),
  709. ];
  710. let input_amount: u64 = inputs.total_amount().unwrap().into();
  711. let invoice = create_fake_invoice((input_amount - 1) * 1000, "".to_string());
  712. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  713. let melt_request = MeltRequest::new(melt_quote.id, inputs, None);
  714. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  715. let response = http_client.post_melt(melt_request.clone()).await;
  716. match response {
  717. Err(err) => match err {
  718. cdk::Error::MultipleUnits => (),
  719. err => {
  720. panic!("Wrong mint error returned: {}", err);
  721. }
  722. },
  723. Ok(_) => {
  724. panic!("Should not have allowed to melt with multiple units");
  725. }
  726. }
  727. }
  728. {
  729. let inputs: Proofs = vec![proofs.first().expect("There is a proof").clone()];
  730. let input_amount: u64 = inputs.total_amount().unwrap().into();
  731. let invoice = create_fake_invoice((input_amount - 1) * 1000, "".to_string());
  732. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  733. let usd_active_keyset_id = wallet_usd.fetch_active_keyset().await.unwrap().id;
  734. let usd_pre_mint = PreMintSecrets::random(
  735. usd_active_keyset_id,
  736. inputs.total_amount().unwrap() + 100.into(),
  737. &SplitTarget::None,
  738. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  739. )
  740. .unwrap();
  741. let pre_mint = PreMintSecrets::random(
  742. active_keyset_id,
  743. 100.into(),
  744. &SplitTarget::None,
  745. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  746. )
  747. .unwrap();
  748. let mut usd_outputs = usd_pre_mint.blinded_messages();
  749. let mut sat_outputs = pre_mint.blinded_messages();
  750. usd_outputs.append(&mut sat_outputs);
  751. let quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  752. let melt_request = MeltRequest::new(quote.id, inputs, Some(usd_outputs));
  753. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  754. let response = http_client.post_melt(melt_request.clone()).await;
  755. match response {
  756. Err(err) => match err {
  757. cdk::Error::MultipleUnits => (),
  758. err => {
  759. panic!("Wrong mint error returned: {}", err);
  760. }
  761. },
  762. Ok(_) => {
  763. panic!("Should not have allowed to melt with multiple units");
  764. }
  765. }
  766. }
  767. }
  768. /// Tests that swapping tokens where input unit doesn't match output unit fails
  769. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  770. async fn test_fake_mint_input_output_mismatch() {
  771. let wallet = Wallet::new(
  772. MINT_URL,
  773. CurrencyUnit::Sat,
  774. Arc::new(memory::empty().await.unwrap()),
  775. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  776. None,
  777. )
  778. .expect("failed to create new wallet");
  779. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  780. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  781. let proofs = proof_streams
  782. .next()
  783. .await
  784. .expect("payment")
  785. .expect("no error");
  786. let wallet_usd = Wallet::new(
  787. MINT_URL,
  788. CurrencyUnit::Usd,
  789. Arc::new(memory::empty().await.unwrap()),
  790. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  791. None,
  792. )
  793. .expect("failed to create new usd wallet");
  794. let usd_active_keyset_id = wallet_usd.fetch_active_keyset().await.unwrap().id;
  795. let inputs = proofs;
  796. let pre_mint = PreMintSecrets::random(
  797. usd_active_keyset_id,
  798. inputs.total_amount().unwrap(),
  799. &SplitTarget::None,
  800. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  801. )
  802. .unwrap();
  803. let swap_request = SwapRequest::new(inputs, pre_mint.blinded_messages());
  804. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  805. let response = http_client.post_swap(swap_request.clone()).await;
  806. match response {
  807. Err(err) => match err {
  808. cdk::Error::UnitMismatch => (),
  809. err => panic!("Wrong error returned: {}", err),
  810. },
  811. Ok(_) => {
  812. panic!("Should not have allowed to mint with multiple units");
  813. }
  814. }
  815. }
  816. /// Tests that swapping tokens where output amount is greater than input amount fails
  817. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  818. async fn test_fake_mint_swap_inflated() {
  819. let wallet = Wallet::new(
  820. MINT_URL,
  821. CurrencyUnit::Sat,
  822. Arc::new(memory::empty().await.unwrap()),
  823. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  824. None,
  825. )
  826. .expect("failed to create new wallet");
  827. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  828. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  829. let proofs = proof_streams
  830. .next()
  831. .await
  832. .expect("payment")
  833. .expect("no error");
  834. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  835. let pre_mint = PreMintSecrets::random(
  836. active_keyset_id,
  837. 101.into(),
  838. &SplitTarget::None,
  839. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  840. )
  841. .unwrap();
  842. let swap_request = SwapRequest::new(proofs, pre_mint.blinded_messages());
  843. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  844. let response = http_client.post_swap(swap_request.clone()).await;
  845. match response {
  846. Err(err) => match err {
  847. cdk::Error::TransactionUnbalanced(_, _, _) => (),
  848. err => {
  849. panic!("Wrong mint error returned: {}", err);
  850. }
  851. },
  852. Ok(_) => {
  853. panic!("Should not have allowed to mint with multiple units");
  854. }
  855. }
  856. }
  857. /// Tests that tokens cannot be spent again after a failed swap attempt
  858. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  859. async fn test_fake_mint_swap_spend_after_fail() {
  860. let wallet = Wallet::new(
  861. MINT_URL,
  862. CurrencyUnit::Sat,
  863. Arc::new(memory::empty().await.unwrap()),
  864. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  865. None,
  866. )
  867. .expect("failed to create new wallet");
  868. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  869. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  870. let proofs = proof_streams
  871. .next()
  872. .await
  873. .expect("payment")
  874. .expect("no error");
  875. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  876. let pre_mint = PreMintSecrets::random(
  877. active_keyset_id,
  878. 100.into(),
  879. &SplitTarget::None,
  880. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  881. )
  882. .unwrap();
  883. let swap_request = SwapRequest::new(proofs.clone(), pre_mint.blinded_messages());
  884. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  885. let response = http_client.post_swap(swap_request.clone()).await;
  886. assert!(response.is_ok());
  887. let pre_mint = PreMintSecrets::random(
  888. active_keyset_id,
  889. 101.into(),
  890. &SplitTarget::None,
  891. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  892. )
  893. .unwrap();
  894. let swap_request = SwapRequest::new(proofs.clone(), pre_mint.blinded_messages());
  895. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  896. let response = http_client.post_swap(swap_request.clone()).await;
  897. match response {
  898. Err(err) => match err {
  899. cdk::Error::TransactionUnbalanced(_, _, _) => (),
  900. err => panic!("Wrong mint error returned expected TransactionUnbalanced, got: {err}"),
  901. },
  902. Ok(_) => panic!("Should not have allowed swap with unbalanced"),
  903. }
  904. let pre_mint = PreMintSecrets::random(
  905. active_keyset_id,
  906. 100.into(),
  907. &SplitTarget::None,
  908. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  909. )
  910. .unwrap();
  911. let swap_request = SwapRequest::new(proofs, pre_mint.blinded_messages());
  912. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  913. let response = http_client.post_swap(swap_request.clone()).await;
  914. match response {
  915. Err(err) => match err {
  916. cdk::Error::TokenAlreadySpent => (),
  917. err => {
  918. panic!("Wrong mint error returned: {}", err);
  919. }
  920. },
  921. Ok(_) => {
  922. panic!("Should not have allowed to mint with multiple units");
  923. }
  924. }
  925. }
  926. /// Tests that tokens cannot be melted after a failed swap attempt
  927. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  928. async fn test_fake_mint_melt_spend_after_fail() {
  929. let wallet = Wallet::new(
  930. MINT_URL,
  931. CurrencyUnit::Sat,
  932. Arc::new(memory::empty().await.unwrap()),
  933. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  934. None,
  935. )
  936. .expect("failed to create new wallet");
  937. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  938. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  939. let proofs = proof_streams
  940. .next()
  941. .await
  942. .expect("payment")
  943. .expect("no error");
  944. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  945. let pre_mint = PreMintSecrets::random(
  946. active_keyset_id,
  947. 100.into(),
  948. &SplitTarget::None,
  949. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  950. )
  951. .unwrap();
  952. let swap_request = SwapRequest::new(proofs.clone(), pre_mint.blinded_messages());
  953. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  954. let response = http_client.post_swap(swap_request.clone()).await;
  955. assert!(response.is_ok());
  956. let pre_mint = PreMintSecrets::random(
  957. active_keyset_id,
  958. 101.into(),
  959. &SplitTarget::None,
  960. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  961. )
  962. .unwrap();
  963. let swap_request = SwapRequest::new(proofs.clone(), pre_mint.blinded_messages());
  964. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  965. let response = http_client.post_swap(swap_request.clone()).await;
  966. match response {
  967. Err(err) => match err {
  968. cdk::Error::TransactionUnbalanced(_, _, _) => (),
  969. err => panic!("Wrong mint error returned expected TransactionUnbalanced, got: {err}"),
  970. },
  971. Ok(_) => panic!("Should not have allowed swap with unbalanced"),
  972. }
  973. let input_amount: u64 = proofs.total_amount().unwrap().into();
  974. let invoice = create_fake_invoice((input_amount - 1) * 1000, "".to_string());
  975. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  976. let melt_request = MeltRequest::new(melt_quote.id, proofs, None);
  977. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  978. let response = http_client.post_melt(melt_request.clone()).await;
  979. match response {
  980. Err(err) => match err {
  981. cdk::Error::TokenAlreadySpent => (),
  982. err => {
  983. panic!("Wrong mint error returned: {}", err);
  984. }
  985. },
  986. Ok(_) => {
  987. panic!("Should not have allowed to melt with multiple units");
  988. }
  989. }
  990. }
  991. /// Tests that attempting to swap with duplicate proofs fails
  992. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  993. async fn test_fake_mint_duplicate_proofs_swap() {
  994. let wallet = Wallet::new(
  995. MINT_URL,
  996. CurrencyUnit::Sat,
  997. Arc::new(memory::empty().await.unwrap()),
  998. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  999. None,
  1000. )
  1001. .expect("failed to create new wallet");
  1002. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  1003. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  1004. let proofs = proof_streams
  1005. .next()
  1006. .await
  1007. .expect("payment")
  1008. .expect("no error");
  1009. let active_keyset_id = wallet.fetch_active_keyset().await.unwrap().id;
  1010. let inputs = vec![proofs[0].clone(), proofs[0].clone()];
  1011. let pre_mint = PreMintSecrets::random(
  1012. active_keyset_id,
  1013. inputs.total_amount().unwrap(),
  1014. &SplitTarget::None,
  1015. &((0..32).map(|x| 2u64.pow(x)).collect::<Vec<_>>()),
  1016. )
  1017. .unwrap();
  1018. let swap_request = SwapRequest::new(inputs.clone(), pre_mint.blinded_messages());
  1019. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  1020. let response = http_client.post_swap(swap_request.clone()).await;
  1021. match response {
  1022. Err(err) => match err {
  1023. cdk::Error::DuplicateInputs => (),
  1024. err => {
  1025. panic!(
  1026. "Wrong mint error returned, expected duplicate inputs: {}",
  1027. err
  1028. );
  1029. }
  1030. },
  1031. Ok(_) => {
  1032. panic!("Should not have allowed duplicate inputs");
  1033. }
  1034. }
  1035. let blinded_message = pre_mint.blinded_messages();
  1036. let inputs = vec![proofs[0].clone()];
  1037. let outputs = vec![blinded_message[0].clone(), blinded_message[0].clone()];
  1038. let swap_request = SwapRequest::new(inputs, outputs);
  1039. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  1040. let response = http_client.post_swap(swap_request.clone()).await;
  1041. match response {
  1042. Err(err) => match err {
  1043. cdk::Error::DuplicateOutputs => (),
  1044. err => {
  1045. panic!(
  1046. "Wrong mint error returned, expected duplicate outputs: {}",
  1047. err
  1048. );
  1049. }
  1050. },
  1051. Ok(_) => {
  1052. panic!("Should not have allow duplicate inputs");
  1053. }
  1054. }
  1055. }
  1056. /// Tests that attempting to melt with duplicate proofs fails
  1057. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  1058. async fn test_fake_mint_duplicate_proofs_melt() {
  1059. let wallet = Wallet::new(
  1060. MINT_URL,
  1061. CurrencyUnit::Sat,
  1062. Arc::new(memory::empty().await.unwrap()),
  1063. Mnemonic::generate(12).unwrap().to_seed_normalized(""),
  1064. None,
  1065. )
  1066. .expect("failed to create new wallet");
  1067. let mint_quote = wallet.mint_quote(100.into(), None).await.unwrap();
  1068. let mut proof_streams = wallet.proof_stream(mint_quote.clone(), SplitTarget::default(), None);
  1069. let proofs = proof_streams
  1070. .next()
  1071. .await
  1072. .expect("payment")
  1073. .expect("no error");
  1074. let inputs = vec![proofs[0].clone(), proofs[0].clone()];
  1075. let invoice = create_fake_invoice(7000, "".to_string());
  1076. let melt_quote = wallet.melt_quote(invoice.to_string(), None).await.unwrap();
  1077. let melt_request = MeltRequest::new(melt_quote.id, inputs, None);
  1078. let http_client = HttpClient::new(MINT_URL.parse().unwrap(), None);
  1079. let response = http_client.post_melt(melt_request.clone()).await;
  1080. match response {
  1081. Err(err) => match err {
  1082. cdk::Error::DuplicateInputs => (),
  1083. err => {
  1084. panic!("Wrong mint error returned: {}", err);
  1085. }
  1086. },
  1087. Ok(_) => {
  1088. panic!("Should not have allow duplicate inputs");
  1089. }
  1090. }
  1091. }