Users are able to deposit/donate/add liquidity with any small amount of tokens they want, but for some small amounts they are not able to withdraw them later.
Users have no restriction to deposit small amounts but they are unwithdrawable later, resulting in loss of funds.
import { expect } from "chai";
import hre, { ethers } from "hardhat";
const { parseUnits, toBeHex } = ethers;
import { mine, loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import {
AaveDIVAWrapper,
IAave,
IDIVA,
MockERC20,
ERC20,
WToken,
} from "../typechain-types";
import {
SetupOutput,
CreateContingentPoolParams,
AddLiquidityParams,
RemoveLiquidityParams,
SetupWithPoolResult,
SetupWithConfirmedPoolResult,
} from "../constants/types";
import { DIVA_ADDRESS, AAVE_ADDRESS } from "../utils/addresses";
import { getExpiryTime, getLastTimestamp } from "../utils/blocktime";
import {
getPoolIdFromAaveDIVAWrapperEvent,
getPoolIdFromDIVAEvent,
} from "../utils/eventUtils";
import { calcTotalDIVAFee } from "../utils/diva";
import { NETWORK_CONFIGS } from "../utils/addresses";
import { NETWORK } from "../hardhat.config";
const network = NETWORK;
const networkConfig = NETWORK_CONFIGS[network];
const collateralToken = networkConfig.collateralTokens.USDT.address;
const collateralTokenHolder = networkConfig.collateralTokens.USDT.holder;
const collateralTokenUnsupported = networkConfig.unsupportedToken.address;
const collateralToken2 = networkConfig.collateralTokens.USDC.address;
const divaAddress = DIVA_ADDRESS[network];
const aaveAddress = AAVE_ADDRESS[network];
describe("AaveDIVAWrapper Issues Test", function () {
async function setup(): Promise<SetupOutput> {
const [owner, acc2, acc3, dataProvider] = await ethers.getSigners();
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [collateralTokenHolder],
});
const impersonatedSigner = await ethers.getSigner(collateralTokenHolder);
const collateralTokenContract: ERC20 = await ethers.getContractAt(
"ERC20",
collateralToken,
);
const collateralTokenDecimals = Number(
await collateralTokenContract.decimals(),
);
const balance = await collateralTokenContract.balanceOf(
impersonatedSigner.address,
);
expect(balance).to.be.gt(parseUnits("1000", collateralTokenDecimals));
const dummyTokenDecimals = 18;
const dummyTokenContract: MockERC20 = await ethers.deployContract(
"MockERC20",
[
"DummyToken",
"DT",
ethers.parseUnits("10000", dummyTokenDecimals),
owner.address,
dummyTokenDecimals,
0,
],
);
await dummyTokenContract.waitForDeployment();
const aaveDIVAWrapper: AaveDIVAWrapper = await ethers.deployContract(
"AaveDIVAWrapper",
[divaAddress, aaveAddress, owner.address],
);
await aaveDIVAWrapper.waitForDeployment();
const diva: IDIVA = await ethers.getContractAt("IDIVA", divaAddress);
const aave: IAave = await ethers.getContractAt("IAave", aaveAddress);
await collateralTokenContract
.connect(impersonatedSigner)
.approve(aaveDIVAWrapper.target, ethers.MaxUint256);
await collateralTokenContract
.connect(impersonatedSigner)
.approve(diva.target, ethers.MaxUint256);
const createContingentPoolParams: CreateContingentPoolParams = {
referenceAsset: "BTC/USD",
expiryTime: await getExpiryTime(60 * 60 * 2),
floor: parseUnits("100"),
inflection: parseUnits("150"),
cap: parseUnits("200"),
gradient: parseUnits("0.5", collateralTokenDecimals),
collateralAmount: 100,
collateralToken: collateralToken,
dataProvider: dataProvider.address,
capacity: ethers.MaxUint256,
longRecipient: impersonatedSigner.address,
shortRecipient: impersonatedSigner.address,
permissionedERC721Token: ethers.ZeroAddress,
};
return {
dummyTokenContract,
dummyTokenDecimals,
owner,
acc2,
acc3,
dataProvider,
impersonatedSigner,
collateralTokenContract,
collateralTokenDecimals,
aaveDIVAWrapper,
aave,
diva,
createContingentPoolParams,
};
}
async function setupWithPool(): Promise<SetupWithPoolResult> {
const s: SetupOutput = await loadFixture(setup);
await s.aaveDIVAWrapper
.connect(s.owner)
.registerCollateralToken(collateralToken);
const wTokenAddress: string =
await s.aaveDIVAWrapper.getWToken(collateralToken);
const wTokenContract: WToken = await ethers.getContractAt(
"WToken",
wTokenAddress,
);
const aTokenAddress: string =
await s.aaveDIVAWrapper.getAToken(collateralToken);
const aTokenContract: ERC20 = await ethers.getContractAt(
"IERC20",
aTokenAddress,
);
await hre.network.provider.send("hardhat_setBalance", [
s.impersonatedSigner.address,
toBeHex(parseUnits("10", 18)),
]);
await s.aaveDIVAWrapper
.connect(s.impersonatedSigner)
.createContingentPool(s.createContingentPoolParams);
const poolId: string = await getPoolIdFromAaveDIVAWrapperEvent(
s.aaveDIVAWrapper,
);
const poolParams: IDIVA.PoolStructOutput =
await s.diva.getPoolParameters(poolId);
const shortTokenContract: ERC20 = await ethers.getContractAt(
"ERC20",
poolParams.shortToken,
);
const longTokenContract: ERC20 = await ethers.getContractAt(
"ERC20",
poolParams.longToken,
);
await shortTokenContract
.connect(s.impersonatedSigner)
.approve(s.aaveDIVAWrapper.target, ethers.MaxUint256);
await longTokenContract
.connect(s.impersonatedSigner)
.approve(s.aaveDIVAWrapper.target, ethers.MaxUint256);
const r: RemoveLiquidityParams = {
poolId: poolId,
positionTokenAmount: 99,
recipient: s.impersonatedSigner.address,
};
const a: AddLiquidityParams = {
poolId: poolId,
collateralAmount: parseUnits("10", s.collateralTokenDecimals),
longRecipient: s.impersonatedSigner.address,
shortRecipient: s.impersonatedSigner.address,
};
const divaFees = await calcTotalDIVAFee(
s.diva,
poolParams,
BigInt(r.positionTokenAmount),
s.collateralTokenDecimals,
);
expect(r.positionTokenAmount).to.be.lt(
s.createContingentPoolParams.collateralAmount,
);
return {
s,
wTokenContract,
wTokenAddress,
aTokenContract,
aTokenAddress,
poolId,
poolParams,
shortTokenContract,
longTokenContract,
r,
divaFees,
a,
};
}
describe("removeLiquidity", async () => {
let s: SetupOutput;
let wTokenContract: WToken;
let aTokenContract: ERC20;
let shortTokenContract: ERC20;
let longTokenContract: ERC20;
let r: RemoveLiquidityParams;
let divaFees: bigint;
beforeEach(async () => {
({
s,
wTokenContract,
aTokenContract,
shortTokenContract,
longTokenContract,
r,
divaFees,
} = await setupWithPool());
expect(r.positionTokenAmount).to.be.gt(0);
expect(r.positionTokenAmount).to.be.lt(
s.createContingentPoolParams.collateralAmount,
);
});
it.only("Should revert", async () => {
await s.aaveDIVAWrapper
.connect(s.impersonatedSigner)
.removeLiquidity(r.poolId, r.positionTokenAmount, r.recipient);
});
});
});
The code used is very similar to the already existing test file, but with other amounts of depositing and removing. You can see the changes made at lines 128
and 217
. Deposits 100
tokens and tries to withdraw 99
.
Create a minimum of how many tokens a user can deposit.