Skip to content

Security plugin #136

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

Open
wants to merge 12 commits into
base: integral-v1.2
Choose a base branch
from
97 changes: 97 additions & 0 deletions src/plugin/contracts/AlgebraBasePluginV3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import '@cryptoalgebra/integral-core/contracts/libraries/Plugins.sol';
import '@cryptoalgebra/integral-core/contracts/interfaces/plugin/IAlgebraPlugin.sol';

import './plugins/DynamicFeePlugin.sol';
import './plugins/FarmingProxyPlugin.sol';
import './plugins/VolatilityOraclePlugin.sol';
import './plugins/SecurityPlugin.sol';

/// @title Algebra Integral 1.2, contains adaptive fee, twap oracle, farming proxy and security plugins
contract AlgebraBasePluginV3 is DynamicFeePlugin, FarmingProxyPlugin, VolatilityOraclePlugin, SecurityPlugin {
using Plugins for uint8;

/// @inheritdoc IAlgebraPlugin
uint8 public constant override defaultPluginConfig =
uint8(
Plugins.BEFORE_POSITION_MODIFY_FLAG |
Plugins.AFTER_INIT_FLAG |
Plugins.BEFORE_SWAP_FLAG |
Plugins.AFTER_SWAP_FLAG |
Plugins.DYNAMIC_FEE |
Plugins.BEFORE_FLASH_FLAG
);

constructor(address _pool, address _factory, address _pluginFactory) BasePlugin(_pool, _factory, _pluginFactory) {}

// ###### HOOKS ######

function beforeInitialize(address, uint160) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig);
return IAlgebraPlugin.beforeInitialize.selector;
}

function afterInitialize(address, uint160, int24 tick) external override onlyPool returns (bytes4) {
_initialize_TWAP(tick);

IAlgebraPool(pool).setFee(_feeConfig.baseFee());
return IAlgebraPlugin.afterInitialize.selector;
}

/// @dev unused
function beforeModifyPosition(
address,
address,
int24,
int24,
int128 liquidity,
bytes calldata
) external override onlyPool returns (bytes4, uint24) {
if (liquidity < 0) {
_checkStatusOnBurn();
} else {
_checkStatus();
}
_updatePluginConfigInPool(defaultPluginConfig); // should not be called, reset config
return (IAlgebraPlugin.beforeModifyPosition.selector, 0);
}

/// @dev unused
function afterModifyPosition(address, address, int24, int24, int128, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig); // should not be called, reset config
return IAlgebraPlugin.afterModifyPosition.selector;
}

function beforeSwap(address, address, bool, int256, uint160, bool, bytes calldata) external override onlyPool returns (bytes4, uint24, uint24) {
_checkStatus();
_writeTimepoint();
uint88 volatilityAverage = _getAverageVolatilityLast();
_updateFee(volatilityAverage);
return (IAlgebraPlugin.beforeSwap.selector, 0, 0);
}

function afterSwap(address, address, bool zeroToOne, int256, uint160, int256, int256, bytes calldata) external override onlyPool returns (bytes4) {
_updateVirtualPoolTick(zeroToOne);
return IAlgebraPlugin.afterSwap.selector;
}

/// @dev unused
function beforeFlash(address, address, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
_checkStatus();
_updatePluginConfigInPool(defaultPluginConfig); // should not be called, reset config
return IAlgebraPlugin.beforeFlash.selector;
}

/// @dev unused
function afterFlash(address, address, uint256, uint256, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig); // should not be called, reset config
return IAlgebraPlugin.afterFlash.selector;
}

function getCurrentFee() external view override returns (uint16 fee) {
uint88 volatilityAverage = _getAverageVolatilityLast();
fee = _getCurrentFee(volatilityAverage);
}
}
78 changes: 78 additions & 0 deletions src/plugin/contracts/AlgebraSecurityPlugin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import '@cryptoalgebra/integral-core/contracts/libraries/Plugins.sol';

import '@cryptoalgebra/integral-core/contracts/interfaces/plugin/IAlgebraPlugin.sol';

import './plugins/SecurityPlugin.sol';

