diff --git a/packages/foundry/contracts/test/variable/Fixture.sol b/packages/foundry/contracts/test/variable/Fixture.sol index aeeecf6e..f6799630 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; @@ -64,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; @@ -80,10 +80,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,17 +104,27 @@ 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(); - 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)); @@ -115,12 +136,14 @@ 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 { - chiRateOracle = new AccumulatorMultiOracle(); + chiRateOracle = AccumulatorMultiOracle(0x95750d6F5fba4ed1cc4Dc42D2c01dFD3DB9a11eC); + vm.startPrank(timelock); chiRateOracle.grantRole( AccumulatorMultiOracle.setSource.selector, address(this) @@ -129,34 +152,25 @@ 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); - daiAggregator = new ChainlinkAggregatorV3Mock(); - daiAggregator.set(1e18 / 2); - - usdcAggregator = new ChainlinkAggregatorV3Mock(); - usdcAggregator.set(1e18 / 2); - 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 +178,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 ----------------- // @@ -241,7 +248,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 c9ede09b..c45967e6 100644 --- a/packages/foundry/contracts/test/variable/FixtureStates.sol +++ b/packages/foundry/contracts/test/variable/FixtureStates.sol @@ -144,13 +144,11 @@ abstract contract ETHVaultPouredAndDebtState is ETHVaultPouredState { } } -abstract contract VYTokenZeroState is ZeroState { - address public timelock; +abstract contract VYTokenZeroState is CompleteSetup { 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/VRCauldron.t.sol b/packages/foundry/contracts/test/variable/VRCauldron.t.sol index 89f314f7..4a5b0ea8 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,13 +450,13 @@ contract FuzzLevelTestsOnBorrowedState is BorrowedState { function testFuzz_levelGoesDownAsPriceGoesUp(int256 price) public { vm.assume(price > 0); - (, bytes6 baseId, ) = cauldron.vaults(vaultId); - (, int256 currentPrice, , ,) = usdcAggregator.latestRoundData(); - + (, bytes6 baseId, bytes6 ilkId) = cauldron.vaults(vaultId); + (, 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/VRLadle.t.sol b/packages/foundry/contracts/test/variable/VRLadle.t.sol index 3c2e0200..942be13d 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,8 +597,9 @@ contract ETHTests is ETHVaultBuiltState { function testPourWithoutSendingETHReverts() public { console.log("pour without sending eth reverts"); - weth.approve(address(wethJoin), 0 ); - vm.expectRevert("ERC20: Insufficient approval"); + weth.approve(address(wethJoin), 0); + // 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); } @@ -609,9 +611,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 +630,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 +646,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/test/variable/VYToken.t.sol b/packages/foundry/contracts/test/variable/VYToken.t.sol index 949bf403..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,7 +226,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); 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 +}