From fafd16ea2a8427682e3ca59a068037206ef25bf5 Mon Sep 17 00:00:00 2001 From: Lucas Manuel Date: Wed, 3 Jul 2024 06:59:39 -0400 Subject: [PATCH] test: Add rate setting logic (SC-483) (#15) * feat: first test working * feat: use larger numbers: * feat: test with initial burn amount passing * feat: update tests to work with updated burn logic, move conversion functions around and use previews * feat: remove todos * fix: update to remove console and update comment * feat: get swap tests working * feat: get all swap tests working * fix: update for three assets in logic * feat: all tests passing * fix: rm commented out test * feat: add preview swap tests * feat: move logic out of single use internal and use conversion rate everywhere * feat: move divRoundUp out of single use internal * feat: add full coverage for conversion tests * feat: add more preview cases * feat: refactor PSM to use three assets * fix: rm comment * feat: add interface, natspec, events, referral code, tests passing * fix: update to rm consolegp * feat: add events testing * feat: make precisions internal and add state var natspec * feat: finish natspec * feat: add readme * feat: add referral code note * fix: update constructor test * fix: update links * fix: reformatting * fix: update testing section * fix: improve overview * feat: add emojis * feat: remove all share burn logic, get all non inflation attack tests to pass * fix: cleanup diff * fix: update to use initial deposit instead of burn * feat: add readme section explaining attack * fix: minimize diff * fix: address bartek comments * feat: update all tests to work with new interfaces * feat: add deposit failure mode tests * feat: update to add assertions for return in deposit * feat: add withdraw failure tests * feat: update to address comments outside sharesToBurn * feat: update inflation attack test and readme * fix: update readme * feat: update test to constrain deposit/withdraw * feat: update to add both cases * feat: update per review * feat: update to use underscore bound, fix test * fix: typo * feat: add overrides, remove referrals, update referral type * fix: update expect emit * feat: update name and remove todos * feat: move files and set up structure * feat: update to rename files, contracts, and errors * fix: rm dup file, update toml * feat: get deposits working * chore: refactor into proper inheritance structure * feat: get all functions working with reverts * feat: update conversion * feat: get swaps working without reverts * feat: add fully working deposit/withdraw/swaps, invariant_B failing * ci: update for ci * fix: update name * chore: rm basly cased file * chore: re add * fix: re add invariant * ci: experiment with 2 million total calls * ci: add show progress flag * fix: move file back * ci: update verbosity * ci: add PR profile * fix: rm redundant files * feat: update from review changes * feat: add afterInvariant hook * fix: update invariant * fix: add fuzz failure * chore: rm indexing comment * feat: refactor structure * feat: both invariants working * fix: update comment * feat: add rate setting logic * fix: update toml * fix: rm redundant files from merge * fix: update tolerances * feat: update to add seeding as part of invariants * fix: update toml * fix: rm redundant files from merge * fix: update tolerances * fix: rm invariant logs * fix: update tolerance * fix: formatting * fix: update test name --- test/invariant/Invariants.t.sol | 88 ++++++++++++++++--- test/invariant/handlers/RateSetterHandler.sol | 30 +++++++ 2 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 test/invariant/handlers/RateSetterHandler.sol diff --git a/test/invariant/Invariants.t.sol b/test/invariant/Invariants.t.sol index edfb6ce..c39957f 100644 --- a/test/invariant/Invariants.t.sol +++ b/test/invariant/Invariants.t.sol @@ -5,15 +5,17 @@ import "forge-std/Test.sol"; import { PSMTestBase } from "test/PSMTestBase.sol"; -import { LpHandler } from "test/invariant/handlers/LpHandler.sol"; -import { SwapperHandler } from "test/invariant/handlers/SwapperHandler.sol"; -import { TransferHandler } from "test/invariant/handlers/TransferHandler.sol"; +import { LpHandler } from "test/invariant/handlers/LpHandler.sol"; +import { RateSetterHandler } from "test/invariant/handlers/RateSetterHandler.sol"; +import { SwapperHandler } from "test/invariant/handlers/SwapperHandler.sol"; +import { TransferHandler } from "test/invariant/handlers/TransferHandler.sol"; abstract contract PSMInvariantTestBase is PSMTestBase { - LpHandler public lpHandler; - SwapperHandler public swapperHandler; - TransferHandler public transferHandler; + LpHandler public lpHandler; + RateSetterHandler public rateSetterHandler; + SwapperHandler public swapperHandler; + TransferHandler public transferHandler; address BURN_ADDRESS = makeAddr("burn-address"); @@ -45,7 +47,7 @@ abstract contract PSMInvariantTestBase is PSMTestBase { assertApproxEqAbs( psm.getPsmTotalValue(), psm.convertToAssetValue(psm.totalShares()), - 2 + 3 ); } @@ -69,12 +71,14 @@ abstract contract PSMInvariantTestBase is PSMTestBase { console.log("withdrawCount ", lpHandler.withdrawCount()); console.log("swapCount ", swapperHandler.swapCount()); console.log("zeroBalanceCount", swapperHandler.zeroBalanceCount()); + console.log("setRateCount ", rateSetterHandler.setRateCount()); console.log( "sum ", lpHandler.depositCount() + lpHandler.withdrawCount() + swapperHandler.swapCount() + - swapperHandler.zeroBalanceCount() + swapperHandler.zeroBalanceCount() + + rateSetterHandler.setRateCount() ); } @@ -196,8 +200,6 @@ contract PSMInvariants_ConstantRate_NoTransfer is PSMInvariantTestBase { lpHandler = new LpHandler(psm, dai, usdc, sDai, 3); swapperHandler = new SwapperHandler(psm, dai, usdc, sDai, 3); - rateProvider.__setConversionRate(1.25e27); - targetContract(address(lpHandler)); targetContract(address(swapperHandler)); } @@ -229,9 +231,73 @@ contract PSMInvariants_ConstantRate_WithTransfers is PSMInvariantTestBase { swapperHandler = new SwapperHandler(psm, dai, usdc, sDai, 3); transferHandler = new TransferHandler(psm, dai, usdc, sDai); - rateProvider.__setConversionRate(1.25e27); + targetContract(address(lpHandler)); + targetContract(address(swapperHandler)); + targetContract(address(transferHandler)); + } + + function invariant_A() public view { + _checkInvariant_A(); + } + + function invariant_B() public view { + _checkInvariant_B(); + } + + function invariant_C() public view { + _checkInvariant_C(); + } + + function afterInvariant() public { + _withdrawAllPositions(); + } + +} + +contract PSMInvariants_RateSetting_NoTransfer is PSMInvariantTestBase { + + function setUp() public override { + super.setUp(); + + lpHandler = new LpHandler(psm, dai, usdc, sDai, 3); + rateSetterHandler = new RateSetterHandler(rateProvider, 1.25e27); + swapperHandler = new SwapperHandler(psm, dai, usdc, sDai, 3); + + targetContract(address(lpHandler)); + targetContract(address(rateSetterHandler)); + targetContract(address(swapperHandler)); + } + + function invariant_A() public view { + _checkInvariant_A(); + } + + function invariant_B() public view { + _checkInvariant_B(); + } + + function invariant_C() public view { + _checkInvariant_C(); + } + + function afterInvariant() public { + _withdrawAllPositions(); + } + +} + +contract PSMInvariants_RateSetting_WithTransfers is PSMInvariantTestBase { + + function setUp() public override { + super.setUp(); + + lpHandler = new LpHandler(psm, dai, usdc, sDai, 3); + rateSetterHandler = new RateSetterHandler(rateProvider, 1.25e27); + swapperHandler = new SwapperHandler(psm, dai, usdc, sDai, 3); + transferHandler = new TransferHandler(psm, dai, usdc, sDai); targetContract(address(lpHandler)); + targetContract(address(rateSetterHandler)); targetContract(address(swapperHandler)); targetContract(address(transferHandler)); } diff --git a/test/invariant/handlers/RateSetterHandler.sol b/test/invariant/handlers/RateSetterHandler.sol new file mode 100644 index 0000000..ffedfd1 --- /dev/null +++ b/test/invariant/handlers/RateSetterHandler.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.13; + +import { StdUtils } from "forge-std/StdUtils.sol"; + +import { MockRateProvider } from "test/mocks/MockRateProvider.sol"; + +contract RateSetterHandler is StdUtils { + + uint256 public rate; + + MockRateProvider public rateProvider; + + uint256 public setRateCount; + + constructor(MockRateProvider rateProvider_, uint256 initialRate) { + rateProvider = rateProvider_; + rate = initialRate; + } + + function setRate(uint256 rateIncrease) external { + // Increase the rate by up to 100% + rate += _bound(rateIncrease, 0, 1e27); + + rateProvider.__setConversionRate(rate); + + setRateCount++; + } + +}