1
+ use std:: collections:: HashMap ;
2
+
1
3
use near_sdk:: { env, ext_contract, is_promise_success, 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 :: {
10
9
common:: Timestamp ,
11
10
event:: { emit, ClaimEventItem , EventKind } ,
12
11
jar:: model:: Jar ,
13
- Contract , ContractExt , JarsStorage ,
12
+ Contract , ContractExt , JarsStorage , Product ,
14
13
} ;
15
14
16
15
#[ ext_contract( ext_self) ]
@@ -29,52 +28,61 @@ impl ClaimApi for Contract {
29
28
fn claim_total ( & mut self , detailed : Option < bool > ) -> PromiseOrValue < ClaimedAmountView > {
30
29
let account_id = env:: predecessor_account_id ( ) ;
31
30
self . migrate_account_jars_if_needed ( account_id. clone ( ) ) ;
32
- let jar_ids = self . account_jars ( & account_id) . iter ( ) . map ( |a| U32 ( a. id ) ) . collect ( ) ;
33
- self . claim_jars_internal ( account_id, jar_ids, detailed)
31
+ self . claim_jars_internal ( account_id, detailed)
34
32
}
35
33
}
36
34
37
35
impl Contract {
38
36
fn claim_jars_internal (
39
37
& mut self ,
40
38
account_id : AccountId ,
41
- jar_ids : Vec < JarIdView > ,
42
39
detailed : Option < bool > ,
43
40
) -> PromiseOrValue < ClaimedAmountView > {
44
41
let now = env:: block_timestamp_ms ( ) ;
45
42
let mut accumulator = ClaimedAmountView :: new ( detailed) ;
46
43
47
- let unlocked_jars: Vec < Jar > = self
48
- . account_jars ( & account_id)
44
+ let account_jars = self . account_jars ( & account_id) ;
45
+
46
+ // UnorderedMap doesn't have cache and deserializes `Product` on each get
47
+ // This cache significantly reduces gas usage
48
+ let mut products_cache: HashMap < ProductId , Product > = HashMap :: new ( ) ;
49
+
50
+ let mut unlocked_jars: Vec < ( ( TokenAmount , u64 ) , & Jar ) > = account_jars
49
51
. iter ( )
50
- . filter ( |jar| !jar. is_pending_withdraw && jar_ids. contains ( & U32 ( jar. id ) ) )
51
- . cloned ( )
52
+ . filter ( |jar| !jar. is_pending_withdraw )
53
+ . map ( |jar| {
54
+ let product = products_cache
55
+ . entry ( jar. product_id . clone ( ) )
56
+ . or_insert_with ( || self . get_product ( & jar. product_id ) ) ;
57
+ ( jar. get_interest ( product, now) , jar)
58
+ } )
52
59
. collect ( ) ;
53
60
54
- let mut event_data: Vec < ClaimEventItem > = vec ! [ ] ;
61
+ unlocked_jars. sort_by ( |a, b| b. 0 . 0 . cmp ( & a. 0 . 0 ) ) ;
62
+
63
+ let jars_to_claim: Vec < _ > = unlocked_jars. into_iter ( ) . take ( 100 ) . collect ( ) ;
55
64
56
- for jar in & unlocked_jars {
57
- let product = self . get_product ( & jar. product_id ) ;
58
- let ( available_interest, remainder) = jar. get_interest ( & product, now) ;
65
+ let mut event_data: Vec < ClaimEventItem > = vec ! [ ] ;
59
66
60
- if available_interest > 0 {
67
+ for ( ( available_interest, remainder) , jar) in & jars_to_claim {
68
+ if * available_interest > 0 {
61
69
let jar = self . get_jar_mut_internal ( & jar. account_id , jar. id ) ;
62
70
63
- jar. claim_remainder = remainder;
71
+ jar. claim_remainder = * remainder;
64
72
65
- jar. claim ( available_interest, available_interest, now) . lock ( ) ;
73
+ jar. claim ( * available_interest, * available_interest, now) . lock ( ) ;
66
74
67
- accumulator. add ( jar. id , available_interest) ;
75
+ accumulator. add ( jar. id , * available_interest) ;
68
76
69
- event_data. push ( ( jar. id , U128 ( available_interest) ) ) ;
77
+ event_data. push ( ( jar. id , U128 ( * available_interest) ) ) ;
70
78
}
71
79
}
72
80
73
81
if accumulator. get_total ( ) . 0 > 0 {
74
82
self . claim_interest (
75
83
& account_id,
76
84
accumulator,
77
- unlocked_jars ,
85
+ jars_to_claim . into_iter ( ) . map ( |a| a . 1 ) . cloned ( ) . collect ( ) ,
78
86
EventKind :: Claim ( event_data) ,
79
87
now,
80
88
)
0 commit comments