Skip to content

Commit

Permalink
Merge pull request ethereum#5 from ikigai-labs-xyz/feature/override-c…
Browse files Browse the repository at this point in the history
…ircuit-breaker

add override circuit breaker
  • Loading branch information
Keinberger committed Aug 22, 2023
2 parents e6291c6 + f159c0b commit 816f950
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 14 deletions.
13 changes: 13 additions & 0 deletions assets/eip-7265/src/core/CircuitBreaker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@ contract CircuitBreaker is IERC7265CircuitBreaker, Ownable {
isOperational = newOperationalStatus;
}

/**
* @dev Override the status of the limiter
* @param identifier The identifier of the limiter
* @param overrideStatus The status to override to
* @return The new status of the limiter
*/
function setLimiterOverriden(
bytes32 identifier,
bool overrideStatus
) external returns (bool) {
return limiters[identifier].overriden = overrideStatus;
}

/// @inheritdoc IERC7265CircuitBreaker
function increaseParameter(
bytes32 identifier,
Expand Down
1 change: 1 addition & 0 deletions assets/eip-7265/src/static/Structs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ struct Limiter {
uint256 listTail;
mapping(uint256 tick => LiqChangeNode node) listNodes;
ISettlementModule settlementModule;
bool overriden;
}
4 changes: 4 additions & 0 deletions assets/eip-7265/src/utils/LimiterLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ library LimiterLib {
if (!isInitialized(limiter)) {
return LimitStatus.Uninitialized;
}
if (limiter.overriden) {
return LimitStatus.Ok;
}

int256 currentLiq = limiter.liqTotal;

// Only enforce rate limit if there is significant liquidity
Expand Down
24 changes: 21 additions & 3 deletions assets/eip-7265/test/core/admin/CircuitBreakerAdminOps.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ contract CircuitBreakerAdminOpsTest is Test {
,
,
,
,

) = circuitBreaker.limiters(identifier);
assertEq(minAmount, 1000e18);
Expand All @@ -151,9 +152,8 @@ contract CircuitBreakerAdminOpsTest is Test {
2000e18,
address(delayedSettlementModule)
);
(minLiquidityThreshold, minAmount, , , , , ) = circuitBreaker.limiters(
identifier
);
(minLiquidityThreshold, minAmount, , , , , , ) = circuitBreaker
.limiters(identifier);
assertEq(minAmount, 2000e18);
assertEq(minLiquidityThreshold, 8000);
}
Expand Down Expand Up @@ -188,4 +188,22 @@ contract CircuitBreakerAdminOpsTest is Test {
false
);
}

function testSetLimiterOverriden() public {
circuitBreaker = new TokenCircuitBreaker(4 hours, 5 minutes, admin);
bytes32 identifier = "test";
bool overrideStatus = true;
bool expected = true;

bool result = circuitBreaker.setLimiterOverriden(
identifier,
overrideStatus
);

assertEq(
result,
expected,
"Limiter override status was not set correctly"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,26 @@ contract TokenCircuitBreakerTest is Test {
withdrawalAmount
);
}

function test_onTokenOutflow_WhenOverriden_transferFundsIfTrigger() public {
// cause firewall trigger (withdraw more than 30%)
// 1 Million USDC deposited
token.mint(alice, 1_000_000e18);

vm.prank(alice);
token.transfer(address(circuitBreaker), 1_000_000e18);
circuitBreaker.onTokenInflow(address(token), 1_000_000e18);
bytes32 tokenIdentifier = circuitBreaker.getTokenIdentifier(
address(token)
);
circuitBreaker.setLimiterOverriden(tokenIdentifier, true);

uint256 withdrawalAmount = 300_001e18;
vm.warp(5 hours);

circuitBreaker.onTokenOutflow(address(token), withdrawalAmount, alice);

// balance of alice should not have increased
assertEq(token.balanceOf(alice), 300_001e18);
}
}
30 changes: 19 additions & 11 deletions assets/eip-7265/test/core/user/CircuitBreakerUserOps.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ contract CircuitBreakerUserOpsTest is Test {
int256 liqInPeriod,
uint256 head,
uint256 tail,
,

) = circuitBreaker.limiters(identifier);

