auth_wallet.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. use std::sync::Arc;
  2. use std::time::Duration;
  3. use cdk::error::Error;
  4. use cdk::nuts::CurrencyUnit;
  5. use cdk::wallet::{SendOptions, Wallet};
  6. use cdk::{Amount, OidcClient};
  7. use cdk_common::amount::SplitTarget;
  8. use cdk_common::{MintInfo, ProofsMethods};
  9. use cdk_sqlite::wallet::memory;
  10. use rand::Rng;
  11. use tracing_subscriber::EnvFilter;
  12. const TEST_USERNAME: &str = "cdk-test";
  13. const TEST_PASSWORD: &str = "cdkpassword";
  14. #[tokio::main]
  15. async fn main() -> Result<(), Error> {
  16. // Set up logging
  17. let default_filter = "debug";
  18. let sqlx_filter = "sqlx=warn,hyper_util=warn,reqwest=warn,rustls=warn";
  19. let env_filter = EnvFilter::new(format!("{},{}", default_filter, sqlx_filter));
  20. tracing_subscriber::fmt().with_env_filter(env_filter).init();
  21. // Initialize the memory store for the wallet
  22. let localstore = memory::empty().await?;
  23. // Generate a random seed for the wallet
  24. let seed = rand::rng().random::<[u8; 64]>();
  25. // Define the mint URL and currency unit
  26. let mint_url = "http://127.0.0.1:8085";
  27. let unit = CurrencyUnit::Sat;
  28. let amount = Amount::from(50);
  29. // Create a new wallet
  30. let wallet = Wallet::new(mint_url, unit, Arc::new(localstore), seed, None)?;
  31. let mint_info = wallet
  32. .fetch_mint_info()
  33. .await
  34. .expect("mint info")
  35. .expect("could not get mint info");
  36. // Request a mint quote from the wallet
  37. let quote = wallet.mint_quote(amount, None).await;
  38. println!("Minting nuts ... {:?}", quote);
  39. // Getting the CAT token is not inscope of cdk and expected to be handled by the implemntor
  40. // We just use this helper fn with password auth for testing
  41. let access_token = get_access_token(&mint_info).await;
  42. wallet.set_cat(access_token).await.unwrap();
  43. wallet
  44. .mint_blind_auth(10.into())
  45. .await
  46. .expect("Could not mint blind auth");
  47. let quote = wallet.mint_quote(amount, None).await.unwrap();
  48. let proofs = wallet
  49. .wait_and_mint_quote(quote, SplitTarget::default(), None, Duration::from_secs(10))
  50. .await
  51. .unwrap();
  52. println!("Received: {}", proofs.total_amount()?);
  53. // Get the total balance of the wallet
  54. let balance = wallet.total_balance().await?;
  55. println!("Wallet balance: {}", balance);
  56. let prepared_send = wallet
  57. .prepare_send(10.into(), SendOptions::default())
  58. .await?;
  59. let token = prepared_send.confirm(None).await?;
  60. println!("Created token: {}", token);
  61. let remaining_blind_auth = wallet.get_unspent_auth_proofs().await?.len();
  62. // We started with 10 blind tokens we expect 8 ath this point
  63. // 1 is used for the mint quote + 1 used for the mint
  64. // The swap is not expected to use one as it will be offline or we have "/swap" as an unprotected endpoint in the mint config
  65. assert_eq!(remaining_blind_auth, 8);
  66. println!("Remaining blind auth: {}", remaining_blind_auth);
  67. Ok(())
  68. }
  69. async fn get_access_token(mint_info: &MintInfo) -> String {
  70. let openid_discovery = mint_info
  71. .nuts
  72. .nut21
  73. .clone()
  74. .expect("Nut21 defined")
  75. .openid_discovery;
  76. let oidc_client = OidcClient::new(openid_discovery, None);
  77. // Get the token endpoint from the OIDC configuration
  78. let token_url = oidc_client
  79. .get_oidc_config()
  80. .await
  81. .expect("Failed to get OIDC config")
  82. .token_endpoint;
  83. // Create the request parameters
  84. let params = [
  85. ("grant_type", "password"),
  86. ("client_id", "cashu-client"),
  87. ("username", TEST_USERNAME),
  88. ("password", TEST_PASSWORD),
  89. ];
  90. // Make the token request directly
  91. let client = reqwest::Client::new();
  92. let response = client
  93. .post(token_url)
  94. .form(&params)
  95. .send()
  96. .await
  97. .expect("Failed to send token request");
  98. let token_response: serde_json::Value = response
  99. .json()
  100. .await
  101. .expect("Failed to parse token response");
  102. token_response["access_token"]
  103. .as_str()
  104. .expect("No access token in response")
  105. .to_string()
  106. }