@@ -3884,23 +3884,12 @@ mod test_purger {
3884
3884
}
3885
3885
3886
3886
fn test_liquidate_suspended_yang_threshold_near_zero (
3887
- starting_ltv : Ray , liquidate_via_absorption : bool , is_recovery_mode : bool
3887
+ starting_ltv : Ray , liquidate_via_absorption : bool , is_recovery_mode : bool , desired_threshold : Ray
3888
3888
) {
3889
3889
let (shrine , abbot , seer , absorber , purger , yangs , gates ) = purger_utils :: purger_deploy_with_searcher (
3890
3890
purger_utils :: SEARCHER_YIN . into (), Option :: None
3891
3891
);
3892
3892
3893
- // We also parametrize the test with the desired threshold for liquidation
3894
- let mut desired_threshold_params : Span <Ray > = array! [
3895
- RAY_PERCENT . into (),
3896
- (RAY_PERCENT / 4 ). into (),
3897
- // This is the smallest possible desired threshold that
3898
- // doesn't result in advancing the time enough to make
3899
- // the suspension permanent
3900
- (RAY_ONE + 1 ). into () / (RAY_ONE * shrine_contract :: SUSPENSION_GRACE_PERIOD . into ()). into (),
3901
- ]
3902
- . span ();
3903
-
3904
3893
let eth : ContractAddress = * yangs [0 ];
3905
3894
let eth_gate : IGateDispatcher = * gates [0 ];
3906
3895
let eth_amt : u128 = WAD_ONE ;
@@ -3925,149 +3914,266 @@ mod test_purger {
3925
3914
// the lowered threshold from suspension
3926
3915
purger_utils :: create_whale_trove (abbot , yangs , gates );
3927
3916
3928
- loop {
3929
- match desired_threshold_params . pop_front () {
3930
- Option :: Some (desired_threshold ) => {
3931
- let (eth_price , _ , _ ) = shrine . get_current_yang_price (eth );
3932
- let forge_amt : Wad = wadray :: rmul_wr (eth_amt . into () * eth_price , starting_ltv );
3933
- let target_trove : u64 = common :: open_trove_helper (
3934
- abbot ,
3935
- target_user ,
3936
- array! [eth ]. span (),
3937
- array! [eth_amt ]. span (),
3938
- array! [eth_gate ]. span (),
3939
- forge_amt
3940
- );
3917
+ let (eth_price , _ , _ ) = shrine . get_current_yang_price (eth );
3918
+ let forge_amt : Wad = wadray :: rmul_wr (eth_amt . into () * eth_price , starting_ltv );
3919
+ let target_trove : u64 = common :: open_trove_helper (
3920
+ abbot , target_user , array! [eth ]. span (), array! [eth_amt ]. span (), array! [eth_gate ]. span (), forge_amt
3921
+ );
3941
3922
3942
- // Suspend ETH
3943
- start_prank (CheatTarget :: One (shrine . contract_address), shrine_utils :: admin ());
3944
- shrine . suspend_yang (eth );
3945
- stop_prank (CheatTarget :: One (shrine . contract_address));
3923
+ // Suspend ETH
3924
+ start_prank (CheatTarget :: One (shrine . contract_address), shrine_utils :: admin ());
3925
+ shrine . suspend_yang (eth );
3926
+ stop_prank (CheatTarget :: One (shrine . contract_address));
3946
3927
3947
- // Advance the time stamp such that the ETH threshold falls to `desired_threshold`
3948
- let decrease_factor : Ray = * desired_threshold / eth_threshold ;
3949
- let ts_diff : u64 = shrine_contract :: SUSPENSION_GRACE_PERIOD
3950
- - scale_u128_by_ray (shrine_contract :: SUSPENSION_GRACE_PERIOD . into (), decrease_factor )
3951
- . try_into ()
3952
- . unwrap ();
3928
+ // Advance the time stamp such that the ETH threshold falls to `desired_threshold`
3929
+ let decrease_factor : Ray = desired_threshold / eth_threshold ;
3930
+ let ts_diff : u64 = shrine_contract :: SUSPENSION_GRACE_PERIOD
3931
+ - scale_u128_by_ray (shrine_contract :: SUSPENSION_GRACE_PERIOD . into (), decrease_factor ). try_into (). unwrap ();
3953
3932
3954
- shrine_utils :: advance_prices_periodically (shrine , yangs , ts_diff );
3933
+ shrine_utils :: advance_prices_periodically (shrine , yangs , ts_diff );
3955
3934
3956
- // Check that the threshold has decreased to the desired value
3957
- // The trove's threshold is equivalent to ETH's threshold since it
3958
- // has deposited only ETH.
3959
- let threshold_before_liquidation = shrine . get_trove_health (target_trove ). threshold;
3935
+ // Check that the threshold has decreased to the desired value
3936
+ // The trove's threshold is equivalent to ETH's threshold since it
3937
+ // has deposited only ETH.
3938
+ let threshold_before_liquidation = shrine . get_trove_health (target_trove ). threshold;
3939
+
3940
+ common :: assert_equalish (
3941
+ threshold_before_liquidation ,
3942
+ desired_threshold , // 0.0000001 = 10^-7 (ray). Precision
3943
+ // is limited by the precision of timestamps,
3944
+ // which is only in seconds
3945
+ 100000000000000000000_u128 . into (),
3946
+ ' wrong eth threshold'
3947
+ );
3948
+
3949
+ // We want to compare the yin balance of the liquidator
3950
+ // before and after the liquidation. In the case of absorption
3951
+ // we check the absorber's balance, and in the case of
3952
+ // searcher liquidation we check the searcher's balance.
3953
+ let before_liquidation_yin_balance : u256 = if liquidate_via_absorption {
3954
+ yin_erc20 . balance_of (absorber . contract_address)
3955
+ } else {
3956
+ yin_erc20 . balance_of (searcher )
3957
+ };
3960
3958
3961
- common :: assert_equalish (
3962
- threshold_before_liquidation ,
3963
- * desired_threshold ,
3964
- // 0.0000001 = 10^-7 (ray). Precision
3965
- // is limited by the precision of timestamps,
3966
- // which is only in seconds
3967
- 100000000000000000000_u128 . into (),
3968
- ' wrong eth threshold'
3969
- );
3959
+ let in_recovery_mode : bool = shrine . is_recovery_mode ();
3960
+ if is_recovery_mode {
3961
+ if ! in_recovery_mode {
3962
+ purger_utils :: trigger_recovery_mode (shrine , seer , yangs , common :: RecoveryModeSetupType :: ExceedsBuffer );
3963
+ }
3964
+ } else {
3965
+ assert (! in_recovery_mode , ' in recovery mode' );
3966
+ }
3970
3967
3971
- // We want to compare the yin balance of the liquidator
3972
- // before and after the liquidation. In the case of absorption
3973
- // we check the absorber's balance, and in the case of
3974
- // searcher liquidation we check the searcher's balance.
3975
- let before_liquidation_yin_balance : u256 = if liquidate_via_absorption {
3976
- yin_erc20 . balance_of (absorber . contract_address)
3977
- } else {
3978
- yin_erc20 . balance_of (searcher )
3979
- };
3968
+ // Liquidate the trove
3969
+ start_prank (CheatTarget :: One (purger . contract_address), searcher );
3980
3970
3981
- let in_recovery_mode : bool = shrine . is_recovery_mode ();
3982
- if is_recovery_mode {
3983
- if ! in_recovery_mode {
3984
- purger_utils :: trigger_recovery_mode (
3985
- shrine , seer , yangs , common :: RecoveryModeSetupType :: ExceedsBuffer
3986
- );
3987
- }
3988
- } else {
3989
- assert (! in_recovery_mode , ' in recovery mode' );
3990
- }
3971
+ if liquidate_via_absorption {
3972
+ purger . absorb (target_trove );
3973
+ } else {
3974
+ // Get the updated debt with accrued interest
3975
+ let before_liquidation_health : Health = shrine . get_trove_health (target_trove );
3976
+ purger . liquidate (target_trove , before_liquidation_health . debt, searcher );
3977
+ }
3991
3978
3992
- // Liquidate the trove
3993
- start_prank ( CheatTarget :: One ( purger . contract_address), searcher );
3979
+ // Sanity checks
3980
+ let target_trove_after_health : Health = shrine . get_trove_health ( target_trove );
3994
3981
3995
- if liquidate_via_absorption {
3996
- purger . absorb (target_trove );
3997
- } else {
3998
- // Get the updated debt with accrued interest
3999
- let before_liquidation_health : Health = shrine . get_trove_health (target_trove );
4000
- purger . liquidate (target_trove , before_liquidation_health . debt, searcher );
4001
- }
3982
+ assert (target_trove_after_health . debt < forge_amt , ' trove not correctly liquidated' );
4002
3983
4003
- // Sanity checks
4004
- let target_trove_after_health : Health = shrine . get_trove_health (target_trove );
3984
+ // Checking that the liquidator's yin balance has decreased
3985
+ // after liquidation
3986
+ if liquidate_via_absorption {
3987
+ assert (
3988
+ yin_erc20 . balance_of (absorber . contract_address) < before_liquidation_yin_balance ,
3989
+ ' absorber yin not used'
3990
+ );
3991
+ } else {
3992
+ assert (yin_erc20 . balance_of (searcher ) < before_liquidation_yin_balance , ' searcher yin not used' );
3993
+ }
3994
+ }
4005
3995
4006
- assert (target_trove_after_health . debt < forge_amt , ' trove not correctly liquidated' );
3996
+ fn suspended_yang_desired_thresholds () -> Span <Ray > {
3997
+ array! [
3998
+ RAY_PERCENT . into (),
3999
+ (RAY_PERCENT / 4 ). into (),
4000
+ // This is the smallest possible desired threshold that
4001
+ // doesn't result in advancing the time enough to make
4002
+ // the suspension permanent
4003
+ (RAY_ONE + 1 ). into () / (RAY_ONE * shrine_contract :: SUSPENSION_GRACE_PERIOD . into ()). into (),
4004
+ ]
4005
+ . span ()
4006
+ }
4007
4007
4008
- // Checking that the liquidator's yin balance has decreased
4009
- // after liquidation
4010
- if liquidate_via_absorption {
4011
- assert (
4012
- yin_erc20 . balance_of (absorber . contract_address) < before_liquidation_yin_balance ,
4013
- ' absorber yin not used'
4014
- );
4015
- } else {
4016
- assert (
4017
- yin_erc20 . balance_of (searcher ) < before_liquidation_yin_balance , ' searcher yin not used'
4018
- );
4019
- }
4008
+ #[test]
4009
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized1a () {
4010
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4011
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , true , desired_threshold );
4012
+ }
4020
4013
4021
- start_prank (CheatTarget :: One (shrine . contract_address), shrine_utils :: admin ());
4022
- shrine . unsuspend_yang (eth );
4023
- stop_prank (CheatTarget :: One (shrine . contract_address));
4024
- },
4025
- Option :: None => { break ; }
4026
- }
4027
- };
4014
+ #[test]
4015
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized1b () {
4016
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4017
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , true , desired_threshold );
4028
4018
}
4029
4019
4030
4020
#[test]
4031
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized1 () {
4032
- test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , true );
4021
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized1c () {
4022
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4023
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , true , desired_threshold );
4033
4024
}
4034
4025
4035
4026
#[test]
4036
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized2 () {
4037
- test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , true );
4027
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized2a () {
4028
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4029
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , true , desired_threshold );
4038
4030
}
4039
4031
4040
4032
#[test]
4041
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized3 () {
4042
- test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , false );
4033
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized2b () {
4034
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4035
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , true , desired_threshold );
4043
4036
}
4044
4037
4045
4038
#[test]
4046
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized4 () {
4047
- test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , false );
4039
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized2c () {
4040
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4041
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , true , desired_threshold );
4042
+ }
4043
+
4044
+ #[test]
4045
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized3a () {
4046
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4047
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , false , desired_threshold );
4048
+ }
4049
+
4050
+ #[test]
4051
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized3b () {
4052
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4053
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , false , desired_threshold );
4054
+ }
4055
+
4056
+ #[test]
4057
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized3c () {
4058
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4059
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), true , false , desired_threshold );
4060
+ }
4061
+
4062
+ #[test]
4063
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized4a () {
4064
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4065
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , false , desired_threshold );
4066
+ }
4067
+
4068
+ #[test]
4069
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized4b () {
4070
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4071
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , false , desired_threshold );
4072
+ }
4073
+
4074
+ #[test]
4075
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized4c () {
4076
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4077
+ test_liquidate_suspended_yang_threshold_near_zero ((50 * RAY_PERCENT ). into (), false , false , desired_threshold );
4048
4078
}
4049
4079
4050
4080
// The minimum LTV for absorption at 1% threshold is approximately 1.097%, so it is rounded
4051
4081
// up to 1.1% for convenience to ensure the target trove is absorbable after adjusting the
4052
4082
// threshold to the desired value.
4053
4083
#[test]
4054
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized5 () {
4055
- test_liquidate_suspended_yang_threshold_near_zero ((RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , true );
4084
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized5a () {
4085
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4086
+ test_liquidate_suspended_yang_threshold_near_zero (
4087
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , true , desired_threshold
4088
+ );
4089
+ }
4090
+
4091
+ #[test]
4092
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized5b () {
4093
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4094
+ test_liquidate_suspended_yang_threshold_near_zero (
4095
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , true , desired_threshold
4096
+ );
4097
+ }
4098
+
4099
+ #[test]
4100
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized5c () {
4101
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4102
+ test_liquidate_suspended_yang_threshold_near_zero (
4103
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , true , desired_threshold
4104
+ );
4105
+ }
4106
+
4107
+ #[test]
4108
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized6a () {
4109
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4110
+ test_liquidate_suspended_yang_threshold_near_zero (
4111
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , true , desired_threshold
4112
+ );
4056
4113
}
4057
4114
4058
4115
#[test]
4059
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized6 () {
4060
- test_liquidate_suspended_yang_threshold_near_zero ((RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , true );
4116
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized6b () {
4117
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4118
+ test_liquidate_suspended_yang_threshold_near_zero (
4119
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , true , desired_threshold
4120
+ );
4061
4121
}
4062
4122
4063
4123
#[test]
4064
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized7 () {
4065
- test_liquidate_suspended_yang_threshold_near_zero ((RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , false );
4124
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized6c () {
4125
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4126
+ test_liquidate_suspended_yang_threshold_near_zero (
4127
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , true , desired_threshold
4128
+ );
4066
4129
}
4067
4130
4068
4131
#[test]
4069
- fn test_liquidate_suspended_yang_threshold_near_zero_parametrized8 () {
4070
- test_liquidate_suspended_yang_threshold_near_zero ((RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , false );
4132
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized7a () {
4133
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4134
+ test_liquidate_suspended_yang_threshold_near_zero (
4135
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , false , desired_threshold
4136
+ );
4137
+ }
4138
+
4139
+ #[test]
4140
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized7b () {
4141
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4142
+ test_liquidate_suspended_yang_threshold_near_zero (
4143
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , false , desired_threshold
4144
+ );
4145
+ }
4146
+
4147
+ #[test]
4148
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized7c () {
4149
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4150
+ test_liquidate_suspended_yang_threshold_near_zero (
4151
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), true , false , desired_threshold
4152
+ );
4153
+ }
4154
+
4155
+ #[test]
4156
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized8a () {
4157
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (0 );
4158
+ test_liquidate_suspended_yang_threshold_near_zero (
4159
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , false , desired_threshold
4160
+ );
4161
+ }
4162
+
4163
+ #[test]
4164
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized8b () {
4165
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (1 );
4166
+ test_liquidate_suspended_yang_threshold_near_zero (
4167
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , false , desired_threshold
4168
+ );
4169
+ }
4170
+
4171
+ #[test]
4172
+ fn test_liquidate_suspended_yang_threshold_near_zero_parametrized8c () {
4173
+ let desired_threshold = * suspended_yang_desired_thresholds (). at (2 );
4174
+ test_liquidate_suspended_yang_threshold_near_zero (
4175
+ (RAY_PERCENT + RAY_PERCENT / 10 ). into (), false , false , desired_threshold
4176
+ );
4071
4177
}
4072
4178
4073
4179
#[derive(Copy , Drop , PartialEq )]
0 commit comments