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

Add DSM and modularize CircuitBreaker #3

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e83cc68
feat: outlined new spec
Keinberger Aug 1, 2023
90821b8
feat: implemented new spec with vincent changes
Keinberger Aug 2, 2023
3926d10
feat: add new modularized circuit breaker
Keinberger Aug 9, 2023
386ef4f
feat: implemented security parameter initialization
Keinberger Aug 9, 2023
7b74846
add Settlement Module Interfaces
vdaubry Aug 9, 2023
1c6ed89
add comments
vdaubry Aug 9, 2023
040dac6
feat: implemented Token Circuit Breaker
Keinberger Aug 11, 2023
c44dd31
_onFirewallTriggered comments
vdaubry Aug 12, 2023
c861354
feat: implemented TokenCircuitBreaker, DSM and tests
Keinberger Aug 12, 2023
71d701e
distinguish ERC20 transfers from native transfers
vdaubry Aug 13, 2023
b10b87c
added comments to explicit decoding
Keinberger Aug 14, 2023
030df04
removed setParameter
Keinberger Aug 14, 2023
6779a6a
test: owner CircuitBreaker functions
Keinberger Aug 14, 2023
a1e4d0d
fixed(test): cb reverts if not operational
Keinberger Aug 14, 2023
ee77e21
formatting
Keinberger Aug 14, 2023
57121df
test: added tests for native breach
Keinberger Aug 14, 2023
88a5a43
test: added tests for TCB
Keinberger Aug 14, 2023
6e1a94d
feat: add CircuitBreaker interface natspec
Keinberger Aug 16, 2023
b409a92
feat: added token circuit breaker natspec
Keinberger Aug 16, 2023
e6713e8
feat: added security parameter added event
Keinberger Aug 17, 2023
bae03bc
fix: renamed _onFirewallTrigger to _onCircuitBreaker
Keinberger Aug 17, 2023
328fd6b
Use latest Ownable contract version
vdaubry Aug 17, 2023
7d186b7
add spec for DSM schedule function
vdaubry Aug 17, 2023
bfeecc0
add spec for execute
vdaubry Aug 17, 2023
5dda06b
Merge pull request #3 from ikigai-labs-xyz/chore/add-dsm-tests
Keinberger Aug 17, 2023
e6291c6
feat: fixed solidity dependency versioning issue
Keinberger Aug 18, 2023
f159c0b
add override circuit breaker
vdaubry Aug 21, 2023
816f950
Merge pull request #5 from ikigai-labs-xyz/feature/override-circuit-b…
Keinberger Aug 22, 2023
36c75ca
fix: renamed TokenCircuitBreaker to AssetCircuitBreaker
Keinberger Aug 22, 2023
52fcf98
Merge pull request #6 from ikigai-labs-xyz/fix/naming-scheme
Keinberger Aug 22, 2023
fe77d4d
feat: add grace period, cooldown period and global rate limiter
Keinberger Aug 26, 2023
5e4a5cf
fix: override rate limit overrides per parameter
Keinberger Sep 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
@@ -0,0 +1,3 @@
[submodule "assets/eip-7265/lib/openzeppelin-contracts"]
path = assets/eip-7265/lib/openzeppelin-contracts
url = https://github.com/Openzeppelin/openzeppelin-contracts
1 change: 1 addition & 0 deletions assets/eip-7265/foundry.toml
Expand Up @@ -2,5 +2,6 @@
src = 'src'
out = 'out'
libs = ['lib']
solc = "0.8.20"

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
10 changes: 10 additions & 0 deletions assets/eip-7265/node_modules/.yarn-integrity

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

