1
+ use std:: collections:: HashMap ;
2
+
1
3
use near_sdk:: { env, ext_contract, json_types:: U128 , near_bindgen, AccountId , PromiseOrValue } ;
2
4
use sweat_jar_model:: {
3
- api:: ClaimApi ,
4
- claimed_amount_view:: ClaimedAmountView ,
5
- jar:: { AggregatedTokenAmountView , JarIdView } ,
6
- U32 ,
5
+ api:: ClaimApi , claimed_amount_view:: ClaimedAmountView , jar:: AggregatedTokenAmountView , ProductId , TokenAmount ,
7
6
} ;
8
7
9
8
use crate :: {
@@ -12,7 +11,7 @@ use crate::{
12
11
internal:: is_promise_success,
13
12
jar:: model:: Jar ,
14
13
score:: AccountScore ,
15
- Contract , ContractExt , JarsStorage ,
14
+ Contract , ContractExt , JarsStorage , Product ,
16
15
} ;
17
16
18
17
#[ allow( dead_code) ] // False positive since rust 1.78. It is used from `ext_contract` macro.
@@ -33,58 +32,67 @@ impl ClaimApi for Contract {
33
32
fn claim_total ( & mut self , detailed : Option < bool > ) -> PromiseOrValue < ClaimedAmountView > {
34
33
let account_id = env:: predecessor_account_id ( ) ;
35
34
self . migrate_account_if_needed ( & account_id) ;
36
- let jar_ids = self . account_jars ( & account_id) . iter ( ) . map ( |a| U32 ( a. id ) ) . collect ( ) ;
37
- self . claim_jars_internal ( account_id, jar_ids, detailed)
35
+ self . claim_jars_internal ( account_id, detailed)
38
36
}
39
37
}
40
38
41
39
impl Contract {
42
40
fn claim_jars_internal (
43
41
& mut self ,
44
42
account_id : AccountId ,
45
- jar_ids : Vec < JarIdView > ,
46
43
detailed : Option < bool > ,
47
44
) -> PromiseOrValue < ClaimedAmountView > {
48
45
let now = env:: block_timestamp_ms ( ) ;
49
46
let mut accumulator = ClaimedAmountView :: new ( detailed) ;
50
47
51
- let unlocked_jars: Vec < Jar > = self
52
- . account_jars ( & account_id)
53
- . iter ( )
54
- . filter ( |jar| !jar. is_pending_withdraw && jar_ids. contains ( & U32 ( jar. id ) ) )
55
- . cloned ( )
56
- . collect ( ) ;
48
+ let account_jars = self . account_jars ( & account_id) ;
57
49
58
- let mut event_data: Vec < ClaimEventItem > = vec ! [ ] ;
50
+ // UnorderedMap doesn't have cache and deserializes `Product` on each get
51
+ // This cache significantly reduces gas usage
52
+ let mut products_cache: HashMap < ProductId , Product > = HashMap :: new ( ) ;
59
53
60
54
let account_score = self . get_score_mut ( & account_id) ;
61
55
62
56
let account_score_before_transfer = account_score. as_ref ( ) . map ( |s| * * s) ;
63
57
64
58
let score = account_score. map ( AccountScore :: claim_score) . unwrap_or_default ( ) ;
65
59
66
- for jar in & unlocked_jars {
67
- let product = self . get_product ( & jar. product_id ) ;
68
- let ( interest, remainder) = jar. get_interest ( & score, & product, now) ;
60
+ let mut unlocked_jars: Vec < ( ( TokenAmount , u64 ) , & Jar ) > = account_jars
61
+ . iter ( )
62
+ . filter ( |jar| !jar. is_pending_withdraw )
63
+ . map ( |jar| {
64
+ let product = products_cache
65
+ . entry ( jar. product_id . clone ( ) )
66
+ . or_insert_with ( || self . get_product ( & jar. product_id ) ) ;
67
+ ( jar. get_interest ( & score, product, now) , jar)
68
+ } )
69
+ . collect ( ) ;
70
+
71
+ unlocked_jars. sort_by ( |a, b| b. 0 . 0 . cmp ( & a. 0 . 0 ) ) ;
72
+
73
+ let jars_to_claim: Vec < _ > = unlocked_jars. into_iter ( ) . take ( 100 ) . collect ( ) ;
74
+
75
+ let mut event_data: Vec < ClaimEventItem > = vec ! [ ] ;
69
76
70
- if interest > 0 {
77
+ for ( ( available_interest, remainder) , jar) in & jars_to_claim {
78
+ if * available_interest > 0 {
71
79
let jar = self . get_jar_mut_internal ( & jar. account_id , jar. id ) ;
72
80
73
- jar. claim_remainder = remainder;
81
+ jar. claim_remainder = * remainder;
74
82
75
- jar. claim ( interest , now) . lock ( ) ;
83
+ jar. claim ( * available_interest , now) . lock ( ) ;
76
84
77
- accumulator. add ( jar. id , interest ) ;
85
+ accumulator. add ( jar. id , * available_interest ) ;
78
86
79
- event_data. push ( ( jar. id , U128 ( interest ) ) ) ;
87
+ event_data. push ( ( jar. id , U128 ( * available_interest ) ) ) ;
80
88
}
81
89
}
82
90
83
91
if accumulator. get_total ( ) . 0 > 0 {
84
92
self . claim_interest (
85
93
& account_id,
86
94
accumulator,
87
- unlocked_jars ,
95
+ jars_to_claim . into_iter ( ) . map ( |a| a . 1 ) . cloned ( ) . collect ( ) ,
88
96
account_score_before_transfer,
89
97
EventKind :: Claim ( event_data) ,
90
98
now,
0 commit comments