123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- use std::str::FromStr;
- use anyhow::Result;
- use cdk::nuts::{Conditions, CurrencyUnit, PublicKey, SpendingConditions};
- use cdk::wallet::types::SendKind;
- use cdk::wallet::{MultiMintWallet, SendMemo, SendOptions};
- use cdk::Amount;
- use clap::Args;
- use crate::sub_commands::balance::mint_balances;
- use crate::utils::{check_sufficient_funds, get_number_input, get_wallet_by_index};
- #[derive(Args)]
- pub struct SendSubCommand {
- /// Token Memo
- #[arg(short, long)]
- memo: Option<String>,
- /// Preimage
- #[arg(long)]
- preimage: Option<String>,
- /// Required number of signatures
- #[arg(long)]
- required_sigs: Option<u64>,
- /// Locktime before refund keys can be used
- #[arg(short, long)]
- locktime: Option<u64>,
- /// Pubkey to lock proofs to
- #[arg(short, long, action = clap::ArgAction::Append)]
- pubkey: Vec<String>,
- /// Refund keys that can be used after locktime
- #[arg(long, action = clap::ArgAction::Append)]
- refund_keys: Vec<String>,
- /// Token as V3 token
- #[arg(short, long)]
- v3: bool,
- /// Should the send be offline only
- #[arg(short, long)]
- offline: bool,
- /// Include fee to redeem in token
- #[arg(short, long)]
- include_fee: bool,
- /// Amount willing to overpay to avoid a swap
- #[arg(short, long)]
- tolerance: Option<u64>,
- /// Currency unit e.g. sat
- #[arg(default_value = "sat")]
- unit: String,
- }
- pub async fn send(
- multi_mint_wallet: &MultiMintWallet,
- sub_command_args: &SendSubCommand,
- ) -> Result<()> {
- let unit = CurrencyUnit::from_str(&sub_command_args.unit)?;
- let mints_amounts = mint_balances(multi_mint_wallet, &unit).await?;
- let mint_number: usize = get_number_input("Enter mint number to create token")?;
- let wallet = get_wallet_by_index(multi_mint_wallet, &mints_amounts, mint_number, unit).await?;
- let token_amount = Amount::from(get_number_input::<u64>("Enter value of token in sats")?);
- check_sufficient_funds(mints_amounts[mint_number].1, token_amount)?;
- let conditions = match &sub_command_args.preimage {
- Some(preimage) => {
- let pubkeys = match sub_command_args.pubkey.is_empty() {
- true => None,
- false => Some(
- sub_command_args
- .pubkey
- .iter()
- .map(|p| PublicKey::from_str(p).unwrap())
- .collect(),
- ),
- };
- let refund_keys = match sub_command_args.refund_keys.is_empty() {
- true => None,
- false => Some(
- sub_command_args
- .refund_keys
- .iter()
- .map(|p| PublicKey::from_str(p).unwrap())
- .collect(),
- ),
- };
- let conditions = Conditions::new(
- sub_command_args.locktime,
- pubkeys,
- refund_keys,
- sub_command_args.required_sigs,
- None,
- )
- .unwrap();
- Some(SpendingConditions::new_htlc(
- preimage.clone(),
- Some(conditions),
- )?)
- }
- None => match sub_command_args.pubkey.is_empty() {
- true => None,
- false => {
- let pubkeys: Vec<PublicKey> = sub_command_args
- .pubkey
- .iter()
- .map(|p| PublicKey::from_str(p).unwrap())
- .collect();
- let refund_keys: Vec<PublicKey> = sub_command_args
- .refund_keys
- .iter()
- .map(|p| PublicKey::from_str(p).unwrap())
- .collect();
- let refund_keys = (!refund_keys.is_empty()).then_some(refund_keys);
- let data_pubkey = pubkeys[0];
- let pubkeys = pubkeys[1..].to_vec();
- let pubkeys = (!pubkeys.is_empty()).then_some(pubkeys);
- let conditions = Conditions::new(
- sub_command_args.locktime,
- pubkeys,
- refund_keys,
- sub_command_args.required_sigs,
- None,
- )
- .unwrap();
- Some(SpendingConditions::P2PKConditions {
- data: data_pubkey,
- conditions: Some(conditions),
- })
- }
- },
- };
- let send_kind = match (sub_command_args.offline, sub_command_args.tolerance) {
- (true, Some(amount)) => SendKind::OfflineTolerance(Amount::from(amount)),
- (true, None) => SendKind::OfflineExact,
- (false, Some(amount)) => SendKind::OnlineTolerance(Amount::from(amount)),
- (false, None) => SendKind::OnlineExact,
- };
- let prepared_send = wallet
- .prepare_send(
- token_amount,
- SendOptions {
- memo: sub_command_args.memo.clone().map(|memo| SendMemo {
- memo,
- include_memo: true,
- }),
- send_kind,
- include_fee: sub_command_args.include_fee,
- conditions,
- ..Default::default()
- },
- )
- .await?;
- let token = wallet.send(prepared_send, None).await?;
- match sub_command_args.v3 {
- true => {
- let token = token;
- println!("{}", token.to_v3_string());
- }
- false => {
- println!("{}", token);
- }
- }
- Ok(())
- }
|