Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ubiquity Pool Security Monitor #959

Open
wants to merge 26 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c9e04d3
feat(pool-monitor): add initial liquidity monitor
alexandr-masl Sep 12, 2024
281ca33
feat(pool-monitor): add immutable for ubiquityPoolFacet
alexandr-masl Sep 12, 2024
32237f5
test(pool-monitor): add pool monitor initial test
alexandr-masl Sep 12, 2024
e691a20
test(pool-monitor): increase test coverage
alexandr-masl Sep 12, 2024
5aa078e
feat(pool-monitor): add pool's initial monitor
alexandr-masl Sep 12, 2024
89505a9
test(pool-monitor): fix monitor parameters
alexandr-masl Sep 13, 2024
c3d3fc6
test(pool-monitor): add pool-monitor to the diamond-test-setup
alexandr-masl Sep 14, 2024
e032f0c
test(pool-monitor): increase pool-monitor test coverage
alexandr-masl Sep 15, 2024
1df5a77
test(pool-monitor): add liquidity drop test
alexandr-masl Sep 15, 2024
dd032cf
feat: remove pool-monitor from the diamond
alexandr-masl Sep 17, 2024
b5dc054
feat: add pause lib-ubiquity-pool logic
alexandr-masl Sep 18, 2024
07fc15d
feat: potential reentrancy fixed
alexandr-masl Sep 19, 2024
3274964
feat: perform act pull_request
alexandr-masl Sep 19, 2024
b2c16f0
feat: add dollar pause method
alexandr-masl Sep 20, 2024
428fb6d
feat: update dollar pause method
alexandr-masl Sep 20, 2024
2ddd382
feat(ubiquity-pool-security-monitor): modularize contract
alexandr-masl Sep 20, 2024
8ee2a93
feat: increase test coverage and add multi-collateral tests
alexandr-masl Sep 21, 2024
9e865ce
test: add events testing
alexandr-masl Sep 24, 2024
3ee67de
test: increase test coverage
alexandr-masl Sep 25, 2024
aca3438
chore: modifying tests configuration
alexandr-masl Sep 25, 2024
8fabd03
docs: add ubiquitypoolsecuritymonitor off-chain part setup readme
alexandr-masl Sep 29, 2024
a5a1532
fix: kebab-case
alexandr-masl Sep 29, 2024
e024fa0
fix: kebab-case
alexandr-masl Sep 29, 2024
9e89435
fix: diagram path for ubiquity-pool-security-monitor
alexandr-masl Sep 29, 2024
2669987
docs: add docs to pool contract, update readme
alexandr-masl Sep 30, 2024
b67985e
docs: add docs to security monitor tests
alexandr-masl Oct 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions packages/contracts/src/dollar/monitors/PoolLiquidityMonitor.sol
alexandr-masl marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Modifiers} from "../libraries/LibAppStorage.sol";
import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import {DEFAULT_ADMIN_ROLE} from "../libraries/Constants.sol";
import {LibUbiquityPool} from "../libraries/LibUbiquityPool.sol";
import "forge-std/console.sol";

contract PoolLiquidityMonitor is Modifiers {
using SafeMath for uint256;

address public defenderRelayer;
uint256 public liquidityVertex;
bool public monitorPaused;
uint256 public thresholdPercentage;

event LiquidityVertexUpdated(uint256 collateralLiquidity);
event MonitorPaused(uint256 collateralLiquidity, uint256 diffPercentage);
event VertexDropped();
event PausedToggled(bool paused);

modifier onlyAuthorized() {
require(
msg.sender == defenderRelayer,
"Not authorized: Only Defender Relayer allowed"
);
_;
}

function setThresholdPercentage(
uint256 _newThresholdPercentage
) external onlyAdmin {
thresholdPercentage = _newThresholdPercentage;
}

function setDefenderRelayer(
address _newDefenderRelayer
) external onlyAdmin {
defenderRelayer = _newDefenderRelayer;
}

function togglePaused() external onlyAdmin {
monitorPaused = !monitorPaused;
emit PausedToggled(monitorPaused);
}

function dropLiquidityVertex() external onlyAdmin {
uint256 currentCollateralLiquidity = LibUbiquityPool
.collateralUsdBalance();

require(currentCollateralLiquidity > 0, "Insufficient liquidity");

liquidityVertex = currentCollateralLiquidity;

emit VertexDropped();
}

function checkLiquidityVertex() external onlyAuthorized {
uint256 currentCollateralLiquidity = LibUbiquityPool
.collateralUsdBalance();

require(currentCollateralLiquidity > 0, "Insufficient liquidity");
require(!monitorPaused, "Monitor paused");

if (currentCollateralLiquidity > liquidityVertex) {
liquidityVertex = currentCollateralLiquidity;

emit LiquidityVertexUpdated(liquidityVertex);
} else {
uint256 liquidityDiffPercentage = liquidityVertex
.sub(currentCollateralLiquidity)
.mul(100)
.div(liquidityVertex);

if (liquidityDiffPercentage >= thresholdPercentage) {
monitorPaused = true;

// Pause the UbiquityDollarToken
// Pause LibUbiquityPool by disabling collateral

emit MonitorPaused(
currentCollateralLiquidity,
liquidityDiffPercentage
);
}
}
}
}
2 changes: 1 addition & 1 deletion packages/contracts/test/diamond/DiamondTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract TestDiamond is DiamondTestSetup {
}

