Files
asle/contracts/src/core/facets/SecurityFacet.sol
defiQUG 507d9a35b1 Add initial project structure and documentation files
- Created .gitignore to exclude sensitive files and directories.
- Added API documentation in API_DOCUMENTATION.md.
- Included deployment instructions in DEPLOYMENT.md.
- Established project structure documentation in PROJECT_STRUCTURE.md.
- Updated README.md with project status and team information.
- Added recommendations and status tracking documents.
- Introduced testing guidelines in TESTING.md.
- Set up CI workflow in .github/workflows/ci.yml.
- Created Dockerfile for backend and frontend setups.
- Added various service and utility files for backend functionality.
- Implemented frontend components and pages for user interface.
- Included mobile app structure and services.
- Established scripts for deployment across multiple chains.
2025-12-03 21:22:31 -08:00

219 lines
7.5 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {ISecurityFacet} from "../../interfaces/ISecurityFacet.sol";
import {LibDiamond} from "../../libraries/LibDiamond.sol";
import {LibAccessControl} from "../../libraries/LibAccessControl.sol";
import {ILiquidityFacet} from "../../interfaces/ILiquidityFacet.sol";
contract SecurityFacet is ISecurityFacet {
struct SecurityStorage {
bool paused;
PauseReason pauseReason;
address pausedBy;
uint256 pauseTime;
uint256 maxPauseDuration; // Maximum pause duration in seconds (0 = unlimited)
mapping(uint256 => CircuitBreaker) circuitBreakers;
mapping(string => uint256) lastAuditTime;
mapping(uint256 => uint256) poolPriceHistory; // poolId => last price
mapping(uint256 => uint256) maxPriceDeviation; // poolId => max deviation in basis points
}
bytes32 private constant SECURITY_STORAGE_POSITION = keccak256("asle.security.storage");
function securityStorage() internal pure returns (SecurityStorage storage ss) {
bytes32 position = SECURITY_STORAGE_POSITION;
assembly {
ss.slot := position
}
}
modifier whenNotPaused() {
require(!securityStorage().paused, "SecurityFacet: System is paused");
_;
}
modifier onlyAuthorized() {
require(
LibAccessControl.hasRole(LibAccessControl.SECURITY_ADMIN_ROLE, msg.sender) ||
LibAccessControl.hasRole(LibAccessControl.DEFAULT_ADMIN_ROLE, msg.sender),
"SecurityFacet: Not authorized"
);
_;
}
function pauseSystem(PauseReason reason) external override onlyAuthorized {
SecurityStorage storage ss = securityStorage();
require(!ss.paused, "SecurityFacet: Already paused");
ss.paused = true;
ss.pauseReason = reason;
ss.pausedBy = msg.sender;
ss.pauseTime = block.timestamp;
emit SystemPaused(reason, msg.sender);
}
function pauseSystemWithDuration(PauseReason reason, uint256 duration) external onlyAuthorized {
SecurityStorage storage ss = securityStorage();
require(!ss.paused, "SecurityFacet: Already paused");
ss.paused = true;
ss.pauseReason = reason;
ss.pausedBy = msg.sender;
ss.pauseTime = block.timestamp;
ss.maxPauseDuration = duration;
emit SystemPaused(reason, msg.sender);
}
function unpauseSystem() external override onlyAuthorized {
SecurityStorage storage ss = securityStorage();
require(ss.paused, "SecurityFacet: Not paused");
// Check if pause has expired (if max duration is set)
if (ss.maxPauseDuration > 0) {
require(block.timestamp >= ss.pauseTime + ss.maxPauseDuration, "SecurityFacet: Pause duration not expired");
}
ss.paused = false;
address unpauser = msg.sender;
ss.maxPauseDuration = 0;
emit SystemUnpaused(unpauser);
}
function isPaused() external view override returns (bool) {
return securityStorage().paused;
}
function setCircuitBreaker(
uint256 poolId,
uint256 threshold,
uint256 timeWindow
) external override onlyAuthorized {
SecurityStorage storage ss = securityStorage();
ss.circuitBreakers[poolId] = CircuitBreaker({
threshold: threshold,
timeWindow: timeWindow,
currentValue: 0,
windowStart: block.timestamp,
triggered: false
});
}
function checkCircuitBreaker(uint256 poolId, uint256 value) external override returns (bool) {
SecurityStorage storage ss = securityStorage();
CircuitBreaker storage cb = ss.circuitBreakers[poolId];
if (cb.triggered) {
return false; // Circuit breaker already triggered
}
// Reset window if expired
if (block.timestamp > cb.windowStart + cb.timeWindow) {
cb.windowStart = block.timestamp;
cb.currentValue = 0;
}
cb.currentValue += value;
if (cb.currentValue > cb.threshold) {
cb.triggered = true;
emit CircuitBreakerTriggered(poolId, cb.currentValue);
// Automatically pause if circuit breaker triggers
if (!ss.paused) {
ss.paused = true;
ss.pauseReason = PauseReason.CircuitBreaker;
ss.pausedBy = address(this);
ss.pauseTime = block.timestamp;
emit SystemPaused(PauseReason.CircuitBreaker, address(this));
}
return false;
}
return true;
}
function resetCircuitBreaker(uint256 poolId) external onlyAuthorized {
SecurityStorage storage ss = securityStorage();
CircuitBreaker storage cb = ss.circuitBreakers[poolId];
require(cb.triggered, "SecurityFacet: Circuit breaker not triggered");
cb.triggered = false;
cb.currentValue = 0;
cb.windowStart = block.timestamp;
}
function triggerCircuitBreaker(uint256 poolId) external override {
SecurityStorage storage ss = securityStorage();
CircuitBreaker storage cb = ss.circuitBreakers[poolId];
require(!cb.triggered, "SecurityFacet: Already triggered");
cb.triggered = true;
emit CircuitBreakerTriggered(poolId, cb.currentValue);
// Optionally pause the system
// Note: This would need to be called externally or through Diamond
// pauseSystem(PauseReason.CircuitBreaker);
}
function recordSecurityAudit(string calldata auditType, bool passed) external override onlyAuthorized {
SecurityStorage storage ss = securityStorage();
ss.lastAuditTime[auditType] = block.timestamp;
emit SecurityAudit(block.timestamp, auditType, passed);
if (!passed && !ss.paused) {
ss.paused = true;
ss.pauseReason = PauseReason.ComplianceViolation;
ss.pausedBy = msg.sender;
ss.pauseTime = block.timestamp;
emit SystemPaused(PauseReason.ComplianceViolation, msg.sender);
}
}
function checkPriceDeviation(uint256 poolId, uint256 currentPrice) external returns (bool) {
SecurityStorage storage ss = securityStorage();
uint256 lastPrice = ss.poolPriceHistory[poolId];
uint256 maxDeviation = ss.maxPriceDeviation[poolId];
if (lastPrice == 0) {
ss.poolPriceHistory[poolId] = currentPrice;
return true;
}
if (maxDeviation == 0) {
maxDeviation = 1000; // Default 10% deviation
}
uint256 deviation;
if (currentPrice > lastPrice) {
deviation = ((currentPrice - lastPrice) * 10000) / lastPrice;
} else {
deviation = ((lastPrice - currentPrice) * 10000) / lastPrice;
}
if (deviation > maxDeviation) {
// Trigger circuit breaker or pause
CircuitBreaker storage cb = ss.circuitBreakers[poolId];
if (!cb.triggered) {
cb.triggered = true;
emit CircuitBreakerTriggered(poolId, deviation);
}
return false;
}
ss.poolPriceHistory[poolId] = currentPrice;
return true;
}
function setMaxPriceDeviation(uint256 poolId, uint256 maxDeviation) external onlyAuthorized {
securityStorage().maxPriceDeviation[poolId] = maxDeviation;
}
}