Skip to main content

gateway_cli/
ecash_commands.rs

1use bitcoin::Address;
2use bitcoin::address::NetworkUnchecked;
3use clap::Subcommand;
4use fedimint_core::config::FederationId;
5use fedimint_core::util::SafeUrl;
6use fedimint_core::{Amount, BitcoinAmountOrAll};
7use fedimint_gateway_client::{
8    backup, get_deposit_address, pegin_from_onchain, receive_ecash, recheck_address, spend_ecash,
9    withdraw, withdraw_to_onchain,
10};
11use fedimint_gateway_common::{
12    BackupPayload, DepositAddressPayload, DepositAddressRecheckPayload, PeginFromOnchainPayload,
13    ReceiveEcashPayload, SpendEcashPayload, WithdrawPayload, WithdrawToOnchainPayload,
14};
15use fedimint_ln_common::client::GatewayApi;
16
17use crate::{CliOutput, CliOutputResult};
18
19/// Ecash management commands for pegging funds into a federation, pegging funds
20/// out of a federation, or spending/receiving ecash.
21#[derive(Subcommand)]
22pub enum EcashCommands {
23    /// Make a backup of snapshot of all e-cash.
24    Backup {
25        #[clap(long)]
26        federation_id: FederationId,
27    },
28    /// Generate a new peg-in address to a federation that the gateway can claim
29    /// e-cash for later.
30    Pegin {
31        #[clap(long)]
32        federation_id: FederationId,
33    },
34    /// Trigger a recheck for deposits on a deposit address
35    PeginRecheck {
36        #[clap(long)]
37        address: bitcoin::Address<NetworkUnchecked>,
38        #[clap(long)]
39        federation_id: FederationId,
40    },
41    /// Send funds from the gateway's onchain wallet to the federation's ecash
42    /// wallet
43    PeginFromOnchain {
44        #[clap(long)]
45        federation_id: FederationId,
46        /// The amount to pegin
47        #[clap(long)]
48        amount: BitcoinAmountOrAll,
49        /// The fee rate to use in satoshis per vbyte.
50        #[clap(long)]
51        fee_rate_sats_per_vbyte: u64,
52    },
53    /// Claim funds from a gateway federation to an on-chain address.
54    Pegout {
55        #[clap(long)]
56        federation_id: FederationId,
57        /// The amount to withdraw
58        #[clap(long)]
59        amount: BitcoinAmountOrAll,
60        /// The address to send the funds to
61        #[clap(long)]
62        address: Address<NetworkUnchecked>,
63    },
64    /// Claim funds from a gateway federation to the gateway's onchain wallet
65    PegoutToOnchain {
66        #[clap(long)]
67        federation_id: FederationId,
68        /// The amount to withdraw
69        #[clap(long)]
70        amount: BitcoinAmountOrAll,
71    },
72    /// Send e-cash out of band
73    Send {
74        #[clap(long)]
75        federation_id: FederationId,
76        amount: Amount,
77    },
78    /// Receive e-cash out of band
79    Receive {
80        /// E-cash notes (`OOBNotes` for v1 or `ECash` for v2)
81        #[clap(long)]
82        notes: String,
83        #[arg(long = "no-wait", action = clap::ArgAction::SetFalse)]
84        wait: bool,
85    },
86}
87
88impl EcashCommands {
89    pub async fn handle(self, client: &GatewayApi, base_url: &SafeUrl) -> CliOutputResult {
90        match self {
91            Self::Backup { federation_id } => {
92                backup(client, base_url, BackupPayload { federation_id }).await?;
93                Ok(CliOutput::Empty)
94            }
95            Self::Pegin { federation_id } => {
96                let address =
97                    get_deposit_address(client, base_url, DepositAddressPayload { federation_id })
98                        .await?;
99
100                Ok(CliOutput::DepositAddress { address })
101            }
102            Self::PeginRecheck {
103                address,
104                federation_id,
105            } => {
106                let response = recheck_address(
107                    client,
108                    base_url,
109                    DepositAddressRecheckPayload {
110                        address,
111                        federation_id,
112                    },
113                )
114                .await?;
115                Ok(CliOutput::DepositRecheck(response))
116            }
117            Self::PeginFromOnchain {
118                federation_id,
119                amount,
120                fee_rate_sats_per_vbyte,
121            } => {
122                let txid = pegin_from_onchain(
123                    client,
124                    base_url,
125                    PeginFromOnchainPayload {
126                        federation_id,
127                        amount,
128                        fee_rate_sats_per_vbyte,
129                    },
130                )
131                .await?;
132
133                Ok(CliOutput::PeginTxid { txid })
134            }
135            Self::Pegout {
136                federation_id,
137                amount,
138                address,
139            } => {
140                let response = withdraw(
141                    client,
142                    base_url,
143                    WithdrawPayload {
144                        federation_id,
145                        amount,
146                        address,
147                        quoted_fees: None,
148                    },
149                )
150                .await?;
151
152                Ok(CliOutput::Withdraw(response))
153            }
154            Self::PegoutToOnchain {
155                federation_id,
156                amount,
157            } => {
158                let response = withdraw_to_onchain(
159                    client,
160                    base_url,
161                    WithdrawToOnchainPayload {
162                        federation_id,
163                        amount,
164                    },
165                )
166                .await?;
167
168                Ok(CliOutput::Withdraw(response))
169            }
170            Self::Send {
171                federation_id,
172                amount,
173            } => {
174                let response = spend_ecash(
175                    client,
176                    base_url,
177                    SpendEcashPayload {
178                        federation_id,
179                        amount,
180                    },
181                )
182                .await?;
183
184                Ok(CliOutput::SpendEcash(response))
185            }
186            Self::Receive { notes, wait } => {
187                let response =
188                    receive_ecash(client, base_url, ReceiveEcashPayload { notes, wait }).await?;
189                Ok(CliOutput::ReceiveEcash(response))
190            }
191        }
192    }
193}