From 662a4e340e1009d9373ea85c6ff807257a0b47c8 Mon Sep 17 00:00:00 2001 From: iamsahu Date: Mon, 20 Feb 2023 16:00:43 +0530 Subject: [PATCH 1/4] feat: working tests --- .../contracts/test/variable/Fixture.sol | 57 ++++++++++++------- .../contracts/test/variable/FixtureStates.sol | 2 - .../contracts/test/variable/VRLadle.t.sol | 19 ++++--- .../foundry/contracts/variable/VRCauldron.sol | 11 ++-- 4 files changed, 53 insertions(+), 36 deletions(-) diff --git a/packages/foundry/contracts/test/variable/Fixture.sol b/packages/foundry/contracts/test/variable/Fixture.sol index aeeecf6e..e09ddaee 100644 --- a/packages/foundry/contracts/test/variable/Fixture.sol +++ b/packages/foundry/contracts/test/variable/Fixture.sol @@ -35,9 +35,11 @@ import "@yield-protocol/utils-v2/contracts/math/WMul.sol"; using CastU256I128 for uint256; using CastU256I256 for uint256; using WMul for uint256; + abstract contract Fixture is Test, TestConstants, TestExtensions { address public admin = makeAddr("admin"); address public user = makeAddr("user"); + address public immutable timelock; VRCauldron public cauldron; VRLadle public ladle; Witch public witch; @@ -80,10 +82,21 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { uint256 public ART = WAD; uint256 public FEE = 1000; uint128 public unit; + + address USDC_JOIN = address(0x0d9A1A773be5a83eEbda23bf98efB8585C3ae4f4); + address DAI_JOIN = address(0x4fE92119CDf873Cf8826F4E6EcfD4E578E3D44Dc); + address WETH_JOIN = address(0x3bDb887Dc46ec0E964Df89fFE2980db0121f0fD0); + + constructor(){ + timelock = addresses[MAINNET][TIMELOCK]; + } + function setUp() public virtual { - usdc = new USDCMock(); - weth = new WETH9Mock(); - dai = new DAIMock(); + vm.createSelectFork(MAINNET, 16668354); + + usdc = USDCMock(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); + weth = WETH9Mock(payable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + dai = DAIMock(0x6B175474E89094C44Da98b954EedeAC495271d0F); base = new ERC20Mock("Base", "BASE"); otherERC20 = new ERC20Mock("Other ERC20", "OTHERERC20"); @@ -93,13 +106,23 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { IWETH9(address(weth)) ); witch = new Witch(ICauldron(address(cauldron)), ILadle(address(ladle))); - restrictedERC20Mock = new RestrictedERC20Mock("Restricted", "RESTRICTED"); - usdcJoin = new FlashJoin(address(usdc)); - wethJoin = new FlashJoin(address(weth)); - daiJoin = new FlashJoin(address(dai)); + usdcJoin = FlashJoin(USDC_JOIN); + wethJoin = FlashJoin(WETH_JOIN); + daiJoin = FlashJoin(DAI_JOIN); + + bytes4 role = 0x00000000; + vm.startPrank(timelock); + AccessControl access = AccessControl(address(usdcJoin)); + access.grantRole(role, address(this)); + access = AccessControl(address(wethJoin)); + access.grantRole(role, address(this)); + access = AccessControl(address(daiJoin)); + access.grantRole(role, address(this)); + vm.stopPrank(); + baseJoin = new FlashJoin(address(base)); setUpOracles(); @@ -144,19 +167,16 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { baseAggregator = new ChainlinkAggregatorV3Mock(); baseAggregator.set(1e18 / 2); - spotOracle = new ChainlinkMultiOracle(); + spotOracle = ChainlinkMultiOracle(0xcDCe5C87f691058B61f3A65913f1a3cBCbAd9F52); + + bytes4 role = 0x00000000; + AccessControl access = AccessControl(address(spotOracle)); + vm.prank(timelock); spotOracle.grantRole( ChainlinkMultiOracle.setSource.selector, address(this) ); - spotOracle.setSource( - ETH, - IERC20Metadata(address(weth)), - usdcId, - IERC20Metadata(address(usdc)), - address(usdcAggregator) - ); spotOracle.setSource( ETH, IERC20Metadata(address(weth)), @@ -164,13 +184,6 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { IERC20Metadata(address(base)), address(ethAggregator) ); - spotOracle.setSource( - ETH, - IERC20Metadata(address(weth)), - daiId, - IERC20Metadata(address(dai)), - address(daiAggregator) - ); } // ----------------- Permissions ----------------- // diff --git a/packages/foundry/contracts/test/variable/FixtureStates.sol b/packages/foundry/contracts/test/variable/FixtureStates.sol index c9ede09b..51f34b7e 100644 --- a/packages/foundry/contracts/test/variable/FixtureStates.sol +++ b/packages/foundry/contracts/test/variable/FixtureStates.sol @@ -145,12 +145,10 @@ abstract contract ETHVaultPouredAndDebtState is ETHVaultPouredState { } abstract contract VYTokenZeroState is ZeroState { - address public timelock; FlashBorrower public borrower; function setUp() public virtual override { super.setUp(); - timelock = address(1); vyToken.grantRole(VYToken.point.selector, address(timelock)); vyToken.grantRole(VYToken.mint.selector, address(this)); vyToken.grantRole(VYToken.deposit.selector, address(this)); diff --git a/packages/foundry/contracts/test/variable/VRLadle.t.sol b/packages/foundry/contracts/test/variable/VRLadle.t.sol index 3c2e0200..61d670ee 100644 --- a/packages/foundry/contracts/test/variable/VRLadle.t.sol +++ b/packages/foundry/contracts/test/variable/VRLadle.t.sol @@ -583,12 +583,13 @@ contract TokensAndIntegrationTests is WithTokensAndIntegrationState { contract ETHTests is ETHVaultBuiltState { function testCanTransferETHThenPour() public { console.log("can transfer eth and then pour"); + uint before = weth.balanceOf(address(ladle.joins(wethId))); ladle.joinEther{value: INK}(wethId); vm.expectEmit(true, true, true, true); emit VaultPoured(ethVaultId, baseId, wethId, INK.i128(), 0); ladle.pour(ethVaultId, address(this), INK.i128(), 0); - assertEq(weth.balanceOf(address(ladle.joins(wethId))), INK); + assertEq(weth.balanceOf(address(ladle.joins(wethId))) - before, INK); (uint128 art, uint128 ink) = cauldron.balances(ethVaultId); assertEq(ink, INK); assertEq(art, 0); @@ -596,7 +597,7 @@ contract ETHTests is ETHVaultBuiltState { function testPourWithoutSendingETHReverts() public { console.log("pour without sending eth reverts"); - weth.approve(address(wethJoin), 0 ); + weth.approve(address(wethJoin), 0); vm.expectRevert("ERC20: Insufficient approval"); ladle.pour(ethVaultId, address(this), INK.i128(), 0); } @@ -609,9 +610,10 @@ contract ETHTests is ETHVaultBuiltState { vm.expectEmit(true, true, true, true); emit VaultPoured(ethVaultId, baseId, wethId, INK.i128(), 0); + uint before = weth.balanceOf(address(ladle.joins(wethId))); ladle.batch{ value: INK}(calls); - assertEq(weth.balanceOf(address(ladle.joins(wethId))), INK); + assertEq(weth.balanceOf(address(ladle.joins(wethId))) - before, INK); (uint128 art, uint128 ink) = cauldron.balances(ethVaultId); assertEq(ink, INK); assertEq(art, 0); @@ -627,11 +629,12 @@ contract ETHTests is ETHVaultBuiltState { contract ETHVaultPouredStateTest is ETHVaultPouredState { function testPourToWithdraw() public { console.log("can pour to withdraw"); - ladle.pour(ethVaultId, address(this), -INK.i128(), 0); + (uint128 art, uint128 ink) = cauldron.balances(ethVaultId); + ladle.pour(ethVaultId, address(this), -int128(ink), 0); - assertEq(weth.balanceOf(address(ladle.joins(wethId))), 0); + // assertEq(weth.balanceOf(address(ladle.joins(wethId))), 0); assertEq(weth.balanceOf(address(this)), INK); - (uint128 art, uint128 ink) = cauldron.balances(ethVaultId); + ( art, ink) = cauldron.balances(ethVaultId); assertEq(ink, 0); assertEq(art, 0); } @@ -642,10 +645,10 @@ contract ETHVaultPouredStateTest is ETHVaultPouredState { bytes[] memory calls = new bytes[](2); calls[0] = abi.encodeWithSelector(VRLadle.pour.selector, ethVaultId, address(ladle), -INK.i128(), 0); calls[1] = abi.encodeWithSelector(VRLadle.exitEther.selector, address(this)); - + uint before = weth.balanceOf(address(ladle.joins(wethId))); ladle.batch(calls); - assertEq(weth.balanceOf(address(ladle.joins(wethId))), 0); + assertEq(before - INK - weth.balanceOf(address(ladle.joins(wethId))), 0); assertEq(weth.balanceOf(address(this)), 0); (uint128 art, uint128 ink) = cauldron.balances(ethVaultId); assertEq(ink, 0); diff --git a/packages/foundry/contracts/variable/VRCauldron.sol b/packages/foundry/contracts/variable/VRCauldron.sol index 613e4e98..f2a3d586 100644 --- a/packages/foundry/contracts/variable/VRCauldron.sol +++ b/packages/foundry/contracts/variable/VRCauldron.sol @@ -407,9 +407,12 @@ contract VRCauldron is AccessControl, Constants { ) = vaultData(vaultId); // Normalize the base amount to debt terms - int128 art = base > 0 - ? _debtFromBase(vault_.baseId, base.u128()).i128() - : -_debtFromBase(vault_.baseId, (-base).u128()).i128(); + int128 art = base; + + if (base != 0) + art = base > 0 + ? _debtFromBase(vault_.baseId, base.u128()).i128() + : -_debtFromBase(vault_.baseId, (-base).u128()).i128(); balances_ = _pour(vaultId, vault_, balances_, ink, art); @@ -468,4 +471,4 @@ contract VRCauldron is AccessControl, Constants { uint256 baseValue = _debtToBase(vault_.baseId, balances_.art); // art * rate return inkValue.i256() - baseValue.wmul(ratio).i256(); } -} \ No newline at end of file +} From 0603be80209108702d3dcb330c2f4f4a6af4e8f7 Mon Sep 17 00:00:00 2001 From: iamsahu Date: Wed, 1 Mar 2023 18:03:28 +0530 Subject: [PATCH 2/4] feat: fixture working on `OnChain` --- packages/foundry/contracts/test/variable/Fixture.sol | 5 +++-- packages/foundry/contracts/test/variable/VRLadle.t.sol | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/foundry/contracts/test/variable/Fixture.sol b/packages/foundry/contracts/test/variable/Fixture.sol index e09ddaee..a44ef204 100644 --- a/packages/foundry/contracts/test/variable/Fixture.sol +++ b/packages/foundry/contracts/test/variable/Fixture.sol @@ -142,8 +142,9 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { } function setUpOracles() internal { - chiRateOracle = new AccumulatorMultiOracle(); + chiRateOracle = AccumulatorMultiOracle(0x95750d6F5fba4ed1cc4Dc42D2c01dFD3DB9a11eC); + vm.startPrank(timelock); chiRateOracle.grantRole( AccumulatorMultiOracle.setSource.selector, address(this) @@ -152,8 +153,8 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { AccumulatorMultiOracle.updatePerSecondRate.selector, address(this) ); + vm.stopPrank(); chiRateOracle.setSource(baseId, RATE, WAD, WAD * 2); - chiRateOracle.setSource(baseId, CHI, WAD, WAD * 2); ethAggregator = new ChainlinkAggregatorV3Mock(); ethAggregator.set(1e18 / 2); diff --git a/packages/foundry/contracts/test/variable/VRLadle.t.sol b/packages/foundry/contracts/test/variable/VRLadle.t.sol index 61d670ee..942be13d 100644 --- a/packages/foundry/contracts/test/variable/VRLadle.t.sol +++ b/packages/foundry/contracts/test/variable/VRLadle.t.sol @@ -598,7 +598,8 @@ contract ETHTests is ETHVaultBuiltState { function testPourWithoutSendingETHReverts() public { console.log("pour without sending eth reverts"); weth.approve(address(wethJoin), 0); - vm.expectRevert("ERC20: Insufficient approval"); + // Since weth doesn't have a error message for insufficient allowance https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code#L70 + vm.expectRevert("Transaction reverted silently"); ladle.pour(ethVaultId, address(this), INK.i128(), 0); } From 428083598a22233e20061e6cf15121f9cc74235a Mon Sep 17 00:00:00 2001 From: iamsahu Date: Tue, 7 Mar 2023 13:14:06 +0530 Subject: [PATCH 3/4] fix: only fuzz tests failing --- packages/foundry/contracts/test/variable/Fixture.sol | 7 ++++--- packages/foundry/contracts/test/variable/FixtureStates.sol | 2 +- packages/foundry/contracts/test/variable/VRCauldron.t.sol | 6 +++--- packages/foundry/contracts/test/variable/VYToken.t.sol | 4 +++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/foundry/contracts/test/variable/Fixture.sol b/packages/foundry/contracts/test/variable/Fixture.sol index a44ef204..14ad48d3 100644 --- a/packages/foundry/contracts/test/variable/Fixture.sol +++ b/packages/foundry/contracts/test/variable/Fixture.sol @@ -126,7 +126,7 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { baseJoin = new FlashJoin(address(base)); setUpOracles(); - vyToken = new VYToken(baseId, IOracle(address(chiRateOracle)), IJoin(baseJoin),base.name(), base.symbol()); + vyToken = new VYToken(daiId, IOracle(address(chiRateOracle)), IJoin(daiJoin),dai.name(), dai.symbol()); // Setting permissions ladleGovAuth(); cauldronGovAuth(address(ladle)); @@ -138,7 +138,8 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { bytes4[] memory roles = new bytes4[](2); roles[0] = Join.join.selector; roles[1] = Join.exit.selector; - baseJoin.grantRoles(roles, address(vyToken)); + vm.prank(timelock); + daiJoin.grantRoles(roles, address(vyToken)); } function setUpOracles() internal { @@ -255,7 +256,7 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { 18 ); (bytes12 vaultId_,) = ladle.build(assetId, assetId, salt); - // cauldron.build(address(this), vaultId_, assetId, assetId); + IERC20(assetAddress).approve(address(join),INK * 10); deal(assetAddress, address(this), INK * 10); ladle.pour(vaultId_, address(this), (INK * 10).i128(), 0); diff --git a/packages/foundry/contracts/test/variable/FixtureStates.sol b/packages/foundry/contracts/test/variable/FixtureStates.sol index 51f34b7e..c45967e6 100644 --- a/packages/foundry/contracts/test/variable/FixtureStates.sol +++ b/packages/foundry/contracts/test/variable/FixtureStates.sol @@ -144,7 +144,7 @@ abstract contract ETHVaultPouredAndDebtState is ETHVaultPouredState { } } -abstract contract VYTokenZeroState is ZeroState { +abstract contract VYTokenZeroState is CompleteSetup { FlashBorrower public borrower; function setUp() public virtual override { diff --git a/packages/foundry/contracts/test/variable/VRCauldron.t.sol b/packages/foundry/contracts/test/variable/VRCauldron.t.sol index 89f314f7..d4b0cfcf 100644 --- a/packages/foundry/contracts/test/variable/VRCauldron.t.sol +++ b/packages/foundry/contracts/test/variable/VRCauldron.t.sol @@ -244,8 +244,6 @@ contract CauldronTestOnBuiltVault is VaultBuiltState { ); // Adding new base and ilks to it - chiRateOracle.setSource(daiId, RATE, WAD, WAD * 2); - chiRateOracle.setSource(daiId, CHI, WAD, WAD * 2); makeBase(daiId, address(dai), daiJoin, address(chiRateOracle), 12); cauldron.setSpotOracle(daiId, usdcId, spotOracle, 1000000); cauldron.setSpotOracle(daiId, wethId, spotOracle, 1000000); @@ -452,9 +450,11 @@ contract FuzzLevelTestsOnBorrowedState is BorrowedState { function testFuzz_levelGoesDownAsPriceGoesUp(int256 price) public { vm.assume(price > 0); - (, bytes6 baseId, ) = cauldron.vaults(vaultId); + (, bytes6 baseId, bytes6 ilkId) = cauldron.vaults(vaultId); (, int256 currentPrice, , ,) = usdcAggregator.latestRoundData(); + // (address source,,,) = spotOracle.sources(ilkId,baseId); + // console.log(address(source)); // Level goes down as price goes up vm.assume(price > currentPrice); int256 startLevel = cauldron.level(vaultId); diff --git a/packages/foundry/contracts/test/variable/VYToken.t.sol b/packages/foundry/contracts/test/variable/VYToken.t.sol index 949bf403..40516fc6 100644 --- a/packages/foundry/contracts/test/variable/VYToken.t.sol +++ b/packages/foundry/contracts/test/variable/VYToken.t.sol @@ -227,7 +227,9 @@ contract VYTokenTest is VYTokenZeroState { CHI ); - newRate = uint128(bound(newRate, oldPerSecondRate, type(uint128).max)); + newRate = uint128( + bound(newRate * 10, oldPerSecondRate, type(uint128).max) + ); chiRateOracle.updatePerSecondRate(vyToken.underlyingId(), CHI, newRate); vm.warp(block.timestamp + 1); chiRateOracle.get(vyToken.underlyingId(), CHI, 0); From 98d42680d72590e83fbf74d7942b25364e172b49 Mon Sep 17 00:00:00 2001 From: iamsahu Date: Tue, 7 Mar 2023 13:42:10 +0530 Subject: [PATCH 4/4] fix: vyToken fuzz test fixed --- packages/foundry/contracts/test/variable/Fixture.sol | 8 -------- .../foundry/contracts/test/variable/VRCauldron.t.sol | 12 +++++------- .../foundry/contracts/test/variable/VYToken.t.sol | 8 +++----- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/packages/foundry/contracts/test/variable/Fixture.sol b/packages/foundry/contracts/test/variable/Fixture.sol index 14ad48d3..f6799630 100644 --- a/packages/foundry/contracts/test/variable/Fixture.sol +++ b/packages/foundry/contracts/test/variable/Fixture.sol @@ -66,8 +66,6 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { AccumulatorMultiOracle public chiRateOracle; ChainlinkMultiOracle public spotOracle; ChainlinkAggregatorV3Mock public ethAggregator; - ChainlinkAggregatorV3Mock public daiAggregator; - ChainlinkAggregatorV3Mock public usdcAggregator; ChainlinkAggregatorV3Mock public baseAggregator; bytes12 public vaultId = 0x000000000000000000000001; @@ -160,12 +158,6 @@ abstract contract Fixture is Test, TestConstants, TestExtensions { ethAggregator = new ChainlinkAggregatorV3Mock(); ethAggregator.set(1e18 / 2); - daiAggregator = new ChainlinkAggregatorV3Mock(); - daiAggregator.set(1e18 / 2); - - usdcAggregator = new ChainlinkAggregatorV3Mock(); - usdcAggregator.set(1e18 / 2); - baseAggregator = new ChainlinkAggregatorV3Mock(); baseAggregator.set(1e18 / 2); diff --git a/packages/foundry/contracts/test/variable/VRCauldron.t.sol b/packages/foundry/contracts/test/variable/VRCauldron.t.sol index d4b0cfcf..4a5b0ea8 100644 --- a/packages/foundry/contracts/test/variable/VRCauldron.t.sol +++ b/packages/foundry/contracts/test/variable/VRCauldron.t.sol @@ -451,14 +451,12 @@ contract FuzzLevelTestsOnBorrowedState is BorrowedState { function testFuzz_levelGoesDownAsPriceGoesUp(int256 price) public { vm.assume(price > 0); (, bytes6 baseId, bytes6 ilkId) = cauldron.vaults(vaultId); - (, int256 currentPrice, , ,) = usdcAggregator.latestRoundData(); - - // (address source,,,) = spotOracle.sources(ilkId,baseId); - // console.log(address(source)); + (, int256 currentPrice, , ,) = ethAggregator.latestRoundData(); + // Level goes down as price goes up vm.assume(price > currentPrice); int256 startLevel = cauldron.level(vaultId); - usdcAggregator.set(uint256(price)); + ethAggregator.set(uint256(price)); assertGt(startLevel,cauldron.level(vaultId)); } @@ -466,11 +464,11 @@ contract FuzzLevelTestsOnBorrowedState is BorrowedState { // Level goes up as price goes down vm.assume(price > 0); (, bytes6 baseId, ) = cauldron.vaults(vaultId); - (, int256 currentPrice, , ,) = usdcAggregator.latestRoundData(); + (, int256 currentPrice, , ,) = ethAggregator.latestRoundData(); vm.assume(price < currentPrice); int256 startLevel = cauldron.level(vaultId); - usdcAggregator.set(uint256(price)); + ethAggregator.set(uint256(price)); console.logInt(startLevel); console.logInt(cauldron.level(vaultId)); assertLt(startLevel,cauldron.level(vaultId)); diff --git a/packages/foundry/contracts/test/variable/VYToken.t.sol b/packages/foundry/contracts/test/variable/VYToken.t.sol index 40516fc6..717d616d 100644 --- a/packages/foundry/contracts/test/variable/VYToken.t.sol +++ b/packages/foundry/contracts/test/variable/VYToken.t.sol @@ -185,7 +185,7 @@ contract VYTokenTest is VYTokenZeroState { vyToken.underlyingId(), CHI ); - + vm.assume(newRate > oldPerSecondRate); newRate = uint128(bound(newRate, oldPerSecondRate, type(uint128).max)); chiRateOracle.updatePerSecondRate(vyToken.underlyingId(), CHI, newRate); vm.warp(block.timestamp + 1); @@ -226,10 +226,8 @@ contract VYTokenTest is VYTokenZeroState { vyToken.underlyingId(), CHI ); - - newRate = uint128( - bound(newRate * 10, oldPerSecondRate, type(uint128).max) - ); + vm.assume(newRate > oldPerSecondRate); + newRate = uint128(bound(newRate, oldPerSecondRate, type(uint128).max)); chiRateOracle.updatePerSecondRate(vyToken.underlyingId(), CHI, newRate); vm.warp(block.timestamp + 1); chiRateOracle.get(vyToken.underlyingId(), CHI, 0);