Skip to content

Commit

Permalink
Rewards Invariants: Significant improvements (#897)
Browse files Browse the repository at this point in the history
* added multiple staked positions

* alphabetized functions, made position with indexes accurate, updateExchangeRates now updates buckets that have position in them

* reverted alphabetization change so PR is easier to read

* cleaned up and removed excess tracking

* cleanup log typo

* cleaned up how already claimed rewards are tracked

* Fix kickWithDeposit handler call in rewards manager regression test

* updateExchangeRate now creates positions

* removed unused tracker

* fixed unit tests

* Add rewardsManager handler with ERC721Pool (#899)

Co-authored-by: Ian Harvey <[email protected]>

* fixed regression_gen

* Rewards invariants erc721pool (#908)

* Add rewardsManager handler with ERC721Pool

* made number of max epochs customizable and removed excess logging

---------

Co-authored-by: prateek105 <[email protected]>
Co-authored-by: Ian Harvey <[email protected]>

* renamed vars made epoch periods longer

* added dynamic updating

* cleaned up map checking

* tests now pass without failing when no position is created via add quote token

* refactored positions cleanly

* refactored rewards and positions

* clean up

* cleanup

* renamed test files, hardcoded pool hash, added MAX_AJNA_AMOUNT to readme

---------

Co-authored-by: Ian Harvey <[email protected]>
Co-authored-by: prateek105 <[email protected]>
Co-authored-by: Prateek Gupta <[email protected]>
  • Loading branch information
4 people authored Jul 4, 2023
1 parent f61fba5 commit 5e7f5cf
Show file tree
Hide file tree
Showing 25 changed files with 1,237 additions and 1,265 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ test-invariant-erc20 :; forge t --mt invariant --nmc ${CONTR
test-invariant-erc721 :; forge t --mt invariant --nmc ${CONTRACT_EXCLUDES} --mc ERC721
test-invariant-position-erc20 :; forge t --mt invariant --nmc ${CONTRACT_EXCLUDES} --mc ERC20PoolPosition
test-invariant-position-erc721 :; forge t --mt invariant --nmc ${CONTRACT_EXCLUDES} --mc ERC721PoolPosition
test-invariant-rewards :; forge t --mt invariant --nmc ${CONTRACT_EXCLUDES} --mc Rewards
test-invariant-rewards-erc20 :; forge t --mt invariant --nmc ${CONTRACT_EXCLUDES} --mc ERC20PoolRewards
test-invariant-rewards-erc721 :; forge t --mt invariant --nmc ${CONTRACT_EXCLUDES} --mc ERC721PoolRewards
test-invariant :; forge t --mt ${MT} --nmc RegressionTest
test-invariant-erc20-precision :; ./tests/forge/invariants/test-invariant-erc20-precision.sh
test-invariant-erc721-precision :; ./tests/forge/invariants/test-invariant-erc721-precision.sh
Expand Down
2 changes: 2 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ Invariant test scenarios can be externally configured by customizing following e
| MAX_POOL_DEBT | ERC20 ERC721 | 1e45 | The max amount of debt that can be taken from the pool. If debt goes above this amount, borrower debt will be repaid |
| SKIP_TIME | ERC20 ERC721 | 24 hours | The upper limit of time that can be skipped after a pool action (fuzzed) |
| 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 |
| MAX_EPOCH_ADVANCE | ERC20 ERC721 | 5 | The maximum number of epochs that will be created before an unstake or claimRewards call |
| MAX_AJNA_AMOUNT | ERC20 ERC721 | 100_000_000 | The maximum amount of ajna provided to the rewards contract |
| FOUNDRY_INVARIANT_RUNS | ERC20 ERC721 | 10 | The number of runs for each scenario |
| FOUNDRY_INVARIANT_DEPTH | ERC20 ERC721 | 200 | The number of actions performed in each scenario |
| 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|
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.18;

import "@std/console.sol";
import { Maths } from 'src/libraries/internal/Maths.sol';
import { Pool } from 'src/base/Pool.sol';
import { ERC20Pool } from 'src/ERC20Pool.sol';
import { ERC721Pool } from 'src/ERC721Pool.sol';
import { ERC20PoolFactory } from 'src/ERC20PoolFactory.sol';
import { ERC721PoolFactory } from 'src/ERC721PoolFactory.sol';
import { PositionManager } from 'src/PositionManager.sol';
import { RewardsManager } from 'src/RewardsManager.sol';

import { TokenWithNDecimals } from '../../utils/Tokens.sol';

import { ERC20PoolRewardsHandler } from './handlers/ERC20PoolRewardsHandler.sol';
import { RewardsInvariants } from './RewardsInvariants.t.sol';

contract ERC20PoolRewardsInvariants is RewardsInvariants {

TokenWithNDecimals internal _collateral;
ERC20Pool internal _erc20pool;
ERC20PoolRewardsHandler internal _erc20poolrewardsHandler;

function setUp() public override virtual {

super.setUp();

_collateral = new TokenWithNDecimals("Collateral", "C", uint8(vm.envOr("COLLATERAL_PRECISION", uint256(18))));
_erc20poolFactory = new ERC20PoolFactory(address(_ajna));
_erc20impl = _erc20poolFactory.implementation();
_erc721poolFactory = new ERC721PoolFactory(address(_ajna));
_erc721impl = _erc721poolFactory.implementation();
_erc20pool = ERC20Pool(_erc20poolFactory.deployPool(address(_collateral), address(_quote), 0.05 * 10**18));
_pool = Pool(address(_erc20pool));
_positionManager = new PositionManager(_erc20poolFactory, _erc721poolFactory);
_rewardsManager = new RewardsManager(address(_ajna), _positionManager);

// fund the rewards manager with 100M ajna
_ajna.mint(address(_rewardsManager), 100_000_000 * 1e18);

excludeContract(address(_ajna));
excludeContract(address(_collateral));
excludeContract(address(_quote));
excludeContract(address(_erc20poolFactory));
excludeContract(address(_erc721poolFactory));
excludeContract(address(_erc20pool));
excludeContract(address(_poolInfo));
excludeContract(address(_erc20impl));
excludeContract(address(_erc721impl));
excludeContract(address(_positionManager));
excludeContract(address(_rewardsManager));

_erc20poolrewardsHandler = new ERC20PoolRewardsHandler(
address(_rewardsManager),
address(_positionManager),
address(_erc20pool),
address(_ajna),
address(_quote),
address(_collateral),
address(_poolInfo),
NUM_ACTORS,
address(this)
);

_handler = address(_erc20poolrewardsHandler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
pragma solidity 0.8.18;

import "@std/console.sol";

import { Pool } from 'src/base/Pool.sol';
import { ERC20Pool } from 'src/ERC20Pool.sol';
import { ERC721Pool } from 'src/ERC721Pool.sol';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.18;

import "@std/console.sol";
import { Maths } from 'src/libraries/internal/Maths.sol';
import { Pool } from 'src/base/Pool.sol';
import { ERC20Pool } from 'src/ERC20Pool.sol';
import { ERC721Pool } from 'src/ERC721Pool.sol';
import { ERC20PoolFactory } from 'src/ERC20PoolFactory.sol';
import { ERC721PoolFactory } from 'src/ERC721PoolFactory.sol';
import { PositionManager } from 'src/PositionManager.sol';
import { RewardsManager } from 'src/RewardsManager.sol';

import { NFTCollateralToken } from '../../utils/Tokens.sol';

import { ERC721PoolRewardsHandler } from './handlers/ERC721PoolRewardsHandler.sol';
import { RewardsInvariants } from './RewardsInvariants.t.sol';

contract ERC721PoolRewardsInvariants is RewardsInvariants {

NFTCollateralToken internal _collateral;
ERC721Pool internal _erc721pool;
ERC721PoolRewardsHandler internal _erc721poolrewardsHandler;

function setUp() public override virtual {

super.setUp();

uint256[] memory tokenIds;
_collateral = new NFTCollateralToken();
_erc20poolFactory = new ERC20PoolFactory(address(_ajna));
_erc20impl = _erc20poolFactory.implementation();
_erc721poolFactory = new ERC721PoolFactory(address(_ajna));
_erc721pool = ERC721Pool(_erc721poolFactory.deployPool(address(_collateral), address(_quote), tokenIds, 0.05 * 10**18));
_erc721impl = _erc721poolFactory.implementation();
_pool = Pool(address(_erc721pool));
_positionManager = new PositionManager(_erc20poolFactory, _erc721poolFactory);
_rewardsManager = new RewardsManager(address(_ajna), _positionManager);

// fund the rewards manager with 100M ajna
_ajna.mint(address(_rewardsManager), 100_000_000 * 1e18);

excludeContract(address(_ajna));
excludeContract(address(_collateral));
excludeContract(address(_quote));
excludeContract(address(_erc20poolFactory));
excludeContract(address(_erc721poolFactory));
excludeContract(address(_erc721pool));
excludeContract(address(_poolInfo));
excludeContract(address(_erc20impl));
excludeContract(address(_erc721impl));
excludeContract(address(_positionManager));
excludeContract(address(_rewardsManager));

_erc721poolrewardsHandler = new ERC721PoolRewardsHandler(
address(_rewardsManager),
address(_positionManager),
address(_erc721pool),
address(_ajna),
address(_quote),
address(_collateral),
address(_poolInfo),
NUM_ACTORS,
address(this)
);

_handler = address(_erc721poolrewardsHandler);
}
}
40 changes: 5 additions & 35 deletions tests/forge/invariants/PositionsAndRewards/RewardsInvariants.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,16 @@
pragma solidity 0.8.18;

import "@std/console.sol";
import { Maths } from 'src/libraries/internal/Maths.sol';
import { RewardsManager } from 'src/RewardsManager.sol';
import { _getEpochInfo } from 'src/RewardsManager.sol';
import { Maths } from 'src/libraries/internal/Maths.sol';
import { RewardsManager, _getEpochInfo } from 'src/RewardsManager.sol';

import { IBaseHandler } from '../interfaces/IBaseHandler.sol';
import { IPositionsAndRewardsHandler } from '../interfaces/IPositionsAndRewardsHandler.sol';
import { RewardsHandler } from './handlers/RewardsHandler.sol';
import { ERC20PoolPositionsInvariants } from './ERC20PoolPositionsInvariants.t.sol';
import { PositionsInvariants } from './PositionsInvariants.sol';

contract RewardsInvariants is ERC20PoolPositionsInvariants {
abstract contract RewardsInvariants is PositionsInvariants {

RewardsManager internal _rewardsManager;
RewardsHandler internal _rewardsHandler;

function setUp() public override virtual {

super.setUp();

_rewardsManager = new RewardsManager(address(_ajna), _positionManager);

// fund the rewards manager with 100M ajna
_ajna.mint(address(_rewardsManager), 100_000_000 * 1e18);

excludeContract(address(_erc20positionHandler));
excludeContract(address(_rewardsManager));

_rewardsHandler = new RewardsHandler(
address(_rewardsManager),
address(_positionManager),
address(_erc20pool),
address(_ajna),
address(_quote),
address(_collateral),
address(_poolInfo),
NUM_ACTORS,
address(this)
);

_handler = address(_rewardsHandler);
}

function invariant_rewards_RW1_RW2() public useCurrentTimestamp {

Expand Down Expand Up @@ -76,7 +46,7 @@ contract RewardsInvariants is ERC20PoolPositionsInvariants {

function invariant_call_summary() public virtual override useCurrentTimestamp {
console.log("\nCall Summary\n");
console.log("--Positions--------");
console.log("--Rewards--------");
console.log("UBRewardsHandler.unstake ", IBaseHandler(_handler).numberOfCalls("UBRewardsHandler.unstake"));
console.log("BRewardsHandler.unstake ", IBaseHandler(_handler).numberOfCalls("BRewardsHandler.unstake"));
console.log("UBRewardsHandler.emergencyUnstake ", IBaseHandler(_handler).numberOfCalls("UBRewardsHandler.emergencyUnstake"));
Expand Down
Loading

0 comments on commit 5e7f5cf

Please sign in to comment.