Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/liquidityBuffer/LiquidityBuffer.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {AccessControlEnumerableUpgradeable} from "openzeppelin-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {Address} from "openzeppelin/utils/Address.sol";
import {Math} from "openzeppelin/utils/math/Math.sol";
import {ILiquidityBuffer} from "./interfaces/ILiquidityBuffer.sol";
import {IPositionManager} from "./interfaces/IPositionManager.sol";
import {IStakingReturnsWrite} from "../interfaces/IStaking.sol";
import {IPauserRead} from "../interfaces/IPauser.sol";
import {ProtocolEvents} from "../interfaces/ProtocolEvents.sol";
interface LiquidityBufferEvents {
event ETHWithdrawnFromManager(uint256 indexed managerId, uint256 amount);
event ETHReturnedToStaking(uint256 amount);
event ETHAllocatedToManager(uint256 indexed managerId, uint256 amount);
event ETHReceivedFromStaking(uint256 amount);
event FeesCollected(uint256 amount);
event InterestClaimed(
uint256 indexed managerId,
uint256 interestAmount
);
event InterestToppedUp(
uint256 amount
);
}
/**
* @title LiquidityBuffer
* @notice Manages liquidity allocation to various position managers for DeFi protocols
*/
contract LiquidityBuffer is Initializable, AccessControlEnumerableUpgradeable, ILiquidityBuffer, LiquidityBufferEvents, ProtocolEvents {
using Address for address;
// ========================================= CONSTANTS =========================================
bytes32 public constant LIQUIDITY_MANAGER_ROLE = keccak256("LIQUIDITY_MANAGER_ROLE");
bytes32 public constant POSITION_MANAGER_ROLE = keccak256("POSITION_MANAGER_ROLE");
bytes32 public constant INTEREST_TOPUP_ROLE = keccak256("INTEREST_TOPUP_ROLE");
bytes32 public constant DRAWDOWN_MANAGER_ROLE = keccak256("DRAWDOWN_MANAGER_ROLE");
uint16 internal constant _BASIS_POINTS_DENOMINATOR = 10_000;
// ========================================= STATE =========================================
/// @notice The staking contract to which the liquidity buffer accepts funds from and returns funds to.
IStakingReturnsWrite public stakingContract;
/// @notice The pauser contract.
/// @dev Keeps the pause state across the protocol.
IPauserRead public pauser;
/// @notice Total number of position managers
uint256 public positionManagerCount;
/// @notice Mapping from manager ID to position manager configuration
mapping(uint256 => PositionManagerConfig) public positionManagerConfigs;
/// @notice Mapping from manager ID to accounting information
mapping(uint256 => PositionAccountant) public positionAccountants;
/// @notice Total funds received from staking contract
uint256 public totalFundsReceived;
/// @notice Total funds returned to staking contract
uint256 public totalFundsReturned;
/// @notice Total allocated balance across all position managers
uint256 public totalAllocatedBalance;
/// @notice Total interest claimed from position managers
uint256 public totalInterestClaimed;
/// @notice Total interest topped up to staking contract
uint256 public totalInterestToppedUp;
/// @notice Total allocation capacity across all managers
uint256 public totalAllocationCapacity;
/// @notice Cumulative drawdown amount
uint256 public cumulativeDrawdown;
/// @notice Default manager ID for deposit and allocation operations
uint256 public defaultManagerId;
/// @notice The address receiving protocol fees.
address payable public feesReceiver;
/// @notice The protocol fees in basis points (1/10000).
uint16 public feesBasisPoints;
uint256 public totalFeesCollected;
/// @notice Tracks pending interest available for top-up operations
uint256 public pendingInterest;
/// @notice Tracks pending principal available for operations
uint256 public pendingPrincipal;
/// @notice Controls whether to execute allocation logic in depositETH method
bool public shouldExecuteAllocation;
/// @notice Mapping from manager address to boolean indicating if it is registered
mapping(address => bool) public isRegisteredManager;
struct Init {
address admin;
address liquidityManager;
address positionManager;
address interestTopUp;
address drawdownManager;
address payable feesReceiver;
IStakingReturnsWrite staking;
IPauserRead pauser;
}
// ========================================= ERRORS =========================================
error LiquidityBuffer__ManagerNotFound();
error LiquidityBuffer__ManagerInactive();
error LiquidityBuffer__ManagerAlreadyRegistered();
error LiquidityBuffer__ExceedsAllocationCap();
error LiquidityBuffer__InsufficientBalance();
error LiquidityBuffer__InsufficientAllocation();
error LiquidityBuffer__DoesNotReceiveETH();
error LiquidityBuffer__Paused();
error LiquidityBuffer__InvalidConfiguration();
error LiquidityBuffer__ZeroAddress();
error LiquidityBuffer__NotStakingContract();
error LiquidityBuffer__NotPositionManagerContract();
error LiquidityBuffer__ExceedsPendingInterest();
error LiquidityBuffer__ExceedsPendingPrincipal();
// ========================================= INITIALIZATION =========================================
constructor() {
_disableInitializers();
}
function initialize(Init memory init) external initializer {
if (
init.admin == address(0) ||
init.liquidityManager == address(0) ||
init.positionManager == address(0) ||
init.interestTopUp == address(0) ||
init.drawdownManager == address(0) ||
init.feesReceiver == address(0) ||
address(init.staking) == address(0) ||
address(init.pauser) == address(0)
) {
revert LiquidityBuffer__ZeroAddress();
}
__AccessControlEnumerable_init();
_grantRole(DEFAULT_ADMIN_ROLE, init.admin);
_grantRole(LIQUIDITY_MANAGER_ROLE, init.liquidityManager);
_grantRole(POSITION_MANAGER_ROLE, init.positionManager);
_grantRole(INTEREST_TOPUP_ROLE, init.interestTopUp);
_grantRole(DRAWDOWN_MANAGER_ROLE, init.drawdownManager);
stakingContract = init.staking;
pauser = init.pauser;
feesReceiver = init.feesReceiver;
shouldExecuteAllocation = true;
_grantRole(LIQUIDITY_MANAGER_ROLE, address(stakingContract));
}
// ========================================= VIEW FUNCTIONS =========================================
function getInterestAmount(uint256 managerId) public view returns (uint256) {
PositionManagerConfig memory config = positionManagerConfigs[managerId];
// Get current underlying balance from position manager
IPositionManager manager = IPositionManager(config.managerAddress);
uint256 currentBalance = manager.getUnderlyingBalance();
// Calculate interest as: current balance - allocated balance
PositionAccountant memory accounting = positionAccountants[managerId];
if (currentBalance > accounting.allocatedBalance) {
return currentBalance - accounting.allocatedBalance;
}
return 0;
}
function getAvailableCapacity() public view returns (uint256) {
return totalAllocationCapacity - totalAllocatedBalance;
}
function getAvailableBalance() public view returns (uint256) {
return totalFundsReceived - totalFundsReturned;
}
function getControlledBalance() public view returns (uint256) {
uint256 totalBalance = address(this).balance;
// Loop through all position manager configs and get their balances
// Note: This function makes external calls in a loop which can be gas-expensive
// Consider caching balances or using a different approach for production
for (uint256 i = 0; i < positionManagerCount; i++) {
PositionManagerConfig storage config = positionManagerConfigs[i];
if (config.isActive) {
IPositionManager manager = IPositionManager(config.managerAddress);
uint256 managerBalance = manager.getUnderlyingBalance();
totalBalance += managerBalance;
}
}
return totalBalance;
}
// ========================================= ADMIN FUNCTIONS =========================================
function addPositionManager(
address managerAddress,
uint256 allocationCap
) external onlyRole(POSITION_MANAGER_ROLE) notZeroAddress(managerAddress) returns (uint256 managerId) {
if (isRegisteredManager[managerAddress]) revert LiquidityBuffer__ManagerAlreadyRegistered();
managerId = positionManagerCount;
positionManagerCount++;
positionManagerConfigs[managerId] = PositionManagerConfig({
managerAddress: managerAddress,
allocationCap: allocationCap,
isActive: true
});
positionAccountants[managerId] = PositionAccountant({
allocatedBalance: 0,
interestClaimedFromManager: 0
});
isRegisteredManager[managerAddress] = true;
totalAllocationCapacity += allocationCap;
emit ProtocolConfigChanged(
this.addPositionManager.selector,
"addPositionManager(address,uint256)",
abi.encode(managerAddress, allocationCap)
);
}
function updatePositionManager(
uint256 managerId,
uint256 newAllocationCap,
bool isActive
) external onlyRole(POSITION_MANAGER_ROLE) {
if (managerId >= positionManagerCount) {
revert LiquidityBuffer__ManagerNotFound();
}
PositionManagerConfig storage config = positionManagerConfigs[managerId];
if (newAllocationCap < positionAccountants[managerId].allocatedBalance) {
revert LiquidityBuffer__InvalidConfiguration();
}
// Update total allocation capacity
totalAllocationCapacity = totalAllocationCapacity + newAllocationCap - config.allocationCap;
config.allocationCap = newAllocationCap;
config.isActive = isActive;
emit ProtocolConfigChanged(
this.updatePositionManager.selector,
"updatePositionManager(uint256,uint256,bool)",
abi.encode(managerId, newAllocationCap, isActive)
);
}
function setCumulativeDrawdown(uint256 drawdownAmount) external onlyRole(DRAWDOWN_MANAGER_ROLE) {
if(drawdownAmount > totalAllocationCapacity) {
revert LiquidityBuffer__ExceedsAllocationCap();
}
cumulativeDrawdown = drawdownAmount;
emit ProtocolConfigChanged(
this.setCumulativeDrawdown.selector,
"setCumulativeDrawdown(uint256)",
abi.encode(drawdownAmount)
);
}
function setDefaultManagerId(uint256 newDefaultManagerId) external onlyRole(POSITION_MANAGER_ROLE) {
if (newDefaultManagerId >= positionManagerCount) {
revert LiquidityBuffer__ManagerNotFound();
}
if (!positionManagerConfigs[newDefaultManagerId].isActive) {
revert LiquidityBuffer__ManagerInactive();
}
defaultManagerId = newDefaultManagerId;
emit ProtocolConfigChanged(
this.setDefaultManagerId.selector,
"setDefaultManagerId(uint256)",
abi.encode(newDefaultManagerId)
);
}
/// @notice Sets the fees basis points.
/// @param newBasisPoints The new fees basis points.
function setFeeBasisPoints(uint16 newBasisPoints) external onlyRole(POSITION_MANAGER_ROLE) {
if (newBasisPoints > _BASIS_POINTS_DENOMINATOR) {
revert LiquidityBuffer__InvalidConfiguration();
}
feesBasisPoints = newBasisPoints;
emit ProtocolConfigChanged(
this.setFeeBasisPoints.selector, "setFeeBasisPoints(uint16)", abi.encode(newBasisPoints)
);
}
/// @notice Sets the fees receiver wallet for the protocol.
/// @param newReceiver The new fees receiver wallet.
function setFeesReceiver(address payable newReceiver)
external
onlyRole(POSITION_MANAGER_ROLE)
notZeroAddress(newReceiver)
{
feesReceiver = newReceiver;
emit ProtocolConfigChanged(this.setFeesReceiver.selector, "setFeesReceiver(address)", abi.encode(newReceiver));
}
/// @notice Sets whether to execute allocation logic in depositETH method.
/// @param executeAllocation Whether to execute allocation logic.
function setShouldExecuteAllocation(bool executeAllocation) external onlyRole(POSITION_MANAGER_ROLE) {
if (shouldExecuteAllocation == executeAllocation) {
revert LiquidityBuffer__InvalidConfiguration();
}
shouldExecuteAllocation = executeAllocation;
emit ProtocolConfigChanged(this.setShouldExecuteAllocation.selector, "setShouldExecuteAllocation(bool)", abi.encode(executeAllocation));
}
function setPositionManagerStatus(uint256 managerId, bool isActive) external onlyRole(POSITION_MANAGER_ROLE) {
if (managerId >= positionManagerCount) {
revert LiquidityBuffer__ManagerNotFound();
}
PositionManagerConfig storage config = positionManagerConfigs[managerId];
if (config.isActive == isActive) {
revert LiquidityBuffer__InvalidConfiguration();
}
config.isActive = isActive;
emit ProtocolConfigChanged(
this.setPositionManagerStatus.selector,
"setPositionManagerStatus(uint256,bool)",
abi.encode(managerId, isActive)
);
}
// ========================================= LIQUIDITY MANAGEMENT =========================================
function depositETH() external payable onlyStakingContract {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
_receiveETHFromStaking(msg.value);
if (shouldExecuteAllocation) {
_allocateETHToManager(defaultManagerId, msg.value);
}
}
function withdrawAndReturn(uint256 managerId, uint256 amount) external onlyRole(LIQUIDITY_MANAGER_ROLE) {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
_withdrawETHFromManager(managerId, amount);
_returnETHToStaking(amount);
}
function allocateETHToManager(uint256 managerId, uint256 amount) external onlyRole(LIQUIDITY_MANAGER_ROLE) {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
_allocateETHToManager(managerId, amount);
}
function withdrawETHFromManager(uint256 managerId, uint256 amount) external onlyRole(LIQUIDITY_MANAGER_ROLE) {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
_withdrawETHFromManager(managerId, amount);
}
function returnETHToStaking(uint256 amount) external onlyRole(LIQUIDITY_MANAGER_ROLE) {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
_returnETHToStaking(amount);
}
function receiveETHFromPositionManager() external payable onlyPositionManagerContract {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
// This function receives ETH from position managers
// The ETH is already in the contract balance, no additional processing needed
}
// ========================================= INTEREST MANAGEMENT =========================================
function claimInterestFromManager(uint256 managerId, uint256 minAmount) external onlyRole(INTEREST_TOPUP_ROLE) returns (uint256) {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
uint256 amount = _claimInterestFromManager(managerId);
if (amount < minAmount) {
revert LiquidityBuffer__InsufficientBalance();
}
return amount;
}
function topUpInterestToStaking(uint256 amount) external onlyRole(INTEREST_TOPUP_ROLE) returns (uint256) {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
if (address(this).balance < amount) {
revert LiquidityBuffer__InsufficientBalance();
}
_topUpInterestToStakingAndCollectFees(amount);
return amount;
}
function claimInterestAndTopUp(uint256 managerId, uint256 minAmount) external onlyRole(INTEREST_TOPUP_ROLE) returns (uint256) {
if (pauser.isLiquidityBufferPaused()) revert LiquidityBuffer__Paused();
uint256 amount = _claimInterestFromManager(managerId);
if (amount < minAmount) {
revert LiquidityBuffer__InsufficientBalance();
}
_topUpInterestToStakingAndCollectFees(amount);
return amount;
}
// ========================================= INTERNAL FUNCTIONS =========================================
function _topUpInterestToStakingAndCollectFees(uint256 amount) internal {
if (amount > pendingInterest) {
revert LiquidityBuffer__ExceedsPendingInterest();
}
pendingInterest -= amount;
uint256 fees = Math.mulDiv(feesBasisPoints, amount, _BASIS_POINTS_DENOMINATOR);
uint256 topUpAmount = amount - fees;
stakingContract.topUp{value: topUpAmount}();
totalInterestToppedUp += topUpAmount;
emit InterestToppedUp(topUpAmount);
if (fees > 0) {
Address.sendValue(feesReceiver, fees);
totalFeesCollected += fees;
emit FeesCollected(fees);
}
}
function _claimInterestFromManager(uint256 managerId) internal returns (uint256) {
// Get interest amount
uint256 interestAmount = getInterestAmount(managerId);
if (interestAmount > 0) {
PositionManagerConfig memory config = positionManagerConfigs[managerId];
// Update accounting BEFORE external call (Checks-Effects-Interactions pattern)
positionAccountants[managerId].interestClaimedFromManager += interestAmount;
totalInterestClaimed += interestAmount;
pendingInterest += interestAmount;
emit InterestClaimed(managerId, interestAmount);
// Withdraw interest from position manager AFTER state updates
IPositionManager manager = IPositionManager(config.managerAddress);
manager.withdraw(interestAmount);
} else {
emit InterestClaimed(managerId, interestAmount);
}
return interestAmount;
}
function _withdrawETHFromManager(uint256 managerId, uint256 amount) internal {
if (managerId >= positionManagerCount) revert LiquidityBuffer__ManagerNotFound();
PositionManagerConfig memory config = positionManagerConfigs[managerId];
if (!config.isActive) revert LiquidityBuffer__ManagerInactive();
PositionAccountant storage accounting = positionAccountants[managerId];
// Check sufficient allocation
if (amount > accounting.allocatedBalance) {
revert LiquidityBuffer__InsufficientAllocation();
}
// Update accounting BEFORE external call (Checks-Effects-Interactions pattern)
accounting.allocatedBalance -= amount;
totalAllocatedBalance -= amount;
pendingPrincipal += amount;
emit ETHWithdrawnFromManager(managerId, amount);
// Call position manager to withdraw AFTER state updates
IPositionManager manager = IPositionManager(config.managerAddress);
manager.withdraw(amount);
}
function _returnETHToStaking(uint256 amount) internal {
// Validate staking contract is set and not zero address
if (address(stakingContract) == address(0)) {
revert LiquidityBuffer__ZeroAddress();
}
if (amount > pendingPrincipal) {
revert LiquidityBuffer__ExceedsPendingPrincipal();
}
// Update accounting BEFORE external call (Checks-Effects-Interactions pattern)
totalFundsReturned += amount;
pendingPrincipal -= amount;
emit ETHReturnedToStaking(amount);
// Send ETH to trusted staking contract AFTER state updates
// Note: stakingContract is a trusted contract set during initialization
stakingContract.receiveReturnsFromLiquidityBuffer{value: amount}();
}
function _allocateETHToManager(uint256 managerId, uint256 amount) internal {
if (amount > pendingPrincipal) {
revert LiquidityBuffer__ExceedsPendingPrincipal();
}
if (managerId >= positionManagerCount) revert LiquidityBuffer__ManagerNotFound();
// check available balance
if (address(this).balance < amount) revert LiquidityBuffer__InsufficientBalance();
// check position manager is active
PositionManagerConfig memory config = positionManagerConfigs[managerId];
if (!config.isActive) revert LiquidityBuffer__ManagerInactive();
// check allocation cap
PositionAccountant storage accounting = positionAccountants[managerId];
if (accounting.allocatedBalance + amount > config.allocationCap) {
revert LiquidityBuffer__ExceedsAllocationCap();
}
// Update accounting BEFORE external call (Checks-Effects-Interactions pattern)
accounting.allocatedBalance += amount;
totalAllocatedBalance += amount;
pendingPrincipal -= amount;
emit ETHAllocatedToManager(managerId, amount);
// deposit to position manager AFTER state updates
IPositionManager manager = IPositionManager(config.managerAddress);
manager.deposit{value: amount}(0);
}
function _receiveETHFromStaking(uint256 amount) internal {
totalFundsReceived += amount;
pendingPrincipal += amount;
emit ETHReceivedFromStaking(amount);
}
/// @notice Ensures that the given address is not the zero address.
/// @param addr The address to check.
modifier notZeroAddress(address addr) {
if (addr == address(0)) {
revert LiquidityBuffer__ZeroAddress();
}
_;
}
/// @dev Validates that the caller is the staking contract.
modifier onlyStakingContract() {
if (msg.sender != address(stakingContract)) {
revert LiquidityBuffer__NotStakingContract();
}
_;
}
modifier onlyPositionManagerContract() {
bool isValidManager = false;
// Loop through all position manager configs to check if sender is a valid manager
for (uint256 i = 0; i < positionManagerCount; i++) {
PositionManagerConfig memory config = positionManagerConfigs[i];
if (msg.sender == config.managerAddress && config.isActive) {
isValidManager = true;
break;
}
}
if (!isValidManager) {
revert LiquidityBuffer__NotPositionManagerContract();
}
_;
}
receive() external payable {
revert LiquidityBuffer__DoesNotReceiveETH();
}
fallback() external payable {
revert LiquidityBuffer__DoesNotReceiveETH();
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlEnumerableUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControlEnumerableUpgradeable.sol";
import "./AccessControlUpgradeable.sol";
import "../utils/structs/EnumerableSetUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable {
function __AccessControlEnumerable_init() internal onlyInitializing {
}
function __AccessControlEnumerable_init_unchained() internal onlyInitializing {
}
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerableUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_roleMembers[role].remove(account);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/Address.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/math/Math.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
"
},
"src/liquidityBuffer/interfaces/ILiquidityBuffer.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title ILiquidityBuffer
* @notice Interface for LiquidityBuffer contract that manages liquidity allocation to position managers
*/
interface ILiquidityBuffer {
struct PositionManagerConfig {
address managerAddress; // position manager contract address
uint256 allocationCap; // maximum allocation limit for this manager
bool isActive; // whether the position manager is operational
}
struct PositionAccountant {
uint256 allocatedBalance; // total allocated balance to this manager
uint256 interestClaimedFromManager; // total interest claimed from this manager
}
/// @notice Deposit funds from staking contract
function depositETH() external payable;
/// @notice Receive funds from position manager
function receiveETHFromPositionManager() external payable;
/// @notice Get available principal balance for allocation
/// @dev Formula: totalFundsReceived - totalFundsReturned
function getAvailableBalance() external view returns (uint256);
function cumulativeDrawdown() external view returns (uint256);
}
"
},
"src/liquidityBuffer/interfaces/IPositionManager.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title IPositionManager
* @dev interface for position manager of AAVE
* This interface defines the operations for managing positions
*/
interface IPositionManager {
function deposit(uint16 referralCode) external payable;
function withdraw(uint256 amount) external;
function getUnderlyingBalance() external view returns (uint256);
function approveToken(address token, address addr, uint256 wad) external;
function revokeToken(address token, address addr) external;
}
"
},
"src/interfaces/IStaking.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IStakingInitiationRead {
/// @notice The total amount of ETH sent to the beacon chain deposit contract.
function totalDepositedInValidators() external view returns (uint256);
/// @notice The number of validators initiated by the staking contract.
function numInitiatedValidators() external view returns (uint256);
/// @notice The block number at which the staking contract has been initialised.
function initializationBlockNumber() external view returns (uint256);
}
interface IStakingReturnsWrite {
/// @notice Accepts funds sent by the returns aggregator.
function receiveReturns() external payable;
/// @notice Accepts funds sent by the unstake requests manager.
function receiveFromUnstakeRequestsManager() external payable;
/// @notice Accepts funds sent by the liquidity buffer.
function receiveReturnsFromLiquidityBuffer() external payable;
/// @notice Top up staking contract.
function topUp() external payable;
}
interface IStaking is IStakingInitiationRead, IStakingReturnsWrite {}
"
},
"src/interfaces/IPauser.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IPauserRead {
/// @notice Flag indicating if staking is paused.
function isStakingPaused() external view returns (bool);
/// @notice Flag indicating if unstake requests are paused.
function isUnstakeRequestsAndClaimsPaused() external view returns (bool);
/// @notice Flag indicating if initiate validators is paused
function isInitiateValidatorsPaused() external view returns (bool);
/// @notice Flag indicating if submit oracle records is paused.
function isSubmitOracleRecordsPaused() external view returns (bool);
/// @notice Flag indicating if allocate ETH is paused.
function isAllocateETHPaused() external view returns (bool);
/// @notice Flag indicating if liquidity buffer is paused.
function isLiquidityBufferPaused() external view returns (bool);
}
interface IPauserWrite {
/// @notice Pauses all actions.
function pauseAll() external;
}
interface IPauser is IPauserRead, IPauserWrite {}
"
},
"src/interfaces/ProtocolEvents.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface ProtocolEvents {
/// @notice Emitted when a protocol configuration has been updated.
/// @param setterSelector The selector of the function that updated the configuration.
/// @param setterSignature The signature of the function that updated the configuration.
/// @param value The abi-encoded data passed to the function that updated the configuration. Since this event will
/// only be emitted by setters, this data corresponds to the updated values in the protocol configuration.
event ProtocolConfigChanged(bytes4 indexed setterSelector, string setterSignature, bytes value);
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/access/IAccessControlEnumerableUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and\
Submitted on: 2025-10-24 18:45:35
Comments
Log in to comment.
No comments yet.