Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LEND-184/Test stealth donation #252

Merged
merged 4 commits into from
Aug 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions test/unit/evault/modules/Vault/deposit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {IEVC} from "ethereum-vault-connector/interfaces/IEthereumVaultConnector.

import "../../../../../src/EVault/shared/types/Types.sol";

import "forge-std/Test.sol";

contract VaultTest_Deposit is EVaultTestBase {
using TypesLib for uint256;

Expand All @@ -32,11 +34,11 @@ contract VaultTest_Deposit is EVaultTestBase {
user = vm.addr(userPK);
user1 = makeAddr("user1");

assetTST.mint(user1, type(uint256).max);
assetTST.mint(user1, type(uint256).max / 4);
hoax(user1);
assetTST.approve(address(eTST), type(uint256).max);

assetTST.mint(user, type(uint256).max);
assetTST.mint(user, type(uint256).max / 4);
startHoax(user);
assetTST.approve(address(eTST), type(uint256).max);
}
Expand Down Expand Up @@ -368,4 +370,63 @@ contract VaultTest_Deposit is EVaultTestBase {
assertEq(eTST.totalSupply(), 2 * amount);
assertEq(eTST.totalAssets(), 2 * amount);
}

function test_deposit_stealthDonation() public {
startHoax(address(this));
oracle.setPrice(address(assetTST), unitOfAccount, 1e18);
oracle.setPrice(address(assetTST2), unitOfAccount, 1e18);
eTST.setLTV(address(eTST2), 0.9e4, 0.9e4, 0);

startHoax(user1);
assetTST.mint(user1, 10e18);
assetTST.approve(address(eTST), type(uint256).max);
assetTST2.mint(user1, 100e18);
assetTST2.approve(address(eTST2), type(uint256).max);
eTST2.deposit(10e18, user1);
evc.enableController(user1, address(eTST));
evc.enableCollateral(user1, address(eTST2));

// attacker deposits 1 wei from one account
startHoax(user);
eTST.deposit(1, user);

// borrows it from a second for 1 second
startHoax(user1);
eTST.borrow(1, user1);
skip(1);

// 1 wei of debt accrued
assertEq(eTST.debtOf(user1), 2);
eTST.repay(type(uint256).max, user1);
eTST.disableController();

// and exchange rate is pushed above 1
assertEq(1.000000999999e18, eTST.convertToAssets(1e18)); // ~= 1.000001

assertEq(eTST.totalAssets(), 2); // 1 deposited + 1 interest repaid
assertEq(eTST.cash(), 2);
assertEq(eTST.totalSupply(), 1); // 1 deposited initially

// in a loop deposit max assets to create 1 share but not enough for 2. The rounding remainder is a stealth
// donation
for (uint256 i; i < 1000; i++) {
eTST.deposit(2, user1);
// 2 were deposited, but they round down to 1 share
assertEq(eTST.balanceOf(user1), 1);
// which is redeemable for 1 asset, the rest is donated
assertEq(eTST.maxWithdraw(user1), 1);

// reset account
eTST.withdraw(1, user1, user1);
assertEq(eTST.balanceOf(user1), 0);
}

// after 1000 iterations, 1000 assets were stealth donated
assertEq(eTST.totalAssets(), 1002);
assertEq(eTST.cash(), 1002);
assertEq(eTST.totalSupply(), 1);

// it will take 1e6 loops to reach exchange rate of 2
assertEq(1.001000998999001e18, eTST.convertToAssets(1e18)); // ~= 1.001
}
}
Loading