// Add this with the other protocol constants
uint8 public constant PROTOCOL_NEW_PROTOCOL = 4; // Increment from the last used ID// Example for adding during initialization
_addProtocol(PROTOCOL_NEW_PROTOCOL, "New Protocol Name", 150, newProtocolAdapter);
// Example for adding post-deployment (must be called by VAULT_MANAGER_ROLE)
function exampleAddingProtocol() external {
// Create and deploy adapter first (see next section)
address adapter = address(newlyDeployedAdapter);
// Then call addProtocol
addProtocol(PROTOCOL_NEW_PROTOCOL, "New Protocol Name", 150, adapter);
}// IProtocolAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IProtocolAdapter {
function createPosition(
address collateralToken,
address debtToken,
uint256 collateralAmount,
uint256 debtAmount
) external returns (bytes memory positionData);
function closePosition(bytes memory positionData) external;
function addCollateral(bytes memory positionData, uint256 amount) external;
function removeCollateral(bytes memory positionData, uint256 amount) external;
function increaseDebt(bytes memory positionData, uint256 amount) external;
function decreaseDebt(bytes memory positionData, uint256 amount) external;
function getHealthFactor(bytes memory positionData) external view returns (uint256);
function canBeLiquidated(bytes memory positionData) external view returns (bool);
}// NewProtocolAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IProtocolAdapter.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract NewProtocolAdapter is IProtocolAdapter {
using SafeERC20 for IERC20;
// Protocol-specific contracts and interfaces
INewProtocol public immutable protocol;
constructor(address _protocol) {
protocol = INewProtocol(_protocol);
}
// Implement all interface functions with protocol-specific logic
function createPosition(
address collateralToken,
address debtToken,
uint256 collateralAmount,
uint256 debtAmount
) external override returns (bytes memory) {
// Protocol-specific implementation
// ...
// Return position data that can be used to identify this position
return abi.encode(/* position identifier data */);
}
// Implement remaining interface functions
// ...
}// Example: Aave adapter for Ethereum mainnet
contract AaveEthereumAdapter is IProtocolAdapter {
// Ethereum mainnet specific implementation
}
// Example: Aave adapter for Polygon
contract AavePolygonAdapter is IProtocolAdapter {
// Polygon specific implementation
}function getChainSpecificAddress() internal view returns (address) {
if (block.chainid == 1) {
return ethereumAddress; // Ethereum mainnet
} else if (block.chainid == 137) {
return polygonAddress; // Polygon
} else if (block.chainid == 42161) {
return arbitrumAddress; // Arbitrum
} else {
revert("Chain not supported");
}
}// Must be called by VAULT_MANAGER_ROLE
function updateThreshold() external {
uint8 protocolId = PROTOCOL_NEW_PROTOCOL;
uint256 newThreshold = 175; // 175% collateralization required
setLiquidationThreshold(protocolId, newThreshold);
}// Must be called by VAULT_MANAGER_ROLE
function disableProtocol() external {
uint8 protocolId = PROTOCOL_NEW_PROTOCOL;
removeProtocol(protocolId);
}// In CollatinatiorFacet.sol
uint8 public constant PROTOCOL_AAVE_V3 = 5; // Assuming 0-4 are already used// IAaveAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IProtocolAdapter.sol";
interface IAaveAdapter is IProtocolAdapter {
// Aave-specific functions
function getReserveData(address asset) external view returns (
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
);
function getAavePool() external view returns (address);
}// AaveV3Adapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IAaveAdapter.sol";
import "@aave/protocol-v3/contracts/interfaces/IPool.sol";
import "@aave/protocol-v3/contracts/interfaces/IPoolAddressesProvider.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract AaveV3Adapter is IAaveAdapter {
using SafeERC20 for IERC20;
// Aave contracts
IPoolAddressesProvider public immutable addressesProvider;
// Position data structure
struct AavePosition {
address user;
address collateralToken;
address debtToken;
uint256 collateralAmount;
uint256 debtAmount;
}
constructor(address _addressesProvider) {
addressesProvider = IPoolAddressesProvider(_addressesProvider);
}
function getAavePool() public view override returns (address) {
return addressesProvider.getPool();
}
function getReserveData(address asset) external view override returns (
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
) {
IPool pool = IPool(getAavePool());
(
, // configuration
, // liquidityIndex
, // currentLiquidityRate
, // variableBorrowIndex
, // currentVariableBorrowRate
, // currentStableBorrowRate
, // lastUpdateTimestamp
, // id
, // aTokenAddress
, // stableDebtTokenAddress
, // variableDebtTokenAddress
, // interestRateStrategyAddress
uint256 baseLTV,
uint256 liquidationThresholdValue,
uint256 liquidationBonusValue,
, // decimals
, // reserve factor
, // is active
, // is frozen
, // is borrowing enabled
, // is stable rate borrowing enabled
, // is paused
, // can be liquidated as collateral
, // can use as collateral
, // can borrow
, // can be eMode collateral
, // can be borrowed in eMode
, // is siloed borrowing
, // is flashloanable
, // is active as collateral
, // is active as borrowing
, // is stable borrowing rate enabled
, // is borrowable in isolation
, // is siloed borrowing
, // is flashloanable
, // is active as collateral
, // is active as borrowing
, // is stable borrowing rate enabled
, // is borrowable in isolation
, // is siloed borrowing
, // is flashloanable
, // is active as collateral
, // is active as borrowing
, // is stable borrowing rate enabled
, // is borrowable in isolation
, // is siloed borrowing
, // is flashloanable
, // is active as collateral
, // is active as borrowing
, // is stable borrowing rate enabled
, // is borrowable in isolation
, // is siloed borrowing
, // is flashloanable
, // is active as collateral
, // is active as borrowing
, // is stable borrowing rate enabled
, // is borrowable in isolation
, // is siloed borrowing
, // is flashloanable
, // is active as collateral
, // is active as borrowing
, // is stable borrowing rate enabled
, // is borrowable in isolation
) = pool.getReserveData(asset);
return (baseLTV, liquidationThresholdValue, liquidationBonusValue);
}
function createPosition(
address collateralToken,
address debtToken,
uint256 collateralAmount,
uint256 debtAmount
) external override returns (bytes memory) {
// Get Aave pool
IPool pool = IPool(getAavePool());
// Transfer collateral from user
IERC20(collateralToken).safeTransferFrom(msg.sender, address(this), collateralAmount);
// Approve Aave to use the collateral
IERC20(collateralToken).approve(address(pool), collateralAmount);
// Supply collateral to Aave
pool.supply(collateralToken, collateralAmount, address(this), 0);
// Enable collateral as collateral
pool.setUserUseReserveAsCollateral(collateralToken, true);
// Borrow if needed
if (debtAmount > 0) {
pool.borrow(debtToken, debtAmount, 2, 0, address(this)); // 2 = variable rate
// Transfer borrowed amount to user
IERC20(debtToken).transfer(msg.sender, debtAmount);
}
// Create and return position data
AavePosition memory position = AavePosition({
user: msg.sender,
collateralToken: collateralToken,
debtToken: debtToken,
collateralAmount: collateralAmount,
debtAmount: debtAmount
});
return abi.encode(position);
}
function closePosition(bytes memory positionData) external override {
AavePosition memory position = abi.decode(positionData, (AavePosition));
IPool pool = IPool(getAavePool());
// Repay debt if any
if (position.debtAmount > 0) {
// Transfer debt tokens from user to repay
IERC20(position.debtToken).safeTransferFrom(
msg.sender,
address(this),
position.debtAmount
);
// Approve Aave to use the debt tokens
IERC20(position.debtToken).approve(address(pool), position.debtAmount);
// Repay the debt
pool.repay(position.debtToken, position.debtAmount, 2, address(this)); // 2 = variable rate
}
// Withdraw collateral
pool.withdraw(position.collateralToken, position.collateralAmount, msg.sender);
}
// Implement other required functions
function addCollateral(bytes memory positionData, uint256 amount) external override {
// Implementation
}
function removeCollateral(bytes memory positionData, uint256 amount) external override {
// Implementation
}
function increaseDebt(bytes memory positionData, uint256 amount) external override {
// Implementation
}
function decreaseDebt(bytes memory positionData, uint256 amount) external override {
// Implementation
}
function getHealthFactor(bytes memory positionData) external view override returns (uint256) {
AavePosition memory position = abi.decode(positionData, (AavePosition));
IPool pool = IPool(getAavePool());
(
uint256 totalCollateralBase,
uint256 totalDebtBase,
uint256 availableBorrowsBase,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
) = pool.getUserAccountData(address(this));
return healthFactor;
}
function canBeLiquidated(bytes memory positionData) external view override returns (bool) {
uint256 healthFactor = this.getHealthFactor(positionData);
return healthFactor < 1e18; // Health factor below 1.0
}
}// Deploy adapter with the correct Aave addresses provider for the target chain
address aaveAddressesProvider;
if (block.chainid == 1) {
// Ethereum mainnet
aaveAddressesProvider = 0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e;
} else if (block.chainid == 137) {
// Polygon
aaveAddressesProvider = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb;
} else if (block.chainid == 42161) {
// Arbitrum
aaveAddressesProvider = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb;
} else {
revert("Chain not supported by Aave V3");
}
// Deploy adapter
AaveV3Adapter aaveAdapter = new AaveV3Adapter(aaveAddressesProvider);
// Register protocol in Collatinator
addProtocol(PROTOCOL_AAVE_V3, "Aave V3", 175, address(aaveAdapter));// Create an Aave position with WETH as collateral and USDC as debt
uint256 positionId = collatinatiorFacet.createPosition(
PROTOCOL_AAVE_V3,
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, // WETH on Ethereum
0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, // USDC on Ethereum
1 ether, // 1 WETH as collateral
1000 * 10**6, // 1000 USDC as debt
0 // Use default liquidation threshold
);