@@ -86,22 +86,25 @@ use std::{
86
86
#[ cfg( target_arch = "wasm32" ) ]
87
87
use web_time:: Instant ;
88
88
89
- // The maximum amount of operations we try to pull
90
- // from fedimint when we need to search through
91
- // their internal list.
89
+ /// The maximum amount of operations we try to pull
90
+ /// from fedimint when we need to search through
91
+ /// their internal list.
92
92
const FEDIMINT_OPERATIONS_LIST_MAX : usize = 100 ;
93
93
94
- // On chain peg in timeout
94
+ /// On chain peg in timeout
95
95
const PEG_IN_TIMEOUT_YEAR : Duration = Duration :: from_secs ( 86400 * 365 ) ;
96
96
97
+ /// For key value storage
97
98
pub const FEDIMINTS_PREFIX_KEY : & str = "fedimints/" ;
98
99
99
100
// Default signet/mainnet federation gateway info
101
+ // TODO: Remove these hardcoded gateways and use our improved gateway selection logic
100
102
const SIGNET_GATEWAY : & str = "0256f5ef1d986e9abf559651b7167de28bfd954683cd0f14703be12d1421aedc55" ;
101
103
const MAINNET_GATEWAY : & str = "025b9f090d3daab012346701f27d1c220d6d290f6b498255cddc492c255532a09d" ;
102
104
const SIGNET_FEDERATION : & str = "c8d423964c7ad944d30f57359b6e5b260e211dcfdb945140e28d4df51fd572d2" ;
103
105
const MAINNET_FEDERATION : & str = "c36038cce5a97e3467f03336fa8e7e3410960b81d1865cda2a609f70a8f51efb" ;
104
106
107
+ // Translate from Fedimint's internal status to our HTLCStatus
105
108
impl From < LnReceiveState > for HTLCStatus {
106
109
fn from ( state : LnReceiveState ) -> Self {
107
110
match state {
@@ -143,40 +146,42 @@ impl From<LnPayState> for HTLCStatus {
143
146
}
144
147
}
145
148
146
- // This is the FederationStorage object saved to the DB
149
+ /// FederationStorage object saved to the DB
147
150
#[ derive( Debug , Serialize , Deserialize , Clone , Default ) ]
148
151
pub struct FederationStorage {
149
152
pub federations : HashMap < String , FederationIndex > ,
150
153
pub version : u32 ,
151
154
}
152
155
153
- // This is the FederationIdentity that refer to a specific federation
154
- // Used for public facing identification.
156
+ /// FederationIdentity that refers to a specific federation
157
+ /// Used for public facing identification. (What the frontend needs to display a federation to the user)
158
+ /// Constructed via FederationMetaConfig -> FederationMeta -> FederationIdentity
155
159
#[ derive( Serialize , Deserialize , Clone , Eq , PartialEq ) ]
156
160
pub struct FederationIdentity {
157
161
pub uuid : String ,
158
162
pub federation_id : FederationId ,
159
163
pub invite_code : InviteCode ,
160
- // https://github.com/fedimint/fedimint/tree/master/docs/meta_fields
164
+ /// https://github.com/fedimint/fedimint/tree/master/docs/meta_fields
161
165
pub federation_name : Option < String > ,
162
166
pub federation_expiry_timestamp : Option < String > ,
163
167
pub welcome_message : Option < String > ,
164
- // undocumented parameters that fedi uses: https://meta.dev.fedibtc.com/meta.json
168
+ /// undocumented parameters that fedi uses: https://meta.dev.fedibtc.com/meta.json
165
169
pub federation_icon_url : Option < String > ,
166
170
pub meta_external_url : Option < String > ,
167
171
pub preview_message : Option < String > ,
168
172
pub popup_end_timestamp : Option < u32 > ,
169
173
pub popup_countdown_message : Option < String > ,
170
174
}
171
175
176
+ /// Fedi's federation listing format
172
177
#[ derive( Serialize , Deserialize , Debug ) ]
173
178
pub ( crate ) struct FederationMetaConfig {
174
179
#[ serde( flatten) ]
175
180
pub federations : std:: collections:: HashMap < String , FederationMeta > ,
176
181
}
177
182
178
- // This is the FederationUrlConfig that refer to a specific federation
179
- // Normal config information that might exist from their URL.
183
+ /// FederationUrlConfig that refer to a specific federation
184
+ /// Normal config information that might exist from their URL.
180
185
#[ derive( Serialize , Deserialize , Clone , Eq , PartialEq , Debug ) ]
181
186
pub struct FederationMeta {
182
187
// https://github.com/fedimint/fedimint/tree/master/docs/meta_fields
@@ -196,14 +201,6 @@ pub struct FederationMeta {
196
201
pub popup_countdown_message : Option < String > ,
197
202
}
198
203
199
- #[ derive( Default , Debug , Clone , Eq , PartialEq , Serialize , Deserialize ) ]
200
- pub struct Site {
201
- pub id : Option < String > ,
202
- pub url : Option < String > ,
203
- pub title : Option < String > ,
204
- pub image_url : Option < String > ,
205
- }
206
-
207
204
#[ derive( Debug , Serialize , Deserialize , PartialEq , Eq , Clone , Default ) ]
208
205
pub struct GatewayFees {
209
206
pub base_msat : u32 ,
@@ -229,6 +226,7 @@ pub struct FedimintBalance {
229
226
pub amount : u64 ,
230
227
}
231
228
229
+ // This is for the sake of test mocking
232
230
#[ cfg_attr( test, mockall:: automock) ]
233
231
pub trait FedimintClient {
234
232
async fn claim_external_receive (
@@ -238,6 +236,8 @@ pub trait FedimintClient {
238
236
) -> Result < ( ) , MutinyError > ;
239
237
}
240
238
239
+ /// FederationClient is Mutiny's main abstraction on top of the fedimint library
240
+ /// We use this object to pay invoices, get addresses, etc.
241
241
pub ( crate ) struct FederationClient < S : MutinyStorage > {
242
242
pub ( crate ) uuid : String ,
243
243
pub ( crate ) fedimint_client : ClientHandleArc ,
@@ -252,6 +252,8 @@ pub(crate) struct FederationClient<S: MutinyStorage> {
252
252
}
253
253
254
254
impl < S : MutinyStorage > FederationClient < S > {
255
+ /// We call this when it's the first time we're joining a federation, and also
256
+ /// when we're starting up the wallet.
255
257
#[ allow( clippy:: too_many_arguments) ]
256
258
pub ( crate ) async fn new (
257
259
uuid : String ,
@@ -285,6 +287,7 @@ impl<S: MutinyStorage> FederationClient<S> {
285
287
log_trace ! ( logger, "Building fedimint client db" ) ;
286
288
let secret = create_federation_secret ( xprivkey, network) ?;
287
289
290
+ // Handle if we've joined the federation already
288
291
let fedimint_client = if is_initialized {
289
292
client_builder
290
293
. open ( get_default_client_secret ( & secret, & federation_id) )
@@ -315,6 +318,7 @@ impl<S: MutinyStorage> FederationClient<S> {
315
318
MutinyError :: FederationConnectionFailed
316
319
} ) ?
317
320
} ;
321
+ // TODO: does this need to be an arc?
318
322
let fedimint_client = Arc :: new ( fedimint_client) ;
319
323
320
324
log_trace ! ( logger, "Retrieving fedimint wallet client module" ) ;
@@ -343,6 +347,9 @@ impl<S: MutinyStorage> FederationClient<S> {
343
347
let client_clone = fedimint_client. clone ( ) ;
344
348
let gateway_clone = gateway. clone ( ) ;
345
349
let logger_clone = logger. clone ( ) ;
350
+
351
+ // don't want to block wallet startup with these gateway updates
352
+ // so we spawn here
346
353
spawn ( async move {
347
354
let start = Instant :: now ( ) ;
348
355
// get lock immediately to block other actions until gateway is set
@@ -396,6 +403,9 @@ impl<S: MutinyStorage> FederationClient<S> {
396
403
Ok ( federation_client)
397
404
}
398
405
406
+ /// The fedimint database has its own representation of transactions, but we need to
407
+ /// track them in our own database. This checks for unprocessed transactions and
408
+ /// processes them.
399
409
pub ( crate ) async fn process_previous_operations ( & self ) -> Result < ( ) , MutinyError > {
400
410
// look for our internal state pending transactions
401
411
let mut pending_invoices: HashSet < [ u8 ; 32 ] > = HashSet :: new ( ) ;
@@ -470,6 +480,7 @@ impl<S: MutinyStorage> FederationClient<S> {
470
480
Ok ( ( ) )
471
481
}
472
482
483
+ /// Subscribe to status of actions like invoice creation, pay invoice, on-chain address creation, etc.
473
484
fn subscribe_operation ( & self , entry : OperationLogEntry , operation_id : OperationId ) {
474
485
subscribe_operation_ext (
475
486
entry,
@@ -482,11 +493,15 @@ impl<S: MutinyStorage> FederationClient<S> {
482
493
) ;
483
494
}
484
495
496
+ /// Get the current gateway fees
485
497
pub ( crate ) async fn gateway_fee ( & self ) -> Result < GatewayFees , MutinyError > {
486
498
let gateway = self . gateway . read ( ) . await ;
487
499
Ok ( gateway. as_ref ( ) . map ( |x| x. fees . into ( ) ) . unwrap_or_default ( ) )
488
500
}
489
501
502
+ /// Create a new lightning invoice
503
+ /// Important limitation: if the FedimintClient hasn't updated the lightning gateways yet, this will
504
+ /// create an invoice that can only be paid inside to the federation.
490
505
pub ( crate ) async fn get_invoice (
491
506
& self ,
492
507
amount : u64 ,
@@ -560,6 +575,7 @@ impl<S: MutinyStorage> FederationClient<S> {
560
575
Ok ( invoice. into ( ) )
561
576
}
562
577
578
+ /// Get a new on-chain address
563
579
pub ( crate ) async fn get_new_address (
564
580
& self ,
565
581
labels : Vec < String > ,
@@ -619,6 +635,8 @@ impl<S: MutinyStorage> FederationClient<S> {
619
635
)
620
636
}
621
637
638
+ /// Pay a lightning invoice
639
+ /// Important limitation: same as get_invoice
622
640
pub ( crate ) async fn pay_invoice (
623
641
& self ,
624
642
invoice : Bolt11Invoice ,
@@ -802,6 +820,7 @@ impl<S: MutinyStorage> FederationClient<S> {
802
820
Err ( MutinyError :: PaymentTimeout )
803
821
}
804
822
823
+ /// Ask the federation for the on chain fee estimate
805
824
pub async fn estimate_tx_fee (
806
825
& self ,
807
826
destination_address : bitcoin:: Address ,
@@ -822,6 +841,7 @@ impl<S: MutinyStorage> FederationClient<S> {
822
841
}
823
842
824
843
/// Someone received a payment on our behalf, we need to claim it
844
+ /// This is used for claiming Hermes lightning address payments
825
845
pub async fn claim_external_receive (
826
846
& self ,
827
847
secret_key : & SecretKey ,
@@ -871,6 +891,7 @@ impl<S: MutinyStorage> FederationClient<S> {
871
891
Ok ( ( ) )
872
892
}
873
893
894
+ /// Get the federation info for displaying to the user
874
895
pub async fn get_mutiny_federation_identity ( & self ) -> FederationIdentity {
875
896
get_federation_identity (
876
897
self . uuid . clone ( ) ,
@@ -881,7 +902,7 @@ impl<S: MutinyStorage> FederationClient<S> {
881
902
. await
882
903
}
883
904
884
- // delete_fedimint_storage is not suggested at the moment due to the lack of easy restores
905
+ /// WARNING delete_fedimint_storage is not suggested at the moment due to the lack of easy restores
885
906
#[ allow( dead_code) ]
886
907
pub async fn delete_fedimint_storage ( & self ) -> Result < ( ) , MutinyError > {
887
908
self . fedimint_storage . delete_store ( ) . await
0 commit comments