/// @title Algebra Integral 1.2 security plugin
contract AlgebraSecurityPlugin is SecurityPlugin {
using Plugins for uint8;

/// @inheritdoc IAlgebraPlugin
uint8 public constant override defaultPluginConfig =
uint8(Plugins.BEFORE_POSITION_MODIFY_FLAG | Plugins.BEFORE_SWAP_FLAG | Plugins.BEFORE_FLASH_FLAG);

constructor(address _pool, address _factory, address _pluginFactory) BasePlugin(_pool, _factory, _pluginFactory) {}

// ###### HOOKS ######

/// @dev unused
function beforeInitialize(address, uint160) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig);
return IAlgebraPlugin.beforeInitialize.selector;
}

/// @dev unused
function afterInitialize(address, uint160, int24) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig);
return IAlgebraPlugin.afterInitialize.selector;
}

/// @dev
function beforeModifyPosition(
address,
address,
int24,
int24,
int128 liquidity,
bytes calldata
) external override onlyPool returns (bytes4, uint24) {
if (liquidity < 0) {
_checkStatusOnBurn();
} else {
_checkStatus();
}
return (IAlgebraPlugin.beforeModifyPosition.selector, 0);
}

/// @dev unused
function afterModifyPosition(address, address, int24, int24, int128, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig); // should not be called, reset config
return IAlgebraPlugin.afterModifyPosition.selector;
}

function beforeSwap(address, address, bool, int256, uint160, bool, bytes calldata) external override onlyPool returns (bytes4, uint24, uint24) {
_checkStatus();
return (IAlgebraPlugin.beforeSwap.selector, 0, 0);
}
/// @dev unused
function afterSwap(address, address, bool, int256, uint160, int256, int256, bytes calldata) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig); // should not be called, reset config
return IAlgebraPlugin.afterSwap.selector;
}

/// @dev
function beforeFlash(address, address, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
_checkStatus();
return IAlgebraPlugin.beforeFlash.selector;
}

/// @dev unused
function afterFlash(address, address, uint256, uint256, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
_updatePluginConfigInPool(defaultPluginConfig); // should not be called, reset config
return IAlgebraPlugin.afterFlash.selector;
}
}
92 changes: 92 additions & 0 deletions src/plugin/contracts/BasePluginV3Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import './interfaces/IBasePluginV3Factory.sol';
import './libraries/AdaptiveFee.sol';
import './AlgebraBasePluginV3.sol';

