@@ -4,7 +4,7 @@ use crate::db::{
4
4
latest_new_state_v5,
5
5
} ,
6
6
get_channel_by_id, insert_channel, insert_validator_messages, list_channels,
7
- spendable:: { fetch_spendable, update_spendable} ,
7
+ spendable:: { fetch_spendable, get_all_spendables_for_channel , update_spendable} ,
8
8
DbPool , PoolError ,
9
9
} ;
10
10
use crate :: { success_response, Application , Auth , ResponseError , RouteParams } ;
@@ -13,18 +13,19 @@ use hex::FromHex;
13
13
use hyper:: { Body , Request , Response } ;
14
14
use primitives:: {
15
15
adapter:: Adapter ,
16
- balances:: UncheckedState ,
16
+ balances:: { CheckedState , UncheckedState } ,
17
17
channel_v5:: Channel as ChannelV5 ,
18
18
config:: TokenInfo ,
19
19
sentry:: {
20
20
channel_list:: { ChannelListQuery , LastApprovedQuery } ,
21
- LastApproved , LastApprovedResponse , SpenderResponse , SuccessResponse ,
21
+ AllSpendersResponse , LastApproved , LastApprovedResponse , Pagination , SpenderResponse ,
22
+ SuccessResponse ,
22
23
} ,
23
24
spender:: { Deposit , Spendable , Spender , SpenderLeaf } ,
24
- validator:: MessageTypes ,
25
+ validator:: { MessageTypes , NewState } ,
25
26
Address , Channel , ChannelId , UnifiedNum ,
26
27
} ;
27
- use slog:: error;
28
+ use slog:: { error, Logger } ;
28
29
use std:: { collections:: HashMap , str:: FromStr } ;
29
30
use tokio_postgres:: error:: SqlState ;
30
31
@@ -287,10 +288,10 @@ pub async fn get_spender_limits<A: Adapter + 'static>(
287
288
. expect ( "Request should have Channel" )
288
289
. to_owned ( ) ;
289
290
290
- let channel_id = channel. id ( ) ;
291
291
let spender = Address :: from_str ( & route_params. index ( 1 ) ) ?;
292
292
293
- let latest_spendable = fetch_spendable ( app. pool . clone ( ) , & spender, & channel_id) . await ?;
293
+ let latest_spendable = fetch_spendable ( app. pool . clone ( ) , & spender, & channel. id ( ) ) . await ?;
294
+
294
295
let token_info = app
295
296
. config
296
297
. token_address_whitelist
@@ -311,21 +312,12 @@ pub async fn get_spender_limits<A: Adapter + 'static>(
311
312
}
312
313
} ;
313
314
314
- let approve_state = match latest_approve_state_v5 ( & app. pool , & channel) . await ? {
315
- Some ( approve_state) => approve_state,
316
- None => return spender_response_without_leaf ( latest_spendable. deposit . total ) ,
317
- } ;
318
-
319
- let state_root = approve_state. msg . state_root . clone ( ) ;
320
-
321
- let new_state = match latest_new_state_v5 ( & app. pool , & channel, & state_root) . await ? {
315
+ let new_state = match get_corresponding_new_state ( & app. pool , & app. logger , & channel) . await ? {
322
316
Some ( new_state) => new_state,
323
317
None => return spender_response_without_leaf ( latest_spendable. deposit . total ) ,
324
318
} ;
325
319
326
- let new_state_checked = new_state. msg . into_inner ( ) . try_checked ( ) ?;
327
-
328
- let total_spent = new_state_checked. balances . spenders . get ( & spender) ;
320
+ let total_spent = new_state. balances . spenders . get ( & spender) ;
329
321
330
322
let spender_leaf = total_spent. map ( |total_spent| SpenderLeaf {
331
323
total_spent : * total_spent,
@@ -342,6 +334,91 @@ pub async fn get_spender_limits<A: Adapter + 'static>(
342
334
Ok ( success_response ( serde_json:: to_string ( & res) ?) )
343
335
}
344
336
337
+ pub async fn get_all_spender_limits < A : Adapter + ' static > (
338
+ req : Request < Body > ,
339
+ app : & Application < A > ,
340
+ ) -> Result < Response < Body > , ResponseError > {
341
+ let channel = req
342
+ . extensions ( )
343
+ . get :: < ChannelV5 > ( )
344
+ . expect ( "Request should have Channel" )
345
+ . to_owned ( ) ;
346
+
347
+ let new_state = get_corresponding_new_state ( & app. pool , & app. logger , & channel) . await ?;
348
+
349
+ let mut all_spender_limits: HashMap < Address , Spender > = HashMap :: new ( ) ;
350
+
351
+ let all_spendables = get_all_spendables_for_channel ( app. pool . clone ( ) , & channel. id ( ) ) . await ?;
352
+
353
+ // Using for loop to avoid async closures
354
+ for spendable in all_spendables {
355
+ let spender = spendable. spender ;
356
+ let spender_leaf = match new_state {
357
+ Some ( ref new_state) => new_state. balances . spenders . get ( & spender) . map ( |balance| {
358
+ SpenderLeaf {
359
+ total_spent : spendable
360
+ . deposit
361
+ . total
362
+ . checked_sub ( balance)
363
+ . unwrap_or_default ( ) ,
364
+ // merkle_proof: [u8; 32], // TODO
365
+ }
366
+ } ) ,
367
+ None => None ,
368
+ } ;
369
+
370
+ let spender_info = Spender {
371
+ total_deposited : spendable. deposit . total ,
372
+ spender_leaf,
373
+ } ;
374
+
375
+ all_spender_limits. insert ( spender, spender_info) ;
376
+ }
377
+
378
+ let res = AllSpendersResponse {
379
+ spenders : all_spender_limits,
380
+ pagination : Pagination {
381
+ // TODO
382
+ page : 1 ,
383
+ total : 1 ,
384
+ total_pages : 1 ,
385
+ } ,
386
+ } ;
387
+
388
+ Ok ( success_response ( serde_json:: to_string ( & res) ?) )
389
+ }
390
+
391
+ async fn get_corresponding_new_state (
392
+ pool : & DbPool ,
393
+ logger : & Logger ,
394
+ channel : & ChannelV5 ,
395
+ ) -> Result < Option < NewState < CheckedState > > , ResponseError > {
396
+ let approve_state = match latest_approve_state_v5 ( pool, channel) . await ? {
397
+ Some ( approve_state) => approve_state,
398
+ None => return Ok ( None ) ,
399
+ } ;
400
+
401
+ let state_root = approve_state. msg . state_root . clone ( ) ;
402
+
403
+ let new_state = match latest_new_state_v5 ( pool, channel, & state_root) . await ? {
404
+ Some ( new_state) => {
405
+ let new_state = new_state. msg . into_inner ( ) . try_checked ( ) . map_err ( |err| {
406
+ error ! ( & logger, "Balances are not aligned in an approved NewState: {}" , & err; "module" => "get_spender_limits" ) ;
407
+ ResponseError :: BadRequest ( "Balances are not aligned in an approved NewState" . to_string ( ) )
408
+ } ) ?;
409
+ Ok ( Some ( new_state) )
410
+ }
411
+ None => {
412
+ error ! ( & logger, "{}" , "Fatal error! The NewState for the last ApproveState was not found" ; "module" => "get_spender_limits" ) ;
413
+ return Err ( ResponseError :: BadRequest (
414
+ "Fatal error! The NewState for the last ApproveState was not found" . to_string ( ) ,
415
+ ) ) ;
416
+ }
417
+ } ;
418
+
419
+ new_state
420
+ }
421
+
345
422
#[ cfg( test) ]
346
423
mod test {
347
424
use super :: * ;
0 commit comments