Expand All @@ -123,7 +124,9 @@ contract CircuitBreakerUserOpsTest is Test {
vm.prank(alice);
deFi.deposit(address(token), 110e18);
assertEq(circuitBreaker.isTokenRateLimited(address(token)), false);
(, , liqTotal, liqInPeriod, , , ) = circuitBreaker.limiters(identifier);
(, , liqTotal, liqInPeriod, , , , ) = circuitBreaker.limiters(
identifier
);
assertEq(liqTotal, 0);
assertEq(liqInPeriod, 120e18);

Expand All @@ -132,7 +135,7 @@ contract CircuitBreakerUserOpsTest is Test {
vm.prank(alice);
deFi.deposit(address(token), 10e18);
assertEq(circuitBreaker.isTokenRateLimited(address(token)), false);
(, , liqTotal, liqInPeriod, head, tail, ) = circuitBreaker.limiters(
(, , liqTotal, liqInPeriod, head, tail, , ) = circuitBreaker.limiters(
identifier
);
assertEq(liqTotal, 120e18);
Expand Down Expand Up @@ -180,6 +183,7 @@ contract CircuitBreakerUserOpsTest is Test {
int256 liqInPeriod,
uint256 head,
uint256 tail,
,

) = circuitBreaker.limiters(identifier);
// only deposits from 2.5 hours and later should be in the window
Expand All @@ -204,7 +208,7 @@ contract CircuitBreakerUserOpsTest is Test {
deFi.withdrawal(address(token), 60e18);
assertEq(circuitBreaker.isTokenRateLimited(address(token)), false);
bytes32 identifier = keccak256(abi.encodePacked(address(token)));
(, , int256 liqTotal, int256 liqInPeriod, , , ) = circuitBreaker
(, , int256 liqTotal, int256 liqInPeriod, , , , ) = circuitBreaker
.limiters(identifier);
assertEq(liqInPeriod, 40e18);
assertEq(liqTotal, 0);
Expand All @@ -218,7 +222,7 @@ contract CircuitBreakerUserOpsTest is Test {

uint256 tail;
uint256 head;
(, , liqTotal, liqInPeriod, head, tail, ) = circuitBreaker.limiters(
(, , liqTotal, liqInPeriod, head, tail, , ) = circuitBreaker.limiters(
identifier
);
assertEq(liqInPeriod, 10e18);
Expand Down Expand Up @@ -246,7 +250,7 @@ contract CircuitBreakerUserOpsTest is Test {
deFi.withdrawal(address(token), uint256(withdrawalAmount));
assertEq(circuitBreaker.isTokenRateLimited(address(token)), true);
bytes32 identifier = keccak256(abi.encodePacked(address(token)));
(, , int256 liqTotal, int256 liqInPeriod, , , ) = circuitBreaker
(, , int256 liqTotal, int256 liqInPeriod, , , , ) = circuitBreaker
.limiters(identifier);
assertEq(liqInPeriod, -withdrawalAmount);
assertEq(liqTotal, 1_000_000e18);
Expand All @@ -270,7 +274,9 @@ contract CircuitBreakerUserOpsTest is Test {
int256 secondAmount = 10_000e18;
deFi.withdrawal(address(token), uint256(secondAmount));
assertEq(circuitBreaker.isTokenRateLimited(address(token)), true);
(, , liqTotal, liqInPeriod, , , ) = circuitBreaker.limiters(identifier);
(, , liqTotal, liqInPeriod, , , , ) = circuitBreaker.limiters(
identifier
);
assertEq(liqInPeriod, -withdrawalAmount - secondAmount);
assertEq(liqTotal, 1_000_000e18);

Expand Down Expand Up @@ -303,7 +309,7 @@ contract CircuitBreakerUserOpsTest is Test {
bytes32 identifier = keccak256(
abi.encodePacked(address(NATIVE_ADDRESS_PROXY))
);
(, , int256 liqTotal, int256 liqInPeriod, , , ) = circuitBreaker
(, , int256 liqTotal, int256 liqInPeriod, , , , ) = circuitBreaker
.limiters(identifier);
assertEq(liqInPeriod, -withdrawalAmount);
assertEq(liqTotal, 10_000e18);
Expand All @@ -327,7 +333,9 @@ contract CircuitBreakerUserOpsTest is Test {
circuitBreaker.isTokenRateLimited(address(NATIVE_ADDRESS_PROXY)),
true
);
(, , liqTotal, liqInPeriod, , , ) = circuitBreaker.limiters(identifier);
(, , liqTotal, liqInPeriod, , , , ) = circuitBreaker.limiters(
identifier
);
assertEq(liqInPeriod, -withdrawalAmount - secondAmount);
assertEq(liqTotal, 10_000e18);

Expand All @@ -346,7 +354,7 @@ contract CircuitBreakerUserOpsTest is Test {
deFi.deposit(address(token), 10e18);

bytes32 identifier = keccak256(abi.encodePacked(address(token)));
(, , , , uint256 head, , ) = circuitBreaker.limiters(identifier);
(, , , , uint256 head, , , ) = circuitBreaker.limiters(identifier);
assertEq(head % 5 minutes, 0);

// 1 minute later 10 usdc deposited, 1 usdc withdrawn all within the same tick length
Expand Down Expand Up @@ -417,7 +425,7 @@ contract CircuitBreakerUserOpsTest is Test {
false
);
bytes32 identifier = keccak256(abi.encodePacked(NATIVE_ADDRESS_PROXY));
(, , int256 liqTotal, int256 liqInPeriod, , , ) = circuitBreaker
(, , int256 liqTotal, int256 liqInPeriod, , , , ) = circuitBreaker
.limiters(identifier);
assertEq(liqInPeriod, 40e18);
assertEq(liqTotal, 0);
Expand All @@ -434,7 +442,7 @@ contract CircuitBreakerUserOpsTest is Test {

uint256 tail;
uint256 head;
(, , liqTotal, liqInPeriod, head, tail, ) = circuitBreaker.limiters(
(, , liqTotal, liqInPeriod, head, tail, , ) = circuitBreaker.limiters(
identifier
);
assertEq(liqInPeriod, 10e18);
Expand Down

0 comments on commit 816f950

Please sign in to comment.