// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../utils/MappedSinglyLinkedList.sol"; import "./BalanceDrip.sol"; /// @title Manages the lifecycle of a set of Balance Drips. library BalanceDripManager { using SafeMathUpgradeable for uint256; using MappedSinglyLinkedList for MappedSinglyLinkedList.Mapping; using BalanceDrip for BalanceDrip.State; struct State { mapping(address => MappedSinglyLinkedList.Mapping) activeBalanceDrips; mapping(address => mapping(address => BalanceDrip.State)) balanceDrips; } /// @notice Activates a drip by setting it's state and adding it to the active balance drips list. /// @param self The BalanceDripManager state /// @param measure The measure token /// @param dripToken The drip token /// @param dripRatePerSecond The amount of the drip token to be dripped per second function activateDrip( State storage self, address measure, address dripToken, uint256 dripRatePerSecond ) internal { require(!self.activeBalanceDrips[measure].contains(dripToken), "BalanceDripManager/drip-active"); if (self.activeBalanceDrips[measure].count == 0) { self.activeBalanceDrips[measure].initialize(); } self.activeBalanceDrips[measure].addAddress(dripToken); self.balanceDrips[measure][dripToken].resetTotalDripped(); self.balanceDrips[measure][dripToken].dripRatePerSecond = dripRatePerSecond; } /// @notice Deactivates an active balance drip. The balance drip is removed from the active balance drips list. /// The drip rate for the balance drip will be set to zero to ensure it's "frozen". /// @param measure The measure token /// @param dripToken The drip token /// @param prevDripToken The previous drip token previous in the list. /// If no previous, then pass the SENTINEL address: 0x0000000000000000000000000000000000000001 /// @param currentTime The current time function deactivateDrip( State storage self, address measure, address dripToken, address prevDripToken, uint32 currentTime, uint256 maxNewTokens ) internal { self.activeBalanceDrips[measure].removeAddress(prevDripToken, dripToken); self.balanceDrips[measure][dripToken].drip(IERC20Upgradeable(measure).totalSupply(), currentTime, maxNewTokens); self.balanceDrips[measure][dripToken].dripRatePerSecond = 0; } /// @notice Gets a list of active balance drip tokens /// @param self The BalanceDripManager state /// @param measure The measure token /// @return An array of Balance Drip token addresses function getActiveBalanceDrips(State storage self, address measure) internal view returns (address[] memory) { return self.activeBalanceDrips[measure].addressArray(); } /// @notice Sets the drip rate for an active balance drip. /// @param self The BalanceDripManager state /// @param measure The measure token /// @param dripToken The drip token /// @param dripRatePerSecond The amount to drip of the token each second /// @param currentTime The current time. function setDripRate( State storage self, address measure, address dripToken, uint256 dripRatePerSecond, uint32 currentTime, uint256 maxNewTokens ) internal { require(self.activeBalanceDrips[measure].contains(dripToken), "BalanceDripManager/drip-not-active"); self.balanceDrips[measure][dripToken].drip(IERC20Upgradeable(measure).totalSupply(), currentTime, maxNewTokens); self.balanceDrips[measure][dripToken].dripRatePerSecond = dripRatePerSecond; } /// @notice Returns whether or not a drip is active for the given measure, dripToken pair /// @param self The BalanceDripManager state /// @param measure The measure token /// @param dripToken The drip token /// @return True if there is an active balance drip for the pair, false otherwise function isDripActive(State storage self, address measure, address dripToken) internal view returns (bool) { return self.activeBalanceDrips[measure].contains(dripToken); } /// @notice Returns the BalanceDrip.State for the given measure, dripToken pair /// @param self The BalanceDripManager state /// @param measure The measure token /// @param dripToken The drip token /// @return The BalanceDrip.State for the pair function getDrip(State storage self, address measure, address dripToken) internal view returns (BalanceDrip.State storage) { return self.balanceDrips[measure][dripToken]; } }