Skip to content

Commit a255759

Browse files
ith-harveyIan Harveyprateek105
authored
Merge Develop into Master (#934)
* Logging for RewardsManager and PositionManager invariants (#925) * added logging for positionManager * added rewards and position logging * clean up * updated rewards mapping back to public so tests pass * how modifier was being called in rewardsPoolHandler * revised so logging pools is not required when logging positions * cleanup * readme cleanup --------- Co-authored-by: Ian Harvey <[email protected]> * Invariants Improvement: Add multiple pool support in position and rewards manager invariant testing (#927) * Add multiple pools in position and rewards manager invariant testing * Fix RW6 regression test * Fix rewardsClaimed and updateRewardsClaimed in Rewards manager * Fix compile error * PR feedback * Add configurable number of pools for position and rewards manager invariant testing * Positions Invariants: Multiple positions, transfer positions (#926) * added randomness * added the ability to transfer positions * increased chance of rewards being claimed in handlers * cleanup * responded to comments --------- Co-authored-by: Ian Harvey <[email protected]> * Fuzz test additions (#924) * Add fuzz test for borrower borrows fuzzed amount and getting kick after some time * Add fuzz test for take fuzzed amount of collateral from auction * Add fuzz test for settle with fuzzed pool deposit * Add fuzz test for add and remove collateral in ERC721Pool * Fuzzed buckets used in borrow and kick fuzz test * PR feedback * Invariant Improvements: Position rewards logging for multiple pools (#931) * Update position and rewards manager invariant logging for multiple pools * Fix regression test to run for any token precision and Quote token limits * PR feedback * Invariants Improvements: Add Multiple position in single handler in Position (#928) * Update Position invariants handler to memorialize and redeem multiple positions * PR feedback * Add partial random positions redeem in redeem position handler * Add random time skips between epochs in rewards manager * Add bucket bankruptcy scenario for rewards manager (#930) * Add bucket bankruptcy scenario for rewards manager * Fix evm reverts * PR feedback * Update prepare test methods to add position in NFT if there is no position in it --------- Co-authored-by: Ian Harvey <[email protected]> Co-authored-by: Prateek Gupta <[email protected]>
1 parent febd576 commit a255759

File tree

57 files changed

+1969
-533
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1969
-533
lines changed

src/RewardsManager.sol

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ import {
1515
IRewardsManagerState,
1616
IRewardsManagerDerivedState
1717
} from './interfaces/rewards/IRewardsManager.sol';
18-
import { StakeInfo, BucketState } from './interfaces/rewards/IRewardsManagerState.sol';
18+
import {
19+
StakeInfo,
20+
BucketState,
21+
PoolRewardsInfo
22+
} from './interfaces/rewards/IRewardsManagerState.sol';
1923

2024
import { PositionManager } from './PositionManager.sol';
2125

@@ -67,13 +71,9 @@ contract RewardsManager is IRewardsManager {
6771

6872
/// @dev `tokenID => epoch => bool has claimed` mapping.
6973
mapping(uint256 => mapping(uint256 => bool)) public override isEpochClaimed;
70-
/// @dev `epoch => rewards claimed` mapping.
71-
mapping(uint256 => uint256) public override rewardsClaimed;
72-
/// @dev `epoch => update bucket rate rewards claimed` mapping. Tracks the total amount of update rewards claimed.
73-
mapping(uint256 => uint256) public override updateRewardsClaimed;
7474

75-
/// @dev Mapping of per pool bucket exchange rates at a given burn event `poolAddress => bucketIndex => epoch => bucket exchange rate`.
76-
mapping(address => mapping(uint256 => mapping(uint256 => uint256))) internal bucketExchangeRates;
75+
/// @dev Mapping `pool address => Pool rewards info`.
76+
mapping(address => PoolRewardsInfo) internal poolRewardsInfo;
7777

7878
/// @dev Mapping `tokenID => Stake info`.
7979
mapping(uint256 => StakeInfo) internal stakes;
@@ -318,7 +318,23 @@ contract RewardsManager is IRewardsManager {
318318
uint256 bucketIndex_,
319319
uint256 epoch_
320320
) external view override returns (bool) {
321-
return bucketExchangeRates[pool_][bucketIndex_][epoch_] != 0;
321+
return poolRewardsInfo[pool_].bucketExchangeRates[bucketIndex_][epoch_] != 0;
322+
}
323+
324+
/// @inheritdoc IRewardsManagerState
325+
function getRewardsClaimed(
326+
address pool_,
327+
uint256 epoch_
328+
) external view override returns (uint256) {
329+
return poolRewardsInfo[pool_].rewardsClaimed[epoch_];
330+
}
331+
332+
/// @inheritdoc IRewardsManagerState
333+
function getUpdateRewardsClaimed(
334+
address pool_,
335+
uint256 epoch_
336+
) external view override returns (uint256) {
337+
return poolRewardsInfo[pool_].updateBucketRewardsClaimed[epoch_];
322338
}
323339

324340
/**************************/
@@ -340,6 +356,8 @@ contract RewardsManager is IRewardsManager {
340356
uint256 lastClaimedEpoch = stakes[tokenId_].lastClaimedEpoch;
341357
uint256 stakingEpoch = stakes[tokenId_].stakingEpoch;
342358

359+
mapping(uint256 => uint256) storage rewardsClaimed = poolRewardsInfo[ajnaPool].rewardsClaimed;
360+
343361
uint256[] memory positionIndexes = positionManager.getPositionIndexesFiltered(tokenId_);
344362

345363
// iterate through all burn periods to calculate and claim rewards
@@ -358,7 +376,7 @@ contract RewardsManager is IRewardsManager {
358376
unchecked { ++epoch; }
359377

360378
// update epoch token claim trackers
361-
rewardsClaimed[epoch] += nextEpochRewards;
379+
rewardsClaimed[epoch] += nextEpochRewards;
362380
isEpochClaimed[tokenId_][epoch] = true;
363381
}
364382
}
@@ -382,7 +400,7 @@ contract RewardsManager is IRewardsManager {
382400
) internal view returns (uint256 epochRewards_) {
383401

384402
uint256 nextEpoch = epoch_ + 1;
385-
uint256 claimedRewardsInNextEpoch = rewardsClaimed[nextEpoch];
403+
uint256 claimedRewardsInNextEpoch = poolRewardsInfo[ajnaPool_].rewardsClaimed[nextEpoch];
386404
uint256 bucketIndex;
387405
uint256 interestEarned;
388406

@@ -397,7 +415,7 @@ contract RewardsManager is IRewardsManager {
397415
if (epoch_ != stakingEpoch_) {
398416

399417
// if staked in a previous epoch then use the initial exchange rate of epoch
400-
bucketRate = bucketExchangeRates[ajnaPool_][bucketIndex][epoch_];
418+
bucketRate = poolRewardsInfo[ajnaPool_].bucketExchangeRates[bucketIndex][epoch_];
401419
} else {
402420

403421
// if staked during the epoch then use the bucket rate at the time of staking
@@ -445,7 +463,7 @@ contract RewardsManager is IRewardsManager {
445463

446464
if (exchangeRate_ != 0) {
447465

448-
uint256 nextExchangeRate = bucketExchangeRates[pool_][bucketIndex_][nextEventEpoch_];
466+
uint256 nextExchangeRate = poolRewardsInfo[pool_].bucketExchangeRates[bucketIndex_][nextEventEpoch_];
449467

450468
// calculate interest earned only if next exchange rate is higher than current exchange rate
451469
if (nextExchangeRate > exchangeRate_) {
@@ -609,6 +627,7 @@ contract RewardsManager is IRewardsManager {
609627
}
610628
else {
611629
if (block.timestamp <= curBurnTime + UPDATE_PERIOD) {
630+
mapping(uint256 => uint256) storage updateRewardsClaimed = poolRewardsInfo[pool_].updateBucketRewardsClaimed;
612631

613632
// update exchange rates and calculate rewards if tokens were burned and within allowed time period
614633
uint256 noOfIndexes = indexes_.length;
@@ -657,7 +676,7 @@ contract RewardsManager is IRewardsManager {
657676
uint256 burnEpoch_
658677
) internal {
659678
// cache storage pointer for reduced gas
660-
mapping(uint256 => uint256) storage _bucketExchangeRates = bucketExchangeRates[pool_][bucketIndex_];
679+
mapping(uint256 => uint256) storage _bucketExchangeRates = poolRewardsInfo[pool_].bucketExchangeRates[bucketIndex_];
661680
uint256 burnExchangeRate = _bucketExchangeRates[burnEpoch_];
662681

663682
// update bucket exchange rate at epoch only if it wasn't previously updated
@@ -686,7 +705,7 @@ contract RewardsManager is IRewardsManager {
686705
uint256 interestEarned_
687706
) internal returns (uint256 rewards_) {
688707
// cache storage pointer for reduced gas
689-
mapping(uint256 => uint256) storage _bucketExchangeRates = bucketExchangeRates[pool_][bucketIndex_];
708+
mapping(uint256 => uint256) storage _bucketExchangeRates = poolRewardsInfo[pool_].bucketExchangeRates[bucketIndex_];
690709
uint256 burnExchangeRate = _bucketExchangeRates[burnEpoch_];
691710

692711
// update bucket exchange rate at epoch only if it wasn't previously updated

src/interfaces/rewards/IRewardsManagerState.sol

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,23 @@ interface IRewardsManagerState {
3333

3434
/**
3535
* @notice Track the total amount of rewards that have been claimed for a given epoch.
36+
* @param pool_ The pool to get the rewards claimed for.
3637
* @param epoch_ The burn epoch to track if rewards were claimed.
3738
* @return The amount of rewards claimed in given epoch.
3839
*/
39-
function rewardsClaimed(
40+
function getRewardsClaimed(
41+
address pool_,
4042
uint256 epoch_
4143
) external view returns (uint256);
4244

4345
/**
4446
* @notice Track the total amount of rewards that have been claimed for a given burn event's bucket updates.
47+
* @param pool_ The pool to get the update rewards claimed for.
4548
* @param epoch_ The burn epoch to track if rewards were claimed.
4649
* @return The amount of update rewards claimed in given epoch.
4750
*/
48-
function updateRewardsClaimed(
51+
function getUpdateRewardsClaimed(
52+
address pool_,
4953
uint256 epoch_
5054
) external view returns (uint256);
5155

@@ -92,3 +96,10 @@ struct BucketState {
9296
uint256 lpsAtStakeTime; // [WAD] LP amount the NFT owner is entitled in current bucket at the time of staking
9397
uint256 rateAtStakeTime; // [WAD] current bucket exchange rate at the time of staking
9498
}
99+
100+
/// @dev Struct holding Pool rewards info
101+
struct PoolRewardsInfo {
102+
mapping(uint256 => uint256) rewardsClaimed; // staking rewards claimed in a epoch
103+
mapping(uint256 => uint256) updateBucketRewardsClaimed; // update exchange rate rewards claimed in a epoch
104+
mapping(uint256 => mapping(uint256 => uint256)) bucketExchangeRates; // bucket exchange rates at a given burn event for each bucket
105+
}

tests/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ python regression_generator.py
5454
### Invariant tests
5555
#### Configuration
5656
Invariant test scenarios can be externally configured by customizing following environment variables:
57-
| Variable | Pool Type | Default | Description |
57+
| Variable | Contract Type | Default | Description |
5858
| ------------- | ------------- | ------------- | ------------- |
5959
| NO_OF_ACTORS | ERC20 ERC721 | 10 | Max number of actors to interact with the pool |
6060
| QUOTE_PRECISION | ERC20 ERC721 | 18 | Precision of token used as quote token |
@@ -77,10 +77,12 @@ Invariant test scenarios can be externally configured by customizing following e
7777
| SKIP_TIME_TO_KICK | ERC20 ERC721 | 200 days | The time to be skipped and drive a new loan undercollateralized. Use a big value to ensure a successful kick |
7878
| MAX_EPOCH_ADVANCE | ERC20 ERC721 | 5 | The maximum number of epochs that will be created before an unstake or claimRewards call |
7979
| MAX_AJNA_AMOUNT | ERC20 ERC721 | 100_000_000 | The maximum amount of ajna provided to the rewards contract |
80+
| NO_OF_POOLS | Position Rewards | 10 | Number of pools to be used in position and rewards manager invariant testing |
8081
| FOUNDRY_INVARIANT_RUNS | ERC20 ERC721 | 10 | The number of runs for each scenario |
8182
| FOUNDRY_INVARIANT_DEPTH | ERC20 ERC721 | 200 | The number of actions performed in each scenario |
82-
| LOGS_VERBOSITY | ERC20 ERC721 | 0 | <p> Details to log <p> 0 = No Logs <p> 1 = pool State <p> 2 = pool State, Auctions details <p> 3 = pool State, Auctions details , Buckets details <p> 4 = pool State, Auctions details , Buckets details, Lender details <p> 5 = pool State, Auctions details , Buckets details, Lender details, Borrower details <p> Note - Log File with name `logFile.txt` will be generated in project directory|
83-
83+
| LOGS_VERBOSITY_POOL | ERC20 ERC721 | 0 | <p> Details to log <p> 0 = No Logs <p> 1 = pool State <p> 2 = pool State, Auctions details <p> 3 = pool State, Auctions details , Buckets details <p> 4 = pool State, Auctions details , Buckets details, Lender details <p> 5 = pool State, Auctions details , Buckets details, Lender details, Borrower details <p> Note - Log File with name `logFile.txt` will be generated in project directory|
84+
| LOGS_VERBOSITY_POSITION | ERC20 ERC721 | 0 | <p> Details to log <p> 0 = No Logs <p> 1 = positionManager details <p> Note - Log File with name `logFile.txt` will be generated in project directory|
85+
| LOGS_VERBOSITY_REWARDS | ERC20 ERC721 | 0 | <p> Details to log <p> 0 = No Logs <p> 1 = rewardsManager details <p> Note - Log File with name `logFile.txt` will be generated in project directory|
8486
#### Invariant names
8587

8688
The `<invariant_name>` placeholder in commands below could take following values:

tests/forge/invariants/ERC20Pool/BasicERC20PoolInvariants.t.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ contract BasicERC20PoolInvariants is BasicInvariants {
3737
_basicERC20PoolHandler = new BasicERC20PoolHandler(
3838
address(_erc20pool),
3939
address(_ajna),
40-
address(_quote),
41-
address(_collateral),
4240
address(_poolInfo),
4341
_numOfActors,
4442
address(this)

tests/forge/invariants/ERC20Pool/LiquidationERC20PoolInvariants.t.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ contract LiquidationERC20PoolInvariants is BasicERC20PoolInvariants, Liquidation
2121
_liquidationERC20PoolHandler = new LiquidationERC20PoolHandler(
2222
address(_erc20pool),
2323
address(_ajna),
24-
address(_quote),
25-
address(_collateral),
2624
address(_poolInfo),
2725
_numOfActors,
2826
address(this)

tests/forge/invariants/ERC20Pool/PanicExitERC20PoolInvariants.t.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ contract PanicExitERC20PoolInvariants is BasicERC20PoolInvariants, LiquidationIn
2929
_panicExitERC20PoolHandler = new PanicExitERC20PoolHandler(
3030
address(_erc20pool),
3131
address(_ajna),
32-
address(_quote),
33-
address(_collateral),
3432
address(_poolInfo),
3533
address(this)
3634
);

tests/forge/invariants/ERC20Pool/RealWorldScenarioInvariants.t.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ contract RealWorldScenarioInvariants is ReserveInvariants, LiquidationERC20PoolI
2222
_reserveERC20PoolHandler = new ReserveERC20PoolHandler(
2323
address(_erc20pool),
2424
address(_ajna),
25-
address(_quote),
26-
address(_collateral),
2725
address(_poolInfo),
2826
_numOfActors,
2927
address(this)

tests/forge/invariants/ERC20Pool/ReserveERC20PoolInvariants.t.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ contract ReserveERC20PoolInvariants is ReserveInvariants, LiquidationERC20PoolIn
2121
_reserveERC20PoolHandler = new ReserveERC20PoolHandler(
2222
address(_erc20pool),
2323
address(_ajna),
24-
address(_quote),
25-
address(_collateral),
2624
address(_poolInfo),
2725
_numOfActors,
2826
address(this)

tests/forge/invariants/ERC20Pool/TradingERC20PoolInvariants.t.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ contract TradingERC20PoolInvariants is BasicERC20PoolInvariants, LiquidationInva
2929
_tradingERC20PoolHandler = new TradingERC20PoolHandler(
3030
address(_erc20pool),
3131
address(_ajna),
32-
address(_quote),
33-
address(_collateral),
3432
address(_poolInfo),
3533
address(this)
3634
);

tests/forge/invariants/ERC20Pool/handlers/BasicERC20PoolHandler.sol

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@ contract BasicERC20PoolHandler is UnboundedBasicERC20PoolHandler, BasicPoolHandl
2121
constructor(
2222
address pool_,
2323
address ajna_,
24-
address quote_,
25-
address collateral_,
2624
address poolInfo_,
2725
uint256 numOfActors_,
2826
address testContract_
29-
) BaseERC20PoolHandler(pool_, ajna_, quote_, collateral_, poolInfo_, numOfActors_, testContract_) {
27+
) BaseERC20PoolHandler(pool_, ajna_, poolInfo_, numOfActors_, testContract_) {
3028

3129
}
3230

0 commit comments

Comments
 (0)