@@ -136,10 +136,17 @@ impl StakePool {
136
136
137
137
/// calculate lamports amount on withdrawal
138
138
pub fn calc_lamports_withdraw_amount ( & self , pool_tokens : u64 ) -> Option < u64 > {
139
- let ( quotient, _) = ( pool_tokens as u128 )
140
- . checked_mul ( self . total_stake_lamports as u128 ) ?
141
- . checked_ceil_div ( self . pool_token_supply as u128 ) ?;
142
- u64:: try_from ( quotient) . ok ( )
139
+ // `checked_ceil_div` returns `None` for a 0 quotient result, but in this
140
+ // case, a return of 0 is valid for small amounts of pool tokens. So
141
+ // we check for that separately
142
+ let numerator = ( pool_tokens as u128 ) . checked_mul ( self . total_stake_lamports as u128 ) ?;
143
+ let denominator = self . pool_token_supply as u128 ;
144
+ if numerator < denominator || denominator == 0 {
145
+ Some ( 0 )
146
+ } else {
147
+ let ( quotient, _) = numerator. checked_ceil_div ( denominator) ?;
148
+ u64:: try_from ( quotient) . ok ( )
149
+ }
143
150
}
144
151
145
152
/// calculate pool tokens to be deducted as withdrawal fees
@@ -783,6 +790,20 @@ mod test {
783
790
assert_eq ! ( fee_lamports, LAMPORTS_PER_SOL ) ;
784
791
}
785
792
793
+ #[ test]
794
+ fn zero_withdraw_calculation ( ) {
795
+ let fee = Fee {
796
+ numerator : 0 ,
797
+ denominator : 1 ,
798
+ } ;
799
+ let stake_pool = StakePool {
800
+ fee,
801
+ ..StakePool :: default ( )
802
+ } ;
803
+ let fee_lamports = stake_pool. calc_lamports_withdraw_amount ( 0 ) . unwrap ( ) ;
804
+ assert_eq ! ( fee_lamports, 0 ) ;
805
+ }
806
+
786
807
#[ test]
787
808
fn divide_by_zero_fee ( ) {
788
809
let stake_pool = StakePool {
0 commit comments