Skip to content

Commit

Permalink
fix: [RFR-01][RFR-03] unify the meaning of minAmountToConvert
Browse files Browse the repository at this point in the history
Problem: With the evolution of the code, the meaning of the
conversion threshold started to change. As a result, we ended up
comparing the amount out (in tokens), balance of underlying *
oracle price (in dollars), with minAmountToConvert. While in most
cases these values would be close to each other as long as some
stablecoin is used for the threshold, it might be problematic
to set this threshold correctly, considering the potential slippage.

Solution: Expect amountOutMin * base price to be greater than
minAmountToConvert. Adjust the failing test accordingly.
  • Loading branch information
kkirka committed Aug 14, 2023
1 parent 1dbf136 commit db0e468
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 54 deletions.
68 changes: 33 additions & 35 deletions contracts/RiskFund/RiskFund.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.13;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import { AccessControlledV8 } from "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol";
import { ResilientOracleInterface } from "@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol";
import { ComptrollerInterface } from "../ComptrollerInterface.sol";
import { IRiskFund } from "./IRiskFund.sol";
import { ReserveHelpers } from "./ReserveHelpers.sol";
Expand Down Expand Up @@ -260,48 +261,45 @@ contract RiskFund is AccessControlledV8, ExponentialNoError, ReserveHelpers, Max
address[] calldata path
) internal returns (uint256) {
require(amountOutMin != 0, "RiskFund: amountOutMin must be greater than 0 to swap vToken");
require(amountOutMin >= minAmountToConvert, "RiskFund: amountOutMin should be greater than minAmountToConvert");
uint256 totalAmount;

address underlyingAsset = vToken.underlying();
address convertibleBaseAsset_ = convertibleBaseAsset;
uint256 balanceOfUnderlyingAsset = _poolsAssetsReserves[comptroller][underlyingAsset];

ComptrollerViewInterface(comptroller).oracle().updatePrice(address(vToken));

uint256 underlyingAssetPrice = ComptrollerViewInterface(comptroller).oracle().getUnderlyingPrice(
address(vToken)
);
if (balanceOfUnderlyingAsset == 0) {
return 0;
}

if (balanceOfUnderlyingAsset > 0) {
Exp memory oraclePrice = Exp({ mantissa: underlyingAssetPrice });
uint256 amountInUsd = mul_ScalarTruncate(oraclePrice, balanceOfUnderlyingAsset);

if (amountInUsd >= minAmountToConvert) {
assetsReserves[underlyingAsset] -= balanceOfUnderlyingAsset;
_poolsAssetsReserves[comptroller][underlyingAsset] -= balanceOfUnderlyingAsset;

if (underlyingAsset != convertibleBaseAsset_) {
require(path[0] == underlyingAsset, "RiskFund: swap path must start with the underlying asset");
require(
path[path.length - 1] == convertibleBaseAsset_,
"RiskFund: finally path must be convertible base asset"
);
address pancakeSwapRouter_ = pancakeSwapRouter;
IERC20Upgradeable(underlyingAsset).approve(pancakeSwapRouter_, 0);
IERC20Upgradeable(underlyingAsset).approve(pancakeSwapRouter_, balanceOfUnderlyingAsset);
uint256[] memory amounts = IPancakeswapV2Router(pancakeSwapRouter_).swapExactTokensForTokens(
balanceOfUnderlyingAsset,
amountOutMin,
path,
address(this),
block.timestamp
);
totalAmount = amounts[path.length - 1];
} else {
totalAmount = balanceOfUnderlyingAsset;
}
}
ResilientOracleInterface oracle = ComptrollerViewInterface(comptroller).oracle();
oracle.updateAssetPrice(convertibleBaseAsset_);
Exp memory baseAssetPrice = Exp({ mantissa: oracle.getPrice(convertibleBaseAsset_) });
uint256 amountOutMinInUsd = mul_ScalarTruncate(baseAssetPrice, amountOutMin);

require(amountOutMinInUsd >= minAmountToConvert, "RiskFund: minAmountToConvert violated");

assetsReserves[underlyingAsset] -= balanceOfUnderlyingAsset;
_poolsAssetsReserves[comptroller][underlyingAsset] -= balanceOfUnderlyingAsset;

if (underlyingAsset != convertibleBaseAsset_) {
require(path[0] == underlyingAsset, "RiskFund: swap path must start with the underlying asset");
require(
path[path.length - 1] == convertibleBaseAsset_,
"RiskFund: finally path must be convertible base asset"
);
address pancakeSwapRouter_ = pancakeSwapRouter;
IERC20Upgradeable(underlyingAsset).approve(pancakeSwapRouter_, 0);
IERC20Upgradeable(underlyingAsset).approve(pancakeSwapRouter_, balanceOfUnderlyingAsset);
uint256[] memory amounts = IPancakeswapV2Router(pancakeSwapRouter_).swapExactTokensForTokens(
balanceOfUnderlyingAsset,
amountOutMin,
path,
address(this),
block.timestamp
);
totalAmount = amounts[path.length - 1];
} else {
totalAmount = balanceOfUnderlyingAsset;
}

return totalAmount;
Expand Down
39 changes: 20 additions & 19 deletions tests/hardhat/Fork/RiskFund.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,25 +630,26 @@ describe("Risk Fund: Tests", function () {
const riskFundUSDCBal = await USDC.balanceOf(riskFund.address);
expect(riskFundUSDCBal).equal(convertToUnit(9, 18));

const amount = await riskFund.callStatic.swapPoolsAssets(
[vUSDT.address, vUSDC.address, vUSDT2.address, vUSDC2.address, vUSDT3.address],
[
convertToUnit(10, 18),
convertToUnit(10, 18),
convertToUnit(10, 18),
convertToUnit(10, 18),
convertToUnit(10, 18),
],
[
[USDT.address, BUSD.address],
[USDC.address, BUSD.address],
[USDT.address, BUSD.address],
[USDC.address, BUSD.address],
[USDT.address, BUSD.address],
],
deadline,
);
expect(amount).equal("0");
await expect(
riskFund.swapPoolsAssets(
[vUSDT.address, vUSDC.address, vUSDT2.address, vUSDC2.address, vUSDT3.address],
[
convertToUnit(9, 18),
convertToUnit(9, 18),
convertToUnit(9, 18),
convertToUnit(9, 18),
convertToUnit(9, 18),
],
[
[USDT.address, BUSD.address],
[USDC.address, BUSD.address],
[USDT.address, BUSD.address],
[USDC.address, BUSD.address],
[USDT.address, BUSD.address],
],
deadline,
),
).to.be.revertedWith("RiskFund: minAmountToConvert violated");
});

it("Above min threshold amount", async function () {
Expand Down

0 comments on commit db0e468

Please sign in to comment.