/// @title Algebra Integral 1.2 default plugin factory
/// @notice This contract creates Algebra adaptive fee plugins for Algebra liquidity pools
/// @dev This plugin factory can only be used for Algebra base pools
contract BasePluginV3Factory is IBasePluginV3Factory {
/// @inheritdoc IBasePluginV3Factory
bytes32 public constant override ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR = keccak256('ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR');

/// @inheritdoc IBasePluginV3Factory
address public immutable override algebraFactory;

/// @inheritdoc IBasePluginV3Factory
AlgebraFeeConfiguration public override defaultFeeConfiguration; // values of constants for sigmoids in fee calculation formula

/// @inheritdoc IBasePluginV3Factory
address public override farmingAddress;

/// @inheritdoc IBasePluginV3Factory
address public override securityRegistry;

/// @inheritdoc IBasePluginV3Factory
mapping(address poolAddress => address pluginAddress) public override pluginByPool;

modifier onlyAdministrator() {
require(IAlgebraFactory(algebraFactory).hasRoleOrOwner(ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR, msg.sender), 'Only administrator');
_;
}

constructor(address _algebraFactory) {
algebraFactory = _algebraFactory;
defaultFeeConfiguration = AdaptiveFee.initialFeeConfiguration();
emit DefaultFeeConfiguration(defaultFeeConfiguration);
}

/// @inheritdoc IAlgebraPluginFactory
function beforeCreatePoolHook(address pool, address, address, address, address, bytes calldata) external override returns (address) {
require(msg.sender == algebraFactory);
return _createPlugin(pool);
}

/// @inheritdoc IAlgebraPluginFactory
function afterCreatePoolHook(address, address, address) external view override {
require(msg.sender == algebraFactory);
}

/// @inheritdoc IBasePluginV3Factory
function createPluginForExistingPool(address token0, address token1) external override returns (address) {
IAlgebraFactory factory = IAlgebraFactory(algebraFactory);
require(factory.hasRoleOrOwner(factory.POOLS_ADMINISTRATOR_ROLE(), msg.sender));

address pool = factory.poolByPair(token0, token1);
require(pool != address(0), 'Pool not exist');

return _createPlugin(pool);
}

function _createPlugin(address pool) internal returns (address) {
require(pluginByPool[pool] == address(0), 'Already created');
address plugin = address(new AlgebraBasePluginV3(pool, algebraFactory, address(this)));
IDynamicFeeManager(plugin).changeFeeConfiguration(defaultFeeConfiguration);
ISecurityPlugin(plugin).setSecurityRegistry(securityRegistry);
pluginByPool[pool] = plugin;
return plugin;
}

/// @inheritdoc IBasePluginV3Factory
function setDefaultFeeConfiguration(AlgebraFeeConfiguration calldata newConfig) external override onlyAdministrator {
AdaptiveFee.validateFeeConfiguration(newConfig);
defaultFeeConfiguration = newConfig;
emit DefaultFeeConfiguration(newConfig);
}

/// @inheritdoc IBasePluginV3Factory
function setFarmingAddress(address newFarmingAddress) external override onlyAdministrator {
require(farmingAddress != newFarmingAddress);
farmingAddress = newFarmingAddress;
emit FarmingAddress(newFarmingAddress);
}

/// @inheritdoc IBasePluginV3Factory
function setSecurityRegistry(address _securityRegistry) external override onlyAdministrator {
require(securityRegistry != _securityRegistry);
securityRegistry = _securityRegistry;
emit SecurityRegistry(_securityRegistry);
}
}
67 changes: 67 additions & 0 deletions src/plugin/contracts/SecurityPluginFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import './interfaces/ISecurityPluginFactory.sol';
import './interfaces/plugins/ISecurityPlugin.sol';
import './AlgebraSecurityPlugin.sol';

/// @title Algebra Integral 1.2 security plugin factory
contract SecurityPluginFactory is ISecurityPluginFactory {
/// @inheritdoc ISecurityPluginFactory
bytes32 public constant override ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR = keccak256('ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR');

/// @inheritdoc ISecurityPluginFactory
address public immutable override algebraFactory;

/// @inheritdoc ISecurityPluginFactory
address public override securityRegistry;

/// @inheritdoc ISecurityPluginFactory
mapping(address poolAddress => address pluginAddress) public override pluginByPool;

modifier onlyAdministrator() {
require(IAlgebraFactory(algebraFactory).hasRoleOrOwner(ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR, msg.sender), 'Only administrator');
_;
}

constructor(address _algebraFactory) {
algebraFactory = _algebraFactory;
}

/// @inheritdoc IAlgebraPluginFactory
function beforeCreatePoolHook(address pool, address, address, address, address, bytes calldata) external override returns (address) {
require(msg.sender == algebraFactory);
return _createPlugin(pool);
}

/// @inheritdoc IAlgebraPluginFactory
function afterCreatePoolHook(address, address, address) external view override {
require(msg.sender == algebraFactory);
}

/// @inheritdoc ISecurityPluginFactory
function createPluginForExistingPool(address token0, address token1) external override returns (address) {
IAlgebraFactory factory = IAlgebraFactory(algebraFactory);
require(factory.hasRoleOrOwner(factory.POOLS_ADMINISTRATOR_ROLE(), msg.sender));

address pool = factory.poolByPair(token0, token1);
require(pool != address(0), 'Pool not exist');

return _createPlugin(pool);
}

function _createPlugin(address pool) internal returns (address) {
require(pluginByPool[pool] == address(0), 'Already created');
ISecurityPlugin plugin = new AlgebraSecurityPlugin(pool, algebraFactory, address(this));
plugin.setSecurityRegistry(securityRegistry);
pluginByPool[pool] = address(plugin);
return address(plugin);
}

/// @inheritdoc ISecurityPluginFactory
function setSecurityRegistry(address _securityRegistry) external override onlyAdministrator {
require(securityRegistry != _securityRegistry);
securityRegistry = _securityRegistry;
emit SecurityRegistry(_securityRegistry);
}
}
Loading