send.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. use std::io::Write;
  2. use std::str::FromStr;
  3. use std::{io, println};
  4. use anyhow::{bail, Result};
  5. use cdk::amount::SplitTarget;
  6. use cdk::nuts::{Conditions, CurrencyUnit, PublicKey, SpendingConditions};
  7. use cdk::wallet::Wallet;
  8. use cdk::Amount;
  9. use clap::Args;
  10. use crate::sub_commands::balance::mint_balances;
  11. #[derive(Args)]
  12. pub struct SendSubCommand {
  13. /// Token Memo
  14. #[arg(short, long)]
  15. memo: Option<String>,
  16. /// Preimage
  17. #[arg(long)]
  18. preimage: Option<String>,
  19. /// Required number of signatures
  20. #[arg(long)]
  21. required_sigs: Option<u64>,
  22. /// Locktime before refund keys can be used
  23. #[arg(short, long)]
  24. locktime: Option<u64>,
  25. /// Publey to lock proofs to
  26. #[arg(short, long, action = clap::ArgAction::Append)]
  27. pubkey: Vec<String>,
  28. /// Publey to lock proofs to
  29. #[arg(long, action = clap::ArgAction::Append)]
  30. refund_keys: Vec<String>,
  31. }
  32. pub async fn send(wallet: Wallet, sub_command_args: &SendSubCommand) -> Result<()> {
  33. let mints_amounts = mint_balances(&wallet).await?;
  34. println!("Enter mint number to create token");
  35. let mut user_input = String::new();
  36. let stdin = io::stdin();
  37. io::stdout().flush().unwrap();
  38. stdin.read_line(&mut user_input)?;
  39. let mint_number: usize = user_input.trim().parse()?;
  40. if mint_number.gt(&(mints_amounts.len() - 1)) {
  41. bail!("Invalid mint number");
  42. }
  43. let mint_url = mints_amounts[mint_number].0.clone();
  44. println!("Enter value of token in sats");
  45. let mut user_input = String::new();
  46. let stdin = io::stdin();
  47. io::stdout().flush().unwrap();
  48. stdin.read_line(&mut user_input)?;
  49. let token_amount = Amount::from(user_input.trim().parse::<u64>()?);
  50. if token_amount.gt(mints_amounts[mint_number]
  51. .1
  52. .get(&CurrencyUnit::Sat)
  53. .unwrap())
  54. {
  55. bail!("Not enough funds");
  56. }
  57. let conditions = match &sub_command_args.preimage {
  58. Some(preimage) => {
  59. let pubkeys = match sub_command_args.pubkey.is_empty() {
  60. true => None,
  61. false => Some(
  62. sub_command_args
  63. .pubkey
  64. .iter()
  65. .map(|p| PublicKey::from_str(p).unwrap())
  66. .collect(),
  67. ),
  68. };
  69. let refund_keys = match sub_command_args.refund_keys.is_empty() {
  70. true => None,
  71. false => Some(
  72. sub_command_args
  73. .refund_keys
  74. .iter()
  75. .map(|p| PublicKey::from_str(p).unwrap())
  76. .collect(),
  77. ),
  78. };
  79. let conditions = Conditions::new(
  80. sub_command_args.locktime,
  81. pubkeys,
  82. refund_keys,
  83. sub_command_args.required_sigs,
  84. None,
  85. )
  86. .unwrap();
  87. Some(SpendingConditions::new_htlc(
  88. preimage.clone(),
  89. Some(conditions),
  90. )?)
  91. }
  92. None => match sub_command_args.pubkey.is_empty() {
  93. true => None,
  94. false => {
  95. let pubkeys: Vec<PublicKey> = sub_command_args
  96. .pubkey
  97. .iter()
  98. .map(|p| PublicKey::from_str(p).unwrap())
  99. .collect();
  100. let refund_keys: Vec<PublicKey> = sub_command_args
  101. .refund_keys
  102. .iter()
  103. .map(|p| PublicKey::from_str(p).unwrap())
  104. .collect();
  105. let refund_keys = (!refund_keys.is_empty()).then_some(refund_keys);
  106. let data_pubkey = pubkeys[0];
  107. let pubkeys = pubkeys[1..].to_vec();
  108. let pubkeys = (!pubkeys.is_empty()).then_some(pubkeys);
  109. let conditions = Conditions::new(
  110. sub_command_args.locktime,
  111. pubkeys,
  112. refund_keys,
  113. sub_command_args.required_sigs,
  114. None,
  115. )
  116. .unwrap();
  117. tracing::debug!("{}", data_pubkey.to_string());
  118. Some(SpendingConditions::P2PKConditions {
  119. data: data_pubkey,
  120. conditions: Some(conditions),
  121. })
  122. }
  123. },
  124. };
  125. let token = wallet
  126. .send(
  127. &mint_url,
  128. CurrencyUnit::Sat,
  129. token_amount,
  130. sub_command_args.memo.clone(),
  131. conditions,
  132. &SplitTarget::default(),
  133. )
  134. .await?;
  135. println!("{}", token);
  136. Ok(())
  137. }