From ce8b4e8d15b47ed96e6fd35b364ec3313d8db9fc Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Mon, 16 Oct 2023 10:44:31 +0200 Subject: [PATCH 1/8] feat: getters without out of gas ---> pagination --- contracts/DistributionCreator.sol | 95 ++++++++++++++++++++++--------- lib/forge-std | 2 +- 2 files changed, 69 insertions(+), 28 deletions(-) diff --git a/contracts/DistributionCreator.sol b/contracts/DistributionCreator.sol index 9e0a98b..4ea979f 100644 --- a/contracts/DistributionCreator.sol +++ b/contracts/DistributionCreator.sol @@ -291,9 +291,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { } /// @notice Returns the list of all currently active distributions on pools of supported AMMs (like Uniswap V3) - function getActiveDistributions() external view returns (ExtensiveDistributionParameters[] memory) { + function getActiveDistributions( + uint32 skip, + uint32 first + ) external view returns (ExtensiveDistributionParameters[] memory) { uint32 roundedEpoch = _getRoundedEpoch(uint32(block.timestamp)); - return _getPoolDistributionsBetweenEpochs(address(0), roundedEpoch, roundedEpoch + EPOCH_DURATION); + return _getPoolDistributionsBetweenEpochs(address(0), roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } /// @notice Returns the list of all the reward tokens supported as well as their minimum amounts @@ -320,9 +323,13 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { /// @notice Returns the list of all the distributions that were or that are going to be live at /// a specific epoch - function getDistributionsForEpoch(uint32 epoch) external view returns (ExtensiveDistributionParameters[] memory) { + function getDistributionsForEpoch( + uint32 epoch, + uint32 skip, + uint32 first + ) external view returns (ExtensiveDistributionParameters[] memory) { uint32 roundedEpoch = _getRoundedEpoch(epoch); - return _getPoolDistributionsBetweenEpochs(address(0), roundedEpoch, roundedEpoch + EPOCH_DURATION); + return _getPoolDistributionsBetweenEpochs(address(0), roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } /// @notice Gets the distributions that were or will be live at some point between `epochStart` (included) and `epochEnd` (excluded) @@ -330,34 +337,50 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { /// @dev Conversely, if a distribution starts after `epochStart` and ends before `epochEnd`, it is returned by this function function getDistributionsBetweenEpochs( uint32 epochStart, - uint32 epochEnd + uint32 epochEnd, + uint32 skip, + uint32 first ) external view returns (ExtensiveDistributionParameters[] memory) { - return _getPoolDistributionsBetweenEpochs(address(0), _getRoundedEpoch(epochStart), _getRoundedEpoch(epochEnd)); + return + _getPoolDistributionsBetweenEpochs( + address(0), + _getRoundedEpoch(epochStart), + _getRoundedEpoch(epochEnd), + skip, + first + ); } /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) function getDistributionsAfterEpoch( - uint32 epochStart + uint32 epochStart, + uint32 skip, + uint32 first ) external view returns (ExtensiveDistributionParameters[] memory) { - return _getPoolDistributionsBetweenEpochs(address(0), _getRoundedEpoch(epochStart), type(uint32).max); + return + _getPoolDistributionsBetweenEpochs(address(0), _getRoundedEpoch(epochStart), type(uint32).max, skip, first); } /// @notice Returns the list of all currently active distributions for a specific UniswapV3 pool function getActivePoolDistributions( - address uniV3Pool + address uniV3Pool, + uint32 skip, + uint32 first ) external view returns (ExtensiveDistributionParameters[] memory) { uint32 roundedEpoch = _getRoundedEpoch(uint32(block.timestamp)); - return _getPoolDistributionsBetweenEpochs(uniV3Pool, roundedEpoch, roundedEpoch + EPOCH_DURATION); + return _getPoolDistributionsBetweenEpochs(uniV3Pool, roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } /// @notice Returns the list of all the distributions that were or that are going to be live at a /// specific epoch and for a specific pool function getPoolDistributionsForEpoch( address uniV3Pool, - uint32 epoch + uint32 epoch, + uint32 skip, + uint32 first ) external view returns (ExtensiveDistributionParameters[] memory) { uint32 roundedEpoch = _getRoundedEpoch(epoch); - return _getPoolDistributionsBetweenEpochs(uniV3Pool, roundedEpoch, roundedEpoch + EPOCH_DURATION); + return _getPoolDistributionsBetweenEpochs(uniV3Pool, roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } /// @notice Returns the list of all distributions that were or will be live at some point between @@ -365,18 +388,30 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { function getPoolDistributionsBetweenEpochs( address uniV3Pool, uint32 epochStart, - uint32 epochEnd + uint32 epochEnd, + uint32 skip, + uint32 first ) external view returns (ExtensiveDistributionParameters[] memory) { - return _getPoolDistributionsBetweenEpochs(uniV3Pool, _getRoundedEpoch(epochStart), _getRoundedEpoch(epochEnd)); + return + _getPoolDistributionsBetweenEpochs( + uniV3Pool, + _getRoundedEpoch(epochStart), + _getRoundedEpoch(epochEnd), + skip, + first + ); } /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) /// for a specific pool function getPoolDistributionsAfterEpoch( address uniV3Pool, - uint32 epochStart + uint32 epochStart, + uint32 skip, + uint32 first ) external view returns (ExtensiveDistributionParameters[] memory) { - return _getPoolDistributionsBetweenEpochs(uniV3Pool, _getRoundedEpoch(epochStart), type(uint32).max); + return + _getPoolDistributionsBetweenEpochs(uniV3Pool, _getRoundedEpoch(epochStart), type(uint32).max, skip, first); } // ============================ GOVERNANCE FUNCTIONS =========================== @@ -527,30 +562,36 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { function _getPoolDistributionsBetweenEpochs( address uniV3Pool, uint32 epochStart, - uint32 epochEnd + uint32 epochEnd, + uint32 skip, + uint32 first ) internal view returns (ExtensiveDistributionParameters[] memory) { uint256 length; uint256 distributionListLength = distributionList.length; - ExtensiveDistributionParameters[] memory activeRewards = new ExtensiveDistributionParameters[]( - distributionListLength - ); - for (uint32 i; i < distributionListLength; ) { + uint256 returnSize = first > distributionListLength ? distributionListLength : first; + ExtensiveDistributionParameters[] memory activeRewards = new ExtensiveDistributionParameters[](returnSize); + uint256 i = 0; + while (true) { DistributionParameters memory distribution = distributionList[i]; if ( _isDistributionLiveBetweenEpochs(distribution, epochStart, epochEnd) && (uniV3Pool == address(0) || distribution.uniV3Pool == uniV3Pool) ) { - (bool success, ExtensiveDistributionParameters memory extensiveParams) = IDistributionCreator( - address(this) - ).tryGetExtensiveDistributionParameters(distribution); - if (success) { - activeRewards[length] = extensiveParams; - length += 1; + if (skip > 0) skip -= 1; + else { + (bool success, ExtensiveDistributionParameters memory extensiveParams) = IDistributionCreator( + address(this) + ).tryGetExtensiveDistributionParameters(distribution); + if (success) { + activeRewards[length] = extensiveParams; + length += 1; + } } } unchecked { ++i; } + if (length == returnSize) break; } assembly { mstore(activeRewards, length) diff --git a/lib/forge-std b/lib/forge-std index cb69e9c..705263c 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit cb69e9c07fbd002819c8c6c8db3caeab76b90d6b +Subproject commit 705263c95892a906d7af65f0f73ce8a4a0c80b80 From 801850b7cabfea469e078002e68a4e70b4223e14 Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:10:14 +0200 Subject: [PATCH 2/8] comments @Picodes + start set up test in foundry --- contracts/DistributionCreator.sol | 183 ++++++++-- package.json | 3 +- test/foundry/DistributionCreator.s.sol | 31 ++ test/foundry/Fixture.s.sol | 70 ++++ .../distributionCreator.test.ts | 327 +++++++++++++----- .../distributionCreatorAlgebra.test.ts | 8 +- 6 files changed, 508 insertions(+), 114 deletions(-) create mode 100644 test/foundry/DistributionCreator.s.sol create mode 100644 test/foundry/Fixture.s.sol diff --git a/contracts/DistributionCreator.sol b/contracts/DistributionCreator.sol index 4ea979f..473d762 100644 --- a/contracts/DistributionCreator.sol +++ b/contracts/DistributionCreator.sol @@ -291,10 +291,29 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { } /// @notice Returns the list of all currently active distributions on pools of supported AMMs (like Uniswap V3) + function getActiveDistributions() + external + view + returns (ExtensiveDistributionParameters[] memory searchDistributions) + { + uint32 roundedEpoch = _getRoundedEpoch(uint32(block.timestamp)); + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + address(0), + roundedEpoch, + roundedEpoch + EPOCH_DURATION, + 0, + type(uint32).max + ); + } + + /// @notice Returns the list of all currently active distributions on pools of supported AMMs (like Uniswap V3) + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getActiveDistributions()` with additional parameters to prevent out of gas error function getActiveDistributions( uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { uint32 roundedEpoch = _getRoundedEpoch(uint32(block.timestamp)); return _getPoolDistributionsBetweenEpochs(address(0), roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } @@ -323,11 +342,29 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { /// @notice Returns the list of all the distributions that were or that are going to be live at /// a specific epoch + function getDistributionsForEpoch( + uint32 epoch + ) external view returns (ExtensiveDistributionParameters[] memory searchDistributions) { + uint32 roundedEpoch = _getRoundedEpoch(epoch); + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + address(0), + roundedEpoch, + roundedEpoch + EPOCH_DURATION, + 0, + type(uint32).max + ); + } + + /// @notice Returns the list of all the distributions that were or that are going to be live at + /// a specific epoch + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getDistributionsForEpoch(uint256 epoch)` with additional parameters to prevent out of gas error function getDistributionsForEpoch( uint32 epoch, uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { uint32 roundedEpoch = _getRoundedEpoch(epoch); return _getPoolDistributionsBetweenEpochs(address(0), roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } @@ -335,12 +372,29 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { /// @notice Gets the distributions that were or will be live at some point between `epochStart` (included) and `epochEnd` (excluded) /// @dev If a distribution starts during `epochEnd`, it is not be returned by this function /// @dev Conversely, if a distribution starts after `epochStart` and ends before `epochEnd`, it is returned by this function + function getDistributionsBetweenEpochs( + uint32 epochStart, + uint32 epochEnd + ) external view returns (ExtensiveDistributionParameters[] memory searchDistributions) { + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + address(0), + _getRoundedEpoch(epochStart), + _getRoundedEpoch(epochEnd), + 0, + type(uint32).max + ); + } + + /// @notice Gets the distributions that were or will be live at some point between `epochStart` (included) and `epochEnd` (excluded) + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getDistributionsBetweenEpochs(uint256 epochStart, uint256 epochEnd)` with additional parameters to prevent out of gas error function getDistributionsBetweenEpochs( uint32 epochStart, uint32 epochEnd, uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { return _getPoolDistributionsBetweenEpochs( address(0), @@ -352,46 +406,118 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { } /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) + function getDistributionsAfterEpoch( + uint32 epochStart + ) external view returns (ExtensiveDistributionParameters[] memory searchDistributions) { + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + address(0), + _getRoundedEpoch(epochStart), + type(uint32).max, + 0, + type(uint32).max + ); + } + + /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getDistributionsAfterEpoch(uint256 epochStart)` with additional parameters to prevent out of gas error function getDistributionsAfterEpoch( uint32 epochStart, uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { return _getPoolDistributionsBetweenEpochs(address(0), _getRoundedEpoch(epochStart), type(uint32).max, skip, first); } /// @notice Returns the list of all currently active distributions for a specific UniswapV3 pool + function getActivePoolDistributions( + address uniV3Pool + ) external view returns (ExtensiveDistributionParameters[] memory searchDistributions) { + uint32 roundedEpoch = _getRoundedEpoch(uint32(block.timestamp)); + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + uniV3Pool, + roundedEpoch, + roundedEpoch + EPOCH_DURATION, + 0, + type(uint32).max + ); + } + + /// @notice Returns the list of all currently active distributions for a specific UniswapV3 pool + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getActivePoolDistributions(address uniV3Pool)` with additional parameters to prevent out of gas error function getActivePoolDistributions( address uniV3Pool, uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { uint32 roundedEpoch = _getRoundedEpoch(uint32(block.timestamp)); return _getPoolDistributionsBetweenEpochs(uniV3Pool, roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } /// @notice Returns the list of all the distributions that were or that are going to be live at a /// specific epoch and for a specific pool + function getPoolDistributionsForEpoch( + address uniV3Pool, + uint32 epoch + ) external view returns (ExtensiveDistributionParameters[] memory searchDistributions) { + uint32 roundedEpoch = _getRoundedEpoch(epoch); + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + uniV3Pool, + roundedEpoch, + roundedEpoch + EPOCH_DURATION, + 0, + type(uint32).max + ); + } + + /// @notice Returns the list of all the distributions that were or that are going to be live at a + /// specific epoch and for a specific pool + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getPoolDistributionsForEpoch(address uniV3Pool,uint32 epoch)` with additional parameters to prevent out of gas error function getPoolDistributionsForEpoch( address uniV3Pool, uint32 epoch, uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { uint32 roundedEpoch = _getRoundedEpoch(epoch); return _getPoolDistributionsBetweenEpochs(uniV3Pool, roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } /// @notice Returns the list of all distributions that were or will be live at some point between /// `epochStart` (included) and `epochEnd` (excluded) for a specific pool + function getPoolDistributionsBetweenEpochs( + address uniV3Pool, + uint32 epochStart, + uint32 epochEnd + ) external view returns (ExtensiveDistributionParameters[] memory searchDistributions) { + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + uniV3Pool, + _getRoundedEpoch(epochStart), + _getRoundedEpoch(epochEnd), + 0, + type(uint32).max + ); + } + + /// @notice Returns the list of all distributions that were or will be live at some point between + /// `epochStart` (included) and `epochEnd` (excluded) for a specific pool + /// specific epoch and for a specific pool + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getPoolDistributionsBetweenEpochs(address uniV3Pool,uint32 epochStart, uint32 epochEnd)` with additional parameters to prevent out of gas error function getPoolDistributionsBetweenEpochs( address uniV3Pool, uint32 epochStart, uint32 epochEnd, uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { return _getPoolDistributionsBetweenEpochs( uniV3Pool, @@ -404,12 +530,30 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) /// for a specific pool + function getPoolDistributionsAfterEpoch( + address uniV3Pool, + uint32 epochStart + ) external view returns (ExtensiveDistributionParameters[] memory searchDistributions) { + (searchDistributions, ) = _getPoolDistributionsBetweenEpochs( + uniV3Pool, + _getRoundedEpoch(epochStart), + type(uint32).max, + 0, + type(uint32).max + ); + } + + /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) + /// for a specific pool + /// @param skip Disregard distibutions with a global index lower than `skip` + /// @param first Limit the lenght of the returned array to `first` + /// @dev Similar to `getPoolDistributionsAfterEpoch(address uniV3Pool,uint32 epochStart)` with additional parameters to prevent out of gas error function getPoolDistributionsAfterEpoch( address uniV3Pool, uint32 epochStart, uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory) { + ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { return _getPoolDistributionsBetweenEpochs(uniV3Pool, _getRoundedEpoch(epochStart), type(uint32).max, skip, first); } @@ -565,27 +709,24 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { uint32 epochEnd, uint32 skip, uint32 first - ) internal view returns (ExtensiveDistributionParameters[] memory) { + ) internal view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { uint256 length; uint256 distributionListLength = distributionList.length; uint256 returnSize = first > distributionListLength ? distributionListLength : first; ExtensiveDistributionParameters[] memory activeRewards = new ExtensiveDistributionParameters[](returnSize); - uint256 i = 0; - while (true) { + uint32 i = skip; + while (i < distributionListLength) { DistributionParameters memory distribution = distributionList[i]; if ( _isDistributionLiveBetweenEpochs(distribution, epochStart, epochEnd) && (uniV3Pool == address(0) || distribution.uniV3Pool == uniV3Pool) ) { - if (skip > 0) skip -= 1; - else { - (bool success, ExtensiveDistributionParameters memory extensiveParams) = IDistributionCreator( - address(this) - ).tryGetExtensiveDistributionParameters(distribution); - if (success) { - activeRewards[length] = extensiveParams; - length += 1; - } + (bool success, ExtensiveDistributionParameters memory extensiveParams) = IDistributionCreator( + address(this) + ).tryGetExtensiveDistributionParameters(distribution); + if (success) { + activeRewards[length] = extensiveParams; + length += 1; } } unchecked { @@ -596,6 +737,6 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { assembly { mstore(activeRewards, length) } - return activeRewards; + return (activeRewards, i); } } diff --git a/package.json b/package.json index ebdb71d..1e225be 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "foundry:gas": "forge test --gas-report", "foundry:run": "docker run -it --rm -v $(pwd):/app -w /app ghcr.io/foundry-rs/foundry sh", "foundry:setup": "curl -L https://foundry.paradigm.xyz | bash && foundryup && git submodule update --init --recursive", + "foundry:size": "forge build --skip test --sizes", "foundry:test": "forge test -vvv", "hardhat:compile": "hardhat compile", "hardhat:coverage": "hardhat coverage", @@ -96,4 +97,4 @@ "solc": "0.8.12", "yargs": "^17.5.1" } -} +} \ No newline at end of file diff --git a/test/foundry/DistributionCreator.s.sol b/test/foundry/DistributionCreator.s.sol new file mode 100644 index 0000000..0022833 --- /dev/null +++ b/test/foundry/DistributionCreator.s.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.17; + +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "./Fixture.s.sol"; + +contract DistributionCreatorOOGTest is Fixture { + using SafeERC20 for IERC20; + + uint256 startTime; + + function setUp() public override { + super.setUp(); + + startTime = block.timestamp; + + vm.startPrank(guardian); + creator.toggleSigningWhitelist(alice); + creator.toggleTokenWhitelist(address(agEUR)); + address[] memory tokens = new address[](1); + uint256[] memory amounts = new uint256[](1); + tokens[0] = address(angle); + amounts[0] = 1e18; + creator.setRewardTokenMinAmounts(tokens, amounts); + vm.stopPrank(); + + angle.mint(address(alice), 1e22); + vm.prank(alice); + angle.approve(address(creator), type(uint256).max); + } +} diff --git a/test/foundry/Fixture.s.sol b/test/foundry/Fixture.s.sol new file mode 100644 index 0000000..9822544 --- /dev/null +++ b/test/foundry/Fixture.s.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.17; + +import { Test, stdError } from "forge-std/Test.sol"; +import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import { DistributionCreator } from "../../contracts/DistributionCreator.sol"; +import { MockTokenPermit } from "../../contracts/mock/MockTokenPermit.sol"; +import { MockUniswapV3Pool } from "../../contracts/mock/MockUniswapV3Pool.sol"; +import { MockCoreBorrow } from "../../contracts/mock/MockCoreBorrow.sol"; +import { ICore } from "../../contracts/interfaces/ICore.sol"; +import { console } from "forge-std/console.sol"; + +contract Fixture is Test { + MockTokenPermit public angle; + MockTokenPermit public agEUR; + MockTokenPermit public token0; + MockTokenPermit public token1; + + MockCoreBorrow public coreBorrow; + MockUniswapV3Pool public pool; + DistributionCreator public creator; + + address public alice; + address public bob; + address public charlie; + address public dylan; + address public guardian; + address public governor; + + function setUp() public virtual { + alice = vm.addr(1); + bob = vm.addr(2); + charlie = vm.addr(3); + dylan = vm.addr(4); + guardian = address(uint160(uint256(keccak256(abi.encodePacked("guardian"))))); + governor = address(uint160(uint256(keccak256(abi.encodePacked("governor"))))); + + vm.label(address(angle), "ANGLE"); + vm.label(address(agEUR), "agEUR"); + vm.label(address(token0), "TOKEN0"); + vm.label(address(token1), "TOKEN1"); + vm.label(alice, "Alice"); + vm.label(bob, "Bob"); + vm.label(charlie, "Charlie"); + vm.label(dylan, "Dylan"); + vm.label(guardian, "Guardian"); + vm.label(governor, "Governor"); + + // tokens + angle = MockTokenPermit(address(new MockTokenPermit("ANGLE", "ANGLE", 18))); + agEUR = MockTokenPermit(address(new MockTokenPermit("agEUR", "agEUR", 18))); + token0 = MockTokenPermit(address(new MockTokenPermit("token0", "TOKEN0", 18))); + token1 = MockTokenPermit(address(new MockTokenPermit("token1", "TOKEN1", 18))); + + // side + coreBorrow = new MockCoreBorrow(); + pool = new MockUniswapV3Pool(); + + // DistributionCreator + creator = new DistributionCreator(); + + // Set + pool.setToken(address(token0), 0); + pool.setToken(address(token1), 1); + coreBorrow.toggleGuardian(address(guardian)); + coreBorrow.toggleGovernor(address(governor)); + creator.initialize(ICore(address(coreBorrow)), address(bob), 1e8); + } +} diff --git a/test/hardhat/distributionCreator/distributionCreator.test.ts b/test/hardhat/distributionCreator/distributionCreator.test.ts index 1aadfa8..ec85378 100644 --- a/test/hardhat/distributionCreator/distributionCreator.test.ts +++ b/test/hardhat/distributionCreator/distributionCreator.test.ts @@ -803,7 +803,7 @@ contract('DistributionCreator', () => { expect(allRewards[0].wrapperTypes[1]).to.be.equal(1); expect(allRewards[0].wrapperTypes[2]).to.be.equal(2); - const activeRewards = await manager.getActiveDistributions(); + const activeRewards = await manager['getActiveDistributions()'](); expect(activeRewards.length).to.be.equal(1); expect(activeRewards[0].base.positionWrappers[0]).to.be.equal(alice.address); expect(activeRewards[0].base.positionWrappers[1]).to.be.equal(bob.address); @@ -813,7 +813,7 @@ contract('DistributionCreator', () => { expect(activeRewards[0].base.wrapperTypes[1]).to.be.equal(1); expect(activeRewards[0].base.wrapperTypes[2]).to.be.equal(2); - const rewardsForEpoch = await manager.getDistributionsForEpoch(startTime); + const rewardsForEpoch = await manager['getDistributionsForEpoch(uint32)'](startTime); expect(rewardsForEpoch.length).to.be.equal(1); expect(rewardsForEpoch[0].base.positionWrappers[0]).to.be.equal(alice.address); expect(rewardsForEpoch[0].base.positionWrappers[1]).to.be.equal(bob.address); @@ -821,9 +821,9 @@ contract('DistributionCreator', () => { expect(rewardsForEpoch[0].base.wrapperTypes[0]).to.be.equal(0); expect(rewardsForEpoch[0].base.wrapperTypes[1]).to.be.equal(1); expect(rewardsForEpoch[0].base.wrapperTypes[2]).to.be.equal(2); - expect((await manager.getDistributionsForEpoch(startTime + 3600)).length).to.be.equal(0); + expect((await manager['getDistributionsForEpoch(uint32)'](startTime + 3600)).length).to.be.equal(0); - const poolRewards = await manager.getActivePoolDistributions(pool.address); + const poolRewards = await manager['getActivePoolDistributions(address)'](pool.address); expect(poolRewards.length).to.be.equal(1); expect(poolRewards[0].base.positionWrappers[0]).to.be.equal(alice.address); expect(poolRewards[0].base.positionWrappers[1]).to.be.equal(bob.address); @@ -831,9 +831,12 @@ contract('DistributionCreator', () => { expect(poolRewards[0].base.wrapperTypes[0]).to.be.equal(0); expect(poolRewards[0].base.wrapperTypes[1]).to.be.equal(1); expect(poolRewards[0].base.wrapperTypes[2]).to.be.equal(2); - expect((await manager.getActivePoolDistributions(bob.address)).length).to.be.equal(0); + expect((await manager['getActivePoolDistributions(address)'](bob.address)).length).to.be.equal(0); - const poolRewardsForEpoch = await manager.getPoolDistributionsForEpoch(pool.address, startTime); + const poolRewardsForEpoch = await manager['getPoolDistributionsForEpoch(address,uint32)']( + pool.address, + startTime, + ); expect(poolRewardsForEpoch.length).to.be.equal(1); expect(poolRewardsForEpoch[0].base.positionWrappers[0]).to.be.equal(alice.address); expect(poolRewardsForEpoch[0].base.positionWrappers[1]).to.be.equal(bob.address); @@ -841,7 +844,9 @@ contract('DistributionCreator', () => { expect(poolRewardsForEpoch[0].base.wrapperTypes[0]).to.be.equal(0); expect(poolRewardsForEpoch[0].base.wrapperTypes[1]).to.be.equal(1); expect(poolRewardsForEpoch[0].base.wrapperTypes[2]).to.be.equal(2); - expect((await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600)).length).to.be.equal(0); + expect( + (await manager['getPoolDistributionsForEpoch(address,uint32)'](pool.address, startTime + 3600)).length, + ).to.be.equal(0); }); it('success - when spans over several epochs', async () => { await pool.setToken(agEUR.address, 0); @@ -863,69 +868,137 @@ contract('DistributionCreator', () => { additionalData: web3.utils.soliditySha3('toong') as string, }; await manager.connect(alice).createDistribution(params2); - const poolRewardsForEpoch = await manager.getPoolDistributionsForEpoch(pool.address, startTime); + const poolRewardsForEpoch = await manager['getPoolDistributionsForEpoch(address,uint32)']( + pool.address, + startTime, + ); expect(poolRewardsForEpoch.length).to.be.equal(1); expect(poolRewardsForEpoch[0].base.positionWrappers[0]).to.be.equal(alice.address); expect(poolRewardsForEpoch[0].base.positionWrappers[1]).to.be.equal(bob.address); expect(poolRewardsForEpoch[0].base.positionWrappers[2]).to.be.equal(deployer.address); - expect((await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600)).length).to.be.equal(1); - expect((await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600 * 9)).length).to.be.equal(1); - expect((await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600 * 10)).length).to.be.equal(0); - const rewardsForEpoch = await manager.getDistributionsForEpoch(startTime); + expect( + (await manager['getPoolDistributionsForEpoch(address,uint32)'](pool.address, startTime + 3600)).length, + ).to.be.equal(1); + expect( + (await manager['getPoolDistributionsForEpoch(address,uint32)'](pool.address, startTime + 3600 * 9)).length, + ).to.be.equal(1); + expect( + (await manager['getPoolDistributionsForEpoch(address,uint32)'](pool.address, startTime + 3600 * 10)).length, + ).to.be.equal(0); + const rewardsForEpoch = await manager['getDistributionsForEpoch(uint32)'](startTime); expect(rewardsForEpoch.length).to.be.equal(1); expect(rewardsForEpoch[0].base.positionWrappers[0]).to.be.equal(alice.address); expect(rewardsForEpoch[0].base.positionWrappers[1]).to.be.equal(bob.address); expect(rewardsForEpoch[0].base.positionWrappers[2]).to.be.equal(deployer.address); - expect((await manager.getDistributionsForEpoch(startTime + 3600)).length).to.be.equal(1); - expect((await manager.getDistributionsForEpoch(startTime + 3600 * 9)).length).to.be.equal(1); - expect((await manager.getDistributionsForEpoch(startTime + 3600 * 10)).length).to.be.equal(0); + expect((await manager['getDistributionsForEpoch(uint32)'](startTime + 3600)).length).to.be.equal(1); + expect((await manager['getDistributionsForEpoch(uint32)'](startTime + 3600 * 9)).length).to.be.equal(1); + expect((await manager['getDistributionsForEpoch(uint32)'](startTime + 3600 * 10)).length).to.be.equal(0); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 9, startTime + 3600 * 10)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 9, startTime + 3600 * 10)) + .length, ).to.be.equal(1); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 10, startTime + 3600 * 13)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 10, startTime + 3600 * 13)) + .length, + ).to.be.equal(0); + expect( + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime - 1, startTime)).length, ).to.be.equal(0); - expect((await manager.getDistributionsBetweenEpochs(startTime - 1, startTime)).length).to.be.equal(0); - expect((await manager.getDistributionsBetweenEpochs(startTime - 1, startTime + 3600)).length).to.be.equal(1); - expect((await manager.getDistributionsBetweenEpochs(startTime - 1, startTime + 3600 * 11)).length).to.be.equal(1); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 4, startTime + 3600 * 9)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime - 1, startTime + 3600)).length, ).to.be.equal(1); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime - 1, startTime)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime - 1, startTime + 3600 * 11)).length, + ).to.be.equal(1); + expect( + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 4, startTime + 3600 * 9)) + .length, + ).to.be.equal(1); + expect( + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime - 1, + startTime, + ) + ).length, ).to.be.equal(0); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime - 1, startTime + 3600)).length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime - 1, + startTime + 3600, + ) + ).length, + ).to.be.equal(1); + expect( + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime - 1, + startTime + 3600 * 11, + ) + ).length, + ).to.be.equal(1); + expect( + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime + 3600 * 4, + startTime + 3600 * 9, + ) + ).length, ).to.be.equal(1); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime - 1, startTime + 3600 * 11)).length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + alice.address, + startTime - 1, + startTime + 3600, + ) + ).length, + ).to.be.equal(0); + expect( + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + alice.address, + startTime - 1, + startTime + 3600 * 11, + ) + ).length, + ).to.be.equal(0); + expect( + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + alice.address, + startTime + 3600 * 4, + startTime + 3600 * 9, + ) + ).length, + ).to.be.equal(0); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime)).length).to.be.equal(1); + expect((await manager['getDistributionsAfterEpoch(uint32)'](0)).length).to.be.equal(1); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime + 3600 * 9)).length).to.be.equal(1); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime + 3600 * 10)).length).to.be.equal(0); + expect( + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, startTime)).length, ).to.be.equal(1); + expect((await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, 0)).length).to.be.equal(1); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime + 3600 * 4, startTime + 3600 * 9)) - .length, + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, startTime + 3600 * 9)).length, ).to.be.equal(1); expect( - (await manager.getPoolDistributionsBetweenEpochs(alice.address, startTime - 1, startTime + 3600)).length, + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, startTime + 3600 * 10)).length, ).to.be.equal(0); expect( - (await manager.getPoolDistributionsBetweenEpochs(alice.address, startTime - 1, startTime + 3600 * 11)).length, + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](alice.address, startTime)).length, ).to.be.equal(0); + expect((await manager['getPoolDistributionsAfterEpoch(address,uint32)'](alice.address, 0)).length).to.be.equal(0); expect( - (await manager.getPoolDistributionsBetweenEpochs(alice.address, startTime + 3600 * 4, startTime + 3600 * 9)) - .length, + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](alice.address, startTime + 3600 * 9)).length, ).to.be.equal(0); - expect((await manager.getDistributionsAfterEpoch(startTime)).length).to.be.equal(1); - expect((await manager.getDistributionsAfterEpoch(0)).length).to.be.equal(1); - expect((await manager.getDistributionsAfterEpoch(startTime + 3600 * 9)).length).to.be.equal(1); - expect((await manager.getDistributionsAfterEpoch(startTime + 3600 * 10)).length).to.be.equal(0); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, startTime)).length).to.be.equal(1); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, 0)).length).to.be.equal(1); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, startTime + 3600 * 9)).length).to.be.equal(1); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, startTime + 3600 * 10)).length).to.be.equal(0); - expect((await manager.getPoolDistributionsAfterEpoch(alice.address, startTime)).length).to.be.equal(0); - expect((await manager.getPoolDistributionsAfterEpoch(alice.address, 0)).length).to.be.equal(0); - expect((await manager.getPoolDistributionsAfterEpoch(alice.address, startTime + 3600 * 9)).length).to.be.equal(0); }); }); describe('createDistributions', () => { @@ -1030,126 +1103,204 @@ contract('DistributionCreator', () => { expect((await manager.getAllDistributions()).length).to.be.equal(4); - const activeRewards = await manager.getActiveDistributions(); + const activeRewards = await manager['getActiveDistributions()'](); expect(activeRewards.length).to.be.equal(1); expect(activeRewards[0].base.amount).to.be.equal(parseEther('0.9')); - const activePoolRewards = await manager.getActivePoolDistributions(pool.address); + const activePoolRewards = await manager['getActivePoolDistributions(address)'](pool.address); expect(activePoolRewards.length).to.be.equal(1); expect(activePoolRewards[0].base.amount).to.be.equal(parseEther('0.9')); - expect(await manager.getActivePoolDistributions(mockPool.address)); + expect(await manager['getActivePoolDistributions(address)'](mockPool.address)); - const epochRewards0 = await manager.getDistributionsForEpoch(startTime + 3600); + const epochRewards0 = await manager['getDistributionsForEpoch(uint32)'](startTime + 3600); expect(epochRewards0.length).to.be.equal(2); expect(epochRewards0[0].base.amount).to.be.equal(parseEther('0.9')); expect(epochRewards0[1].base.amount).to.be.equal(parseEther('1.8')); - const epochRewards1 = await manager.getDistributionsForEpoch(startTime + 3600 * 2); + const epochRewards1 = await manager['getDistributionsForEpoch(uint32)'](startTime + 3600 * 2); expect(epochRewards1.length).to.be.equal(2); expect(epochRewards1[0].base.amount).to.be.equal(parseEther('0.9')); expect(epochRewards1[1].base.amount).to.be.equal(parseEther('2.7')); - const epochRewards2 = await manager.getDistributionsForEpoch(startTime + 3600 * 3); + const epochRewards2 = await manager['getDistributionsForEpoch(uint32)'](startTime + 3600 * 3); expect(epochRewards2.length).to.be.equal(1); expect(epochRewards2[0].base.amount).to.be.equal(parseEther('2.7')); - const epochRewards3 = await manager.getDistributionsForEpoch(startTime + 3600 * 10); + const epochRewards3 = await manager['getDistributionsForEpoch(uint32)'](startTime + 3600 * 10); expect(epochRewards3.length).to.be.equal(1); expect(epochRewards3[0].base.amount).to.be.equal(parseEther('3.6')); - const poolRewards0 = await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600); + const poolRewards0 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + pool.address, + startTime + 3600, + ); expect(poolRewards0.length).to.be.equal(1); expect(poolRewards0[0].base.amount).to.be.equal(parseEther('0.9')); - const poolRewards1 = await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600 * 2); + const poolRewards1 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + pool.address, + startTime + 3600 * 2, + ); expect(poolRewards1.length).to.be.equal(2); expect(poolRewards1[0].base.amount).to.be.equal(parseEther('0.9')); expect(poolRewards1[1].base.amount).to.be.equal(parseEther('2.7')); - const poolRewards2 = await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600 * 3); + const poolRewards2 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + pool.address, + startTime + 3600 * 3, + ); expect(poolRewards2.length).to.be.equal(1); expect(poolRewards2[0].base.amount).to.be.equal(parseEther('2.7')); - const poolRewards3 = await manager.getPoolDistributionsForEpoch(pool.address, startTime + 3600 * 10); + const poolRewards3 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + pool.address, + startTime + 3600 * 10, + ); expect(poolRewards3.length).to.be.equal(0); - const poolRewards01 = await manager.getPoolDistributionsForEpoch(mockPool.address, startTime + 3600); + const poolRewards01 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + mockPool.address, + startTime + 3600, + ); expect(poolRewards01.length).to.be.equal(1); expect(poolRewards01[0].base.amount).to.be.equal(parseEther('1.8')); - const poolRewards11 = await manager.getPoolDistributionsForEpoch(mockPool.address, startTime + 3600 * 2); + const poolRewards11 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + mockPool.address, + startTime + 3600 * 2, + ); expect(poolRewards11.length).to.be.equal(0); - const poolRewards21 = await manager.getPoolDistributionsForEpoch(mockPool.address, startTime + 3600 * 3); + const poolRewards21 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + mockPool.address, + startTime + 3600 * 3, + ); expect(poolRewards21.length).to.be.equal(0); - const poolRewards31 = await manager.getPoolDistributionsForEpoch(mockPool.address, startTime + 3600 * 10); + const poolRewards31 = await manager['getPoolDistributionsForEpoch(address,uint32)']( + mockPool.address, + startTime + 3600 * 10, + ); expect(poolRewards31.length).to.be.equal(1); expect(poolRewards31[0].base.amount).to.be.equal(parseEther('3.6')); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 9, startTime + 3600 * 10)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 9, startTime + 3600 * 10)) + .length, ).to.be.equal(0); - expect((await manager.getDistributionsBetweenEpochs(startTime, startTime + 3600 * 2)).length).to.be.equal(2); - expect((await manager.getDistributionsBetweenEpochs(startTime, startTime + 3600 * 3)).length).to.be.equal(3); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 2, startTime + 3600 * 3)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime, startTime + 3600 * 2)).length, + ).to.be.equal(2); + expect( + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime, startTime + 3600 * 3)).length, + ).to.be.equal(3); + expect( + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 2, startTime + 3600 * 3)) + .length, ).to.be.equal(2); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 4, startTime + 3600 * 11)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 4, startTime + 3600 * 11)) + .length, ).to.be.equal(2); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 4, startTime + 3600 * 10)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 4, startTime + 3600 * 10)) + .length, ).to.be.equal(1); expect( - (await manager.getDistributionsBetweenEpochs(startTime + 3600 * 10, startTime + 3600 * 12)).length, + (await manager['getDistributionsBetweenEpochs(uint32,uint32)'](startTime + 3600 * 10, startTime + 3600 * 12)) + .length, ).to.be.equal(1); - expect((await manager.getDistributionsAfterEpoch(startTime)).length).to.be.equal(4); - expect((await manager.getDistributionsAfterEpoch(startTime + 3600 * 2)).length).to.be.equal(3); - expect((await manager.getDistributionsAfterEpoch(startTime + 3600 * 3)).length).to.be.equal(2); - expect((await manager.getDistributionsAfterEpoch(startTime + 3600 * 5)).length).to.be.equal(1); - expect((await manager.getDistributionsAfterEpoch(startTime + 3600 * 13)).length).to.be.equal(0); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime)).length).to.be.equal(4); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime + 3600 * 2)).length).to.be.equal(3); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime + 3600 * 3)).length).to.be.equal(2); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime + 3600 * 5)).length).to.be.equal(1); + expect((await manager['getDistributionsAfterEpoch(uint32)'](startTime + 3600 * 13)).length).to.be.equal(0); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime, startTime + 3600)).length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime, + startTime + 3600, + ) + ).length, ).to.be.equal(1); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime, startTime + 2 * 3600)).length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime, + startTime + 2 * 3600, + ) + ).length, ).to.be.equal(1); expect( - (await manager.getPoolDistributionsBetweenEpochs(mockPool.address, startTime, startTime + 2 * 3600)).length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + mockPool.address, + startTime, + startTime + 2 * 3600, + ) + ).length, ).to.be.equal(1); expect( - (await manager.getPoolDistributionsBetweenEpochs(mockPool.address, startTime + 3 * 3600, startTime + 10 * 3600)) - .length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + mockPool.address, + startTime + 3 * 3600, + startTime + 10 * 3600, + ) + ).length, ).to.be.equal(0); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime, startTime + 3 * 3600)).length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime, + startTime + 3 * 3600, + ) + ).length, ).to.be.equal(2); expect( - (await manager.getPoolDistributionsBetweenEpochs(pool.address, startTime + 3 * 3600, startTime + 100 * 3600)) - .length, + ( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( + pool.address, + startTime + 3 * 3600, + startTime + 100 * 3600, + ) + ).length, ).to.be.equal(1); expect( ( - await manager.getPoolDistributionsBetweenEpochs( + await manager['getPoolDistributionsBetweenEpochs(address,uint32,uint32)']( mockPool.address, startTime + 3 * 3600, startTime + 100 * 3600, ) ).length, ).to.be.equal(1); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, startTime)).length).to.be.equal(2); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, startTime + 3600 * 2)).length).to.be.equal(2); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, startTime + 3600 * 3)).length).to.be.equal(1); - expect((await manager.getPoolDistributionsAfterEpoch(pool.address, startTime + 3600 * 5)).length).to.be.equal(0); - expect((await manager.getPoolDistributionsAfterEpoch(mockPool.address, startTime + 3600 * 1)).length).to.be.equal( - 2, - ); - expect((await manager.getPoolDistributionsAfterEpoch(mockPool.address, startTime + 3600 * 2)).length).to.be.equal( - 1, - ); expect( - (await manager.getPoolDistributionsAfterEpoch(mockPool.address, startTime + 3600 * 13)).length, + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, startTime)).length, + ).to.be.equal(2); + expect( + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, startTime + 3600 * 2)).length, + ).to.be.equal(2); + expect( + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, startTime + 3600 * 3)).length, + ).to.be.equal(1); + expect( + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](pool.address, startTime + 3600 * 5)).length, + ).to.be.equal(0); + expect( + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](mockPool.address, startTime + 3600 * 1)) + .length, + ).to.be.equal(2); + expect( + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](mockPool.address, startTime + 3600 * 2)) + .length, + ).to.be.equal(1); + expect( + (await manager['getPoolDistributionsAfterEpoch(address,uint32)'](mockPool.address, startTime + 3600 * 13)) + .length, ).to.be.equal(0); }); }); diff --git a/test/hardhat/distributionCreator/distributionCreatorAlgebra.test.ts b/test/hardhat/distributionCreator/distributionCreatorAlgebra.test.ts index f39d7b0..a2adf00 100644 --- a/test/hardhat/distributionCreator/distributionCreatorAlgebra.test.ts +++ b/test/hardhat/distributionCreator/distributionCreatorAlgebra.test.ts @@ -107,9 +107,9 @@ contract('DistributionCreator - Algebra', () => { expect(reward.additionalData).to.be.equal(web3.utils.soliditySha3('test2ng')); const rewardId = solidityKeccak256(['address', 'uint256'], [alice.address, 0]); expect(reward.rewardId).to.be.equal(rewardId); - const activeDistributions = await manager.getActiveDistributions(); + const activeDistributions = await manager['getActiveDistributions()']; expect(activeDistributions.length).to.be.equal(0); - const distributions = await manager.getDistributionsAfterEpoch(reward.epochStart - 1); + const distributions = await manager['getDistributionsAfterEpoch(uint32)'](reward.epochStart - 1); expect(distributions[0].poolFee).to.be.equal(0); }); it('success - on a pool that does not have a fee in it', async () => { @@ -148,9 +148,9 @@ contract('DistributionCreator - Algebra', () => { expect(reward.additionalData).to.be.equal(web3.utils.soliditySha3('test2ng')); const rewardId = solidityKeccak256(['address', 'uint256'], [alice.address, 0]); expect(reward.rewardId).to.be.equal(rewardId); - const activeDistributions = await manager.getActiveDistributions(); + const activeDistributions = await manager['getActiveDistributions()']; expect(activeDistributions.length).to.be.equal(0); - const distributions = await manager.getDistributionsAfterEpoch(reward.epochStart - 1); + const distributions = await manager['getDistributionsAfterEpoch(uint32)'](reward.epochStart - 1); expect(distributions[0].poolFee).to.be.equal(0); }); }); From c18162c01d28c9942d02af682b3869613fdf72c5 Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:55:14 +0200 Subject: [PATCH 3/8] test oog indeed happens --- foundry.toml | 2 +- test/foundry/DistributionCreator.s.sol | 72 ++++++++++++++++++++++++-- test/foundry/Fixture.s.sol | 16 +++++- 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/foundry.toml b/foundry.toml index 12b1018..f01189b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,7 +6,7 @@ libs = ['node_modules', 'lib'] script = 'scripts/foundry' cache_path = 'cache-forge' gas_reports = ["*"] -via_ir = true +via_ir = false optimizer_runs=100 # solc_version = '0.8.17' diff --git a/test/foundry/DistributionCreator.s.sol b/test/foundry/DistributionCreator.s.sol index 0022833..1df2c38 100644 --- a/test/foundry/DistributionCreator.s.sol +++ b/test/foundry/DistributionCreator.s.sol @@ -2,17 +2,19 @@ pragma solidity ^0.8.17; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { DistributionParameters } from "../../contracts/DistributionCreator.sol"; import "./Fixture.s.sol"; contract DistributionCreatorOOGTest is Fixture { using SafeERC20 for IERC20; - uint256 startTime; + uint32 startTime; + uint256 constant maxDistribForOOG = 1e4; function setUp() public override { super.setUp(); - startTime = block.timestamp; + startTime = uint32(block.timestamp); vm.startPrank(guardian); creator.toggleSigningWhitelist(alice); @@ -20,7 +22,7 @@ contract DistributionCreatorOOGTest is Fixture { address[] memory tokens = new address[](1); uint256[] memory amounts = new uint256[](1); tokens[0] = address(angle); - amounts[0] = 1e18; + amounts[0] = 1e8; creator.setRewardTokenMinAmounts(tokens, amounts); vm.stopPrank(); @@ -28,4 +30,68 @@ contract DistributionCreatorOOGTest is Fixture { vm.prank(alice); angle.approve(address(creator), type(uint256).max); } + + function testFuzz_GetDistributionsOutOfGas() public { + address[] memory positionWrappers = new address[](3); + uint32[] memory wrapperTypes = new uint32[](3); + positionWrappers[0] = alice; + positionWrappers[1] = bob; + positionWrappers[2] = charlie; + wrapperTypes[0] = 0; + wrapperTypes[1] = 1; + wrapperTypes[2] = 2; + + vm.startPrank(alice); + // struct DistributionParameters memory + // create a bunch of distributions to make the view function call fail + DistributionParameters memory params = DistributionParameters({ + uniV3Pool: address(pool), + rewardToken: address(angle), + positionWrappers: positionWrappers, + wrapperTypes: wrapperTypes, + amount: 1e10, + propToken0: 4000, + propToken1: 2000, + propFees: 4000, + isOutOfRangeIncentivized: 0, + epochStart: startTime, + numEpoch: 25, + boostedReward: 0, + boostingAddress: address(0), + rewardId: keccak256("TEST"), + additionalData: hex"" + }); + for (uint256 i; i < maxDistribForOOG + 1; i++) { + // params.epochStart += uint32(10 * i); + creator.createDistribution(params); + } + vm.stopPrank(); + + uint32 endTime = startTime + 25 * EPOCH_DURATION; + + // All calls will revert because it is oog + vm.expectRevert(); + creator.getActiveDistributions(); + + vm.expectRevert(); + creator.getDistributionsForEpoch(startTime); + + vm.expectRevert(); + creator.getDistributionsBetweenEpochs(startTime, endTime); + + vm.expectRevert(); + creator.getDistributionsAfterEpoch(startTime); + + vm.expectRevert(); + creator.getActivePoolDistributions(address(pool)); + + vm.expectRevert(); + creator.getPoolDistributionsForEpoch(address(pool), startTime); + + vm.expectRevert(); + creator.getPoolDistributionsBetweenEpochs(address(pool), startTime, endTime); + + vm.expectRevert(); + creator.getPoolDistributionsAfterEpoch(address(pool), startTime); + } } diff --git a/test/foundry/Fixture.s.sol b/test/foundry/Fixture.s.sol index 9822544..f4f65a2 100644 --- a/test/foundry/Fixture.s.sol +++ b/test/foundry/Fixture.s.sol @@ -4,14 +4,18 @@ pragma solidity ^0.8.17; import { Test, stdError } from "forge-std/Test.sol"; import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { DistributionCreator } from "../../contracts/DistributionCreator.sol"; import { MockTokenPermit } from "../../contracts/mock/MockTokenPermit.sol"; import { MockUniswapV3Pool } from "../../contracts/mock/MockUniswapV3Pool.sol"; import { MockCoreBorrow } from "../../contracts/mock/MockCoreBorrow.sol"; import { ICore } from "../../contracts/interfaces/ICore.sol"; +import "../../contracts/utils/UUPSHelper.sol"; import { console } from "forge-std/console.sol"; contract Fixture is Test { + uint32 public constant EPOCH_DURATION = 3600; + MockTokenPermit public angle; MockTokenPermit public agEUR; MockTokenPermit public token0; @@ -19,6 +23,7 @@ contract Fixture is Test { MockCoreBorrow public coreBorrow; MockUniswapV3Pool public pool; + DistributionCreator public creatorImpl; DistributionCreator public creator; address public alice; @@ -58,7 +63,8 @@ contract Fixture is Test { pool = new MockUniswapV3Pool(); // DistributionCreator - creator = new DistributionCreator(); + creatorImpl = new DistributionCreator(); + creator = DistributionCreator(deployUUPS(address(creatorImpl), hex"")); // Set pool.setToken(address(token0), 0); @@ -67,4 +73,12 @@ contract Fixture is Test { coreBorrow.toggleGovernor(address(governor)); creator.initialize(ICore(address(coreBorrow)), address(bob), 1e8); } + + /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + UTILS + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ + + function deployUUPS(address implementation, bytes memory data) public returns (address) { + return address(new ERC1967Proxy(implementation, data)); + } } From 8460af92d388182776a71fd4f46157dfefc18289 Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:44:17 +0200 Subject: [PATCH 4/8] tests done --- contracts/DistributionCreator.sol | 6 +- test/foundry/DistributionCreator.s.sol | 338 ++++++++++++++++++++++++- 2 files changed, 334 insertions(+), 10 deletions(-) diff --git a/contracts/DistributionCreator.sol b/contracts/DistributionCreator.sol index 473d762..c6b3d40 100644 --- a/contracts/DistributionCreator.sol +++ b/contracts/DistributionCreator.sol @@ -313,7 +313,11 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { function getActiveDistributions( uint32 skip, uint32 first - ) external view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { + ) + external + view + returns (ExtensiveDistributionParameters[] memory searchDistributions, uint256 lastIndexDistribution) + { uint32 roundedEpoch = _getRoundedEpoch(uint32(block.timestamp)); return _getPoolDistributionsBetweenEpochs(address(0), roundedEpoch, roundedEpoch + EPOCH_DURATION, skip, first); } diff --git a/test/foundry/DistributionCreator.s.sol b/test/foundry/DistributionCreator.s.sol index 1df2c38..51b8b51 100644 --- a/test/foundry/DistributionCreator.s.sol +++ b/test/foundry/DistributionCreator.s.sol @@ -2,19 +2,26 @@ pragma solidity ^0.8.17; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { DistributionParameters } from "../../contracts/DistributionCreator.sol"; +import { DistributionParameters, ExtensiveDistributionParameters } from "../../contracts/DistributionCreator.sol"; import "./Fixture.s.sol"; contract DistributionCreatorOOGTest is Fixture { using SafeERC20 for IERC20; - uint32 startTime; uint256 constant maxDistribForOOG = 1e4; + uint256 constant nbrDistrib = 10; + uint32 initStartTime; + uint32 initEndTime; + uint32 startTime; + uint32 endTime; + uint32 numEpoch; function setUp() public override { super.setUp(); - startTime = uint32(block.timestamp); + initStartTime = uint32(block.timestamp); + numEpoch = 25; + initEndTime = startTime + numEpoch * EPOCH_DURATION; vm.startPrank(guardian); creator.toggleSigningWhitelist(alice); @@ -29,6 +36,46 @@ contract DistributionCreatorOOGTest is Fixture { angle.mint(address(alice), 1e22); vm.prank(alice); angle.approve(address(creator), type(uint256).max); + + address[] memory positionWrappers = new address[](3); + uint32[] memory wrapperTypes = new uint32[](3); + positionWrappers[0] = alice; + positionWrappers[1] = bob; + positionWrappers[2] = charlie; + wrapperTypes[0] = 0; + wrapperTypes[1] = 1; + wrapperTypes[2] = 2; + + vm.startPrank(alice); + // struct DistributionParameters memory + // create a bunch of distributions to make the view function call fail + DistributionParameters memory params = DistributionParameters({ + uniV3Pool: address(pool), + rewardToken: address(angle), + positionWrappers: positionWrappers, + wrapperTypes: wrapperTypes, + amount: 1e10, + propToken0: 4000, + propToken1: 2000, + propFees: 4000, + isOutOfRangeIncentivized: 0, + epochStart: initStartTime, + numEpoch: 25, + boostedReward: 0, + boostingAddress: address(0), + rewardId: keccak256("TEST"), + additionalData: hex"" + }); + // create a first distrib way before the others + creator.createDistribution(params); + + vm.warp(startTime + 3600 * 24 * 1000); + startTime = uint32(block.timestamp); + endTime = startTime + numEpoch * EPOCH_DURATION; + params.epochStart = startTime; + for (uint256 i; i < nbrDistrib; i++) creator.createDistribution(params); + + vm.stopPrank(); } function testFuzz_GetDistributionsOutOfGas() public { @@ -61,14 +108,14 @@ contract DistributionCreatorOOGTest is Fixture { rewardId: keccak256("TEST"), additionalData: hex"" }); - for (uint256 i; i < maxDistribForOOG + 1; i++) { - // params.epochStart += uint32(10 * i); - creator.createDistribution(params); - } - vm.stopPrank(); - uint32 endTime = startTime + 25 * EPOCH_DURATION; + vm.warp(startTime + 3600 * 24 * 10); + startTime = uint32(block.timestamp); + endTime = startTime + numEpoch * EPOCH_DURATION; + params.epochStart = startTime; + for (uint256 i; i < maxDistribForOOG; i++) creator.createDistribution(params); + vm.stopPrank(); // All calls will revert because it is oog vm.expectRevert(); creator.getActiveDistributions(); @@ -94,4 +141,277 @@ contract DistributionCreatorOOGTest is Fixture { vm.expectRevert(); creator.getPoolDistributionsAfterEpoch(address(pool), startTime); } + + function testFuzz_getActiveDistributions() public { + uint256 lastIndexDistribution; + { + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getActivePoolDistributions(address(pool), 0, 1); + ExtensiveDistributionParameters[] memory searchDistributions; + (searchDistributions, lastIndexDistribution) = creator.getActiveDistributions(0, 1); + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(lastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, 1); + // The first distribution is finsihed + assertEq(lastIndexDistribution, 2); + assertEq(searchDistributions[0].base.rewardId, bytes32(keccak256(abi.encodePacked(alice, uint256(1))))); + } + + uint32 first = 2; + lastIndexDistribution = 2; + for (uint i; i < nbrDistrib / first; i++) { + { + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getActivePoolDistributions(address(pool), uint32(lastIndexDistribution), first); + ExtensiveDistributionParameters[] memory searchDistributions; + (searchDistributions, lastIndexDistribution) = creator.getActiveDistributions( + uint32(lastIndexDistribution), + first + ); + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(lastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, (i != nbrDistrib / first - 1) ? first : first - 1); + assertEq( + lastIndexDistribution, + (i != nbrDistrib / first - 1) ? 2 + (i + 1) * first : 2 + (i + 1) * first - 1 + ); + assertEq( + searchDistributions[0].base.rewardId, + bytes32(keccak256(abi.encodePacked(alice, uint256(2 + i * first)))) + ); + } + } + } + + function testFuzz_getDistributionsForEpoch() public { + uint256 lastIndexDistribution; + { + ExtensiveDistributionParameters[] memory searchDistributions; + (searchDistributions, lastIndexDistribution) = creator.getDistributionsForEpoch(initStartTime, 0, 1); + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getPoolDistributionsForEpoch(address(pool), initStartTime, 0, 1); + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(lastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, 1); + // The first distribution is finsihed + assertEq(lastIndexDistribution, 1); + assertEq(searchDistributions[0].base.rewardId, bytes32(keccak256(abi.encodePacked(alice, uint256(0))))); + } + + uint32 first = 2; + lastIndexDistribution = 6; + { + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getPoolDistributionsForEpoch(address(pool), startTime, uint32(lastIndexDistribution), first); + (ExtensiveDistributionParameters[] memory searchDistributions, uint256 endLastIndexDistribution) = creator + .getDistributionsForEpoch(startTime, uint32(lastIndexDistribution), first); + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(endLastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, first); + assertEq(endLastIndexDistribution, lastIndexDistribution + first); + assertEq( + searchDistributions[0].base.rewardId, + bytes32(keccak256(abi.encodePacked(alice, lastIndexDistribution))) + ); + } + } + + function testFuzz_getDistributionsBetweenEpochs() public { + uint256 lastIndexDistribution; + { + ExtensiveDistributionParameters[] memory searchDistributions; + (searchDistributions, lastIndexDistribution) = creator.getDistributionsBetweenEpochs( + initStartTime, + startTime + 1, + 0, + 100 + ); + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getPoolDistributionsBetweenEpochs(address(pool), initStartTime, startTime + 1, 0, 100); + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(lastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, 1); + // The first distribution is finsihed + assertEq(lastIndexDistribution, 11); + assertEq(searchDistributions[0].base.rewardId, bytes32(keccak256(abi.encodePacked(alice, uint256(0))))); + } + + uint32 first = 2; + lastIndexDistribution = 6; + { + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getPoolDistributionsBetweenEpochs( + address(pool), + startTime, + endTime + 2, + uint32(lastIndexDistribution), + first + ); + (ExtensiveDistributionParameters[] memory searchDistributions, uint256 endLastIndexDistribution) = creator + .getDistributionsBetweenEpochs(startTime, endTime + 2, uint32(lastIndexDistribution), first); + + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(endLastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, first); + assertEq(endLastIndexDistribution, lastIndexDistribution + first); + assertEq( + searchDistributions[0].base.rewardId, + bytes32(keccak256(abi.encodePacked(alice, lastIndexDistribution))) + ); + } + } + + function testFuzz_getDistributionsAfterEpoch() public { + uint256 lastIndexDistribution; + { + ExtensiveDistributionParameters[] memory searchDistributions; + (searchDistributions, lastIndexDistribution) = creator.getDistributionsAfterEpoch(initStartTime, 0, 100); + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getPoolDistributionsAfterEpoch(address(pool), initStartTime, 0, 100); + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(lastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, 11); + // The first distribution is finsihed + assertEq(lastIndexDistribution, 11); + assertEq(searchDistributions[0].base.rewardId, bytes32(keccak256(abi.encodePacked(alice, uint256(0))))); + } + + { + ExtensiveDistributionParameters[] memory searchDistributions; + (searchDistributions, lastIndexDistribution) = creator.getDistributionsAfterEpoch(startTime, 0, 100); + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getPoolDistributionsAfterEpoch(address(pool), startTime, 0, 100); + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(lastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, 10); + // The first distribution is finsihed + assertEq(lastIndexDistribution, 11); + assertEq(searchDistributions[0].base.rewardId, bytes32(keccak256(abi.encodePacked(alice, uint256(1))))); + } + + uint32 first = 3; + lastIndexDistribution = 5; + { + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getPoolDistributionsAfterEpoch( + address(pool), + initStartTime, + uint32(lastIndexDistribution), + first + ); + (ExtensiveDistributionParameters[] memory searchDistributions, uint256 endLastIndexDistribution) = creator + .getDistributionsAfterEpoch(initStartTime, uint32(lastIndexDistribution), first); + + assertEq(searchDistributions.length, searchDistributionsPool.length); + assertEq(endLastIndexDistribution, lastIndexDistributionPool); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, first); + assertEq(endLastIndexDistribution, lastIndexDistribution + first); + assertEq( + searchDistributions[0].base.rewardId, + bytes32(keccak256(abi.encodePacked(alice, lastIndexDistribution))) + ); + } + } + + /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + WITH DIFFERENT POOLS + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ + function testFuzz_getActiveDistributionsWithDifferentPool() public { + address[] memory positionWrappers = new address[](3); + uint32[] memory wrapperTypes = new uint32[](3); + positionWrappers[0] = alice; + positionWrappers[1] = bob; + positionWrappers[2] = charlie; + wrapperTypes[0] = 0; + wrapperTypes[1] = 1; + wrapperTypes[2] = 2; + + MockUniswapV3Pool pool2 = new MockUniswapV3Pool(); + pool2.setToken(address(token0), 0); + pool2.setToken(address(token1), 1); + + vm.startPrank(alice); + DistributionParameters memory params = DistributionParameters({ + uniV3Pool: address(pool2), + rewardToken: address(angle), + positionWrappers: positionWrappers, + wrapperTypes: wrapperTypes, + amount: 1e10, + propToken0: 4000, + propToken1: 2000, + propFees: 4000, + isOutOfRangeIncentivized: 0, + epochStart: startTime, + numEpoch: 25, + boostedReward: 0, + boostingAddress: address(0), + rewardId: keccak256("TEST"), + additionalData: hex"" + }); + + for (uint256 i; i < 4; i++) creator.createDistribution(params); + + vm.stopPrank(); + + uint32 first = 5; + uint256 lastIndexDistribution = 8; + { + ( + ExtensiveDistributionParameters[] memory searchDistributionsPool, + uint256 lastIndexDistributionPool + ) = creator.getActivePoolDistributions(address(pool), uint32(lastIndexDistribution), first); + ExtensiveDistributionParameters[] memory searchDistributions; + (searchDistributions, lastIndexDistribution) = creator.getActiveDistributions( + uint32(lastIndexDistribution), + first + ); + assertEq(searchDistributionsPool.length, 3); + assertEq(lastIndexDistributionPool, 15); + assertEq(searchDistributions[0].base.rewardId, searchDistributionsPool[0].base.rewardId); + + assertEq(searchDistributions.length, first); + assertEq(lastIndexDistribution, 13); + assertEq( + searchDistributions[0].base.rewardId, + bytes32(keccak256(abi.encodePacked(alice, uint256(lastIndexDistribution - first)))) + ); + assertEq(searchDistributions[0].base.uniV3Pool, address(pool)); + } + } } From a3092f6d0d927426613ecaa2d33bdd5d7d5965b6 Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:45:36 +0200 Subject: [PATCH 5/8] reset compilation via-ir --- foundry.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foundry.toml b/foundry.toml index f01189b..12b1018 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,7 +6,7 @@ libs = ['node_modules', 'lib'] script = 'scripts/foundry' cache_path = 'cache-forge' gas_reports = ["*"] -via_ir = false +via_ir = true optimizer_runs=100 # solc_version = '0.8.17' From f680d2ff5247794b480cd61241f9e4c51b088a90 Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:00:59 +0200 Subject: [PATCH 6/8] removed return name value in `_getPoolDistributionsBetweenEpochs` --- contracts/DistributionCreator.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/DistributionCreator.sol b/contracts/DistributionCreator.sol index c6b3d40..6ce17c4 100644 --- a/contracts/DistributionCreator.sol +++ b/contracts/DistributionCreator.sol @@ -713,7 +713,7 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { uint32 epochEnd, uint32 skip, uint32 first - ) internal view returns (ExtensiveDistributionParameters[] memory, uint256 lastIndexDistribution) { + ) internal view returns (ExtensiveDistributionParameters[] memory, uint256) { uint256 length; uint256 distributionListLength = distributionList.length; uint256 returnSize = first > distributionListLength ? distributionListLength : first; From 79c11c857db29e5cbd9840e06247b4a994e92af7 Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:03:09 +0200 Subject: [PATCH 7/8] comments @sogipec --- contracts/DistributionCreator.sol | 69 ++++++++++++++++++------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/contracts/DistributionCreator.sol b/contracts/DistributionCreator.sol index 6ce17c4..9ead6d5 100644 --- a/contracts/DistributionCreator.sol +++ b/contracts/DistributionCreator.sol @@ -306,10 +306,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Returns the list of all currently active distributions on pools of supported AMMs (like Uniswap V3) /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getActiveDistributions()` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` + /// @notice Similar to `getActiveDistributions()` with additional parameters to prevent out of gas error function getActiveDistributions( uint32 skip, uint32 first @@ -359,11 +361,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Returns the list of all the distributions that were or that are going to be live at - /// a specific epoch + /// @notice Similar to `getDistributionsForEpoch(uint256 epoch)` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getDistributionsForEpoch(uint256 epoch)` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` function getDistributionsForEpoch( uint32 epoch, uint32 skip, @@ -389,10 +392,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Gets the distributions that were or will be live at some point between `epochStart` (included) and `epochEnd` (excluded) + /// @notice Similar to `getDistributionsBetweenEpochs(uint256 epochStart, uint256 epochEnd)` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getDistributionsBetweenEpochs(uint256 epochStart, uint256 epochEnd)` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` function getDistributionsBetweenEpochs( uint32 epochStart, uint32 epochEnd, @@ -422,10 +427,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) + /// @notice Similar to `getDistributionsAfterEpoch(uint256 epochStart)` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getDistributionsAfterEpoch(uint256 epochStart)` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` function getDistributionsAfterEpoch( uint32 epochStart, uint32 skip, @@ -449,10 +456,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Returns the list of all currently active distributions for a specific UniswapV3 pool + /// @notice Similar to `getActivePoolDistributions(address uniV3Pool)` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getActivePoolDistributions(address uniV3Pool)` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` function getActivePoolDistributions( address uniV3Pool, uint32 skip, @@ -478,11 +487,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Returns the list of all the distributions that were or that are going to be live at a - /// specific epoch and for a specific pool + /// @notice Similar to `getPoolDistributionsForEpoch(address uniV3Pool,uint32 epoch)` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getPoolDistributionsForEpoch(address uniV3Pool,uint32 epoch)` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` function getPoolDistributionsForEpoch( address uniV3Pool, uint32 epoch, @@ -509,12 +519,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Returns the list of all distributions that were or will be live at some point between - /// `epochStart` (included) and `epochEnd` (excluded) for a specific pool - /// specific epoch and for a specific pool + /// @notice Similar to `getPoolDistributionsBetweenEpochs(address uniV3Pool,uint32 epochStart, uint32 epochEnd)` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getPoolDistributionsBetweenEpochs(address uniV3Pool,uint32 epochStart, uint32 epochEnd)` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` function getPoolDistributionsBetweenEpochs( address uniV3Pool, uint32 epochStart, @@ -547,11 +557,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } - /// @notice Returns the list of all distributions that were or will be live after `epochStart` (included) - /// for a specific pool + /// @notice Similar to `getPoolDistributionsAfterEpoch(address uniV3Pool,uint32 epochStart)` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` - /// @param first Limit the lenght of the returned array to `first` - /// @dev Similar to `getPoolDistributionsAfterEpoch(address uniV3Pool,uint32 epochStart)` with additional parameters to prevent out of gas error + /// @param first Limit the length of the returned array to `first` + /// @return searchDistributions Eligible distributions + /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions + /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` function getPoolDistributionsAfterEpoch( address uniV3Pool, uint32 epochStart, From f7f1cad70c6895d4c955549e22acccc140c353be Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:16:27 +0200 Subject: [PATCH 8/8] last comment @sogipec --- contracts/DistributionCreator.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/DistributionCreator.sol b/contracts/DistributionCreator.sol index 9ead6d5..92e7196 100644 --- a/contracts/DistributionCreator.sol +++ b/contracts/DistributionCreator.sol @@ -306,12 +306,12 @@ contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { ); } + /// @notice Similar to `getActiveDistributions()` with additional parameters to prevent out of gas error /// @param skip Disregard distibutions with a global index lower than `skip` /// @param first Limit the length of the returned array to `first` /// @return searchDistributions Eligible distributions /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions /// For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` - /// @notice Similar to `getActiveDistributions()` with additional parameters to prevent out of gas error function getActiveDistributions( uint32 skip, uint32 first