215 changes: 215 additions & 0 deletions assets/eip-7265/src/core/AssetCircuitBreaker.sol
@@ -0,0 +1,215 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import {SafeERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";

import {IERC7265CircuitBreaker} from "../interfaces/IERC7265CircuitBreaker.sol";
import {IAssetCircuitBreaker} from "../interfaces/IAssetCircuitBreaker.sol";
import {ISettlementModule} from "../interfaces/ISettlementModule.sol";

import {CircuitBreaker} from "./CircuitBreaker.sol";

import {Limiter} from "../static/Structs.sol";
import {LimiterLib, LimitStatus} from "../utils/LimiterLib.sol";

contract AssetCircuitBreaker is CircuitBreaker, IAssetCircuitBreaker {
using LimiterLib for Limiter;
using SafeERC20 for IERC20;

error TokenCirtcuitBreaker__NativeTransferFailed();

uint8 private constant FUNCTION_SELECTOR_SIZE = 4;
bytes4 private constant TRANSFER_SELECTOR =
bytes4(keccak256("transfer(address,uint256)"));

// Using address(1) as a proxy for native token (ETH, BNB, etc), address(0) could be problematic
address public immutable NATIVE_ADDRESS_PROXY = address(1);

constructor(
uint256 _rateLimitCooldownPeriod,
uint256 _withdrawalPeriod,
uint256 _liquidityTickLength,
address _initialOwner
) CircuitBreaker(_rateLimitCooldownPeriod, _withdrawalPeriod, _liquidityTickLength, _initialOwner) {}

/// @dev OWNABLE FUNCTIONS

function registerAsset(
address _asset,
uint256 _minLiqRetainedBps,
uint256 _limitBeginThreshold,
address _settlementModule
) external override onlyOwner {
_addSecurityParameter(
getTokenIdentifier(_asset),
_minLiqRetainedBps,
_limitBeginThreshold,
_settlementModule
);
}

function updateAssetParams(
address _asset,
uint256 _minLiqRetainedBps,
uint256 _limitBeginThreshold,
address _settlementModule
) external override onlyOwner {
_updateSecurityParameter(
getTokenIdentifier(_asset),
_minLiqRetainedBps,
_limitBeginThreshold,
_settlementModule
);
}

/// @dev TOKEN FUNCTIONS

function onTokenInflow(
address _token,
uint256 _amount
) external override onlyProtected onlyOperational {
_increaseParameter(
getTokenIdentifier(_token),
_amount,
_token,
0,
new bytes(0)
);
emit AssetDeposit(_token, msg.sender, _amount);
}

// @dev Funds have been transferred to the circuit breaker before calling onTokenOutflow
function onTokenOutflow(
address _token,
uint256 _amount,
address _recipient
) external override onlyProtected onlyOperational {
// compute calldata to call the erc20 contract and transfer funds to _recipient
bytes memory data = abi.encodeWithSelector(
bytes4(keccak256("transfer(address,uint256)")),
_recipient,
_amount
);

bool firewallTriggered = _decreaseParameter(
getTokenIdentifier(_token),
_amount,
_token,
0,
data
);
if (!firewallTriggered)
_safeTransferIncludingNative(_token, _recipient, _amount);

emit AssetDeposit(_token, msg.sender, _amount);
}

function onNativeAssetInflow(
uint256 _amount
) external override onlyProtected onlyOperational {
_increaseParameter(
getTokenIdentifier(NATIVE_ADDRESS_PROXY),
_amount,
address(0),
0,
new bytes(0)
);
emit AssetDeposit(NATIVE_ADDRESS_PROXY, msg.sender, _amount);
}

function onNativeAssetOutflow(
address _recipient
) external payable override onlyProtected onlyOperational {
bool firewallTriggered = _decreaseParameter(
getTokenIdentifier(NATIVE_ADDRESS_PROXY),
msg.value,
_recipient,
msg.value,
new bytes(0)
);

if (!firewallTriggered)
_safeTransferIncludingNative(
NATIVE_ADDRESS_PROXY,
_recipient,
msg.value
);

emit AssetDeposit(NATIVE_ADDRESS_PROXY, msg.sender, msg.value);
}

function isTokenRateLimited(address token) external view returns (bool) {
return
limiters[getTokenIdentifier(token)].status() ==
LimitStatus.Triggered;
}

/// @dev INTERNAL FUNCTIONS

function getTokenIdentifier(address token) public pure returns (bytes32) {
return keccak256(abi.encodePacked(token));
}

/// @dev FIREWALL TRIGGER OVERRIDE

function _onCircuitBreakerTrigger(
Limiter storage limiter,
address settlementTarget,
uint256 settlementValue,
bytes memory settlementPayload
) internal override {
// check if bytes are just 0
// if not => extract recipient and value from abi encoded bytes data
// use the data to call _safeTransferIncludingNative

if (settlementPayload.length > 0) {
// decoding the calldata
// extracting the function selector (which is always bytes4) from the bytes calldata, in order to properly decode the calldata
bytes memory dataWithoutSelector = new bytes(
settlementPayload.length - FUNCTION_SELECTOR_SIZE
);
for (uint256 i = 0; i < dataWithoutSelector.length; i++) {
dataWithoutSelector[i] = settlementPayload[
i + FUNCTION_SELECTOR_SIZE
];
}
(, uint256 amount) = abi.decode(
dataWithoutSelector,
(address, uint256)
);

_safeTransferIncludingNative(
settlementTarget,
address(limiter.settlementModule),
amount
);
} else {
_safeTransferIncludingNative(
NATIVE_ADDRESS_PROXY,
address(limiter.settlementModule),
settlementValue
);
}

limiter.settlementModule.prevent(
settlementTarget,
settlementValue,
settlementPayload
);
}

function _safeTransferIncludingNative(
address _token,
address _recipient,
uint256 _amount
) internal {
if (_token == NATIVE_ADDRESS_PROXY) {
(bool success, ) = _recipient.call{value: _amount}("");
if (!success) revert TokenCirtcuitBreaker__NativeTransferFailed();
} else {
IERC20(_token).safeTransfer(_recipient, _amount);
}
}
}