1616
1717#[ cfg( test) ]
1818use std:: collections:: btree_map;
19+ use std:: collections:: btree_map:: Entry ;
1920use std:: collections:: { btree_set, BTreeMap , BTreeSet } ;
2021use std:: mem;
2122
@@ -174,6 +175,25 @@ impl<'a> Delegation<'a> {
174175 Ok ( ( ) )
175176 }
176177
178+ pub fn subtract_quantity ( & mut self , delegatee : Address , quantity : StakeQuantity ) -> StateResult < ( ) > {
179+ if quantity == 0 {
180+ return Ok ( ( ) )
181+ }
182+
183+ if let Entry :: Occupied ( mut entry) = self . delegatees . entry ( delegatee) {
184+ if * entry. get ( ) > quantity {
185+ * entry. get_mut ( ) -= quantity;
186+ return Ok ( ( ) )
187+ } else if * entry. get ( ) == quantity {
188+ entry. remove ( ) ;
189+ return Ok ( ( ) )
190+ }
191+ }
192+
193+ Err ( RuntimeError :: FailedToHandleCustomAction ( "Cannot subtract more than that is delegated to" . to_string ( ) )
194+ . into ( ) )
195+ }
196+
177197 #[ cfg( test) ]
178198 pub fn get_quantity ( & self , delegatee : & Address ) -> StakeQuantity {
179199 self . delegatees . get ( delegatee) . cloned ( ) . unwrap_or ( 0 )
@@ -581,6 +601,45 @@ mod tests {
581601 assert_eq ! ( & delegated, & [ ( & delegatee1, & 100 ) ] ) ;
582602 }
583603
604+ #[ test]
605+ fn delegation_can_subtract ( ) {
606+ let mut state = helpers:: get_temp_state ( ) ;
607+
608+ // Prepare
609+ let delegator = Address :: random ( ) ;
610+ let delegatee = Address :: random ( ) ;
611+
612+ let mut delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
613+ delegation. add_quantity ( delegatee, 100 ) . unwrap ( ) ;
614+ delegation. save_to_state ( & mut state) . unwrap ( ) ;
615+
616+ // Do subtract
617+ let mut delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
618+ delegation. subtract_quantity ( delegatee, 30 ) . unwrap ( ) ;
619+ delegation. save_to_state ( & mut state) . unwrap ( ) ;
620+
621+ // Assert
622+ let delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
623+ assert_eq ! ( delegation. get_quantity( & delegatee) , 70 ) ;
624+ }
625+
626+ #[ test]
627+ fn delegation_cannot_subtract_mor_than_delegated ( ) {
628+ let mut state = helpers:: get_temp_state ( ) ;
629+
630+ // Prepare
631+ let delegator = Address :: random ( ) ;
632+ let delegatee = Address :: random ( ) ;
633+
634+ let mut delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
635+ delegation. add_quantity ( delegatee, 100 ) . unwrap ( ) ;
636+ delegation. save_to_state ( & mut state) . unwrap ( ) ;
637+
638+ // Do subtract
639+ let mut delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
640+ assert ! ( delegation. subtract_quantity( delegatee, 130 ) . is_err( ) ) ;
641+ }
642+
584643 #[ test]
585644 fn delegation_empty_removed_from_state ( ) {
586645 let mut state = helpers:: get_temp_state ( ) ;
@@ -598,6 +657,28 @@ mod tests {
598657 assert_eq ! ( result, None ) ;
599658 }
600659
660+ #[ test]
661+ fn delegation_became_empty_removed_from_state ( ) {
662+ let mut state = helpers:: get_temp_state ( ) ;
663+
664+ // Prepare
665+ let delegator = Address :: random ( ) ;
666+ let delegatee = Address :: random ( ) ;
667+
668+ let mut delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
669+ delegation. add_quantity ( delegatee, 100 ) . unwrap ( ) ;
670+ delegation. save_to_state ( & mut state) . unwrap ( ) ;
671+
672+ // Do subtract
673+ let mut delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
674+ delegation. subtract_quantity ( delegatee, 100 ) . unwrap ( ) ;
675+ delegation. save_to_state ( & mut state) . unwrap ( ) ;
676+
677+ // Assert
678+ let result = state. action_data ( & get_delegation_key ( & delegator) ) . unwrap ( ) ;
679+ assert_eq ! ( result, None ) ;
680+ }
681+
601682 #[ test]
602683 fn load_and_save_intermediate_rewards ( ) {
603684 let mut state = helpers:: get_temp_state ( ) ;
0 commit comments