From 6262bc037b66ac558dc4afab67227491ea82587f Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Sun, 13 Oct 2024 21:34:37 +0200 Subject: [PATCH 01/14] Update repo architecture --- src/{ => base}/LBHooksBaseParentRewarder.sol | 4 ++-- src/{ => base}/LBHooksBaseRewarder.sol | 4 ++-- src/{ => base}/LBHooksBaseSimpleRewarder.sol | 4 ++-- src/{ => rewarder}/LBHooksExtraRewarder.sol | 10 +++++----- src/{ => rewarder}/LBHooksMCRewarder.sol | 6 +++--- src/{ => rewarder}/LBHooksSimpleRewarder.sol | 10 +++++----- test/LBHooksLens.t.sol | 10 +++++----- test/LBHooksManager.t.sol | 6 +++--- test/TestHelper.sol | 6 +++--- test/{ => base}/LBHooksBaseRewarder.t.sol | 6 +++--- test/{ => rewarder}/LBHooksExtraRewarder.t.sol | 10 +++++----- test/{ => rewarder}/LBHooksRewarder.t.sol | 6 +++--- test/{ => rewarder}/LBHooksSimpleRewarder.t.sol | 10 +++++----- 13 files changed, 46 insertions(+), 46 deletions(-) rename src/{ => base}/LBHooksBaseParentRewarder.sol (97%) rename src/{ => base}/LBHooksBaseRewarder.sol (99%) rename src/{ => base}/LBHooksBaseSimpleRewarder.sol (97%) rename src/{ => rewarder}/LBHooksExtraRewarder.sol (87%) rename src/{ => rewarder}/LBHooksMCRewarder.sol (95%) rename src/{ => rewarder}/LBHooksSimpleRewarder.sol (85%) rename test/{ => base}/LBHooksBaseRewarder.t.sol (99%) rename test/{ => rewarder}/LBHooksExtraRewarder.t.sol (99%) rename test/{ => rewarder}/LBHooksRewarder.t.sol (97%) rename test/{ => rewarder}/LBHooksSimpleRewarder.t.sol (99%) diff --git a/src/LBHooksBaseParentRewarder.sol b/src/base/LBHooksBaseParentRewarder.sol similarity index 97% rename from src/LBHooksBaseParentRewarder.sol rename to src/base/LBHooksBaseParentRewarder.sol index c609899..8aa13c0 100644 --- a/src/LBHooksBaseParentRewarder.sol +++ b/src/base/LBHooksBaseParentRewarder.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.20; import {Hooks} from "@lb-protocol/src/libraries/Hooks.sol"; import {LBHooksBaseRewarder, ILBHooksBaseRewarder} from "./LBHooksBaseRewarder.sol"; -import {ILBHooksBaseParentRewarder} from "./interfaces/ILBHooksBaseParentRewarder.sol"; -import {ILBHooksExtraRewarder} from "./interfaces/ILBHooksExtraRewarder.sol"; +import {ILBHooksBaseParentRewarder} from "../interfaces/ILBHooksBaseParentRewarder.sol"; +import {ILBHooksExtraRewarder} from "../interfaces/ILBHooksExtraRewarder.sol"; /** * @title LB Hooks Base Parent Rewarder diff --git a/src/LBHooksBaseRewarder.sol b/src/base/LBHooksBaseRewarder.sol similarity index 99% rename from src/LBHooksBaseRewarder.sol rename to src/base/LBHooksBaseRewarder.sol index d147301..a228872 100644 --- a/src/LBHooksBaseRewarder.sol +++ b/src/base/LBHooksBaseRewarder.sol @@ -14,8 +14,8 @@ import {BinHelper} from "@lb-protocol/src/libraries/BinHelper.sol"; import {Hooks} from "@lb-protocol/src/libraries/Hooks.sol"; import {SafeCast} from "@lb-protocol/src/libraries/math/SafeCast.sol"; -import {ILBHooksBaseRewarder} from "./interfaces/ILBHooksBaseRewarder.sol"; -import {TokenHelper, IERC20} from "./library/TokenHelper.sol"; +import {ILBHooksBaseRewarder} from "../interfaces/ILBHooksBaseRewarder.sol"; +import {TokenHelper, IERC20} from "../library/TokenHelper.sol"; /** * @title LB Hooks Base Rewarder diff --git a/src/LBHooksBaseSimpleRewarder.sol b/src/base/LBHooksBaseSimpleRewarder.sol similarity index 97% rename from src/LBHooksBaseSimpleRewarder.sol rename to src/base/LBHooksBaseSimpleRewarder.sol index c6c5ed2..660dad5 100644 --- a/src/LBHooksBaseSimpleRewarder.sol +++ b/src/base/LBHooksBaseSimpleRewarder.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.20; import {LBHooksBaseRewarder, Hooks} from "./LBHooksBaseRewarder.sol"; -import {ILBHooksBaseSimpleRewarder} from "./interfaces/ILBHooksBaseSimpleRewarder.sol"; +import {ILBHooksBaseSimpleRewarder} from "../interfaces/ILBHooksBaseSimpleRewarder.sol"; -import {TokenHelper} from "./library/TokenHelper.sol"; +import {TokenHelper} from "../library/TokenHelper.sol"; /** * @title LB Hooks Base Simple Rewarder diff --git a/src/LBHooksExtraRewarder.sol b/src/rewarder/LBHooksExtraRewarder.sol similarity index 87% rename from src/LBHooksExtraRewarder.sol rename to src/rewarder/LBHooksExtraRewarder.sol index 0c08f92..f0472ef 100644 --- a/src/LBHooksExtraRewarder.sol +++ b/src/rewarder/LBHooksExtraRewarder.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {LBHooksBaseRewarder, Hooks} from "./LBHooksBaseRewarder.sol"; -import {ILBHooksExtraRewarder} from "./interfaces/ILBHooksExtraRewarder.sol"; -import {ILBHooksBaseParentRewarder} from "./interfaces/ILBHooksBaseParentRewarder.sol"; -import {LBHooksBaseSimpleRewarder} from "./LBHooksBaseSimpleRewarder.sol"; +import {LBHooksBaseRewarder, Hooks} from "../base/LBHooksBaseRewarder.sol"; +import {ILBHooksExtraRewarder} from "../interfaces/ILBHooksExtraRewarder.sol"; +import {ILBHooksBaseParentRewarder} from "../interfaces/ILBHooksBaseParentRewarder.sol"; +import {LBHooksBaseSimpleRewarder} from "../base/LBHooksBaseSimpleRewarder.sol"; -import {TokenHelper} from "./library/TokenHelper.sol"; +import {TokenHelper} from "../library/TokenHelper.sol"; /** * @title LB Hooks Extra Rewarder diff --git a/src/LBHooksMCRewarder.sol b/src/rewarder/LBHooksMCRewarder.sol similarity index 95% rename from src/LBHooksMCRewarder.sol rename to src/rewarder/LBHooksMCRewarder.sol index 8299a48..cc1a41f 100644 --- a/src/LBHooksMCRewarder.sol +++ b/src/rewarder/LBHooksMCRewarder.sol @@ -5,10 +5,10 @@ import {IERC20Metadata, IERC20} from "@openzeppelin/contracts/token/ERC20/extens import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import {IMasterChef, IMasterChefRewarder} from "@moe-core/src/interfaces/IMasterChef.sol"; -import {LBHooksBaseParentRewarder, LBHooksBaseRewarder} from "./LBHooksBaseParentRewarder.sol"; -import {ILBHooksMCRewarder} from "./interfaces/ILBHooksMCRewarder.sol"; +import {LBHooksBaseParentRewarder, LBHooksBaseRewarder} from "../base/LBHooksBaseParentRewarder.sol"; +import {ILBHooksMCRewarder} from "../interfaces/ILBHooksMCRewarder.sol"; -import {TokenHelper} from "./library/TokenHelper.sol"; +import {TokenHelper} from "../library/TokenHelper.sol"; /** * @title LB Hooks MasterChef Rewarder diff --git a/src/LBHooksSimpleRewarder.sol b/src/rewarder/LBHooksSimpleRewarder.sol similarity index 85% rename from src/LBHooksSimpleRewarder.sol rename to src/rewarder/LBHooksSimpleRewarder.sol index cfeeddb..ba92b69 100644 --- a/src/LBHooksSimpleRewarder.sol +++ b/src/rewarder/LBHooksSimpleRewarder.sol @@ -3,12 +3,12 @@ pragma solidity ^0.8.20; import {Hooks} from "@lb-protocol/src/libraries/Hooks.sol"; -import {LBHooksBaseSimpleRewarder} from "./LBHooksBaseSimpleRewarder.sol"; -import {LBHooksBaseParentRewarder} from "./LBHooksBaseParentRewarder.sol"; -import {LBHooksBaseRewarder} from "./LBHooksBaseRewarder.sol"; -import {ILBHooksSimpleRewarder} from "./interfaces/ILBHooksSimpleRewarder.sol"; +import {LBHooksBaseSimpleRewarder} from "../base/LBHooksBaseSimpleRewarder.sol"; +import {LBHooksBaseParentRewarder} from "../base/LBHooksBaseParentRewarder.sol"; +import {LBHooksBaseRewarder} from "../base/LBHooksBaseRewarder.sol"; +import {ILBHooksSimpleRewarder} from "../interfaces/ILBHooksSimpleRewarder.sol"; -import {TokenHelper} from "./library/TokenHelper.sol"; +import {TokenHelper} from "../library/TokenHelper.sol"; /** * @title LB Hooks Simple Rewarder diff --git a/test/LBHooksLens.t.sol b/test/LBHooksLens.t.sol index 09d5f33..6eb292a 100644 --- a/test/LBHooksLens.t.sol +++ b/test/LBHooksLens.t.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.20; -import "./TestHelper.sol"; +import "test/TestHelper.sol"; -import {ILBHooksBaseRewarder, LBHooksBaseRewarder} from "../src/LBHooksBaseRewarder.sol"; -import "../src/LBHooksMCRewarder.sol"; -import "../src/LBHooksExtraRewarder.sol"; -import "../src/LBHooksLens.sol"; +import {ILBHooksBaseRewarder, LBHooksBaseRewarder} from "src/base/LBHooksBaseRewarder.sol"; +import "src/rewarder/LBHooksMCRewarder.sol"; +import "src/rewarder/LBHooksExtraRewarder.sol"; +import "src/LBHooksLens.sol"; contract LBHooksLensTest is TestHelper { LBHooksMCRewarder lbHooks; diff --git a/test/LBHooksManager.t.sol b/test/LBHooksManager.t.sol index d48c02e..61e4f6e 100644 --- a/test/LBHooksManager.t.sol +++ b/test/LBHooksManager.t.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.20; -import "./TestHelper.sol"; +import "test/TestHelper.sol"; -import "../src/LBHooksMCRewarder.sol"; -import "../src/LBHooksExtraRewarder.sol"; +import "src/rewarder/LBHooksMCRewarder.sol"; +import "src/rewarder/LBHooksExtraRewarder.sol"; contract LBHooksManagerTest is TestHelper { bytes32 rewarderHooksParameters; diff --git a/test/TestHelper.sol b/test/TestHelper.sol index 719556b..a3811b1 100644 --- a/test/TestHelper.sol +++ b/test/TestHelper.sol @@ -10,9 +10,9 @@ import {ImmutableClone} from "@lb-protocol/src/libraries/ImmutableClone.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import "./mocks/MockERC20.sol"; -import "./mocks/MockMasterChef.sol"; -import "../src/LBHooksManager.sol"; +import "test/mocks/MockERC20.sol"; +import "test/mocks/MockMasterChef.sol"; +import "src/LBHooksManager.sol"; abstract contract TestHelper is Test { uint16 public constant DEFAULT_BIN_STEP = 25; diff --git a/test/LBHooksBaseRewarder.t.sol b/test/base/LBHooksBaseRewarder.t.sol similarity index 99% rename from test/LBHooksBaseRewarder.t.sol rename to test/base/LBHooksBaseRewarder.t.sol index dca0c53..47bb492 100644 --- a/test/LBHooksBaseRewarder.t.sol +++ b/test/base/LBHooksBaseRewarder.t.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.20; -import {TestHelper} from "./TestHelper.sol"; +import "test/TestHelper.sol"; -import "./mocks/MockERC20.sol"; -import "../src/LBHooksBaseRewarder.sol"; +import "test/mocks/MockERC20.sol"; +import "src/base/LBHooksBaseRewarder.sol"; contract LBHooksBaseRewarderTest is TestHelper { MockLBHooksRewarder hooks; diff --git a/test/LBHooksExtraRewarder.t.sol b/test/rewarder/LBHooksExtraRewarder.t.sol similarity index 99% rename from test/LBHooksExtraRewarder.t.sol rename to test/rewarder/LBHooksExtraRewarder.t.sol index 08b5056..d273ad4 100644 --- a/test/LBHooksExtraRewarder.t.sol +++ b/test/rewarder/LBHooksExtraRewarder.t.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.20; -import "./TestHelper.sol"; +import "test/TestHelper.sol"; -import "../src/LBHooksBaseRewarder.sol"; -import "../src/LBHooksBaseSimpleRewarder.sol"; -import "../src/LBHooksMCRewarder.sol"; -import "../src/LBHooksExtraRewarder.sol"; +import "src/base/LBHooksBaseRewarder.sol"; +import "src/base/LBHooksBaseSimpleRewarder.sol"; +import "src/rewarder/LBHooksMCRewarder.sol"; +import "src/rewarder/LBHooksExtraRewarder.sol"; contract LBHooksExtraRewarderTest is TestHelper { LBHooksMCRewarder lbHooks; diff --git a/test/LBHooksRewarder.t.sol b/test/rewarder/LBHooksRewarder.t.sol similarity index 97% rename from test/LBHooksRewarder.t.sol rename to test/rewarder/LBHooksRewarder.t.sol index 3be73d7..1f2df77 100644 --- a/test/LBHooksRewarder.t.sol +++ b/test/rewarder/LBHooksRewarder.t.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.20; -import "./TestHelper.sol"; +import "test/TestHelper.sol"; -import "../src/LBHooksMCRewarder.sol"; -import "../src/interfaces/ILBHooksBaseRewarder.sol"; +import "src/rewarder/LBHooksMCRewarder.sol"; +import "src/interfaces/ILBHooksBaseRewarder.sol"; contract LBHooksRewarderTest is TestHelper { LBHooksMCRewarder lbHooks; diff --git a/test/LBHooksSimpleRewarder.t.sol b/test/rewarder/LBHooksSimpleRewarder.t.sol similarity index 99% rename from test/LBHooksSimpleRewarder.t.sol rename to test/rewarder/LBHooksSimpleRewarder.t.sol index 8d87507..9c4fe18 100644 --- a/test/LBHooksSimpleRewarder.t.sol +++ b/test/rewarder/LBHooksSimpleRewarder.t.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.20; -import "./TestHelper.sol"; +import "test/TestHelper.sol"; -import "../src/LBHooksBaseRewarder.sol"; -import "../src/LBHooksBaseSimpleRewarder.sol"; -import "../src/LBHooksSimpleRewarder.sol"; -import "../src/LBHooksExtraRewarder.sol"; +import "src/base/LBHooksBaseRewarder.sol"; +import "src/base/LBHooksBaseSimpleRewarder.sol"; +import "src/rewarder/LBHooksSimpleRewarder.sol"; +import "src/rewarder/LBHooksExtraRewarder.sol"; contract LBHooksSimpleRewarderTest is TestHelper { LBHooksSimpleRewarder lbHooks; From ecb21a802cddfd9a56b8127a4b9cc96a0f9f8466 Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 00:00:21 +0200 Subject: [PATCH 02/14] Refactor contracts to allow different way to calculate the rewarded range --- src/base/LBHooksBaseRewarder.sol | 65 +++---------------------- src/base/LBHooksRewarderVirtual.sol | 58 ++++++++++++++++++++++ src/interfaces/ILBHooksBaseRewarder.sol | 4 -- src/rewarder/LBHooksExtraRewarder.sol | 7 ++- src/rewarder/LBHooksMCRewarder.sol | 2 +- src/rewarder/LBHooksSimpleRewarder.sol | 11 ++++- 6 files changed, 81 insertions(+), 66 deletions(-) create mode 100644 src/base/LBHooksRewarderVirtual.sol diff --git a/src/base/LBHooksBaseRewarder.sol b/src/base/LBHooksBaseRewarder.sol index a228872..21ac6b2 100644 --- a/src/base/LBHooksBaseRewarder.sol +++ b/src/base/LBHooksBaseRewarder.sol @@ -1,10 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import { - Ownable2StepUpgradeable, - OwnableUpgradeable -} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {LBBaseHooks} from "@lb-protocol/src/LBBaseHooks.sol"; import {Uint256x256Math} from "@lb-protocol/src/libraries/math/Uint256x256Math.sol"; import {Clone} from "@lb-protocol/src/libraries/Clone.sol"; @@ -16,27 +12,25 @@ import {SafeCast} from "@lb-protocol/src/libraries/math/SafeCast.sol"; import {ILBHooksBaseRewarder} from "../interfaces/ILBHooksBaseRewarder.sol"; import {TokenHelper, IERC20} from "../library/TokenHelper.sol"; +import {LBHooksRewarderVirtual} from "./LBHooksRewarderVirtual.sol"; /** * @title LB Hooks Base Rewarder * @dev Base contract for any LB Hooks Rewarder */ -abstract contract LBHooksBaseRewarder is LBBaseHooks, Ownable2StepUpgradeable, Clone, ILBHooksBaseRewarder { +abstract contract LBHooksBaseRewarder is LBBaseHooks, LBHooksRewarderVirtual, Clone, ILBHooksBaseRewarder { using Uint256x256Math for uint256; using SafeCast for uint256; address public immutable implementation; - int256 internal constant MAX_NUMBER_OF_BINS = 11; + uint256 internal constant MAX_NUMBER_OF_BINS = 11; uint8 internal constant OFFSET_PRECISION = 128; bytes32 internal constant FLAGS = Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_MINT_FLAG | Hooks.BEFORE_BURN_FLAG | Hooks.BEFORE_TRANSFER_FLAG; address internal immutable _lbHooksManager; - int24 internal _deltaBinA; - int24 internal _deltaBinB; - uint256 internal _totalUnclaimedRewards; mapping(uint256 => Bin) internal _bins; @@ -177,25 +171,6 @@ abstract contract LBHooksBaseRewarder is LBBaseHooks, Ownable2StepUpgradeable, C _claim(user, ids, _unclaimedRewards[user]); } - /** - * @dev Sets the delta bins - * The delta bins are used to determine the range of bins to be rewarded, - * from [activeId + deltaBinA, activeId + deltaBinB[ (exclusive). - * @param deltaBinA The delta bin A - * @param deltaBinB The delta bin B - */ - function setDeltaBins(int24 deltaBinA, int24 deltaBinB) external virtual override onlyOwner { - if (deltaBinA > deltaBinB) revert LBHooksBaseRewarder__InvalidDeltaBins(); - if (int256(deltaBinB) - deltaBinA > MAX_NUMBER_OF_BINS) revert LBHooksBaseRewarder__ExceedsMaxNumberOfBins(); - - _updateAccruedRewardsPerShare(); - - _deltaBinA = deltaBinA; - _deltaBinB = deltaBinB; - - emit DeltaBinsSet(deltaBinA, deltaBinB); - } - /** * @dev Sweeps the given token to the given address * @param token The address of the token @@ -238,15 +213,14 @@ abstract contract LBHooksBaseRewarder is LBBaseHooks, Ownable2StepUpgradeable, C internal view virtual + override returns (uint256[] memory rewardedIds, uint24 activeId, uint256 binStart, uint256 binEnd) { activeId = _getLBPair().getActiveId(); - (int24 deltaBinA, int24 deltaBinB) = (_deltaBinA, _deltaBinB); - - binStart = uint256(int256(uint256(activeId)) + deltaBinA); - binEnd = uint256(int256(uint256(activeId)) + deltaBinB); + (binStart, binEnd) = _getRewardedBounds(activeId); if (binStart > type(uint24).max || binEnd > type(uint24).max) revert LBHooksBaseRewarder__Overflow(); + if (binEnd - binStart > MAX_NUMBER_OF_BINS) revert LBHooksBaseRewarder__ExceedsMaxNumberOfBins(); uint256 length = binEnd - binStart; rewardedIds = new uint256[](length); @@ -326,7 +300,7 @@ abstract contract LBHooksBaseRewarder is LBBaseHooks, Ownable2StepUpgradeable, C /** * @dev Internal function to update the accrued rewards per share */ - function _updateAccruedRewardsPerShare() internal virtual { + function _updateAccruedRewardsPerShare() internal virtual override { uint256 pendingTotalRewards = _updateRewards(); if (pendingTotalRewards == 0) return; @@ -480,29 +454,4 @@ abstract contract LBHooksBaseRewarder is LBBaseHooks, Ownable2StepUpgradeable, C _updateUser(from, ids); _updateUser(to, ids); } - - /** - * @dev Internal function that can be overriden to add custom logic when the rewarder is set - * @param data The data used to initialize the rewarder - */ - function _onHooksSet(bytes calldata data) internal virtual {} - - /** - * @dev Internal function that can be overriden to add custom logic when the rewards are claimed - * @param user The address of the user - * @param ids The ids of the bins - */ - function _onClaim(address user, uint256[] memory ids) internal virtual {} - - /** - * @dev Internal function that **MUST** be overriden to return the total pending rewards - * @return pendingTotalRewards The total pending rewards - */ - function _getPendingTotalRewards() internal view virtual returns (uint256 pendingTotalRewards); - - /** - * @dev Internal function that **MUST** be overriden to update and return the total pending rewards - * @return pendingTotalRewards The total pending rewards - */ - function _updateRewards() internal virtual returns (uint256 pendingTotalRewards); } diff --git a/src/base/LBHooksRewarderVirtual.sol b/src/base/LBHooksRewarderVirtual.sol new file mode 100644 index 0000000..e772b79 --- /dev/null +++ b/src/base/LBHooksRewarderVirtual.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; + +abstract contract LBHooksRewarderVirtual is Ownable2StepUpgradeable { + /** + * @dev Internal function that can be overriden to add custom logic when the rewarder is set + * @param data The data used to initialize the rewarder + */ + function _onHooksSet(bytes calldata data) internal virtual; + + /** + * @dev Internal function that can be overriden to add custom logic when the rewards are claimed + * @param user The address of the user + * @param ids The ids of the bins + */ + function _onClaim(address user, uint256[] memory ids) internal virtual; + + /** + * @dev Internal function that **MUST** be overriden to return the total pending rewards + * @return pendingTotalRewards The total pending rewards + */ + function _getPendingTotalRewards() internal view virtual returns (uint256 pendingTotalRewards); + + /** + * @dev Internal function that **MUST** be overriden to return the rewarded start and end id (exclusive) + * @param activeId The active id + * @return binStart The bin start to be rewarded + * @return binEnd The bin end to be rewarded, exclusive + */ + function _getRewardedBounds(uint24 activeId) internal view virtual returns (uint256 binStart, uint256 binEnd); + + /** + * @dev Internal helper function that **MUST** be overriden to return the rewarded range + * @return rewardedIds The list of the rewarded ids from binStart to binEnd + * @return activeId The active id + * @return binStart The bin start to be rewarded + * @return binEnd The bin end to be rewarded + */ + function _getRewardedRange() + internal + view + virtual + returns (uint256[] memory rewardedIds, uint24 activeId, uint256 binStart, uint256 binEnd); + + /** + * @dev Internal function that **MUST** be overriden to update and return the total pending rewards + * @return pendingTotalRewards The total pending rewards + */ + function _updateRewards() internal virtual returns (uint256 pendingTotalRewards); + + /** + * @dev Internal function that **MUST** be overriden to update the accrued rewards per share + * @dev Internal function to update the accrued rewards per share + */ + function _updateAccruedRewardsPerShare() internal virtual; +} diff --git a/src/interfaces/ILBHooksBaseRewarder.sol b/src/interfaces/ILBHooksBaseRewarder.sol index 077525c..890bf2b 100644 --- a/src/interfaces/ILBHooksBaseRewarder.sol +++ b/src/interfaces/ILBHooksBaseRewarder.sol @@ -9,7 +9,6 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; * @dev Interface for the LB Hooks Base Rewarder */ interface ILBHooksBaseRewarder is ILBHooks { - error LBHooksBaseRewarder__InvalidDeltaBins(); error LBHooksBaseRewarder__Overflow(); error LBHooksBaseRewarder__NativeTransferFailed(); error LBHooksBaseRewarder__UnlinkedHooks(); @@ -21,7 +20,6 @@ interface ILBHooksBaseRewarder is ILBHooks { error LBHooksBaseRewarder__UnauthorizedCaller(); error LBHooksBaseRewarder__ExceedsMaxNumberOfBins(); - event DeltaBinsSet(int24 deltaBinA, int24 deltaBinB); event Claim(address indexed user, uint256 amount); struct Bin { @@ -41,7 +39,5 @@ interface ILBHooksBaseRewarder is ILBHooks { function claim(address user, uint256[] calldata ids) external; - function setDeltaBins(int24 deltaBinA, int24 deltaBinB) external; - function sweep(IERC20 token, address to) external; } diff --git a/src/rewarder/LBHooksExtraRewarder.sol b/src/rewarder/LBHooksExtraRewarder.sol index f0472ef..c621f00 100644 --- a/src/rewarder/LBHooksExtraRewarder.sol +++ b/src/rewarder/LBHooksExtraRewarder.sol @@ -13,7 +13,7 @@ import {TokenHelper} from "../library/TokenHelper.sol"; * @dev This contract will be used as a second rewarder on top of the main rewarder to distribute a second token to the LPs * It will reward the LPs that are inside the range set in this contract */ -contract LBHooksExtraRewarder is LBHooksBaseSimpleRewarder, ILBHooksExtraRewarder { +abstract contract LBHooksExtraRewarder is LBHooksBaseSimpleRewarder, ILBHooksExtraRewarder { /** * @dev Constructor of the contract * @param lbHooksManager The address of the LBHooksManager contract @@ -73,4 +73,9 @@ contract LBHooksExtraRewarder is LBHooksBaseSimpleRewarder, ILBHooksExtraRewarde revert LBHooksExtraRewarder__ParentRewarderNotLinked(); } } + + /** + * @dev Overrides the internal function that is called when the rewards are claimed + */ + function _onClaim(address, uint256[] memory) internal virtual override {} } diff --git a/src/rewarder/LBHooksMCRewarder.sol b/src/rewarder/LBHooksMCRewarder.sol index cc1a41f..a23a080 100644 --- a/src/rewarder/LBHooksMCRewarder.sol +++ b/src/rewarder/LBHooksMCRewarder.sol @@ -17,7 +17,7 @@ import {TokenHelper} from "../library/TokenHelper.sol"; * It can also have an extra rewarder to distribute a second token to the LPs * It will reward the LPs that are inside the range set in this contract */ -contract LBHooksMCRewarder is LBHooksBaseParentRewarder, ERC20Upgradeable, ILBHooksMCRewarder { +abstract contract LBHooksMCRewarder is LBHooksBaseParentRewarder, ERC20Upgradeable, ILBHooksMCRewarder { IMasterChef internal immutable _masterChef; IERC20 internal immutable _moe; diff --git a/src/rewarder/LBHooksSimpleRewarder.sol b/src/rewarder/LBHooksSimpleRewarder.sol index ba92b69..93475bc 100644 --- a/src/rewarder/LBHooksSimpleRewarder.sol +++ b/src/rewarder/LBHooksSimpleRewarder.sol @@ -5,6 +5,7 @@ import {Hooks} from "@lb-protocol/src/libraries/Hooks.sol"; import {LBHooksBaseSimpleRewarder} from "../base/LBHooksBaseSimpleRewarder.sol"; import {LBHooksBaseParentRewarder} from "../base/LBHooksBaseParentRewarder.sol"; +import {LBHooksRewarderVirtual} from "../base/LBHooksRewarderVirtual.sol"; import {LBHooksBaseRewarder} from "../base/LBHooksBaseRewarder.sol"; import {ILBHooksSimpleRewarder} from "../interfaces/ILBHooksSimpleRewarder.sol"; @@ -16,7 +17,11 @@ import {TokenHelper} from "../library/TokenHelper.sol"; * It can also have an extra rewarder to distribute a second token to the LPs * It will reward the LPs that are inside the range set in this contract */ -contract LBHooksSimpleRewarder is LBHooksBaseSimpleRewarder, LBHooksBaseParentRewarder, ILBHooksSimpleRewarder { +abstract contract LBHooksSimpleRewarder is + LBHooksBaseSimpleRewarder, + LBHooksBaseParentRewarder, + ILBHooksSimpleRewarder +{ /** * @dev Constructor of the contract * @param lbHooksManager The address of the LBHooksManager contract @@ -26,7 +31,7 @@ contract LBHooksSimpleRewarder is LBHooksBaseSimpleRewarder, LBHooksBaseParentRe function _onClaim(address user, uint256[] memory ids) internal virtual - override(LBHooksBaseRewarder, LBHooksBaseParentRewarder) + override(LBHooksRewarderVirtual, LBHooksBaseParentRewarder) { LBHooksBaseParentRewarder._onClaim(user, ids); } @@ -66,4 +71,6 @@ contract LBHooksSimpleRewarder is LBHooksBaseSimpleRewarder, LBHooksBaseParentRe ) internal virtual override(LBHooksBaseRewarder, LBHooksBaseParentRewarder) { LBHooksBaseParentRewarder._beforeBatchTransferFrom(sender, from, to, ids, amounts); } + + function _onHooksSet(bytes calldata) internal virtual override {} } From 5134033d891c54cccf45ad31d66db7ed401497c9 Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 00:00:40 +0200 Subject: [PATCH 03/14] Add delta active id rewarder --- src/delta/LBHooksDelta.sol | 52 ++++++++++++++++++++++++ src/delta/LBHooksDeltaExtraRewarder.sol | 13 ++++++ src/delta/LBHooksDeltaMCRewarder.sol | 15 +++++++ src/delta/LBHooksDeltaSimpleRewarder.sol | 13 ++++++ 4 files changed, 93 insertions(+) create mode 100644 src/delta/LBHooksDelta.sol create mode 100644 src/delta/LBHooksDeltaExtraRewarder.sol create mode 100644 src/delta/LBHooksDeltaMCRewarder.sol create mode 100644 src/delta/LBHooksDeltaSimpleRewarder.sol diff --git a/src/delta/LBHooksDelta.sol b/src/delta/LBHooksDelta.sol new file mode 100644 index 0000000..58c9539 --- /dev/null +++ b/src/delta/LBHooksDelta.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "../base/LBHooksRewarderVirtual.sol"; + +abstract contract LBHooksDelta is LBHooksRewarderVirtual { + error LBHooksDelta__InvalidDeltaBins(); + + event DeltaBinsSet(int24 deltaBinA, int24 deltaBinB); + + int24 internal _deltaBinA; + int24 internal _deltaBinB; + + /** + * @dev Sets the delta bins + * The delta bins are used to determine the range of bins to be rewarded, + * from [activeId + deltaBinA, activeId + deltaBinB[ (exclusive). + * @param deltaBinA The delta bin A + * @param deltaBinB The delta bin B + */ + function setDeltaBins(int24 deltaBinA, int24 deltaBinB) external virtual onlyOwner { + if (deltaBinA > deltaBinB) revert LBHooksDelta__InvalidDeltaBins(); + + _updateAccruedRewardsPerShare(); + + _deltaBinA = deltaBinA; + _deltaBinB = deltaBinB; + + _getRewardedRange(); // Make sure that the constraints are respected + + emit DeltaBinsSet(deltaBinA, deltaBinB); + } + + /** + * @dev Returns the rewarded start and end id (exclusive) + * @param activeId The active id + * @return binStart The bin start to be rewarded + * @return binEnd The bin end to be rewarded, exclusive + */ + function _getRewardedBounds(uint24 activeId) + internal + view + virtual + override + returns (uint256 binStart, uint256 binEnd) + { + (int24 deltaBinA, int24 deltaBinB) = (_deltaBinA, _deltaBinB); + + binStart = uint256(int256(uint256(activeId)) + deltaBinA); + binEnd = uint256(int256(uint256(activeId)) + deltaBinB); + } +} diff --git a/src/delta/LBHooksDeltaExtraRewarder.sol b/src/delta/LBHooksDeltaExtraRewarder.sol new file mode 100644 index 0000000..fd29b40 --- /dev/null +++ b/src/delta/LBHooksDeltaExtraRewarder.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksExtraRewarder} from "../rewarder/LBHooksExtraRewarder.sol"; +import {LBHooksDelta} from "./LBHooksDelta.sol"; + +contract LBHooksDeltaExtraRewarder is LBHooksExtraRewarder, LBHooksDelta { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager) LBHooksExtraRewarder(lbHooksManager) {} +} diff --git a/src/delta/LBHooksDeltaMCRewarder.sol b/src/delta/LBHooksDeltaMCRewarder.sol new file mode 100644 index 0000000..e6b44d4 --- /dev/null +++ b/src/delta/LBHooksDeltaMCRewarder.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksMCRewarder, IMasterChef, IERC20} from "../rewarder/LBHooksMCRewarder.sol"; +import {LBHooksDelta} from "./LBHooksDelta.sol"; + +contract LBHooksDeltaMCRewarder is LBHooksMCRewarder, LBHooksDelta { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager, IMasterChef masterChef, IERC20 moe) + LBHooksMCRewarder(lbHooksManager, masterChef, moe) + {} +} diff --git a/src/delta/LBHooksDeltaSimpleRewarder.sol b/src/delta/LBHooksDeltaSimpleRewarder.sol new file mode 100644 index 0000000..51fa33c --- /dev/null +++ b/src/delta/LBHooksDeltaSimpleRewarder.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksSimpleRewarder} from "../rewarder/LBHooksSimpleRewarder.sol"; +import {LBHooksDelta} from "./LBHooksDelta.sol"; + +contract LBHooksDeltaSimpleRewarder is LBHooksSimpleRewarder, LBHooksDelta { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager) LBHooksSimpleRewarder(lbHooksManager) {} +} From bc6680b68a968e36306dcbf7b7f6d856c64384bf Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 00:00:48 +0200 Subject: [PATCH 04/14] Add static range --- src/static/LBHooksStatic.sol | 40 ++++++++++++++++++++++ src/static/LBHooksStaticExtraRewarder.sol | 13 +++++++ src/static/LBHooksStaticMCRewarder.sol | 15 ++++++++ src/static/LBHooksStaticSimpleRewarder.sol | 13 +++++++ 4 files changed, 81 insertions(+) create mode 100644 src/static/LBHooksStatic.sol create mode 100644 src/static/LBHooksStaticExtraRewarder.sol create mode 100644 src/static/LBHooksStaticMCRewarder.sol create mode 100644 src/static/LBHooksStaticSimpleRewarder.sol diff --git a/src/static/LBHooksStatic.sol b/src/static/LBHooksStatic.sol new file mode 100644 index 0000000..8ccd789 --- /dev/null +++ b/src/static/LBHooksStatic.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "../base/LBHooksRewarderVirtual.sol"; + +abstract contract LBHooksStatic is LBHooksRewarderVirtual { + error LBHooksStatic__InvalidBins(); + + event BinRangeSet(uint24 binStart, uint24 binEnd); + + uint24 internal _binStart; + uint24 internal _binEnd; + + /** + * @dev Sets the range of bins to be rewarded + * @param binStart The bin start to be rewarded + * @param binEnd The bin end to be rewarded, exclusive + */ + function setRange(uint24 binStart, uint24 binEnd) external onlyOwner { + if (binStart > binEnd) revert LBHooksStatic__InvalidBins(); + + _updateAccruedRewardsPerShare(); + + _binStart = binStart; + _binEnd = binEnd; + + _getRewardedRange(); // Make sure that the constraints are respected + + emit BinRangeSet(binStart, binEnd); + } + + /** + * @dev Returns the rewarded start and end id (exclusive) + * @return binStart The bin start to be rewarded + * @return binEnd The bin end to be rewarded, exclusive + */ + function _getRewardedBounds(uint24) internal view virtual override returns (uint256 binStart, uint256 binEnd) { + return (uint256(_binStart), uint256(_binEnd)); + } +} diff --git a/src/static/LBHooksStaticExtraRewarder.sol b/src/static/LBHooksStaticExtraRewarder.sol new file mode 100644 index 0000000..0bdb448 --- /dev/null +++ b/src/static/LBHooksStaticExtraRewarder.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksExtraRewarder} from "../rewarder/LBHooksExtraRewarder.sol"; +import {LBHooksStatic} from "./LBHooksStatic.sol"; + +contract LBHooksStaticExtraRewarder is LBHooksExtraRewarder, LBHooksStatic { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager) LBHooksExtraRewarder(lbHooksManager) {} +} diff --git a/src/static/LBHooksStaticMCRewarder.sol b/src/static/LBHooksStaticMCRewarder.sol new file mode 100644 index 0000000..d402ec7 --- /dev/null +++ b/src/static/LBHooksStaticMCRewarder.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksMCRewarder, IMasterChef, IERC20} from "../rewarder/LBHooksMCRewarder.sol"; +import {LBHooksStatic} from "./LBHooksStatic.sol"; + +contract LBHooksStaticMCRewarder is LBHooksMCRewarder, LBHooksStatic { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager, IMasterChef masterChef, IERC20 moe) + LBHooksMCRewarder(lbHooksManager, masterChef, moe) + {} +} diff --git a/src/static/LBHooksStaticSimpleRewarder.sol b/src/static/LBHooksStaticSimpleRewarder.sol new file mode 100644 index 0000000..29de740 --- /dev/null +++ b/src/static/LBHooksStaticSimpleRewarder.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksSimpleRewarder} from "../rewarder/LBHooksSimpleRewarder.sol"; +import {LBHooksStatic} from "./LBHooksStatic.sol"; + +contract LBHooksStaticSimpleRewarder is LBHooksSimpleRewarder, LBHooksStatic { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager) LBHooksSimpleRewarder(lbHooksManager) {} +} From ac771a9b8ca3f22722a33c1143bef77ada391f6f Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 00:30:46 +0200 Subject: [PATCH 05/14] Add oracle range --- src/interfaces/IChainlinkAggregatorV3.sol | 24 +++++++ src/interfaces/IOracleId.sol | 10 +++ src/oracle/LBHooksOracle.sol | 45 ++++++++++++ src/oracle/LBHooksOracleExtraRewarder.sol | 13 ++++ src/oracle/LBHooksOracleMCRewarder.sol | 15 ++++ src/oracle/LBHooksOracleSimpleRewarder.sol | 13 ++++ src/oracle/OracleIdChainlink.sol | 82 ++++++++++++++++++++++ 7 files changed, 202 insertions(+) create mode 100644 src/interfaces/IChainlinkAggregatorV3.sol create mode 100644 src/interfaces/IOracleId.sol create mode 100644 src/oracle/LBHooksOracle.sol create mode 100644 src/oracle/LBHooksOracleExtraRewarder.sol create mode 100644 src/oracle/LBHooksOracleMCRewarder.sol create mode 100644 src/oracle/LBHooksOracleSimpleRewarder.sol create mode 100644 src/oracle/OracleIdChainlink.sol diff --git a/src/interfaces/IChainlinkAggregatorV3.sol b/src/interfaces/IChainlinkAggregatorV3.sol new file mode 100644 index 0000000..6eea994 --- /dev/null +++ b/src/interfaces/IChainlinkAggregatorV3.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/** + * @title Chainlink Aggregator V3 Interface + * @notice Interface used to interact with Chainlink datafeeds. + */ +interface IChainlinkAggregatorV3 { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + function getRoundData(uint80 _roundId) + external + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); + + function latestRoundData() + external + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); +} diff --git a/src/interfaces/IOracleId.sol b/src/interfaces/IOracleId.sol new file mode 100644 index 0000000..c24e528 --- /dev/null +++ b/src/interfaces/IOracleId.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/** + * @title Oracle Id Interface + * @dev Interface for the Oracle Id + */ +interface IOracleId { + function getLatestId() external view returns (uint24); +} diff --git a/src/oracle/LBHooksOracle.sol b/src/oracle/LBHooksOracle.sol new file mode 100644 index 0000000..dae61f4 --- /dev/null +++ b/src/oracle/LBHooksOracle.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "../base/LBHooksRewarderVirtual.sol"; +import "../interfaces/IOracleId.sol"; + +abstract contract LBHooksOracle is LBHooksRewarderVirtual { + error LBHooksOracle__InvalidDeltaBins(); + error LBHooksOracle__InvalidOracle(); + + event ParametersSet(address oracle, int24 deltaBinA, int24 deltaBinB); + + IOracleId internal _oracle; + int24 internal _deltaBinA; + int24 internal _deltaBinB; + + function setParameters(IOracleId oracle, int24 deltaBinA, int24 deltaBinB) external onlyOwner { + if (deltaBinA > deltaBinB) revert LBHooksOracle__InvalidDeltaBins(); + if (address(oracle) == address(0)) revert LBHooksOracle__InvalidOracle(); + + _updateAccruedRewardsPerShare(); + + _oracle = oracle; + _deltaBinA = deltaBinA; + _deltaBinB = deltaBinB; + + _getRewardedRange(); // Make sure that the constraints are respected + + emit ParametersSet(address(oracle), deltaBinA, deltaBinB); + } + + /** + * @dev Returns the rewarded start and end id (exclusive) + * @return binStart The bin start to be rewarded + * @return binEnd The bin end to be rewarded, exclusive + */ + function _getRewardedBounds(uint24) internal view virtual override returns (uint256 binStart, uint256 binEnd) { + (IOracleId oracle, int24 deltaBinA, int24 deltaBinB) = (_oracle, _deltaBinA, _deltaBinB); + + uint24 oracleId = oracle.getLatestId(); + + binStart = uint256(int256(uint256(oracleId)) + deltaBinA); + binEnd = uint256(int256(uint256(oracleId)) + deltaBinB); + } +} diff --git a/src/oracle/LBHooksOracleExtraRewarder.sol b/src/oracle/LBHooksOracleExtraRewarder.sol new file mode 100644 index 0000000..4d57c07 --- /dev/null +++ b/src/oracle/LBHooksOracleExtraRewarder.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksExtraRewarder} from "../rewarder/LBHooksExtraRewarder.sol"; +import {LBHooksOracle} from "./LBHooksOracle.sol"; + +contract LBHooksOracleExtraRewarder is LBHooksExtraRewarder, LBHooksOracle { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager) LBHooksExtraRewarder(lbHooksManager) {} +} diff --git a/src/oracle/LBHooksOracleMCRewarder.sol b/src/oracle/LBHooksOracleMCRewarder.sol new file mode 100644 index 0000000..c0ffd2c --- /dev/null +++ b/src/oracle/LBHooksOracleMCRewarder.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksMCRewarder, IMasterChef, IERC20} from "../rewarder/LBHooksMCRewarder.sol"; +import {LBHooksOracle} from "./LBHooksOracle.sol"; + +contract LBHooksOracleMCRewarder is LBHooksMCRewarder, LBHooksOracle { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager, IMasterChef masterChef, IERC20 moe) + LBHooksMCRewarder(lbHooksManager, masterChef, moe) + {} +} diff --git a/src/oracle/LBHooksOracleSimpleRewarder.sol b/src/oracle/LBHooksOracleSimpleRewarder.sol new file mode 100644 index 0000000..6a69f5f --- /dev/null +++ b/src/oracle/LBHooksOracleSimpleRewarder.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {LBHooksSimpleRewarder} from "../rewarder/LBHooksSimpleRewarder.sol"; +import {LBHooksOracle} from "./LBHooksOracle.sol"; + +contract LBHooksOracleSimpleRewarder is LBHooksSimpleRewarder, LBHooksOracle { + /** + * @dev Constructor of the contract + * @param lbHooksManager The address of the LBHooksManager contract + */ + constructor(address lbHooksManager) LBHooksSimpleRewarder(lbHooksManager) {} +} diff --git a/src/oracle/OracleIdChainlink.sol b/src/oracle/OracleIdChainlink.sol new file mode 100644 index 0000000..135242f --- /dev/null +++ b/src/oracle/OracleIdChainlink.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {PriceHelper} from "@lb-protocol/src/libraries/PriceHelper.sol"; + +import "../interfaces/IOracleId.sol"; +import "../interfaces/IChainlinkAggregatorV3.sol"; + +/** + * @title Oracle Id + * @dev Contract that uses a chainlink price oracle to return the id of that price + */ +contract OracleIdChainlink is IOracleId { + error OracleIdChainlink__InvalidPrice(); + error OracleIdChainlink__StalePrice(); + + IChainlinkAggregatorV3 internal immutable _oracle; + bool internal immutable _isInverse; + uint256 internal immutable _oraclePrecision; + uint256 internal immutable _heartbeat; + + uint16 internal immutable _binStep; + + /** + * @dev Constructor of the contract + * @param oracle The address of the chainlink aggregator + * @param isInverse If the oracle is inversed, ie, if the actual price is the inverse of the oracle price + * @param heartbeat The heartbeat of the oracle + * @param binStep The bin step of the pair + */ + constructor(IChainlinkAggregatorV3 oracle, bool isInverse, uint256 heartbeat, uint16 binStep) { + _oracle = oracle; + _isInverse = isInverse; + _oraclePrecision = 10 ** oracle.decimals(); + _heartbeat = heartbeat; + _binStep = binStep; + } + + /** + * @dev Returns the Oracle Id parameters + * @return oracle The oracle address + * @return isInverse If the oracle is inversed, ie, if the actual price is the inverse of the oracle price + * @return oraclePrecision The oracle precision + * @return heartbeat The heartbeat of the oracle + * @return binStep The binStep of the pair + */ + function getOracleIdParameters() + external + view + returns ( + IChainlinkAggregatorV3 oracle, + bool isInverse, + uint256 oraclePrecision, + uint256 heartbeat, + uint256 binStep + ) + { + return (_oracle, _isInverse, _oraclePrecision, _heartbeat, _binStep); + } + + /** + * @dev Returns the latest id of the chainlink aggregator + * @return The latest id + */ + function getLatestId() external view override returns (uint24) { + (, int256 answer,, uint256 updatedAt,) = _oracle.latestRoundData(); + + if (answer <= 0) revert OracleIdChainlink__InvalidPrice(); + if (block.timestamp > updatedAt + _heartbeat) revert OracleIdChainlink__StalePrice(); + + uint256 priceX128 = + _isInverse ? (_oraclePrecision << 128) / uint256(answer) : (uint256(answer) << 128) / _oraclePrecision; + + uint24 id = PriceHelper.getIdFromPrice(priceX128, _binStep); + + uint256 priceAfterX128 = PriceHelper.getPriceFromId(id + 1, _binStep); + + unchecked { + return priceAfterX128 > priceX128 ? id : id + 1; + } + } +} From eedb09a3fd8c8edd7a786cd3dde96b55a8bea771 Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 00:30:51 +0200 Subject: [PATCH 06/14] Fix tests --- test/LBHooksLens.t.sol | 18 +++++---- test/LBHooksManager.t.sol | 13 ++++--- test/base/LBHooksBaseRewarder.t.sol | 7 +++- .../LBHooksExtraRewarder.t.sol | 18 +++++---- .../{rewarder => delta}/LBHooksRewarder.t.sol | 11 +++--- .../LBHooksSimpleRewarder.t.sol | 38 +++++++++---------- 6 files changed, 57 insertions(+), 48 deletions(-) rename test/{rewarder => delta}/LBHooksExtraRewarder.t.sol (97%) rename test/{rewarder => delta}/LBHooksRewarder.t.sol (95%) rename test/{rewarder => delta}/LBHooksSimpleRewarder.t.sol (96%) diff --git a/test/LBHooksLens.t.sol b/test/LBHooksLens.t.sol index 6eb292a..d84376a 100644 --- a/test/LBHooksLens.t.sol +++ b/test/LBHooksLens.t.sol @@ -5,13 +5,13 @@ pragma solidity ^0.8.20; import "test/TestHelper.sol"; import {ILBHooksBaseRewarder, LBHooksBaseRewarder} from "src/base/LBHooksBaseRewarder.sol"; -import "src/rewarder/LBHooksMCRewarder.sol"; -import "src/rewarder/LBHooksExtraRewarder.sol"; +import "src/delta/LBHooksDeltaMCRewarder.sol"; +import "src/delta/LBHooksDeltaExtraRewarder.sol"; import "src/LBHooksLens.sol"; contract LBHooksLensTest is TestHelper { - LBHooksMCRewarder lbHooks; - LBHooksExtraRewarder lbHooksExtra; + LBHooksDeltaMCRewarder lbHooks; + LBHooksDeltaExtraRewarder lbHooksExtra; LBHooksLens lbHooksLens; function setUp() public override { @@ -19,14 +19,16 @@ contract LBHooksLensTest is TestHelper { lbHooksManager.setLBHooksParameters( ILBHooksManager.LBHooksType.MCRewarder, - Hooks.setHooks(hooksParameters, address(new LBHooksMCRewarder(address(lbHooksManager), masterchef, moe))) + Hooks.setHooks( + hooksParameters, address(new LBHooksDeltaMCRewarder(address(lbHooksManager), masterchef, moe)) + ) ); lbHooksManager.setLBHooksParameters( ILBHooksManager.LBHooksType.ExtraRewarder, - Hooks.setHooks(hooksParameters, address(new LBHooksExtraRewarder(address(lbHooksManager)))) + Hooks.setHooks(hooksParameters, address(new LBHooksDeltaExtraRewarder(address(lbHooksManager)))) ); - lbHooks = LBHooksMCRewarder( + lbHooks = LBHooksDeltaMCRewarder( payable( address( lbHooksManager.createLBHooksMCRewarder( @@ -36,7 +38,7 @@ contract LBHooksLensTest is TestHelper { ) ); - lbHooksExtra = LBHooksExtraRewarder( + lbHooksExtra = LBHooksDeltaExtraRewarder( payable( address( lbHooksManager.createLBHooksExtraRewarder( diff --git a/test/LBHooksManager.t.sol b/test/LBHooksManager.t.sol index 61e4f6e..caa1952 100644 --- a/test/LBHooksManager.t.sol +++ b/test/LBHooksManager.t.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.20; import "test/TestHelper.sol"; -import "src/rewarder/LBHooksMCRewarder.sol"; -import "src/rewarder/LBHooksExtraRewarder.sol"; +import "src/delta/LBHooksDeltaMCRewarder.sol"; +import "src/delta/LBHooksDeltaExtraRewarder.sol"; contract LBHooksManagerTest is TestHelper { bytes32 rewarderHooksParameters; @@ -14,10 +14,11 @@ contract LBHooksManagerTest is TestHelper { function setUp() public override { super.setUp(); - rewarderHooksParameters = - Hooks.setHooks(hooksParameters, address(new LBHooksMCRewarder(address(lbHooksManager), masterchef, moe))); + rewarderHooksParameters = Hooks.setHooks( + hooksParameters, address(new LBHooksDeltaMCRewarder(address(lbHooksManager), masterchef, moe)) + ); extraRewarderHooksParameters = - Hooks.setHooks(hooksParameters, address(new LBHooksExtraRewarder(address(lbHooksManager)))); + Hooks.setHooks(hooksParameters, address(new LBHooksDeltaExtraRewarder(address(lbHooksManager)))); } function test_GetLBHooksParameters() public { @@ -96,7 +97,7 @@ contract LBHooksManagerTest is TestHelper { lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.MCRewarder), 0, "test_createLBHooksMCRewarder::1" ); - LBHooksMCRewarder lbHooks = LBHooksMCRewarder( + LBHooksDeltaMCRewarder lbHooks = LBHooksDeltaMCRewarder( payable( address( lbHooksManager.createLBHooksMCRewarder( diff --git a/test/base/LBHooksBaseRewarder.t.sol b/test/base/LBHooksBaseRewarder.t.sol index 47bb492..8051a75 100644 --- a/test/base/LBHooksBaseRewarder.t.sol +++ b/test/base/LBHooksBaseRewarder.t.sol @@ -6,6 +6,7 @@ import "test/TestHelper.sol"; import "test/mocks/MockERC20.sol"; import "src/base/LBHooksBaseRewarder.sol"; +import "src/delta/LBHooksDelta.sol"; contract LBHooksBaseRewarderTest is TestHelper { MockLBHooksRewarder hooks; @@ -268,7 +269,7 @@ contract LBHooksBaseRewarderTest is TestHelper { deltaBinA = int24(bound(deltaBinA, type(int24).min + 1, type(int24).max)); deltaBinB = int24(bound(deltaBinB, type(int24).min, deltaBinA - 1)); - vm.expectRevert(ILBHooksBaseRewarder.LBHooksBaseRewarder__InvalidDeltaBins.selector); + vm.expectRevert(LBHooksDelta.LBHooksDelta__InvalidDeltaBins.selector); hooks.setDeltaBins(deltaBinA, deltaBinB); deltaBinA = int24(bound(deltaBinA, type(int24).min, type(int24).max - 11 - 1)); @@ -279,7 +280,7 @@ contract LBHooksBaseRewarderTest is TestHelper { } } -contract MockLBHooksRewarder is LBHooksBaseRewarder { +contract MockLBHooksRewarder is LBHooksBaseRewarder, LBHooksDelta { uint256 private _lastTimestamp; constructor() LBHooksBaseRewarder(address(0)) {} @@ -317,4 +318,6 @@ contract MockLBHooksRewarder is LBHooksBaseRewarder { } } } + + function _onClaim(address, uint256[] memory) internal virtual override {} } diff --git a/test/rewarder/LBHooksExtraRewarder.t.sol b/test/delta/LBHooksExtraRewarder.t.sol similarity index 97% rename from test/rewarder/LBHooksExtraRewarder.t.sol rename to test/delta/LBHooksExtraRewarder.t.sol index d273ad4..3c628de 100644 --- a/test/rewarder/LBHooksExtraRewarder.t.sol +++ b/test/delta/LBHooksExtraRewarder.t.sol @@ -6,26 +6,28 @@ import "test/TestHelper.sol"; import "src/base/LBHooksBaseRewarder.sol"; import "src/base/LBHooksBaseSimpleRewarder.sol"; -import "src/rewarder/LBHooksMCRewarder.sol"; -import "src/rewarder/LBHooksExtraRewarder.sol"; +import "src/delta/LBHooksDeltaMCRewarder.sol"; +import "src/delta/LBHooksDeltaExtraRewarder.sol"; contract LBHooksExtraRewarderTest is TestHelper { - LBHooksMCRewarder lbHooks; - LBHooksExtraRewarder lbHooksExtra; + LBHooksDeltaMCRewarder lbHooks; + LBHooksDeltaExtraRewarder lbHooksExtra; function setUp() public override { super.setUp(); lbHooksManager.setLBHooksParameters( ILBHooksManager.LBHooksType.MCRewarder, - Hooks.setHooks(hooksParameters, address(new LBHooksMCRewarder(address(lbHooksManager), masterchef, moe))) + Hooks.setHooks( + hooksParameters, address(new LBHooksDeltaMCRewarder(address(lbHooksManager), masterchef, moe)) + ) ); lbHooksManager.setLBHooksParameters( ILBHooksManager.LBHooksType.ExtraRewarder, - Hooks.setHooks(hooksParameters, address(new LBHooksExtraRewarder(address(lbHooksManager)))) + Hooks.setHooks(hooksParameters, address(new LBHooksDeltaExtraRewarder(address(lbHooksManager)))) ); - lbHooks = LBHooksMCRewarder( + lbHooks = LBHooksDeltaMCRewarder( payable( address( lbHooksManager.createLBHooksMCRewarder( @@ -35,7 +37,7 @@ contract LBHooksExtraRewarderTest is TestHelper { ) ); - lbHooksExtra = LBHooksExtraRewarder( + lbHooksExtra = LBHooksDeltaExtraRewarder( payable( address( lbHooksManager.createLBHooksExtraRewarder( diff --git a/test/rewarder/LBHooksRewarder.t.sol b/test/delta/LBHooksRewarder.t.sol similarity index 95% rename from test/rewarder/LBHooksRewarder.t.sol rename to test/delta/LBHooksRewarder.t.sol index 1f2df77..cd6e66d 100644 --- a/test/rewarder/LBHooksRewarder.t.sol +++ b/test/delta/LBHooksRewarder.t.sol @@ -4,21 +4,22 @@ pragma solidity ^0.8.20; import "test/TestHelper.sol"; -import "src/rewarder/LBHooksMCRewarder.sol"; +import "src/delta/LBHooksDeltaMCRewarder.sol"; import "src/interfaces/ILBHooksBaseRewarder.sol"; contract LBHooksRewarderTest is TestHelper { - LBHooksMCRewarder lbHooks; + LBHooksDeltaMCRewarder lbHooks; function setUp() public override { super.setUp(); - hooksParameters = - Hooks.setHooks(hooksParameters, address(new LBHooksMCRewarder(address(lbHooksManager), masterchef, moe))); + hooksParameters = Hooks.setHooks( + hooksParameters, address(new LBHooksDeltaMCRewarder(address(lbHooksManager), masterchef, moe)) + ); lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder, hooksParameters); - lbHooks = LBHooksMCRewarder( + lbHooks = LBHooksDeltaMCRewarder( payable( address( lbHooksManager.createLBHooksMCRewarder( diff --git a/test/rewarder/LBHooksSimpleRewarder.t.sol b/test/delta/LBHooksSimpleRewarder.t.sol similarity index 96% rename from test/rewarder/LBHooksSimpleRewarder.t.sol rename to test/delta/LBHooksSimpleRewarder.t.sol index 9c4fe18..75ae251 100644 --- a/test/rewarder/LBHooksSimpleRewarder.t.sol +++ b/test/delta/LBHooksSimpleRewarder.t.sol @@ -6,26 +6,26 @@ import "test/TestHelper.sol"; import "src/base/LBHooksBaseRewarder.sol"; import "src/base/LBHooksBaseSimpleRewarder.sol"; -import "src/rewarder/LBHooksSimpleRewarder.sol"; -import "src/rewarder/LBHooksExtraRewarder.sol"; +import "src/delta/LBHooksDeltaSimpleRewarder.sol"; +import "src/delta/LBHooksDeltaExtraRewarder.sol"; contract LBHooksSimpleRewarderTest is TestHelper { - LBHooksSimpleRewarder lbHooks; - LBHooksExtraRewarder lbHooksExtra; + LBHooksDeltaSimpleRewarder lbHooks; + LBHooksDeltaExtraRewarder lbHooksExtra; function setUp() public override { super.setUp(); lbHooksManager.setLBHooksParameters( ILBHooksManager.LBHooksType.SimpleRewarder, - Hooks.setHooks(hooksParameters, address(new LBHooksSimpleRewarder(address(lbHooksManager)))) + Hooks.setHooks(hooksParameters, address(new LBHooksDeltaSimpleRewarder(address(lbHooksManager)))) ); lbHooksManager.setLBHooksParameters( ILBHooksManager.LBHooksType.ExtraRewarder, - Hooks.setHooks(hooksParameters, address(new LBHooksExtraRewarder(address(lbHooksManager)))) + Hooks.setHooks(hooksParameters, address(new LBHooksDeltaExtraRewarder(address(lbHooksManager)))) ); - lbHooks = LBHooksSimpleRewarder( + lbHooks = LBHooksDeltaSimpleRewarder( payable( address( lbHooksManager.createLBHooksSimpleRewarder( @@ -39,7 +39,7 @@ contract LBHooksSimpleRewarderTest is TestHelper { ) ); - lbHooksExtra = LBHooksExtraRewarder( + lbHooksExtra = LBHooksDeltaExtraRewarder( payable( address( lbHooksManager.createLBHooksExtraRewarder( @@ -242,20 +242,20 @@ contract LBHooksSimpleRewarderTest is TestHelper { ); assertApproxEqRel(lbHooks.getRemainingRewards(), 358e18, 1e14, "test_GetPendingRewardSwapAndTransfer::58"); - assertEq(lbHooksExtra.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::58"); - assertEq(lbHooksExtra.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::59"); + assertEq(lbHooksExtra.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::59"); + assertEq(lbHooksExtra.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::60"); vm.prank(alice); lbHooks.claim(alice, ids); - assertEq(lbHooks.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::60"); + assertEq(lbHooks.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::61"); assertApproxEqRel( - lbHooks.getPendingRewards(bob, ids), 26.5e18, 1e14, "test_GetPendingRewardSwapAndTransfer::61" + lbHooks.getPendingRewards(bob, ids), 26.5e18, 1e14, "test_GetPendingRewardSwapAndTransfer::62" ); - assertApproxEqRel(rewardToken01.balanceOf(alice), 15.5e18, 1e14, "test_GetPendingRewardSwapAndTransfer::62"); + assertApproxEqRel(rewardToken01.balanceOf(alice), 15.5e18, 1e14, "test_GetPendingRewardSwapAndTransfer::63"); - assertEq(lbHooksExtra.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::63"); - assertEq(lbHooksExtra.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::64"); + assertEq(lbHooksExtra.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::64"); + assertEq(lbHooksExtra.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::65"); vm.prank(address(lbHooksManager)); factory.removeLBHooksOnPair(token0, token1, DEFAULT_BIN_STEP); @@ -266,11 +266,11 @@ contract LBHooksSimpleRewarderTest is TestHelper { vm.expectRevert(ILBHooksBaseRewarder.LBHooksBaseRewarder__UnlinkedHooks.selector); lbHooksExtra.claim(address(this), ids); - assertEq(lbHooks.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::65"); - assertEq(lbHooks.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::66"); + assertEq(lbHooks.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::66"); + assertEq(lbHooks.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::67"); - assertEq(lbHooksExtra.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::67"); - assertEq(lbHooksExtra.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::68"); + assertEq(lbHooksExtra.getPendingRewards(alice, ids), 0, "test_GetPendingRewardSwapAndTransfer::68"); + assertEq(lbHooksExtra.getPendingRewards(bob, ids), 0, "test_GetPendingRewardSwapAndTransfer::69"); } function test_GetPendingRewardMintAndBurn() public { From ae9691051a1aa567183644c678c3ae06727dc758 Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 00:38:59 +0200 Subject: [PATCH 07/14] Fix oracle --- src/oracle/LBHooksOracle.sol | 26 +++++++++++++++++++++----- src/oracle/LBHooksOracleMCRewarder.sol | 2 ++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/oracle/LBHooksOracle.sol b/src/oracle/LBHooksOracle.sol index dae61f4..5390a06 100644 --- a/src/oracle/LBHooksOracle.sol +++ b/src/oracle/LBHooksOracle.sol @@ -6,7 +6,6 @@ import "../interfaces/IOracleId.sol"; abstract contract LBHooksOracle is LBHooksRewarderVirtual { error LBHooksOracle__InvalidDeltaBins(); - error LBHooksOracle__InvalidOracle(); event ParametersSet(address oracle, int24 deltaBinA, int24 deltaBinB); @@ -14,9 +13,24 @@ abstract contract LBHooksOracle is LBHooksRewarderVirtual { int24 internal _deltaBinA; int24 internal _deltaBinB; + /** + * @dev Returns the oracle id address + * @return The oracle id address + */ + function getOracle() external view returns (address) { + return address(_oracle); + } + + /** + * @dev Sets the oracle and the delta bins + * The delta bins are used to determine the range of bins to be rewarded, + * from [oracleId + deltaBinA, oracleId + deltaBinB[ (exclusive). + * @param oracle The oracle address + * @param deltaBinA The delta bin A + * @param deltaBinB The delta bin B + */ function setParameters(IOracleId oracle, int24 deltaBinA, int24 deltaBinB) external onlyOwner { if (deltaBinA > deltaBinB) revert LBHooksOracle__InvalidDeltaBins(); - if (address(oracle) == address(0)) revert LBHooksOracle__InvalidOracle(); _updateAccruedRewardsPerShare(); @@ -37,9 +51,11 @@ abstract contract LBHooksOracle is LBHooksRewarderVirtual { function _getRewardedBounds(uint24) internal view virtual override returns (uint256 binStart, uint256 binEnd) { (IOracleId oracle, int24 deltaBinA, int24 deltaBinB) = (_oracle, _deltaBinA, _deltaBinB); - uint24 oracleId = oracle.getLatestId(); + if (address(oracle) != address(0)) { + uint24 oracleId = oracle.getLatestId(); - binStart = uint256(int256(uint256(oracleId)) + deltaBinA); - binEnd = uint256(int256(uint256(oracleId)) + deltaBinB); + binStart = uint256(int256(uint256(oracleId)) + deltaBinA); + binEnd = uint256(int256(uint256(oracleId)) + deltaBinB); + } } } diff --git a/src/oracle/LBHooksOracleMCRewarder.sol b/src/oracle/LBHooksOracleMCRewarder.sol index c0ffd2c..5ab9b2b 100644 --- a/src/oracle/LBHooksOracleMCRewarder.sol +++ b/src/oracle/LBHooksOracleMCRewarder.sol @@ -8,6 +8,8 @@ contract LBHooksOracleMCRewarder is LBHooksMCRewarder, LBHooksOracle { /** * @dev Constructor of the contract * @param lbHooksManager The address of the LBHooksManager contract + * @param masterChef The address of the MasterChef contract + * @param moe The address of the MOE token */ constructor(address lbHooksManager, IMasterChef masterChef, IERC20 moe) LBHooksMCRewarder(lbHooksManager, masterChef, moe) From 4100ce219ac5835a6b1a1d372cdc7156bc6e6a7e Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 01:22:45 +0200 Subject: [PATCH 08/14] Test static methods --- test/static/LBHooksStatic.t.sol | 94 +++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 test/static/LBHooksStatic.t.sol diff --git a/test/static/LBHooksStatic.t.sol b/test/static/LBHooksStatic.t.sol new file mode 100644 index 0000000..813b24d --- /dev/null +++ b/test/static/LBHooksStatic.t.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import "test/TestHelper.sol"; + +import "src/static/LBHooksStatic.sol"; +import "src/base/LBHooksBaseRewarder.sol"; + +contract MockLBHooksStatic is LBHooksBaseRewarder, LBHooksStatic { + constructor(address manager) LBHooksBaseRewarder(manager) {} + + function getMaxNumberOfBins() public pure returns (uint256) { + return MAX_NUMBER_OF_BINS; + } + + function _onHooksSet(bytes calldata data) internal override {} + + function _onClaim(address user, uint256[] memory ids) internal override {} + + function _getPendingTotalRewards() internal view override returns (uint256 pendingTotalRewards) {} + + function _updateRewards() internal override returns (uint256 pendingTotalRewards) {} +} + +contract TestLBHooksStatic is TestHelper { + MockLBHooksStatic lbHooks; + + function setUp() public override { + super.setUp(); + + lbHooksManager.setLBHooksParameters( + ILBHooksManager.LBHooksType.SimpleRewarder, + Hooks.setHooks(hooksParameters, address(new MockLBHooksStatic(address(lbHooksManager)))) + ); + + lbHooks = MockLBHooksStatic( + payable( + address( + lbHooksManager.createLBHooksSimpleRewarder( + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + IERC20(address(rewardToken01)), + address(this) + ) + ) + ) + ); + } + + function test_Fuzz_SetRange(uint24 binStart, uint24 binEnd) public { + uint256 maxLastBin = binStart + lbHooks.getMaxNumberOfBins(); + binEnd = uint24(bound(binEnd, binStart, maxLastBin > type(uint24).max ? type(uint24).max : maxLastBin)); + (uint256 bStart, uint256 bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, 0, "test_Fuzz_SetRange::1"); + assertEq(bEnd, 0, "test_Fuzz_SetRange::2"); + + lbHooks.setRange(binStart, binEnd); + (bStart, bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, binStart, "test_Fuzz_SetRange::3"); + assertEq(bEnd, binEnd, "test_Fuzz_SetRange::4"); + + lbHooks.setRange(0, 0); + (bStart, bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, 0, "test_Fuzz_SetRange::5"); + assertEq(bEnd, 0, "test_Fuzz_SetRange::6"); + + lbHooks.setRange(binStart, binEnd); + (bStart, bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, binStart, "test_Fuzz_SetRange::7"); + assertEq(bEnd, binEnd, "test_Fuzz_SetRange::8"); + } + + function test_Fuzz_Revert_SetRange(uint24 binStart, uint24 binEnd) public { + uint24 bStart = uint24(bound(binStart, 1, type(uint24).max)); + uint24 bEnd = uint24(bound(binEnd, 0, bStart - 1)); + + vm.expectRevert(LBHooksStatic.LBHooksStatic__InvalidBins.selector); + lbHooks.setRange(bStart, bEnd); + + uint256 maxNumberOfBins = lbHooks.getMaxNumberOfBins(); + + bStart = uint24(bound(binStart, 0, type(uint24).max - (maxNumberOfBins + 1))); + bEnd = uint24(bound(binEnd, bStart + maxNumberOfBins + 1, type(uint24).max)); + + vm.expectRevert(ILBHooksBaseRewarder.LBHooksBaseRewarder__ExceedsMaxNumberOfBins.selector); + lbHooks.setRange(bStart, bEnd); + } +} From 1a7a1d454ff95f61f4ab6880e4e6ee0a9dfb7ec5 Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 01:49:33 +0200 Subject: [PATCH 09/14] Test and fix oracle methods --- src/oracle/OracleIdChainlink.sol | 8 +- test/oracle/LBHooksOracle.t.sol | 122 +++++++++++++++++++++++++++++++ test/oracle/OracleId.t.sol | 119 ++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 test/oracle/LBHooksOracle.t.sol create mode 100644 test/oracle/OracleId.t.sol diff --git a/src/oracle/OracleIdChainlink.sol b/src/oracle/OracleIdChainlink.sol index 135242f..74075c4 100644 --- a/src/oracle/OracleIdChainlink.sol +++ b/src/oracle/OracleIdChainlink.sol @@ -65,7 +65,7 @@ contract OracleIdChainlink is IOracleId { function getLatestId() external view override returns (uint24) { (, int256 answer,, uint256 updatedAt,) = _oracle.latestRoundData(); - if (answer <= 0) revert OracleIdChainlink__InvalidPrice(); + if (answer <= 0 || uint256(answer) > type(uint128).max) revert OracleIdChainlink__InvalidPrice(); if (block.timestamp > updatedAt + _heartbeat) revert OracleIdChainlink__StalePrice(); uint256 priceX128 = @@ -73,10 +73,8 @@ contract OracleIdChainlink is IOracleId { uint24 id = PriceHelper.getIdFromPrice(priceX128, _binStep); - uint256 priceAfterX128 = PriceHelper.getPriceFromId(id + 1, _binStep); + uint256 priceAtId = PriceHelper.getPriceFromId(id, _binStep); - unchecked { - return priceAfterX128 > priceX128 ? id : id + 1; - } + return priceAtId > priceX128 ? id - 1 : id; } } diff --git a/test/oracle/LBHooksOracle.t.sol b/test/oracle/LBHooksOracle.t.sol new file mode 100644 index 0000000..b674647 --- /dev/null +++ b/test/oracle/LBHooksOracle.t.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "test/TestHelper.sol"; + +import "src/Oracle/LBHooksOracle.sol"; +import "src/base/LBHooksBaseRewarder.sol"; +import "./OracleId.t.sol"; + +contract MockLBHooksOracle is LBHooksBaseRewarder, LBHooksOracle { + constructor(address manager) LBHooksBaseRewarder(manager) {} + + function getMaxNumberOfBins() public pure returns (uint256) { + return MAX_NUMBER_OF_BINS; + } + + function _onHooksSet(bytes calldata data) internal override {} + + function _onClaim(address user, uint256[] memory ids) internal override {} + + function _getPendingTotalRewards() internal view override returns (uint256 pendingTotalRewards) {} + + function _updateRewards() internal override returns (uint256 pendingTotalRewards) {} +} + +contract TestLBHooksOracle is TestHelper { + MockOracle oracle; + OracleIdChainlink oracleId; + MockLBHooksOracle lbHooks; + + function setUp() public override { + super.setUp(); + + oracle = new MockOracle(); + oracle.setDecimals(8); + + oracleId = new OracleIdChainlink(IChainlinkAggregatorV3(address(oracle)), false, 60, 1); + + lbHooksManager.setLBHooksParameters( + ILBHooksManager.LBHooksType.SimpleRewarder, + Hooks.setHooks(hooksParameters, address(new MockLBHooksOracle(address(lbHooksManager)))) + ); + + lbHooks = MockLBHooksOracle( + payable( + address( + lbHooksManager.createLBHooksSimpleRewarder( + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + IERC20(address(rewardToken01)), + address(this) + ) + ) + ) + ); + } + + function test_Fuzz_SetParameters(int24 deltaBinA, int24 deltaBinB) public { + oracle.setAnswer(1e8, block.timestamp); + uint24 latestId = oracleId.getLatestId(); + + deltaBinA = int24(bound(deltaBinA, type(int24).min, type(int24).max)); + int256 maxLastBin = int256(deltaBinA) + int256(lbHooks.getMaxNumberOfBins()); + deltaBinB = int24(bound(deltaBinB, deltaBinA, maxLastBin > type(int24).max ? type(int24).max : maxLastBin)); + (uint256 bStart, uint256 bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, 0, "test_Fuzz_SetParameters::1"); + assertEq(bEnd, 0, "test_Fuzz_SetParameters::2"); + + lbHooks.setParameters(oracleId, deltaBinA, deltaBinB); + (bStart, bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, uint256(int256(uint256(latestId)) + deltaBinA), "test_Fuzz_SetParameters::3"); + assertEq(bEnd, uint256(int256(uint256(latestId)) + deltaBinB), "test_Fuzz_SetParameters::4"); + + lbHooks.setParameters(oracleId, 0, 0); + (bStart, bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, latestId, "test_Fuzz_SetParameters::5"); + assertEq(bEnd, latestId, "test_Fuzz_SetParameters::6"); + + lbHooks.setParameters(oracleId, deltaBinA, deltaBinB); + (bStart, bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, uint256(int256(uint256(latestId)) + deltaBinA), "test_Fuzz_SetParameters::7"); + assertEq(bEnd, uint256(int256(uint256(latestId)) + deltaBinB), "test_Fuzz_SetParameters::8"); + + lbHooks.setParameters(IOracleId(address(0)), deltaBinA, deltaBinB); + (bStart, bEnd) = lbHooks.getRewardedRange(); + + assertEq(bStart, 0, "test_Fuzz_SetParameters::9"); + assertEq(bEnd, 0, "test_Fuzz_SetParameters::10"); + } + + function test_Fuzz_Revert_SetRange(int24 binStart, int24 binEnd) public { + oracle.setAnswer(1e8, block.timestamp); + uint24 latestId = oracleId.getLatestId(); + + int24 bStart = int24(bound(binStart, type(int24).min + 1, type(int24).max)); + int24 bEnd = int24(bound(binEnd, type(int24).min, bStart - 1)); + + vm.expectRevert(LBHooksOracle.LBHooksOracle__InvalidDeltaBins.selector); + lbHooks.setParameters(oracleId, bStart, bEnd); + + uint24 maxNumberOfBins = uint24(lbHooks.getMaxNumberOfBins()); + + bStart = int24(bound(binStart, type(int24).min, type(int24).max - int24(maxNumberOfBins + 1))); + bEnd = int24(bound(binEnd, bStart + int24(maxNumberOfBins) + 1, type(int24).max)); + + vm.expectRevert(ILBHooksBaseRewarder.LBHooksBaseRewarder__ExceedsMaxNumberOfBins.selector); + lbHooks.setParameters(oracleId, int24(bStart), int24(bEnd)); + + oracle.setAnswer(1e18, block.timestamp); + latestId = oracleId.getLatestId(); + + bStart = int24(bound(binStart, int24(type(uint24).max - latestId) + 1, type(int24).max)); + + vm.expectRevert(ILBHooksBaseRewarder.LBHooksBaseRewarder__Overflow.selector); + lbHooks.setParameters(oracleId, bStart, bStart); + } +} diff --git a/test/oracle/OracleId.t.sol b/test/oracle/OracleId.t.sol new file mode 100644 index 0000000..e6a393a --- /dev/null +++ b/test/oracle/OracleId.t.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "forge-std/Test.sol"; + +import "src/Oracle/OracleIdChainlink.sol"; + +contract MockOracle { + uint8 public decimals; + int256 public answer; + uint256 updatedAt; + + function setDecimals(uint8 _decimals) public { + decimals = _decimals; + } + + function setAnswer(int256 _answer, uint256 _updatedAt) public { + answer = _answer; + updatedAt = _updatedAt; + } + + function latestRoundData() public view returns (uint80, int256, uint256, uint256, uint80) { + return (0, answer, 0, updatedAt, 0); + } +} + +contract TestOracleId is Test { + MockOracle oracle; + OracleIdChainlink oracleId; + OracleIdChainlink oracleIdInversed; + + function setUp() public { + oracle = new MockOracle(); + oracle.setDecimals(8); + + oracleId = new OracleIdChainlink(IChainlinkAggregatorV3(address(oracle)), false, 60, 1); + oracleIdInversed = new OracleIdChainlink(IChainlinkAggregatorV3(address(oracle)), true, 60, 1); + } + + function test_Constructor() public { + (IChainlinkAggregatorV3 o, bool isInverse, uint256 oraclePrecision, uint256 heartbeat, uint256 binStep) = + oracleId.getOracleIdParameters(); + + assertEq(address(o), address(oracle), "test_Constructor::1"); + assertEq(isInverse, false, "test_Constructor::2"); + assertEq(oraclePrecision, 10 ** 8, "test_Constructor::3"); + assertEq(heartbeat, 60, "test_Constructor::4"); + assertEq(binStep, 1, "test_Constructor::5"); + + (o, isInverse, oraclePrecision, heartbeat, binStep) = oracleIdInversed.getOracleIdParameters(); + + assertEq(address(o), address(oracle), "test_Constructor::6"); + assertEq(isInverse, true, "test_Constructor::7"); + assertEq(oraclePrecision, 10 ** 8, "test_Constructor::8"); + assertEq(heartbeat, 60, "test_Constructor::9"); + assertEq(binStep, 1, "test_Constructor::10"); + } + + function test_Fuzz_GetOracleId(int256 price) public { + price = bound(price, 1, int256(uint256(type(uint128).max))); + + oracle.setAnswer(price, block.timestamp); + + uint24 id = oracleId.getLatestId(); + + uint256 priceX128 = (uint256(price) << 128) / 1e8; + + uint256 priceAtIdMinus1 = PriceHelper.getPriceFromId(id - 1, 1); + uint256 priceAtId = PriceHelper.getPriceFromId(id, 1); + uint256 priceAtIdPlus1 = PriceHelper.getPriceFromId(id + 1, 1); + + assertLt(priceAtIdMinus1, priceX128, "test_Fuzz_GetOracleId::1"); + assertLe(priceAtId, priceX128, "test_Fuzz_GetOracleId::2"); + assertGt(priceAtIdPlus1, priceX128, "test_Fuzz_GetOracleId::3"); + } + + function test_Fuzz_GetOracleIdInversed(int256 price) public { + price = bound(price, 1, int256(uint256(type(uint128).max))); + + oracle.setAnswer(price, block.timestamp); + + uint24 id = oracleIdInversed.getLatestId(); + + uint256 priceX128 = (uint256(1e8) << 128) / uint256(price); + + uint256 priceAtIdMinus1 = PriceHelper.getPriceFromId(id - 1, 1); + uint256 priceAtId = PriceHelper.getPriceFromId(id, 1); + uint256 priceAtIdPlus1 = PriceHelper.getPriceFromId(id + 1, 1); + + assertLt(priceAtIdMinus1, priceX128, "test_Fuzz_GetOracleIdInversed::1"); + assertLe(priceAtId, priceX128, "test_Fuzz_GetOracleIdInversed::2"); + assertGt(priceAtIdPlus1, priceX128, "test_Fuzz_GetOracleIdInversed::3"); + } + + function test_Fuzz_Revert_GetOracleId(int256 price) public { + int256 p = bound(price, type(int256).min, 0); + + oracle.setAnswer(p, block.timestamp); + + vm.expectRevert(OracleIdChainlink.OracleIdChainlink__InvalidPrice.selector); + oracleId.getLatestId(); + + p = bound(price, int256(uint256(type(uint128).max)) + 1, type(int256).max); + + oracle.setAnswer(p, block.timestamp); + + vm.expectRevert(OracleIdChainlink.OracleIdChainlink__InvalidPrice.selector); + oracleId.getLatestId(); + + vm.warp(type(uint256).max); + + uint256 latestUpdatedAt = bound(uint256(price), 0, block.timestamp - (60 + 1)); + + oracle.setAnswer(1e8, latestUpdatedAt); + + vm.expectRevert(OracleIdChainlink.OracleIdChainlink__StalePrice.selector); + oracleId.getLatestId(); + } +} From 1e6a8794abc90c530f574ea24399acd3177ffc53 Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 10:11:21 +0200 Subject: [PATCH 10/14] Add missing natspec --- src/base/LBHooksRewarderVirtual.sol | 4 ++++ src/delta/LBHooksDelta.sol | 5 +++++ src/delta/LBHooksDeltaExtraRewarder.sol | 4 ++++ src/delta/LBHooksDeltaMCRewarder.sol | 4 ++++ src/delta/LBHooksDeltaSimpleRewarder.sol | 4 ++++ src/oracle/LBHooksOracle.sol | 5 +++++ src/oracle/LBHooksOracleExtraRewarder.sol | 4 ++++ src/oracle/LBHooksOracleMCRewarder.sol | 4 ++++ src/oracle/LBHooksOracleSimpleRewarder.sol | 4 ++++ src/oracle/OracleIdChainlink.sol | 2 +- src/static/LBHooksStatic.sol | 5 +++++ src/static/LBHooksStaticExtraRewarder.sol | 4 ++++ src/static/LBHooksStaticMCRewarder.sol | 4 ++++ src/static/LBHooksStaticSimpleRewarder.sol | 4 ++++ 14 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/base/LBHooksRewarderVirtual.sol b/src/base/LBHooksRewarderVirtual.sol index e772b79..0c9b97d 100644 --- a/src/base/LBHooksRewarderVirtual.sol +++ b/src/base/LBHooksRewarderVirtual.sol @@ -3,6 +3,10 @@ pragma solidity ^0.8.20; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +/** + * @title LB Hooks Rewarder Virtual + * @dev Abstract contract for the LB Hooks Rewarders, it contains the important functions that the rewarders should implement + */ abstract contract LBHooksRewarderVirtual is Ownable2StepUpgradeable { /** * @dev Internal function that can be overriden to add custom logic when the rewarder is set diff --git a/src/delta/LBHooksDelta.sol b/src/delta/LBHooksDelta.sol index 58c9539..793580f 100644 --- a/src/delta/LBHooksDelta.sol +++ b/src/delta/LBHooksDelta.sol @@ -3,6 +3,11 @@ pragma solidity ^0.8.20; import "../base/LBHooksRewarderVirtual.sol"; +/** + * @title LB Hooks Delta Rewarder + * @dev Abstract contract for the LB Hooks Delta Rewarder + * This contract allows to distribute rewards to LPs of the [activeId + deltaBinA, activeId + deltaBinB[ bins + */ abstract contract LBHooksDelta is LBHooksRewarderVirtual { error LBHooksDelta__InvalidDeltaBins(); diff --git a/src/delta/LBHooksDeltaExtraRewarder.sol b/src/delta/LBHooksDeltaExtraRewarder.sol index fd29b40..b76d515 100644 --- a/src/delta/LBHooksDeltaExtraRewarder.sol +++ b/src/delta/LBHooksDeltaExtraRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksExtraRewarder} from "../rewarder/LBHooksExtraRewarder.sol"; import {LBHooksDelta} from "./LBHooksDelta.sol"; +/** + * @title LB Hooks Delta Extra Rewarder + * @dev Implementation of the LB Hooks Delta Extra Rewarder + */ contract LBHooksDeltaExtraRewarder is LBHooksExtraRewarder, LBHooksDelta { /** * @dev Constructor of the contract diff --git a/src/delta/LBHooksDeltaMCRewarder.sol b/src/delta/LBHooksDeltaMCRewarder.sol index e6b44d4..c60996a 100644 --- a/src/delta/LBHooksDeltaMCRewarder.sol +++ b/src/delta/LBHooksDeltaMCRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksMCRewarder, IMasterChef, IERC20} from "../rewarder/LBHooksMCRewarder.sol"; import {LBHooksDelta} from "./LBHooksDelta.sol"; +/** + * @title LB Hooks Delta MC Rewarder + * @dev Implementation of the LB Hooks Delta MC Rewarder + */ contract LBHooksDeltaMCRewarder is LBHooksMCRewarder, LBHooksDelta { /** * @dev Constructor of the contract diff --git a/src/delta/LBHooksDeltaSimpleRewarder.sol b/src/delta/LBHooksDeltaSimpleRewarder.sol index 51fa33c..c1af541 100644 --- a/src/delta/LBHooksDeltaSimpleRewarder.sol +++ b/src/delta/LBHooksDeltaSimpleRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksSimpleRewarder} from "../rewarder/LBHooksSimpleRewarder.sol"; import {LBHooksDelta} from "./LBHooksDelta.sol"; +/** + * @title LB Hooks Delta Simple Rewarder + * @dev Implementation of the LB Hooks Delta Simple Rewarder + */ contract LBHooksDeltaSimpleRewarder is LBHooksSimpleRewarder, LBHooksDelta { /** * @dev Constructor of the contract diff --git a/src/oracle/LBHooksOracle.sol b/src/oracle/LBHooksOracle.sol index 5390a06..65ec902 100644 --- a/src/oracle/LBHooksOracle.sol +++ b/src/oracle/LBHooksOracle.sol @@ -4,6 +4,11 @@ pragma solidity ^0.8.20; import "../base/LBHooksRewarderVirtual.sol"; import "../interfaces/IOracleId.sol"; +/** + * @title LB Hooks Oracle + * @dev Abstract contract for the LB Hooks Oracle Rewarder + * This contract allows to distribute rewardsto LPs of the [oracleId + deltaBinA, oracleId + deltaBinB[ bins + */ abstract contract LBHooksOracle is LBHooksRewarderVirtual { error LBHooksOracle__InvalidDeltaBins(); diff --git a/src/oracle/LBHooksOracleExtraRewarder.sol b/src/oracle/LBHooksOracleExtraRewarder.sol index 4d57c07..e6da4e7 100644 --- a/src/oracle/LBHooksOracleExtraRewarder.sol +++ b/src/oracle/LBHooksOracleExtraRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksExtraRewarder} from "../rewarder/LBHooksExtraRewarder.sol"; import {LBHooksOracle} from "./LBHooksOracle.sol"; +/** + * @title LB Hooks Oracle Extra Rewarder + * @dev Implementation of the LB Hooks Oracle Extra Rewarder + */ contract LBHooksOracleExtraRewarder is LBHooksExtraRewarder, LBHooksOracle { /** * @dev Constructor of the contract diff --git a/src/oracle/LBHooksOracleMCRewarder.sol b/src/oracle/LBHooksOracleMCRewarder.sol index 5ab9b2b..36f3a57 100644 --- a/src/oracle/LBHooksOracleMCRewarder.sol +++ b/src/oracle/LBHooksOracleMCRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksMCRewarder, IMasterChef, IERC20} from "../rewarder/LBHooksMCRewarder.sol"; import {LBHooksOracle} from "./LBHooksOracle.sol"; +/** + * @title LB Hooks Oracle MC Rewarder + * @dev Implementation of the LB Hooks Oracle MC Rewarder + */ contract LBHooksOracleMCRewarder is LBHooksMCRewarder, LBHooksOracle { /** * @dev Constructor of the contract diff --git a/src/oracle/LBHooksOracleSimpleRewarder.sol b/src/oracle/LBHooksOracleSimpleRewarder.sol index 6a69f5f..df57511 100644 --- a/src/oracle/LBHooksOracleSimpleRewarder.sol +++ b/src/oracle/LBHooksOracleSimpleRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksSimpleRewarder} from "../rewarder/LBHooksSimpleRewarder.sol"; import {LBHooksOracle} from "./LBHooksOracle.sol"; +/** + * @title LB Hooks Oracle Simple Rewarder + * @dev Implementation of the LB Hooks Oracle Simple Rewarder + */ contract LBHooksOracleSimpleRewarder is LBHooksSimpleRewarder, LBHooksOracle { /** * @dev Constructor of the contract diff --git a/src/oracle/OracleIdChainlink.sol b/src/oracle/OracleIdChainlink.sol index 74075c4..0210bd7 100644 --- a/src/oracle/OracleIdChainlink.sol +++ b/src/oracle/OracleIdChainlink.sol @@ -8,7 +8,7 @@ import "../interfaces/IChainlinkAggregatorV3.sol"; /** * @title Oracle Id - * @dev Contract that uses a chainlink price oracle to return the id of that price + * @dev Contract that uses a chainlink price oracle to return the bin id of that price */ contract OracleIdChainlink is IOracleId { error OracleIdChainlink__InvalidPrice(); diff --git a/src/static/LBHooksStatic.sol b/src/static/LBHooksStatic.sol index 8ccd789..f0418cf 100644 --- a/src/static/LBHooksStatic.sol +++ b/src/static/LBHooksStatic.sol @@ -3,6 +3,11 @@ pragma solidity ^0.8.20; import "../base/LBHooksRewarderVirtual.sol"; +/** + * @title LB Hooks Static Rewarder + * @dev Abstract contract for the LB Hooks Static Rewarder + * This contract allows to distribute rewards to LPs of the [binStart, binEnd[ bins + */ abstract contract LBHooksStatic is LBHooksRewarderVirtual { error LBHooksStatic__InvalidBins(); diff --git a/src/static/LBHooksStaticExtraRewarder.sol b/src/static/LBHooksStaticExtraRewarder.sol index 0bdb448..f6d05a6 100644 --- a/src/static/LBHooksStaticExtraRewarder.sol +++ b/src/static/LBHooksStaticExtraRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksExtraRewarder} from "../rewarder/LBHooksExtraRewarder.sol"; import {LBHooksStatic} from "./LBHooksStatic.sol"; +/** + * @title LB Hooks Static Extra Rewarder + * @dev Implementation of the LB Hooks Static Extra Rewarder + */ contract LBHooksStaticExtraRewarder is LBHooksExtraRewarder, LBHooksStatic { /** * @dev Constructor of the contract diff --git a/src/static/LBHooksStaticMCRewarder.sol b/src/static/LBHooksStaticMCRewarder.sol index d402ec7..6fcfc52 100644 --- a/src/static/LBHooksStaticMCRewarder.sol +++ b/src/static/LBHooksStaticMCRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksMCRewarder, IMasterChef, IERC20} from "../rewarder/LBHooksMCRewarder.sol"; import {LBHooksStatic} from "./LBHooksStatic.sol"; +/** + * @title LB Hooks Static MC Rewarder + * @dev Implementation of the LB Hooks Static MC Rewarder + */ contract LBHooksStaticMCRewarder is LBHooksMCRewarder, LBHooksStatic { /** * @dev Constructor of the contract diff --git a/src/static/LBHooksStaticSimpleRewarder.sol b/src/static/LBHooksStaticSimpleRewarder.sol index 29de740..5415764 100644 --- a/src/static/LBHooksStaticSimpleRewarder.sol +++ b/src/static/LBHooksStaticSimpleRewarder.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.20; import {LBHooksSimpleRewarder} from "../rewarder/LBHooksSimpleRewarder.sol"; import {LBHooksStatic} from "./LBHooksStatic.sol"; +/** + * @title LB Hooks Static Simple Rewarder + * @dev Implementation of the LB Hooks Static Simple Rewarder + */ contract LBHooksStaticSimpleRewarder is LBHooksSimpleRewarder, LBHooksStatic { /** * @dev Constructor of the contract From 8c9efa9b5606b4f6c7f039883b067abb4323282c Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 10:26:26 +0200 Subject: [PATCH 11/14] Update LB Hooks Manager --- src/LBHooksLens.sol | 2 +- src/LBHooksManager.sol | 40 +++++---- src/interfaces/ILBHooksManager.sol | 24 ++++-- test/LBHooksLens.t.sol | 15 ++-- test/LBHooksManager.t.sol | 113 ++++++++++++++++++------- test/delta/LBHooksExtraRewarder.t.sol | 6 +- test/delta/LBHooksRewarder.t.sol | 3 +- test/delta/LBHooksSimpleRewarder.t.sol | 6 +- test/oracle/LBHooksOracle.t.sol | 3 +- test/static/LBHooksStatic.t.sol | 3 +- 10 files changed, 151 insertions(+), 64 deletions(-) diff --git a/src/LBHooksLens.sol b/src/LBHooksLens.sol index fd4b53b..8c64137 100644 --- a/src/LBHooksLens.sol +++ b/src/LBHooksLens.sol @@ -198,7 +198,7 @@ contract LBHooksLens { parameters.rewardToken = getRewardToken(hooks); (parameters.rangeStart, parameters.rangeEnd) = getRewardedRange(hooks); - if (parameters.hooksType == ILBHooksManager.LBHooksType.MCRewarder) { + if (uint8(parameters.hooksType) % 3 == 1) { parameters.pid = getPid(hooks); parameters.moePerSecond = getMoePerSecond(parameters.pid); } else { diff --git a/src/LBHooksManager.sol b/src/LBHooksManager.sol index f3afdae..b0d0614 100644 --- a/src/LBHooksManager.sol +++ b/src/LBHooksManager.sol @@ -106,25 +106,28 @@ contract LBHooksManager is Ownable2StepUpgradeable, ILBHooksManager { * @dev Creates a new LB Hooks Rewarder * This will also try to set the LB Hooks parameters on the pair * Only callable by the owner + * @param lbHooksType The LB Hooks type * @param tokenX The address of the token X * @param tokenY The address of the token Y * @param binStep The bin step * @param initialOwner The address of the initial owner * @return rewarder The address of the LB Hooks Rewarder */ - function createLBHooksMCRewarder(IERC20 tokenX, IERC20 tokenY, uint16 binStep, address initialOwner) - external - override - onlyOwner - returns (address rewarder) - { - (ILBPair lbPair, bytes32 hooksParameters) = - _getLBPairAndHooksParameters(LBHooksType.MCRewarder, tokenX, tokenY, binStep); + function createLBHooksMCRewarder( + LBHooksType lbHooksType, + IERC20 tokenX, + IERC20 tokenY, + uint16 binStep, + address initialOwner + ) external override onlyOwner returns (address rewarder) { + if (uint8(lbHooksType) % 3 != 1) revert LBHooksManager__InvalidLBHooksType(); + + (ILBPair lbPair, bytes32 hooksParameters) = _getLBPairAndHooksParameters(lbHooksType, tokenX, tokenY, binStep); uint256 pid = _masterChef.getNumberOfFarms(); bytes memory immutableData = abi.encodePacked(lbPair, pid); - rewarder = _cloneHooks(LBHooksType.MCRewarder, Hooks.getHooks(hooksParameters), immutableData); + rewarder = _cloneHooks(lbHooksType, Hooks.getHooks(hooksParameters), immutableData); _masterChef.add(IERC20(rewarder), IMasterChefRewarder(address(0))); @@ -140,6 +143,7 @@ contract LBHooksManager is Ownable2StepUpgradeable, ILBHooksManager { /** * @dev Creates a new LB Hooks Simple Rewarder * Only callable by the owner + * @param lbHooksType The LB Hooks type * @param tokenX The address of the token X * @param tokenY The address of the token Y * @param binStep The bin step @@ -148,20 +152,24 @@ contract LBHooksManager is Ownable2StepUpgradeable, ILBHooksManager { * @return rewarder The address of the LB Hooks Simple Rewarder */ function createLBHooksSimpleRewarder( + LBHooksType lbHooksType, IERC20 tokenX, IERC20 tokenY, uint16 binStep, IERC20 rewardToken, address initialOwner ) external override onlyOwner returns (address rewarder) { - (ILBPair lbPair, bytes32 hooksParameters) = - _getLBPairAndHooksParameters(LBHooksType.SimpleRewarder, tokenX, tokenY, binStep); + if (lbHooksType == LBHooksType.Invalid || uint8(lbHooksType) % 3 != 0) { + revert LBHooksManager__InvalidLBHooksType(); + } + + (ILBPair lbPair, bytes32 hooksParameters) = _getLBPairAndHooksParameters(lbHooksType, tokenX, tokenY, binStep); address lbHooksAddress = Hooks.getHooks(lbPair.getLBHooksParameters()); bytes memory immutableData = abi.encodePacked(lbPair, rewardToken, lbHooksAddress); - rewarder = _cloneHooks(LBHooksType.SimpleRewarder, Hooks.getHooks(hooksParameters), immutableData); + rewarder = _cloneHooks(lbHooksType, Hooks.getHooks(hooksParameters), immutableData); _lbFactory.setLBHooksParametersOnPair( tokenX, tokenY, binStep, Hooks.setHooks(hooksParameters, rewarder), abi.encode(initialOwner) @@ -180,14 +188,16 @@ contract LBHooksManager is Ownable2StepUpgradeable, ILBHooksManager { * @return extraRewarder The address of the LB Hooks Extra Rewarder */ function createLBHooksExtraRewarder( + LBHooksType lbHooksType, IERC20 tokenX, IERC20 tokenY, uint16 binStep, IERC20 rewardToken, address initialOwner ) external override onlyOwner returns (address extraRewarder) { - (ILBPair lbPair, bytes32 hooksParameters) = - _getLBPairAndHooksParameters(LBHooksType.ExtraRewarder, tokenX, tokenY, binStep); + if (uint8(lbHooksType) % 3 != 2) revert LBHooksManager__InvalidLBHooksType(); + + (ILBPair lbPair, bytes32 hooksParameters) = _getLBPairAndHooksParameters(lbHooksType, tokenX, tokenY, binStep); address lbHooksAddress = Hooks.getHooks(lbPair.getLBHooksParameters()); @@ -195,7 +205,7 @@ contract LBHooksManager is Ownable2StepUpgradeable, ILBHooksManager { bytes memory immutableData = abi.encodePacked(lbPair, rewardToken, lbHooksAddress); - extraRewarder = _cloneHooks(LBHooksType.ExtraRewarder, Hooks.getHooks(hooksParameters), immutableData); + extraRewarder = _cloneHooks(lbHooksType, Hooks.getHooks(hooksParameters), immutableData); ILBHooksBaseParentRewarder(lbHooksAddress).setLBHooksExtraRewarder(extraRewarder, abi.encode(initialOwner)); } diff --git a/src/interfaces/ILBHooksManager.sol b/src/interfaces/ILBHooksManager.sol index 190c86d..ee24f4c 100644 --- a/src/interfaces/ILBHooksManager.sol +++ b/src/interfaces/ILBHooksManager.sol @@ -17,9 +17,15 @@ interface ILBHooksManager { enum LBHooksType { Invalid, - MCRewarder, - ExtraRewarder, - SimpleRewarder + DeltaMCRewarder, + DeltaExtraRewarder, + DeltaSimpleRewarder, + StaticMCRewarder, + StaticExtraRewarder, + StaticSimpleRewarder, + OracleMCRewarder, + OracleExtraRewarder, + OracleSimpleRewarder } event HooksParametersSet(LBHooksType lbHooksType, bytes32 hooksParameters); @@ -36,11 +42,16 @@ interface ILBHooksManager { function setLBHooksParameters(LBHooksType lbHooksType, bytes32 hooksParameters) external; - function createLBHooksMCRewarder(IERC20 tokenX, IERC20 tokenY, uint16 binStep, address initialOwner) - external - returns (address); + function createLBHooksMCRewarder( + LBHooksType lbHooksType, + IERC20 tokenX, + IERC20 tokenY, + uint16 binStep, + address initialOwner + ) external returns (address); function createLBHooksSimpleRewarder( + LBHooksType lbHooksType, IERC20 tokenX, IERC20 tokenY, uint16 binStep, @@ -49,6 +60,7 @@ interface ILBHooksManager { ) external returns (address); function createLBHooksExtraRewarder( + LBHooksType lbHooksType, IERC20 tokenX, IERC20 tokenY, uint16 binStep, diff --git a/test/LBHooksLens.t.sol b/test/LBHooksLens.t.sol index d84376a..05fa01a 100644 --- a/test/LBHooksLens.t.sol +++ b/test/LBHooksLens.t.sol @@ -18,13 +18,13 @@ contract LBHooksLensTest is TestHelper { super.setUp(); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.MCRewarder, + ILBHooksManager.LBHooksType.DeltaMCRewarder, Hooks.setHooks( hooksParameters, address(new LBHooksDeltaMCRewarder(address(lbHooksManager), masterchef, moe)) ) ); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.ExtraRewarder, + ILBHooksManager.LBHooksType.DeltaExtraRewarder, Hooks.setHooks(hooksParameters, address(new LBHooksDeltaExtraRewarder(address(lbHooksManager)))) ); @@ -32,7 +32,11 @@ contract LBHooksLensTest is TestHelper { payable( address( lbHooksManager.createLBHooksMCRewarder( - IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, address(this) + ILBHooksManager.LBHooksType.DeltaMCRewarder, + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + address(this) ) ) ) @@ -42,6 +46,7 @@ contract LBHooksLensTest is TestHelper { payable( address( lbHooksManager.createLBHooksExtraRewarder( + ILBHooksManager.LBHooksType.DeltaExtraRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, @@ -81,7 +86,7 @@ contract LBHooksLensTest is TestHelper { ); assertEq( uint8(rewarderData.parameters.hooksType), - uint8(ILBHooksManager.LBHooksType.MCRewarder), + uint8(ILBHooksManager.LBHooksType.DeltaMCRewarder), "test_GetPendingRewardSwapAndTransfer::2" ); assertEq(rewarderData.parameters.rewardToken.token, address(moe), "test_GetPendingRewardSwapAndTransfer::3"); @@ -95,7 +100,7 @@ contract LBHooksLensTest is TestHelper { assertEq( uint8(extraRewarderData.parameters.hooksType), - uint8(ILBHooksManager.LBHooksType.ExtraRewarder), + uint8(ILBHooksManager.LBHooksType.DeltaExtraRewarder), "test_GetPendingRewardSwapAndTransfer::11" ); assertEq( diff --git a/test/LBHooksManager.t.sol b/test/LBHooksManager.t.sol index caa1952..0a85d4a 100644 --- a/test/LBHooksManager.t.sol +++ b/test/LBHooksManager.t.sol @@ -22,39 +22,41 @@ contract LBHooksManagerTest is TestHelper { } function test_GetLBHooksParameters() public { - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder, rewarderHooksParameters); - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.ExtraRewarder, extraRewarderHooksParameters); + lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.DeltaMCRewarder, rewarderHooksParameters); + lbHooksManager.setLBHooksParameters( + ILBHooksManager.LBHooksType.DeltaExtraRewarder, extraRewarderHooksParameters + ); assertEq( - lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder), + lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.DeltaMCRewarder), rewarderHooksParameters, "test_GetLBHooksParameters::1" ); assertEq( - lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.ExtraRewarder), + lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.DeltaExtraRewarder), extraRewarderHooksParameters, "test_GetLBHooksParameters::2" ); - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder, bytes32(0)); + lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.DeltaMCRewarder, bytes32(0)); assertEq( - lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder), + lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.DeltaMCRewarder), bytes32(0), "test_GetLBHooksParameters::3" ); - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.ExtraRewarder, bytes32(0)); + lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.DeltaExtraRewarder, bytes32(0)); assertEq( - lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.ExtraRewarder), + lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.DeltaExtraRewarder), bytes32(0), "test_GetLBHooksParameters::4" ); assertEq( - lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.ExtraRewarder), + lbHooksManager.getLBHooksParameters(ILBHooksManager.LBHooksType.DeltaExtraRewarder), bytes32(0), "test_GetLBHooksParameters::5" ); @@ -78,46 +80,66 @@ contract LBHooksManagerTest is TestHelper { function test_createLBHooksMCRewarder() public { vm.expectRevert(ILBHooksManager.LBHooksManager__LBPairNotFound.selector); lbHooksManager.createLBHooksMCRewarder( - IERC20(address(token0)), IERC20(address(token0)), DEFAULT_BIN_STEP, address(this) + ILBHooksManager.LBHooksType.DeltaMCRewarder, + IERC20(address(token0)), + IERC20(address(token0)), + DEFAULT_BIN_STEP, + address(this) ); vm.expectRevert(ILBHooksManager.LBHooksManager__UnorderedTokens.selector); lbHooksManager.createLBHooksMCRewarder( - IERC20(address(token1)), IERC20(address(token0)), DEFAULT_BIN_STEP, address(this) + ILBHooksManager.LBHooksType.DeltaMCRewarder, + IERC20(address(token1)), + IERC20(address(token0)), + DEFAULT_BIN_STEP, + address(this) ); vm.expectRevert(ILBHooksManager.LBHooksManager__LBHooksParametersNotSet.selector); lbHooksManager.createLBHooksMCRewarder( - IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, address(this) + ILBHooksManager.LBHooksType.DeltaMCRewarder, + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + address(this) ); - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder, rewarderHooksParameters); + lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.DeltaMCRewarder, rewarderHooksParameters); assertEq( - lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.MCRewarder), 0, "test_createLBHooksMCRewarder::1" + lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.DeltaMCRewarder), + 0, + "test_createLBHooksMCRewarder::1" ); LBHooksDeltaMCRewarder lbHooks = LBHooksDeltaMCRewarder( payable( address( lbHooksManager.createLBHooksMCRewarder( - IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, address(this) + ILBHooksManager.LBHooksType.DeltaMCRewarder, + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + address(this) ) ) ) ); assertEq( - lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.MCRewarder), 1, "test_createLBHooksMCRewarder::2" + lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.DeltaMCRewarder), + 1, + "test_createLBHooksMCRewarder::2" ); assertEq( - address(lbHooksManager.getHooksAt(ILBHooksManager.LBHooksType.MCRewarder, 0)), + address(lbHooksManager.getHooksAt(ILBHooksManager.LBHooksType.DeltaMCRewarder, 0)), address(lbHooks), "test_createLBHooksMCRewarder::3" ); assertEq( uint8(lbHooksManager.getLBHooksType(lbHooks)), - uint8(ILBHooksManager.LBHooksType.MCRewarder), + uint8(ILBHooksManager.LBHooksType.DeltaMCRewarder), "test_createLBHooksMCRewarder::4" ); } @@ -125,56 +147,87 @@ contract LBHooksManagerTest is TestHelper { function test_CreateLBHooksExtraRewarder() public { vm.expectRevert(ILBHooksManager.LBHooksManager__LBPairNotFound.selector); lbHooksManager.createLBHooksExtraRewarder( - IERC20(address(token0)), IERC20(address(token0)), DEFAULT_BIN_STEP, IERC20(address(0)), address(this) + ILBHooksManager.LBHooksType.DeltaExtraRewarder, + IERC20(address(token0)), + IERC20(address(token0)), + DEFAULT_BIN_STEP, + IERC20(address(0)), + address(this) ); vm.expectRevert(ILBHooksManager.LBHooksManager__UnorderedTokens.selector); lbHooksManager.createLBHooksExtraRewarder( - IERC20(address(token1)), IERC20(address(token0)), DEFAULT_BIN_STEP, IERC20(address(0)), address(this) + ILBHooksManager.LBHooksType.DeltaExtraRewarder, + IERC20(address(token1)), + IERC20(address(token0)), + DEFAULT_BIN_STEP, + IERC20(address(0)), + address(this) ); vm.expectRevert(ILBHooksManager.LBHooksManager__LBHooksParametersNotSet.selector); lbHooksManager.createLBHooksExtraRewarder( - IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, IERC20(address(0)), address(this) + ILBHooksManager.LBHooksType.DeltaExtraRewarder, + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + IERC20(address(0)), + address(this) ); - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder, rewarderHooksParameters); - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.ExtraRewarder, extraRewarderHooksParameters); + lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.DeltaMCRewarder, rewarderHooksParameters); + lbHooksManager.setLBHooksParameters( + ILBHooksManager.LBHooksType.DeltaExtraRewarder, extraRewarderHooksParameters + ); vm.expectRevert(ILBHooksManager.LBHooksManager__LBHooksNotSetOnPair.selector); lbHooksManager.createLBHooksExtraRewarder( - IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, IERC20(address(0)), address(this) + ILBHooksManager.LBHooksType.DeltaExtraRewarder, + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + IERC20(address(0)), + address(this) ); lbHooksManager.createLBHooksMCRewarder( - IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, address(this) + ILBHooksManager.LBHooksType.DeltaMCRewarder, + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + address(this) ); assertEq( - lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.ExtraRewarder), + lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.DeltaExtraRewarder), 0, "test_CreateLBHooksExtraRewarder::1" ); ILBHooksExtraRewarder lbHooks = ILBHooksExtraRewarder( lbHooksManager.createLBHooksExtraRewarder( - IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, IERC20(address(0)), address(this) + ILBHooksManager.LBHooksType.DeltaExtraRewarder, + IERC20(address(token0)), + IERC20(address(token1)), + DEFAULT_BIN_STEP, + IERC20(address(0)), + address(this) ) ); assertEq( - lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.ExtraRewarder), + lbHooksManager.getHooksLength(ILBHooksManager.LBHooksType.DeltaExtraRewarder), 1, "test_CreateLBHooksExtraRewarder::2" ); assertEq( - address(lbHooksManager.getHooksAt(ILBHooksManager.LBHooksType.ExtraRewarder, 0)), + address(lbHooksManager.getHooksAt(ILBHooksManager.LBHooksType.DeltaExtraRewarder, 0)), address(lbHooks), "test_CreateLBHooksExtraRewarder::3" ); assertEq( uint8(lbHooksManager.getLBHooksType(lbHooks)), - uint8(ILBHooksManager.LBHooksType.ExtraRewarder), + uint8(ILBHooksManager.LBHooksType.DeltaExtraRewarder), "test_CreateLBHooksExtraRewarder::4" ); } diff --git a/test/delta/LBHooksExtraRewarder.t.sol b/test/delta/LBHooksExtraRewarder.t.sol index 3c628de..1bdd4f3 100644 --- a/test/delta/LBHooksExtraRewarder.t.sol +++ b/test/delta/LBHooksExtraRewarder.t.sol @@ -17,13 +17,13 @@ contract LBHooksExtraRewarderTest is TestHelper { super.setUp(); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.MCRewarder, + ILBHooksManager.LBHooksType.DeltaMCRewarder, Hooks.setHooks( hooksParameters, address(new LBHooksDeltaMCRewarder(address(lbHooksManager), masterchef, moe)) ) ); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.ExtraRewarder, + ILBHooksManager.LBHooksType.DeltaExtraRewarder, Hooks.setHooks(hooksParameters, address(new LBHooksDeltaExtraRewarder(address(lbHooksManager)))) ); @@ -31,6 +31,7 @@ contract LBHooksExtraRewarderTest is TestHelper { payable( address( lbHooksManager.createLBHooksMCRewarder( + ILBHooksManager.LBHooksType.DeltaMCRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, address(this) ) ) @@ -41,6 +42,7 @@ contract LBHooksExtraRewarderTest is TestHelper { payable( address( lbHooksManager.createLBHooksExtraRewarder( + ILBHooksManager.LBHooksType.DeltaExtraRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, diff --git a/test/delta/LBHooksRewarder.t.sol b/test/delta/LBHooksRewarder.t.sol index cd6e66d..a5658d1 100644 --- a/test/delta/LBHooksRewarder.t.sol +++ b/test/delta/LBHooksRewarder.t.sol @@ -17,12 +17,13 @@ contract LBHooksRewarderTest is TestHelper { hooksParameters, address(new LBHooksDeltaMCRewarder(address(lbHooksManager), masterchef, moe)) ); - lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.MCRewarder, hooksParameters); + lbHooksManager.setLBHooksParameters(ILBHooksManager.LBHooksType.DeltaMCRewarder, hooksParameters); lbHooks = LBHooksDeltaMCRewarder( payable( address( lbHooksManager.createLBHooksMCRewarder( + ILBHooksManager.LBHooksType.DeltaMCRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, address(this) ) ) diff --git a/test/delta/LBHooksSimpleRewarder.t.sol b/test/delta/LBHooksSimpleRewarder.t.sol index 75ae251..c4747e8 100644 --- a/test/delta/LBHooksSimpleRewarder.t.sol +++ b/test/delta/LBHooksSimpleRewarder.t.sol @@ -17,11 +17,11 @@ contract LBHooksSimpleRewarderTest is TestHelper { super.setUp(); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.SimpleRewarder, + ILBHooksManager.LBHooksType.DeltaSimpleRewarder, Hooks.setHooks(hooksParameters, address(new LBHooksDeltaSimpleRewarder(address(lbHooksManager)))) ); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.ExtraRewarder, + ILBHooksManager.LBHooksType.DeltaExtraRewarder, Hooks.setHooks(hooksParameters, address(new LBHooksDeltaExtraRewarder(address(lbHooksManager)))) ); @@ -29,6 +29,7 @@ contract LBHooksSimpleRewarderTest is TestHelper { payable( address( lbHooksManager.createLBHooksSimpleRewarder( + ILBHooksManager.LBHooksType.DeltaSimpleRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, @@ -43,6 +44,7 @@ contract LBHooksSimpleRewarderTest is TestHelper { payable( address( lbHooksManager.createLBHooksExtraRewarder( + ILBHooksManager.LBHooksType.DeltaExtraRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, diff --git a/test/oracle/LBHooksOracle.t.sol b/test/oracle/LBHooksOracle.t.sol index b674647..008116a 100644 --- a/test/oracle/LBHooksOracle.t.sol +++ b/test/oracle/LBHooksOracle.t.sol @@ -37,7 +37,7 @@ contract TestLBHooksOracle is TestHelper { oracleId = new OracleIdChainlink(IChainlinkAggregatorV3(address(oracle)), false, 60, 1); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.SimpleRewarder, + ILBHooksManager.LBHooksType.DeltaSimpleRewarder, Hooks.setHooks(hooksParameters, address(new MockLBHooksOracle(address(lbHooksManager)))) ); @@ -45,6 +45,7 @@ contract TestLBHooksOracle is TestHelper { payable( address( lbHooksManager.createLBHooksSimpleRewarder( + ILBHooksManager.LBHooksType.DeltaSimpleRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, diff --git a/test/static/LBHooksStatic.t.sol b/test/static/LBHooksStatic.t.sol index 813b24d..4935ded 100644 --- a/test/static/LBHooksStatic.t.sol +++ b/test/static/LBHooksStatic.t.sol @@ -30,7 +30,7 @@ contract TestLBHooksStatic is TestHelper { super.setUp(); lbHooksManager.setLBHooksParameters( - ILBHooksManager.LBHooksType.SimpleRewarder, + ILBHooksManager.LBHooksType.DeltaSimpleRewarder, Hooks.setHooks(hooksParameters, address(new MockLBHooksStatic(address(lbHooksManager)))) ); @@ -38,6 +38,7 @@ contract TestLBHooksStatic is TestHelper { payable( address( lbHooksManager.createLBHooksSimpleRewarder( + ILBHooksManager.LBHooksType.DeltaSimpleRewarder, IERC20(address(token0)), IERC20(address(token1)), DEFAULT_BIN_STEP, From bedd58e62d13eb933836cf9f4aea3ff7dcaeef2b Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Mon, 14 Oct 2024 10:26:34 +0200 Subject: [PATCH 12/14] Add getters --- src/delta/LBHooksDelta.sol | 9 +++++++++ src/oracle/LBHooksOracle.sol | 10 ++++++---- src/static/LBHooksStatic.sol | 9 +++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/delta/LBHooksDelta.sol b/src/delta/LBHooksDelta.sol index 793580f..9568786 100644 --- a/src/delta/LBHooksDelta.sol +++ b/src/delta/LBHooksDelta.sol @@ -16,6 +16,15 @@ abstract contract LBHooksDelta is LBHooksRewarderVirtual { int24 internal _deltaBinA; int24 internal _deltaBinB; + /** + * @dev Returns the delta bins + * @return deltaBinA The delta bin A + * @return deltaBinB The delta bin B + */ + function getParameters() external view returns (int24 deltaBinA, int24 deltaBinB) { + return (_deltaBinA, _deltaBinB); + } + /** * @dev Sets the delta bins * The delta bins are used to determine the range of bins to be rewarded, diff --git a/src/oracle/LBHooksOracle.sol b/src/oracle/LBHooksOracle.sol index 65ec902..baf8a49 100644 --- a/src/oracle/LBHooksOracle.sol +++ b/src/oracle/LBHooksOracle.sol @@ -19,11 +19,13 @@ abstract contract LBHooksOracle is LBHooksRewarderVirtual { int24 internal _deltaBinB; /** - * @dev Returns the oracle id address - * @return The oracle id address + * @dev Returns the oracle parameters + * @return oracle The oracle id address + * @return deltaBinA The delta binA + * @return deltaBinB The delta binB */ - function getOracle() external view returns (address) { - return address(_oracle); + function getParameters() external view returns (IOracleId oracle, int24 deltaBinA, int24 deltaBinB) { + return (_oracle, _deltaBinA, _deltaBinB); } /** diff --git a/src/static/LBHooksStatic.sol b/src/static/LBHooksStatic.sol index f0418cf..7f5e865 100644 --- a/src/static/LBHooksStatic.sol +++ b/src/static/LBHooksStatic.sol @@ -16,6 +16,15 @@ abstract contract LBHooksStatic is LBHooksRewarderVirtual { uint24 internal _binStart; uint24 internal _binEnd; + /** + * @dev Returns the range of bins to be rewarded + * @return binStart The bin start to be rewarded + * @return binEnd The bin end to be rewarded, exclusive + */ + function getParameters() external view returns (uint24 binStart, uint24 binEnd) { + return (_binStart, _binEnd); + } + /** * @dev Sets the range of bins to be rewarded * @param binStart The bin start to be rewarded From 27025439994b6d2e05701d48d940adf1411c1ecb Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Tue, 15 Oct 2024 15:45:09 -0300 Subject: [PATCH 13/14] typo --- src/oracle/LBHooksOracle.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oracle/LBHooksOracle.sol b/src/oracle/LBHooksOracle.sol index baf8a49..a1ed338 100644 --- a/src/oracle/LBHooksOracle.sol +++ b/src/oracle/LBHooksOracle.sol @@ -7,7 +7,7 @@ import "../interfaces/IOracleId.sol"; /** * @title LB Hooks Oracle * @dev Abstract contract for the LB Hooks Oracle Rewarder - * This contract allows to distribute rewardsto LPs of the [oracleId + deltaBinA, oracleId + deltaBinB[ bins + * This contract allows to distribute rewards to LPs of the [oracleId + deltaBinA, oracleId + deltaBinB[ bins */ abstract contract LBHooksOracle is LBHooksRewarderVirtual { error LBHooksOracle__InvalidDeltaBins(); From caaabdc4bba17fded1e3a736b482f4b5f998e9e0 Mon Sep 17 00:00:00 2001 From: 0x0Louis Date: Tue, 15 Oct 2024 17:44:51 -0300 Subject: [PATCH 14/14] Return 0 instead of revert --- src/oracle/LBHooksOracle.sol | 6 ++++-- src/oracle/OracleIdChainlink.sol | 6 +----- test/oracle/OracleId.t.sol | 11 ++++------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/oracle/LBHooksOracle.sol b/src/oracle/LBHooksOracle.sol index a1ed338..0497541 100644 --- a/src/oracle/LBHooksOracle.sol +++ b/src/oracle/LBHooksOracle.sol @@ -61,8 +61,10 @@ abstract contract LBHooksOracle is LBHooksRewarderVirtual { if (address(oracle) != address(0)) { uint24 oracleId = oracle.getLatestId(); - binStart = uint256(int256(uint256(oracleId)) + deltaBinA); - binEnd = uint256(int256(uint256(oracleId)) + deltaBinB); + if (oracleId > 0) { + binStart = uint256(int256(uint256(oracleId)) + deltaBinA); + binEnd = uint256(int256(uint256(oracleId)) + deltaBinB); + } } } } diff --git a/src/oracle/OracleIdChainlink.sol b/src/oracle/OracleIdChainlink.sol index 0210bd7..0787658 100644 --- a/src/oracle/OracleIdChainlink.sol +++ b/src/oracle/OracleIdChainlink.sol @@ -11,9 +11,6 @@ import "../interfaces/IChainlinkAggregatorV3.sol"; * @dev Contract that uses a chainlink price oracle to return the bin id of that price */ contract OracleIdChainlink is IOracleId { - error OracleIdChainlink__InvalidPrice(); - error OracleIdChainlink__StalePrice(); - IChainlinkAggregatorV3 internal immutable _oracle; bool internal immutable _isInverse; uint256 internal immutable _oraclePrecision; @@ -65,8 +62,7 @@ contract OracleIdChainlink is IOracleId { function getLatestId() external view override returns (uint24) { (, int256 answer,, uint256 updatedAt,) = _oracle.latestRoundData(); - if (answer <= 0 || uint256(answer) > type(uint128).max) revert OracleIdChainlink__InvalidPrice(); - if (block.timestamp > updatedAt + _heartbeat) revert OracleIdChainlink__StalePrice(); + if (answer <= 0 || uint256(answer) > type(uint128).max || block.timestamp > updatedAt + _heartbeat) return 0; uint256 priceX128 = _isInverse ? (_oraclePrecision << 128) / uint256(answer) : (uint256(answer) << 128) / _oraclePrecision; diff --git a/test/oracle/OracleId.t.sol b/test/oracle/OracleId.t.sol index e6a393a..d70c4cb 100644 --- a/test/oracle/OracleId.t.sol +++ b/test/oracle/OracleId.t.sol @@ -92,20 +92,18 @@ contract TestOracleId is Test { assertGt(priceAtIdPlus1, priceX128, "test_Fuzz_GetOracleIdInversed::3"); } - function test_Fuzz_Revert_GetOracleId(int256 price) public { + function test_Fuzz_GetOracleId_Zero(int256 price) public { int256 p = bound(price, type(int256).min, 0); oracle.setAnswer(p, block.timestamp); - vm.expectRevert(OracleIdChainlink.OracleIdChainlink__InvalidPrice.selector); - oracleId.getLatestId(); + assertEq(oracleId.getLatestId(), 0); p = bound(price, int256(uint256(type(uint128).max)) + 1, type(int256).max); oracle.setAnswer(p, block.timestamp); - vm.expectRevert(OracleIdChainlink.OracleIdChainlink__InvalidPrice.selector); - oracleId.getLatestId(); + assertEq(oracleId.getLatestId(), 0); vm.warp(type(uint256).max); @@ -113,7 +111,6 @@ contract TestOracleId is Test { oracle.setAnswer(1e8, latestUpdatedAt); - vm.expectRevert(OracleIdChainlink.OracleIdChainlink__StalePrice.selector); - oracleId.getLatestId(); + assertEq(oracleId.getLatestId(), 0); } }