Files
no_five/contracts/core/CollateralToggleManager.sol
2025-11-20 15:35:25 -08:00

177 lines
5.3 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/**
* @title CollateralToggleManager
* @notice Manages Aave v3 collateral enable/disable and sub-vault operations
* @dev Enables efficient batch operations for collateral management
*/
contract CollateralToggleManager is Ownable, AccessControl, ReentrancyGuard {
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
bytes32 public constant KERNEL_ROLE = keccak256("KERNEL_ROLE");
// Aave v3 Pool interface
interface IPoolV3 {
function setUserUseReserveAsCollateral(
address asset,
bool useAsCollateral
) external;
function getUserAccountData(address user)
external
view
returns (
uint256 totalCollateralBase,
uint256 totalDebtBase,
uint256 availableBorrowsBase,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
}
IPoolV3 public aavePool;
address public aaveUserAccount;
// Collateral status tracking
mapping(address => bool) public collateralEnabled;
address[] public managedAssets;
event CollateralToggled(address indexed asset, bool enabled);
event BatchCollateralToggled(address[] assets, bool[] enabled);
event AavePoolUpdated(address oldPool, address newPool);
event AaveUserAccountUpdated(address oldAccount, address newAccount);
constructor(
address _aavePool,
address _aaveUserAccount,
address initialOwner
) Ownable(initialOwner) {
require(_aavePool != address(0), "Invalid Aave pool");
require(_aaveUserAccount != address(0), "Invalid Aave account");
aavePool = IPoolV3(_aavePool);
aaveUserAccount = _aaveUserAccount;
_grantRole(DEFAULT_ADMIN_ROLE, initialOwner);
}
/**
* @notice Enable or disable collateral for an asset
*/
function toggleCollateral(
address asset,
bool useAsCollateral
) external onlyRole(KERNEL_ROLE) nonReentrant {
require(asset != address(0), "Invalid asset");
// Update Aave
aavePool.setUserUseReserveAsCollateral(asset, useAsCollateral);
// Track status
if (!collateralEnabled[asset] && managedAssets.length > 0) {
bool alreadyTracked = false;
for (uint256 i = 0; i < managedAssets.length; i++) {
if (managedAssets[i] == asset) {
alreadyTracked = true;
break;
}
}
if (!alreadyTracked) {
managedAssets.push(asset);
}
}
collateralEnabled[asset] = useAsCollateral;
emit CollateralToggled(asset, useAsCollateral);
}
/**
* @notice Batch toggle collateral for multiple assets
*/
function batchToggleCollateral(
address[] calldata assets,
bool[] calldata useAsCollateral
) external onlyRole(KERNEL_ROLE) nonReentrant {
require(assets.length == useAsCollateral.length, "Array length mismatch");
require(assets.length > 0 && assets.length <= 20, "Invalid array length"); // Reasonable limit
for (uint256 i = 0; i < assets.length; i++) {
toggleCollateral(assets[i], useAsCollateral[i]);
}
emit BatchCollateralToggled(assets, useAsCollateral);
}
/**
* @notice Get collateral status for an asset
*/
function isCollateralEnabled(address asset) external view returns (bool) {
return collateralEnabled[asset];
}
/**
* @notice Get all managed assets
*/
function getManagedAssets() external view returns (address[] memory) {
return managedAssets;
}
/**
* @notice Get Aave position health factor
*/
function getHealthFactor() external view returns (uint256) {
try aavePool.getUserAccountData(aaveUserAccount) returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint256 healthFactor
) {
return healthFactor;
} catch {
return 0;
}
}
/**
* @notice Update Aave pool
*/
function setAavePool(address newPool) external onlyOwner {
require(newPool != address(0), "Invalid pool");
address oldPool = address(aavePool);
aavePool = IPoolV3(newPool);
emit AavePoolUpdated(oldPool, newPool);
}
/**
* @notice Update Aave user account
*/
function setAaveUserAccount(address newAccount) external onlyOwner {
require(newAccount != address(0), "Invalid account");
address oldAccount = aaveUserAccount;
aaveUserAccount = newAccount;
emit AaveUserAccountUpdated(oldAccount, newAccount);
}
/**
* @notice Grant kernel role
*/
function grantKernel(address kernel) external onlyOwner {
_grantRole(KERNEL_ROLE, kernel);
}
/**
* @notice Revoke kernel role
*/
function revokeKernel(address kernel) external onlyOwner {
_revokeRole(KERNEL_ROLE, kernel);
}
}