diff --git a/contracts/AccessControlManager.sol b/contracts/AccessControlManager.sol index e2cc1af..700873c 100644 --- a/contracts/AccessControlManager.sol +++ b/contracts/AccessControlManager.sol @@ -1,38 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -/* - * █ - ***** ▓▓▓ - * ▓▓▓▓▓▓▓ - * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ - ***** //////// ▓▓▓▓▓▓▓ - * ///////////// ▓▓▓ - ▓▓ ////////////////// █ ▓▓ - ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ - ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ - ▓▓ ////////////////////////////////////////// ▓▓ - ▓▓ //////////////////////▓▓▓▓///////////////////// - ,//////////////////////////////////////////////////// - .////////////////////////////////////////////////////////// - .//////////////////////////██.,//////////////////////////█ - .//////////////////////████..,./////////////////////██ - ...////////////////███████.....,.////////////////███ - ,.,////////////████████ ........,///////////████ - .,.,//////█████████ ,.......///////████ - ,..//████████ ........./████ - ..,██████ .....,███ - .██ ,.,█ - - - - ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ - ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ - ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ - ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ -*/ - pragma solidity ^0.8.17; import { AccessControlEnumerableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; diff --git a/contracts/Disputer.sol b/contracts/Disputer.sol index 5ef17f4..20a13e4 100644 --- a/contracts/Disputer.sol +++ b/contracts/Disputer.sol @@ -1,38 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -/* - * █ - ***** ▓▓▓ - * ▓▓▓▓▓▓▓ - * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ - ***** //////// ▓▓▓▓▓▓▓ - * ///////////// ▓▓▓ - ▓▓ ////////////////// █ ▓▓ - ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ - ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ - ▓▓ ////////////////////////////////////////// ▓▓ - ▓▓ //////////////////////▓▓▓▓///////////////////// - ,//////////////////////////////////////////////////// - .////////////////////////////////////////////////////////// - .//////////////////////////██.,//////////////////////////█ - .//////////////////////████..,./////////////////////██ - ...////////////////███████.....,.////////////////███ - ,.,////////////████████ ........,///////////████ - .,.,//////█████████ ,.......///////████ - ,..//████████ ........./████ - ..,██████ .....,███ - .██ ,.,█ - - - - ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ - ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ - ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ - ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ -*/ - pragma solidity ^0.8.24; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/DistributionCreator.sol b/contracts/DistributionCreator.sol index bb0d27b..a8615e1 100644 --- a/contracts/DistributionCreator.sol +++ b/contracts/DistributionCreator.sol @@ -1,38 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -/* - * █ - ***** ▓▓▓ - * ▓▓▓▓▓▓▓ - * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ - ***** //////// ▓▓▓▓▓▓▓ - * ///////////// ▓▓▓ - ▓▓ ////////////////// █ ▓▓ - ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ - ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ - ▓▓ ////////////////////////////////////////// ▓▓ - ▓▓ //////////////////////▓▓▓▓///////////////////// - ,//////////////////////////////////////////////////// - .////////////////////////////////////////////////////////// - .//////////////////////////██.,//////////////////////////█ - .//////////////////////████..,./////////////////////██ - ...////////////////███████.....,.////////////////███ - ,.,////////////████████ ........,///////////████ - .,.,//////█████████ ,.......///////████ - ,..//████████ ........./████ - ..,██████ .....,███ - .██ ,.,█ - - - - ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ - ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ - ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ - ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ -*/ - pragma solidity ^0.8.17; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; diff --git a/contracts/Distributor.sol b/contracts/Distributor.sol index 8423962..60c8d50 100644 --- a/contracts/Distributor.sol +++ b/contracts/Distributor.sol @@ -1,38 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -/* - * █ - ***** ▓▓▓ - * ▓▓▓▓▓▓▓ - * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ - ***** //////// ▓▓▓▓▓▓▓ - * ///////////// ▓▓▓ - ▓▓ ////////////////// █ ▓▓ - ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ - ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ - ▓▓ ////////////////////////////////////////// ▓▓ - ▓▓ //////////////////////▓▓▓▓///////////////////// - ,//////////////////////////////////////////////////// - .////////////////////////////////////////////////////////// - .//////////////////////////██.,//////////////////////////█ - .//////////////////////████..,./////////////////////██ - ...////////////////███████.....,.////////////////███ - ,.,////////////████████ ........,///////////████ - .,.,//////█████████ ,.......///////████ - ,..//████████ ........./████ - ..,██████ .....,███ - .██ ,.,█ - - - - ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ - ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ - ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ - ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ -*/ - pragma solidity ^0.8.17; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/partners/middleman/MerklFraxIncentivizationHandler.sol b/contracts/partners/middleman/MerklFraxIncentivizationHandler.sol deleted file mode 100644 index 7ab6058..0000000 --- a/contracts/partners/middleman/MerklFraxIncentivizationHandler.sol +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.17; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; - -import { DistributionCreator, DistributionParameters } from "../../DistributionCreator.sol"; -import { Errors } from "../../utils/Errors.sol"; - -/// @title MerklFraxIncentivizationHandler -/// @author Angle Labs, Inc. -/// @notice Manages the transfer of rewards sent by FRAX `IncentivizingLiquidityAmo` contract to the -/// `DistributionCreator` contract -/// @dev This contract is built under the assumption that the `DistributionCreator` contract has already whitelisted -/// this contract for it to distribute rewards without having to sign a message -contract MerklFraxIncentivizationHandler is Ownable { - using SafeERC20 for IERC20; - - /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PARAMETERS - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - - address public operatorAddress; - - /// @notice Maps a gauge, incentive token pair to its reward parameters - mapping(address => mapping(address => DistributionParameters)) public gaugeParams; - - /// @notice Maps an incentive token to a set of (pool, leftovers) - /// @dev Merkl imposes that each token distribution comes with a minimum amount per hour - /// We use this mapping to keep track of leftovers to be distributed during future distributions - mapping(address => mapping(address => uint256)) public leftovers; - - /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - MODIFIER / EVENT - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - - modifier onlyByOwnerOperator() { - require(msg.sender == operatorAddress || msg.sender == owner(), "Not owner or operator"); - _; - } - - event GaugeSet(address indexed gauge, address indexed incentiveTokenAddress); - - constructor(address _operatorAddress) Ownable() { - operatorAddress = _operatorAddress; - } - - /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - REFERENCES - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - - /// @notice Address of the Merkl contract managing rewards to be distributed - /// @dev Address is the same across the different chains on which it is deployed - function merklDistributionCreator() public view virtual returns (DistributionCreator) { - return DistributionCreator(0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd); - } - - /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - EXTERNAL FUNCTIONS - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - - /// @notice Specifies the reward distribution parameters for `poolAddress` - function setGauge( - address poolAddress, - address incentiveTokenAddress, - DistributionParameters memory params - ) external onlyByOwnerOperator { - if (poolAddress == address(0) || incentiveTokenAddress == address(0)) revert Errors.InvalidParams(); - gaugeParams[poolAddress][incentiveTokenAddress] = params; - emit GaugeSet(poolAddress, incentiveTokenAddress); - } - - /// @notice Sets the operator of the contract - function setOperator(address _operatorAddress) external onlyByOwnerOperator { - operatorAddress = _operatorAddress; - } - - /// @notice Function called by FRAX contract to stream rewards to `poolAddress` - /// @dev Params for the incentivization of the pool must have been set prior to any call for - /// a `(poolAddress,incentiveTokenAddress)` pair - function incentivizePool( - address poolAddress, - address, - address, - address incentiveTokenAddress, - uint256, - uint256 amount - ) external { - IERC20(incentiveTokenAddress).safeTransferFrom(msg.sender, address(this), amount); - DistributionParameters memory params = gaugeParams[poolAddress][incentiveTokenAddress]; - if (params.uniV3Pool == address(0)) revert Errors.InvalidParams(); - DistributionCreator creator = merklDistributionCreator(); - // Minimum amount of incentive tokens to be distributed per hour - uint256 minAmount = creator.rewardTokenMinAmounts(incentiveTokenAddress) * params.numEpoch; - params.epochStart = uint32(block.timestamp); - // Adding the leftover amounts to the total amount to be distributed - uint256 leftover = leftovers[incentiveTokenAddress][poolAddress]; - amount += leftover; - params.amount = amount; - if (amount > 0) { - if (amount > minAmount) { - if (leftover > 0) leftovers[incentiveTokenAddress][poolAddress] = 0; - _handleIncentiveTokenAllowance(IERC20(incentiveTokenAddress), address(creator), amount); - merklDistributionCreator().createDistribution(params); - } else { - leftovers[incentiveTokenAddress][poolAddress] = amount; - } - } - } - - /// @notice Restores the allowance for the ANGLE token to the `DistributionCreator` contract - function _handleIncentiveTokenAllowance(IERC20 incentiveTokenAddress, address spender, uint256 amount) internal { - uint256 currentAllowance = incentiveTokenAddress.allowance(address(this), spender); - if (currentAllowance < amount) incentiveTokenAddress.safeIncreaseAllowance(spender, amount - currentAllowance); - } -} diff --git a/contracts/partners/middleman/MerklGaugeMiddleman.sol b/contracts/partners/middleman/MerklGaugeMiddleman.sol deleted file mode 100644 index 4dc8a37..0000000 --- a/contracts/partners/middleman/MerklGaugeMiddleman.sol +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -/* - * █ - ***** ▓▓▓ - * ▓▓▓▓▓▓▓ - * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ - ***** //////// ▓▓▓▓▓▓▓ - * ///////////// ▓▓▓ - ▓▓ ////////////////// █ ▓▓ - ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ - ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ - ▓▓ ////////////////////////////////////////// ▓▓ - ▓▓ //////////////////////▓▓▓▓///////////////////// - ,//////////////////////////////////////////////////// - .////////////////////////////////////////////////////////// - .//////////////////////////██.,//////////////////////////█ - .//////////////////////████..,./////////////////////██ - ...////////////////███████.....,.////////////////███ - ,.,////////////████████ ........,///////////████ - .,.,//////█████████ ,.......///////████ - ,..//████████ ........./████ - ..,██████ .....,███ - .██ ,.,█ - - - - ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ - ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ - ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ - ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ -*/ - -pragma solidity ^0.8.17; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; - -import { DistributionCreator, DistributionParameters } from "../../DistributionCreator.sol"; -import { IAccessControlManager } from "../../interfaces/IAccessControlManager.sol"; -import { Errors } from "../../utils/Errors.sol"; - -/// @title MerklGaugeMiddleman -/// @author Angle Labs, Inc. -/// @notice Manages the transfer of ANGLE rewards to the `DistributionCreator` contract -/// @dev This contract is built under the assumption that the `DistributionCreator` contract has already whitelisted -/// this contract for it to distribute rewards without having to sign a message -/// @dev Transient funds left in this contract after a call may be exploited -contract MerklGaugeMiddleman { - using SafeERC20 for IERC20; - - // ================================= PARAMETERS ================================ - - /// @notice Contract handling access control - IAccessControlManager public accessControlManager; - - /// @notice Maps a gauge to its reward parameters - mapping(address => DistributionParameters) public gaugeParams; - - // =================================== EVENT =================================== - - event GaugeSet(address indexed gauge); - - constructor(IAccessControlManager _accessControlManager) { - if (address(_accessControlManager) == address(0)) revert Errors.ZeroAddress(); - accessControlManager = _accessControlManager; - IERC20 _angle = angle(); - // Condition left here for testing purposes - if (address(_angle) != address(0)) - _angle.safeIncreaseAllowance(address(merklDistributionCreator()), type(uint256).max); - } - - // ================================= REFERENCES ================================ - - /// @notice Address of the ANGLE token - function angle() public view virtual returns (IERC20) { - return IERC20(0x31429d1856aD1377A8A0079410B297e1a9e214c2); - } - - /// @notice Address of the Merkl contract managing rewards to be distributed - /// @dev Address is the same across the different chains on which it is deployed - function merklDistributionCreator() public view virtual returns (DistributionCreator) { - return DistributionCreator(0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd); - } - - // ============================= EXTERNAL FUNCTIONS ============================ - - /// @notice Restores the allowance for the ANGLE token to the `DistributionCreator` contract - function setAngleAllowance() external { - IERC20 _angle = angle(); - address manager = address(merklDistributionCreator()); - uint256 currentAllowance = _angle.allowance(address(this), manager); - if (currentAllowance < type(uint256).max) - _angle.safeIncreaseAllowance(manager, type(uint256).max - currentAllowance); - } - - /// @notice Specifies the reward distribution parameters for `gauge` - function setGauge(address gauge, DistributionParameters memory params) external { - if (!accessControlManager.isGovernorOrGuardian(msg.sender)) revert Errors.NotGovernorOrGuardian(); - gaugeParams[gauge] = params; - emit GaugeSet(gauge); - } - - /// @notice Transmits rewards from the `AngleDistributor` to the `DistributionCreator` with the correct - /// parameters - /// @dev Callable by any contract - /// @dev This method can be used to recover leftover ANGLE tokens in the contract - function notifyReward(address gauge, uint256 amount) public { - DistributionParameters memory params = gaugeParams[gauge]; - if (params.uniV3Pool == address(0)) revert Errors.InvalidParams(); - if (amount == 0) amount = angle().balanceOf(address(this)); - params.epochStart = uint32(block.timestamp); - params.amount = amount; - DistributionCreator creator = merklDistributionCreator(); - if (amount > 0) { - // Need to deal with minimum distribution amounts - if (amount > creator.rewardTokenMinAmounts(address(angle())) * params.numEpoch) { - merklDistributionCreator().createDistribution(params); - } else { - // Sending leftover ANGLE tokens to the `msg.sender` - angle().safeTransfer(msg.sender, amount); - } - } - } - - /// @notice Fetches tokens and transmits rewards in the same transaction - function notifyRewardWithTransfer(address gauge, uint256 amount) external { - angle().safeTransferFrom(msg.sender, address(this), amount); - notifyReward(gauge, amount); - } -} diff --git a/contracts/partners/middleman/MerklGaugeMiddlemanPolygon.sol b/contracts/partners/middleman/MerklGaugeMiddlemanPolygon.sol deleted file mode 100644 index 07d7b64..0000000 --- a/contracts/partners/middleman/MerklGaugeMiddlemanPolygon.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.17; - -import { MerklGaugeMiddleman, IAccessControlManager, IERC20 } from "./MerklGaugeMiddleman.sol"; - -/// @title MerklGaugeMiddlemanPolygon -/// @author Angle Labs, Inc. -contract MerklGaugeMiddlemanPolygon is MerklGaugeMiddleman { - constructor(IAccessControlManager _accessControlManager) MerklGaugeMiddleman(_accessControlManager) {} - - function angle() public pure override returns (IERC20) { - return IERC20(0x900F717EA076E1E7a484ad9DD2dB81CEEc60eBF1); - } -} diff --git a/contracts/partners/middleman/MerklGaugeMiddlemanTemplate.sol b/contracts/partners/middleman/MerklGaugeMiddlemanTemplate.sol new file mode 100644 index 0000000..cce5090 --- /dev/null +++ b/contracts/partners/middleman/MerklGaugeMiddlemanTemplate.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.17; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; + +import { DistributionCreator, CampaignParameters } from "../../DistributionCreator.sol"; +import { Errors } from "../../utils/Errors.sol"; + +/// @title MerklGaugeMiddlemanTemplate +/// @notice Template for building a gauge system creating well-formated incentive campaigns on Merkl +/// @dev This is a template built for the case of a gauge which can be called through the function: +/// `notifyReward(address token, address gauge, uint256 amount)` with a transferFrom in it. Feel free +/// to reach out to us if your use case is different and you're looking to adapt this contract. +contract MerklGaugeMiddlemanTemplate is Ownable { + using SafeERC20 for IERC20; + + /// @notice Maps a (token,gauge) pair to its campaign parameters + /// @dev Parameters for a campaign can be obtained easily from the Merkl creation frontend + mapping(address => mapping(address => CampaignParameters)) public gaugeParams; + + /// @notice Merkl address to create campaigns + /// @dev Can be left as null by default on most chains. This address is normally the same across the different + /// chains on which Merkl is deployed, but there can be some exceptions + address public distributionCreator; + + event GaugeParametersSet(address indexed token, address indexed gauge, CampaignParameters params); + event DistributionCreatorSet(address indexed _distributionCreator); + + constructor(address _owner, address _distributionCreator) { + transferOwnership(_owner); + distributionCreator = _distributionCreator; + } + + /// @notice Address of the Merkl contract managing rewards to be distributed + function merklDistributionCreator() public view virtual returns (DistributionCreator _distributionCreator) { + _distributionCreator = DistributionCreator(distributionCreator); + if (address(_distributionCreator) == address(0)) + return DistributionCreator(0x8BB4C975Ff3c250e0ceEA271728547f3802B36Fd); + } + + /// @notice Called by the gauge system to effectively create a campaign on `token` for `gauge` + /// starting as of now with the parameters previously specified through the `setGaugeParameters` function + /// @dev This function will do nothing if the reward distribution amount is too small with respect to the + /// amount of tokens distributed + /// @dev Requires an allowance to be given by the caller to this contract + function notifyReward(address token, address gauge, uint256 amount) public { + CampaignParameters memory params = gaugeParams[token][gauge]; + if (params.campaignData.length == 0) revert Errors.InvalidParams(); + DistributionCreator _distributionCreator = merklDistributionCreator(); + // Need to deal with Merkl minimum distribution amounts + if (amount * 3600 > _distributionCreator.rewardTokenMinAmounts(token) * params.duration) { + _handleAllowance(token, address(_distributionCreator), amount); + IERC20(token).safeTransferFrom(msg.sender, address(this), amount); + params.startTimestamp = uint32(block.timestamp); + params.amount = amount; + params.rewardToken = token; + _distributionCreator.createCampaign(params); + } + } + + /// @notice Specifies the campaign parameters for the pair `token,gauge` + /// @dev These parameters can be obtained from the Merkl campaign creation frontend + function setGaugeParameters(address gauge, address token, CampaignParameters memory params) external onlyOwner { + gaugeParams[token][gauge] = params; + emit GaugeParametersSet(token, gauge, params); + } + + /// @dev Infinite allowances on Merkl contracts are safe here (this contract never holds funds and Merkl is safe) + function _handleAllowance(address token, address _distributionCreator, uint256 amount) internal { + uint256 currentAllowance = IERC20(token).allowance(address(this), _distributionCreator); + if (currentAllowance < amount) + IERC20(token).safeIncreaseAllowance(_distributionCreator, type(uint256).max - currentAllowance); + } + + /// @notice Recovers idle tokens left on the contract + function recoverToken(address token, address to, uint256 amount) external onlyOwner { + IERC20(token).safeTransfer(to, amount); + } + + /// @notice Updates the distributionCreator value if needed + function setDistributionCreator(address _distributionCreator) external onlyOwner { + distributionCreator = _distributionCreator; + emit DistributionCreatorSet(_distributionCreator); + } +} diff --git a/contracts/partners/tokenWrappers/AaveTokenWrapper.sol b/contracts/partners/tokenWrappers/AaveTokenWrapper.sol index f49a53e..c3b190b 100644 --- a/contracts/partners/tokenWrappers/AaveTokenWrapper.sol +++ b/contracts/partners/tokenWrappers/AaveTokenWrapper.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.17; diff --git a/contracts/partners/tokenWrappers/BaseTokenWrapper.sol b/contracts/partners/tokenWrappers/BaseTokenWrapper.sol index 6e4b829..04f0727 100644 --- a/contracts/partners/tokenWrappers/BaseTokenWrapper.sol +++ b/contracts/partners/tokenWrappers/BaseTokenWrapper.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.17; diff --git a/contracts/partners/tokenWrappers/PufferPointTokenWrapper.sol b/contracts/partners/tokenWrappers/PufferPointTokenWrapper.sol index 25edfaf..d775ad8 100644 --- a/contracts/partners/tokenWrappers/PufferPointTokenWrapper.sol +++ b/contracts/partners/tokenWrappers/PufferPointTokenWrapper.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.17; diff --git a/contracts/partners/tokenWrappers/PullTokenWrapper.sol b/contracts/partners/tokenWrappers/PullTokenWrapper.sol index 953a790..6056354 100644 --- a/contracts/partners/tokenWrappers/PullTokenWrapper.sol +++ b/contracts/partners/tokenWrappers/PullTokenWrapper.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.17; diff --git a/contracts/struct/CampaignParameters.sol b/contracts/struct/CampaignParameters.sol index b5164ad..41e641c 100644 --- a/contracts/struct/CampaignParameters.sol +++ b/contracts/struct/CampaignParameters.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0; diff --git a/contracts/struct/DistributionParameters.sol b/contracts/struct/DistributionParameters.sol index 20e0621..1cf93f1 100644 --- a/contracts/struct/DistributionParameters.sol +++ b/contracts/struct/DistributionParameters.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0; diff --git a/contracts/struct/RewardTokenAmounts.sol b/contracts/struct/RewardTokenAmounts.sol index b00443a..7f8e688 100644 --- a/contracts/struct/RewardTokenAmounts.sol +++ b/contracts/struct/RewardTokenAmounts.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0; diff --git a/contracts/utils/UUPSHelper.sol b/contracts/utils/UUPSHelper.sol index 6258df8..7493694 100644 --- a/contracts/utils/UUPSHelper.sol +++ b/contracts/utils/UUPSHelper.sol @@ -1,38 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -/* - * █ - ***** ▓▓▓ - * ▓▓▓▓▓▓▓ - * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ - ***** //////// ▓▓▓▓▓▓▓ - * ///////////// ▓▓▓ - ▓▓ ////////////////// █ ▓▓ - ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ - ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ - ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ - ▓▓ ////////////////////////////////////////// ▓▓ - ▓▓ //////////////////////▓▓▓▓///////////////////// - ,//////////////////////////////////////////////////// - .////////////////////////////////////////////////////////// - .//////////////////////////██.,//////////////////////////█ - .//////////////////////████..,./////////////////////██ - ...////////////////███████.....,.////////////////███ - ,.,////////////████████ ........,///////////████ - .,.,//////█████████ ,.......///////████ - ,..//████████ ........./████ - ..,██████ .....,███ - .██ ,.,█ - - - - ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ - ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ - ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ - ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ -*/ - pragma solidity ^0.8.17; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";