function testHasMultipleFacets() public {
assertEq(facetAddressList.length, 19);
assertEq(facetAddressList.length, 20);
}

function testFacetsHaveCorrectSelectors() public {
Expand Down
25 changes: 23 additions & 2 deletions packages/contracts/test/diamond/DiamondTestSetup.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "forge-std/Test.sol";

import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {Diamond, DiamondArgs} from "../../src/dollar/Diamond.sol";
import {ERC1155Ubiquity} from "../../src/dollar/core/ERC1155Ubiquity.sol";
Expand Down Expand Up @@ -31,6 +33,7 @@ import {MockERC20} from "../../src/dollar/mocks/MockERC20.sol";
import {DiamondInit} from "../../src/dollar/upgradeInitializers/DiamondInit.sol";
import {DiamondTestHelper} from "../helpers/DiamondTestHelper.sol";
import {UUPSTestHelper} from "../helpers/UUPSTestHelper.sol";
import {PoolLiquidityMonitor} from "../../src/dollar/monitors/PoolLiquidityMonitor.sol";
import {CREDIT_NFT_MANAGER_ROLE, CREDIT_TOKEN_BURNER_ROLE, CREDIT_TOKEN_MINTER_ROLE, CURVE_DOLLAR_MANAGER_ROLE, DOLLAR_TOKEN_BURNER_ROLE, DOLLAR_TOKEN_MINTER_ROLE, GOVERNANCE_TOKEN_BURNER_ROLE, GOVERNANCE_TOKEN_MANAGER_ROLE, GOVERNANCE_TOKEN_MINTER_ROLE, STAKING_SHARE_MINTER_ROLE} from "../../src/dollar/libraries/Constants.sol";

/**
Expand Down Expand Up @@ -61,6 +64,7 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
StakingFacet stakingFacet;
StakingFormulasFacet stakingFormulasFacet;
UbiquityPoolFacet ubiquityPoolFacet;
PoolLiquidityMonitor poolLiquidityMonitor;

// diamond facet implementation instances (should not be used in tests, use only on upgrades)
AccessControlFacet accessControlFacetImplementation;
Expand All @@ -82,6 +86,7 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
StakingFacet stakingFacetImplementation;
StakingFormulasFacet stakingFormulasFacetImplementation;
UbiquityPoolFacet ubiquityPoolFacetImplementation;
PoolLiquidityMonitor poolLiquidityMonitorImplementation;

// facet names with addresses
string[] facetNames;
Expand Down Expand Up @@ -114,6 +119,7 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
bytes4[] selectorsOfStakingFacet;
bytes4[] selectorsOfStakingFormulasFacet;
bytes4[] selectorsOfUbiquityPoolFacet;
bytes4[] selectorsOfPoolLiquidityMonitor;

/// @notice Deploys diamond and connects facets
function setUp() public virtual {
Expand Down Expand Up @@ -183,6 +189,10 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
"/out/UbiquityPoolFacet.sol/UbiquityPoolFacet.json"
);

selectorsOfPoolLiquidityMonitor = getSelectorsFromAbi(
"/out/PoolLiquidityMonitor.sol/PoolLiquidityMonitor.json"
);

// deploy facet implementation instances
accessControlFacetImplementation = new AccessControlFacet();
bondingCurveFacetImplementation = new BondingCurveFacet();
Expand All @@ -203,6 +213,7 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
stakingFacetImplementation = new StakingFacet();
stakingFormulasFacetImplementation = new StakingFormulasFacet();
ubiquityPoolFacetImplementation = new UbiquityPoolFacet();
poolLiquidityMonitorImplementation = new PoolLiquidityMonitor();

// prepare diamond init args
diamondInit = new DiamondInit();
Expand All @@ -225,7 +236,8 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
"OwnershipFacet",
"StakingFacet",
"StakingFormulasFacet",
"UbiquityPoolFacet"
"UbiquityPoolFacet",
"PoolLiquidityMonitor"
];
DiamondInit.Args memory initArgs = DiamondInit.Args({
admin: admin,
Expand All @@ -245,7 +257,7 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
)
});

FacetCut[] memory cuts = new FacetCut[](19);
FacetCut[] memory cuts = new FacetCut[](20);

cuts[0] = (
FacetCut({
Expand Down Expand Up @@ -387,6 +399,14 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
})
);

cuts[19] = (
alexandr-masl marked this conversation as resolved.
Show resolved Hide resolved
FacetCut({
facetAddress: address(poolLiquidityMonitorImplementation),
action: FacetCutAction.Add,
functionSelectors: selectorsOfPoolLiquidityMonitor
})
);

// deploy diamond
vm.prank(owner);
diamond = new Diamond(_args, cuts);
Expand Down Expand Up @@ -417,6 +437,7 @@ abstract contract DiamondTestSetup is DiamondTestHelper, UUPSTestHelper {
stakingFacet = StakingFacet(address(diamond));
stakingFormulasFacet = StakingFormulasFacet(address(diamond));
ubiquityPoolFacet = UbiquityPoolFacet(address(diamond));
poolLiquidityMonitor = PoolLiquidityMonitor(address(diamond));

// get all addresses
facetAddressList = diamondLoupeFacet.facetAddresses();
Expand Down
Loading
Loading