LendingPool:
function deposit(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
...
@> uint256 mintedAmount = ReserveLibrary.deposit(reserve, rateData, amount, msg.sender);
@> _rebalanceLiquidity();
emit Deposit(msg.sender, amount, mintedAmount);
}
ReserveLibrary:
function deposit(ReserveData storage reserve,ReserveRateData storage rateData,uint256 amount,address depositor) internal returns (uint256 amountMinted) {
...
@> IERC20(reserve.reserveAssetAddress).safeTransferFrom(
msg.sender,
reserve.reserveRTokenAddress,
amount
);
LendingPool:
function _rebalanceLiquidity() internal {
if (address(curveVault) == address(0)) {
return;
}
uint256 totalDeposits = reserve.totalLiquidity;
uint256 desiredBuffer = totalDeposits.percentMul(liquidityBufferRatio);
uint256 currentBuffer = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
if (currentBuffer > desiredBuffer) {
uint256 excess = currentBuffer - desiredBuffer;
@> _depositIntoVault(excess);
}
function _depositIntoVault(uint256 amount) internal {
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}
The problem is that the curve vault will try to transfer from the Lending pool, but this contract doesn't hold any tokens, as they are directly deposited from the depositor to the RToken
contract. Hence this will cause the function to revert everytime.
pragma solidity ^0.8.19;
import {Test, console2} from "../lib/forge-std/src/Test.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {LendingPool} from "../contracts/core/pools/LendingPool/LendingPool.sol";
import {ILendingPool} from "../contracts/interfaces/core/pools/LendingPool/ILendingPool.sol";
import {RToken} from "../contracts/core/tokens/RToken.sol";
import {DebtToken} from "../contracts/core/tokens/DebtToken.sol";
import {RAACHousePrices} from "../contracts/core/primitives/RAACHousePrices.sol";
import {RAACNFT} from "../contracts/core/tokens/RAACNFT.sol";
import {IRAACNFT} from "../contracts/interfaces/core/tokens/IRAACNFT.sol";
import {WadRayMath} from "../contracts/libraries/math/WadRayMath.sol";
import {ICurveCrvUSDVault} from "../contracts/interfaces/curve/ICurveCrvUSDVault.sol";
contract CrvUSD is IERC20, ERC20 {
constructor() ERC20("crvUSD", "CRVUSD") {}
function mint(address to, uint256 amount) public {
_mint(to, amount);
}
}
contract MockCurveVault is ICurveCrvUSDVault {
CrvUSD crvUSD;
constructor(CrvUSD _crvUSD) {
crvUSD = _crvUSD;
}
function deposit(uint256 assets, address receiver) external returns (uint256 shares) {
crvUSD.transferFrom(msg.sender, address(this), assets);
}
function withdraw(uint256 assets, address receiver, address owner, uint256 maxLoss, address[] calldata strategies) external returns (uint256 shares) {}
function asset() external view returns (address) {}
function totalAssets() external view returns (uint256) {}
function pricePerShare() external view returns (uint256) {}
function totalIdle() external view returns (uint256) {}
function totalDebt() external view returns (uint256) {}
function isShutdown() external view returns (bool) {}
}
contract Tester is Test {
LendingPool lendingPool;
CrvUSD crvUSD;
RToken rToken;
DebtToken debtToken;
RAACHousePrices housePrices;
RAACNFT nft;
MockCurveVault vault;
uint256 initialPrimeRate = 1e26;
address owner = makeAddr("owner");
address bob = makeAddr("bob");
address lender = makeAddr("lender");
function setUp() external {
vm.startPrank(owner);
crvUSD = new CrvUSD();
vault = new MockCurveVault(crvUSD);
rToken = new RToken("RToken", "RT", owner, address(crvUSD));
debtToken = new DebtToken("DebtToken", "DT", owner);
housePrices = new RAACHousePrices(owner);
nft = new RAACNFT(address(crvUSD), address(housePrices), owner);
lendingPool = new LendingPool(
address(crvUSD),
address(rToken),
address(debtToken),
address(nft),
address(housePrices),
initialPrimeRate
);
housePrices.setOracle(owner);
housePrices.setHousePrice(1, 1000e18);
debtToken.setReservePool(address(lendingPool));
rToken.setReservePool(address(lendingPool));
lendingPool.setCurveVault(address(vault));
vm.stopPrank();
}
function testX() public {
vm.startPrank(lender);
crvUSD.mint(lender, 8000e18);
crvUSD.approve(address(lendingPool), type(uint256).max);
vm.expectRevert();
lendingPool.deposit(1000e18);
vm.stopPrank();
}
}