Initial commit
This commit is contained in:
141
contracts/governance/policies/PolicyLiquiditySpread.sol
Normal file
141
contracts/governance/policies/PolicyLiquiditySpread.sol
Normal file
@@ -0,0 +1,141 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import "../IPolicyModule.sol";
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
|
||||
/**
|
||||
* @title PolicyLiquiditySpread
|
||||
* @notice Policy module that validates liquidity spreads
|
||||
* @dev Ensures sufficient liquidity depth for operations
|
||||
*/
|
||||
contract PolicyLiquiditySpread is IPolicyModule, Ownable {
|
||||
string public constant override name = "LiquiditySpread";
|
||||
|
||||
bool private _enabled = true;
|
||||
|
||||
// Maximum acceptable spread (basis points, e.g., 50 = 0.5%)
|
||||
uint256 public maxSpreadBps = 50; // 0.5%
|
||||
uint256 private constant BPS_SCALE = 10000;
|
||||
|
||||
// Minimum liquidity depth required (in USD, scaled by 1e8)
|
||||
mapping(address => uint256) public minLiquidityDepth;
|
||||
|
||||
// Interface for checking liquidity
|
||||
interface ILiquidityChecker {
|
||||
function getLiquidityDepth(address asset) external view returns (uint256);
|
||||
function getSpread(address asset, uint256 amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
ILiquidityChecker public liquidityChecker;
|
||||
|
||||
event MaxSpreadUpdated(uint256 oldSpread, uint256 newSpread);
|
||||
event MinLiquidityDepthUpdated(address indexed asset, uint256 oldDepth, uint256 newDepth);
|
||||
event LiquidityCheckerUpdated(address oldChecker, address newChecker);
|
||||
|
||||
modifier onlyEnabled() {
|
||||
require(_enabled, "Policy disabled");
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address initialOwner, address _liquidityChecker) Ownable(initialOwner) {
|
||||
liquidityChecker = ILiquidityChecker(_liquidityChecker);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Check if module is enabled
|
||||
*/
|
||||
function isEnabled() external view override returns (bool) {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Enable or disable the module
|
||||
*/
|
||||
function setEnabled(bool enabled) external override onlyOwner {
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Evaluate policy for proposed action
|
||||
* @param actionType Action type (SWAP, FLASH_LOAN, etc.)
|
||||
* @param actionData Encoded action data: (asset, amount, spreadBps, liquidityDepth)
|
||||
*/
|
||||
function evaluate(
|
||||
bytes32 actionType,
|
||||
bytes memory actionData
|
||||
) external view override onlyEnabled returns (PolicyDecision memory) {
|
||||
// For swaps and flash loans, check liquidity
|
||||
if (actionType != keccak256("SWAP") && actionType != keccak256("FLASH_LOAN")) {
|
||||
return PolicyDecision({
|
||||
allowed: true,
|
||||
reason: ""
|
||||
});
|
||||
}
|
||||
|
||||
(address asset, uint256 amount, uint256 spreadBps, uint256 liquidityDepth) =
|
||||
abi.decode(actionData, (address, uint256, uint256, uint256));
|
||||
|
||||
// Check spread
|
||||
if (spreadBps > maxSpreadBps) {
|
||||
return PolicyDecision({
|
||||
allowed: false,
|
||||
reason: "Spread too high"
|
||||
});
|
||||
}
|
||||
|
||||
// Check minimum liquidity depth
|
||||
uint256 requiredDepth = minLiquidityDepth[asset];
|
||||
if (requiredDepth > 0 && liquidityDepth < requiredDepth) {
|
||||
return PolicyDecision({
|
||||
allowed: false,
|
||||
reason: "Insufficient liquidity depth"
|
||||
});
|
||||
}
|
||||
|
||||
// Additional check: ensure liquidity depth is sufficient for the amount
|
||||
// Rule: liquidity should be at least 2x the operation amount
|
||||
if (liquidityDepth < amount * 2) {
|
||||
return PolicyDecision({
|
||||
allowed: false,
|
||||
reason: "Liquidity depth insufficient for operation size"
|
||||
});
|
||||
}
|
||||
|
||||
return PolicyDecision({
|
||||
allowed: true,
|
||||
reason: ""
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Update maximum spread
|
||||
*/
|
||||
function setMaxSpread(uint256 newSpreadBps) external onlyOwner {
|
||||
require(newSpreadBps <= BPS_SCALE, "Invalid spread");
|
||||
uint256 oldSpread = maxSpreadBps;
|
||||
maxSpreadBps = newSpreadBps;
|
||||
emit MaxSpreadUpdated(oldSpread, newSpreadBps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Update minimum liquidity depth for an asset
|
||||
*/
|
||||
function setMinLiquidityDepth(address asset, uint256 depth) external onlyOwner {
|
||||
require(asset != address(0), "Invalid asset");
|
||||
uint256 oldDepth = minLiquidityDepth[asset];
|
||||
minLiquidityDepth[asset] = depth;
|
||||
emit MinLiquidityDepthUpdated(asset, oldDepth, depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Update liquidity checker contract
|
||||
*/
|
||||
function setLiquidityChecker(address newChecker) external onlyOwner {
|
||||
require(newChecker != address(0), "Invalid checker");
|
||||
address oldChecker = address(liquidityChecker);
|
||||
liquidityChecker = ILiquidityChecker(newChecker);
|
||||
emit LiquidityCheckerUpdated(oldChecker, newChecker);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user