diff --git a/test/TestVault01.t.sol b/test/TestVault01.t.sol new file mode 100644 index 0000000..360e938 --- /dev/null +++ b/test/TestVault01.t.sol @@ -0,0 +1,186 @@ +pragma solidity ^0.8.0; + +import {SafeERC20} from + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {console} from "@forge-std/console.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Test} from "@forge-std/Test.sol"; + +import {Vault} from "src/exercises/01/Vault01.sol"; +import {SIP01} from "src/exercises/01/SIP01.sol"; + +contract TestVault01 is Test, SIP01 { + using SafeERC20 for IERC20; + + Vault public vault; + + /// @notice user addresses + address public immutable userA = address(1111); + address public immutable userB = address(2222); + address public immutable userC = address(3333); + + /// @notice token addresses + address public usdc; + address public usdt; + + function setUp() public { + /// set the environment variables + vm.setEnv("DO_RUN", "false"); + vm.setEnv("DO_BUILD", "false"); + vm.setEnv("DO_DEPLOY", "true"); + vm.setEnv("DO_SIMULATE", "false"); + vm.setEnv("DO_PRINT", "false"); + vm.setEnv("DO_VALIDATE", "true"); + + /// setup the proposal + setupProposal(); + + /// run the proposal + deploy(); + + usdc = addresses.getAddress("USDC"); + usdt = addresses.getAddress("USDT"); + vault = Vault(addresses.getAddress("V1_VAULT")); + } + + function testVaultDepositUsdc() public { + uint256 usdcDepositAmount = 1_000e6; + + _vaultDeposit(usdc, address(this), usdcDepositAmount); + } + + function testMultipleUsersDepositUsdc() public { + uint256 usdcDepositAmount = 1_000e6; + + _vaultDeposit(usdc, userA, usdcDepositAmount); + _vaultDeposit(usdc, userB, usdcDepositAmount); + _vaultDeposit(usdc, userC, usdcDepositAmount); + } + + function testVaultWithdrawalUsdc() public { + uint256 usdcDepositAmount = 1_000e6; + + _vaultDeposit(usdc, address(this), usdcDepositAmount); + + vault.withdraw(usdc, usdcDepositAmount); + + assertEq( + vault.balanceOf(address(this)), + 0, + "vault usdc balance not 0" + ); + assertEq( + vault.totalSupplied(), 0, "vault total supplied not 0" + ); + assertEq( + IERC20(usdc).balanceOf(address(this)), + usdcDepositAmount, + "user's usdc balance not increased" + ); + } + + function testVaultDepositUsdt() public { + uint256 usdtDepositAmount = 1_000e8; + + _vaultDeposit(usdt, address(this), usdtDepositAmount); + } + + function testVaultWithdrawalUsdt() public { + uint256 usdtDepositAmount = 1_000e8; + + _vaultDeposit(usdt, address(this), usdtDepositAmount); + vault.withdraw(usdt, usdtDepositAmount); + + assertEq( + vault.balanceOf(address(this)), + 0, + "vault usdt balance not 0" + ); + assertEq( + vault.totalSupplied(), 0, "vault total supplied not 0" + ); + assertEq( + IERC20(usdt).balanceOf(address(this)), + usdtDepositAmount, + "user's usdt balance not increased" + ); + } + + function testSwapTwoUsers() public { + uint256 usdcDepositAmount = 1_000e6; + uint256 usdtDepositAmount = 1_000e8; + + _vaultDeposit(usdc, userA, usdcDepositAmount); + _vaultDeposit(usdt, userB, usdtDepositAmount); + + vm.prank(userA); + vault.withdraw(usdt, usdcDepositAmount); + assertEq( + IERC20(usdt).balanceOf(userA), + usdcDepositAmount, + "userA usdt balance not increased" + ); + + vm.prank(userB); + vault.withdraw(usdc, usdcDepositAmount); + assertEq( + IERC20(usdc).balanceOf(userB), + usdcDepositAmount, + "userB usdc balance not increased" + ); + assertEq( + IERC20(usdt).balanceOf(userA), + usdcDepositAmount, + "userB usdt balance remains unchanged" + ); + } + + function _vaultDeposit( + address token, + address sender, + uint256 amount + ) private { + uint256 startingTotalSupplied = vault.totalSupplied(); + uint256 startingTotalBalance = + IERC20(token).balanceOf(address(vault)); + uint256 startingUserBalance = vault.balanceOf(sender); + + deal(token, sender, amount); + + vm.startPrank(sender); + IERC20(token).safeIncreaseAllowance( + addresses.getAddress("V1_VAULT"), amount + ); + + /// this executes 3 state transitions: + /// 1. deposit dai into the vault + /// 2. increase the user's balance in the vault + /// 3. increase the total supplied amount in the vault + vault.deposit(token, amount); + vm.stopPrank(); + + uint256 normalizedAmount = + vault.getNormalizedAmount(token, amount); + + assertEq( + vault.balanceOf(sender), + startingUserBalance + normalizedAmount, + "user vault balance not increased" + ); + assertEq( + vault.totalSupplied(), + startingTotalSupplied + normalizedAmount, + "vault total supplied not increased by deposited amount" + ); + assertEq( + IERC20(token).balanceOf(address(vault)), + startingTotalBalance + amount, + "token balance not increased" + ); + } +} + +interface USDT { + function approve(address, uint256) external; + function transferFrom(address, address, uint256) external; +} diff --git a/test/TestVault02.t.sol b/test/TestVault02.t.sol index 6ca5bf3..3e75d90 100644 --- a/test/TestVault02.t.sol +++ b/test/TestVault02.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {console} from "@forge-std/console.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Test} from "@forge-std/Test.sol"; @@ -79,10 +78,6 @@ contract TestVault02 is Test, SIP02 { addresses.getAddress("V2_VAULT"), usdtDepositAmount ); - /// this executes 3 state transitions: - /// 1. deposit dai into the vault - /// 2. increase the user's balance in the vault - /// 3. increase the total supplied amount in the vault vault.deposit(usdt, usdtDepositAmount); assertEq( @@ -141,6 +136,11 @@ contract TestVault02 is Test, SIP02 { vm.prank(userB); vault.withdraw(usdc, usdcDepositAmount); + assertEq( + IERC20(usdc).balanceOf(userB), + usdcDepositAmount, + "userB usdc balance not increased" + ); assertEq( IERC20(usdt).balanceOf(userA), usdcDepositAmount, diff --git a/test/TestVault03.t.sol b/test/TestVault03.t.sol new file mode 100644 index 0000000..7a60912 --- /dev/null +++ b/test/TestVault03.t.sol @@ -0,0 +1,211 @@ +pragma solidity ^0.8.0; + +import {SafeERC20} from + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Test, console} from "@forge-std/Test.sol"; + +import {SIP03} from "src/exercises/03/SIP03.sol"; +import {Vault} from "src/exercises/03/Vault03.sol"; + +contract TestVault03 is Test, SIP03 { + using SafeERC20 for IERC20; + + Vault public vault; + + /// @notice user addresses + address public immutable userA = address(1111); + address public immutable userB = address(2222); + address public immutable userC = address(3333); + + /// @notice token addresses + address public dai; + address public usdc; + address public usdt; + + function _loadUsers() private { + address[] memory users = new address[](3); + users[0] = userA; + users[1] = userB; + users[2] = userC; + + for (uint256 i = 0; i < users.length; i++) { + uint256 daiDepositAmount = 1_000e18; + uint256 usdtDepositAmount = 1_000e8; + uint256 usdcDepositAmount = 1_000e6; + + _vaultDeposit(dai, users[i], daiDepositAmount); + _vaultDeposit(usdc, users[i], usdcDepositAmount); + _vaultDeposit(usdt, users[i], usdtDepositAmount); + } + } + + function setUp() public { + /// set the environment variables + vm.setEnv("DO_RUN", "false"); + vm.setEnv("DO_BUILD", "false"); + vm.setEnv("DO_DEPLOY", "true"); + vm.setEnv("DO_SIMULATE", "false"); + vm.setEnv("DO_PRINT", "false"); + vm.setEnv("DO_VALIDATE", "false"); + + setupProposal(); + + deploy(); + + dai = addresses.getAddress("DAI"); + usdc = addresses.getAddress("USDC"); + usdt = addresses.getAddress("USDT"); + vault = Vault(addresses.getAddress("VAULT_PROXY")); + + vm.prank(vault.owner()); + vault.setMaxSupply(100_000_000e18); + + /// load data into newly deployed contract + _loadUsers(); + } + + function testSetup() public view { + validate(); + assertEq( + vault.maxSupply(), 100_000_000e18, "max supply not set" + ); + assertEq( + vault.totalSupplied(), + ( + vault.getNormalizedAmount(dai, 1_000e18) + + vault.getNormalizedAmount(usdc, 1_000e6) + + vault.getNormalizedAmount(usdt, 1_000e8) + ) * 3, + "total supplied not set" + ); + } + + function testVaultDepositDai() public { + uint256 daiDepositAmount = 1_000e18; + + _vaultDeposit(dai, address(this), daiDepositAmount); + } + + function testVaultWithdrawalDai() public { + uint256 daiDepositAmount = 1_000e18; + + _vaultDeposit(dai, address(this), daiDepositAmount); + uint256 startingVaultBalance = vault.balanceOf(address(this)); + uint256 startingTotalSupplied = vault.totalSupplied(); + + vault.withdraw(dai, daiDepositAmount); + + assertEq( + vault.balanceOf(address(this)), + startingVaultBalance - daiDepositAmount, + "vault dai balance not 0" + ); + assertEq( + vault.totalSupplied(), + startingTotalSupplied - daiDepositAmount, + "vault total supplied not 0" + ); + assertEq( + IERC20(dai).balanceOf(address(this)), + daiDepositAmount, + "user's dai balance not increased" + ); + } + + function testVaultWithdrawUSDC() public { + uint256 usdcDepositAmount = 1_000e6; + + _vaultDeposit(usdc, address(this), usdcDepositAmount); + uint256 startingVaultBalance = vault.balanceOf(address(this)); + uint256 startingTotalSupplied = vault.totalSupplied(); + + vault.withdraw(usdc, usdcDepositAmount); + + assertEq( + vault.balanceOf(address(this)), + startingVaultBalance + - vault.getNormalizedAmount(usdc, usdcDepositAmount), + "vault usdc balance not 0" + ); + assertEq( + vault.totalSupplied(), + startingTotalSupplied + - vault.getNormalizedAmount(usdc, usdcDepositAmount), + "vault total supplied not 0" + ); + assertEq( + IERC20(usdc).balanceOf(address(this)), + usdcDepositAmount, + "user's usdc balance not increased" + ); + } + + function testVaultWithdrawUSDT() public { + uint256 usdtDepositAmount = 1_000e8; + + _vaultDeposit(usdt, address(this), usdtDepositAmount); + uint256 startingVaultBalance = vault.balanceOf(address(this)); + uint256 startingTotalSupplied = vault.totalSupplied(); + + vault.withdraw(usdt, usdtDepositAmount); + + assertEq( + vault.balanceOf(address(this)), + startingVaultBalance + - vault.getNormalizedAmount(usdt, usdtDepositAmount), + "vault usdt balance not 0" + ); + assertEq( + vault.totalSupplied(), + startingTotalSupplied + - vault.getNormalizedAmount(usdt, usdtDepositAmount), + "vault total supplied not 0" + ); + assertEq( + IERC20(usdt).balanceOf(address(this)), + usdtDepositAmount, + "user's usdt balance not increased" + ); + } + + function _vaultDeposit( + address token, + address sender, + uint256 amount + ) private { + uint256 startingTotalSupplied = vault.totalSupplied(); + uint256 startingTotalBalance = + IERC20(token).balanceOf(address(vault)); + uint256 startingUserBalance = vault.balanceOf(sender); + + deal(token, sender, amount); + + vm.startPrank(sender); + IERC20(token).safeIncreaseAllowance( + addresses.getAddress("VAULT_PROXY"), amount + ); + + vault.deposit(token, amount); + vm.stopPrank(); + + uint256 normalizedAmount = + vault.getNormalizedAmount(token, amount); + + assertEq( + vault.balanceOf(sender), + startingUserBalance + normalizedAmount, + "user vault balance not increased" + ); + assertEq( + vault.totalSupplied(), + startingTotalSupplied + normalizedAmount, + "vault total supplied not increased by deposited amount" + ); + assertEq( + IERC20(token).balanceOf(address(vault)), + startingTotalBalance + amount, + "token balance not increased" + ); + } +} diff --git a/test/TestVault04.t.sol b/test/TestVault04.t.sol index 85966c8..5936333 100644 --- a/test/TestVault04.t.sol +++ b/test/TestVault04.t.sol @@ -4,6 +4,10 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Test, console} from "@forge-std/Test.sol"; +import {ERC1967Utils} from + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import {ProxyAdmin} from + "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import {SIP03} from "src/exercises/03/SIP03.sol"; import {SIP04} from "src/exercises/04/SIP04.sol"; @@ -24,23 +28,6 @@ contract TestVault04 is Test, SIP04 { address public usdc; address public usdt; - function _loadUsers() private { - address[] memory users = new address[](3); - users[0] = userA; - users[1] = userB; - users[2] = userC; - - for (uint256 i = 0; i < users.length; i++) { - uint256 daiDepositAmount = 1_000e18; - uint256 usdtDepositAmount = 1_000e8; - uint256 usdcDepositAmount = 1_000e6; - - _vaultDeposit(dai, users[i], daiDepositAmount); - _vaultDeposit(usdc, users[i], usdcDepositAmount); - _vaultDeposit(usdt, users[i], usdtDepositAmount); - } - } - function setUp() public { /// set the environment variables vm.setEnv("DO_RUN", "false"); @@ -65,9 +52,6 @@ contract TestVault04 is Test, SIP04 { vm.prank(vault.owner()); vault.setMaxSupply(100_000_000e18); - /// load data into newly deployed contract - _loadUsers(); - /// setup the proposal setupProposal(); @@ -82,101 +66,19 @@ contract TestVault04 is Test, SIP04 { simulate(); } - function testSetup() public view { - assertTrue( - vault.authorizedToken(address(dai)), "Dai not whitelisted" - ); - assertTrue( - vault.authorizedToken(address(usdc)), - "Usdc not whitelisted" - ); - assertTrue( - vault.authorizedToken(address(usdt)), - "Usdt not whitelisted" - ); - } - - function testVaultDepositDai() public { - uint256 daiDepositAmount = 1_000e18; - - _vaultDeposit(dai, address(this), daiDepositAmount); - } - - function testVaultWithdrawalDai() public { - uint256 daiDepositAmount = 1_000e18; - - _vaultDeposit(dai, address(this), daiDepositAmount); - uint256 startingVaultBalance = vault.balanceOf(address(this)); - uint256 startingTotalSupplied = vault.totalSupplied(); - - vault.withdraw(dai, daiDepositAmount); - - assertEq( - vault.balanceOf(address(this)), - startingVaultBalance - daiDepositAmount, - "vault dai balance not 0" - ); - assertEq( - vault.totalSupplied(), - startingTotalSupplied - daiDepositAmount, - "vault total supplied not 0" - ); + function testValidate() public view { assertEq( - IERC20(dai).balanceOf(address(this)), - daiDepositAmount, - "user's dai balance not increased" + vault.maxSupply(), 1_000_000e18, "max supply not set" ); - } - function testWithdrawAlreadyDepositedUSDC() public { - uint256 usdcDepositAmount = 1_000e6; + bytes32 adminSlot = + vm.load(address(vault), ERC1967Utils.ADMIN_SLOT); + address proxyAdmin = address(uint160(uint256(adminSlot))); - _vaultDeposit(usdc, address(this), usdcDepositAmount); - - vault.withdraw(usdc, usdcDepositAmount); - } - - function _vaultDeposit( - address token, - address sender, - uint256 amount - ) private { - uint256 startingTotalSupplied = vault.totalSupplied(); - uint256 startingTotalBalance = - IERC20(token).balanceOf(address(vault)); - uint256 startingUserBalance = vault.balanceOf(sender); - - deal(token, sender, amount); - - vm.startPrank(sender); - IERC20(token).safeIncreaseAllowance( - addresses.getAddress("VAULT_PROXY"), amount - ); - - /// this executes 3 state transitions: - /// 1. deposit dai into the vault - /// 2. increase the user's balance in the vault - /// 3. increase the total supplied amount in the vault - vault.deposit(token, amount); - vm.stopPrank(); - - uint256 normalizedAmount = - vault.getNormalizedAmount(token, amount); - - assertEq( - vault.balanceOf(sender), - startingUserBalance + normalizedAmount, - "user vault balance not increased" - ); - assertEq( - vault.totalSupplied(), - startingTotalSupplied + normalizedAmount, - "vault total supplied not increased by deposited amount" - ); assertEq( - IERC20(token).balanceOf(address(vault)), - startingTotalBalance + amount, - "token balance not increased" + ProxyAdmin(proxyAdmin).owner(), + addresses.getAddress("COMPOUND_TIMELOCK_BRAVO"), + "owner not set" ); } }