From c8aa329cbd0c993a5d3f133416363a17b6872266 Mon Sep 17 00:00:00 2001 From: IliaAzhel Date: Fri, 19 Jul 2024 12:29:05 +0300 Subject: [PATCH] [Core] add plugin fee tests --- src/core/contracts/test/MockPoolPlugin.sol | 23 ++++-- src/core/test/AlgebraPool.spec.ts | 90 ++++++++++++++++++++++ src/plugin/contracts/test/MockPool.sol | 5 ++ 3 files changed, 113 insertions(+), 5 deletions(-) diff --git a/src/core/contracts/test/MockPoolPlugin.sol b/src/core/contracts/test/MockPoolPlugin.sol index fe79db9d7..27ebf15db 100644 --- a/src/core/contracts/test/MockPoolPlugin.sol +++ b/src/core/contracts/test/MockPoolPlugin.sol @@ -10,6 +10,9 @@ import '../libraries/Plugins.sol'; contract MockPoolPlugin is IAlgebraPlugin, IAlgebraDynamicFeePlugin { address public pool; uint8 public selectorsDisableConfig; + uint24 public overrideFee; + uint24 public pluginFee; + bool public isDisabled; constructor(address _pool) { pool = _pool; @@ -60,10 +63,19 @@ contract MockPoolPlugin is IAlgebraPlugin, IAlgebraDynamicFeePlugin { selectorsDisableConfig = newSelectorsDisableConfig; } - function handlePluginFee(uint256, uint256) external pure override returns (bytes4) { + function handlePluginFee(uint256, uint256) external view override returns (bytes4 selector) { + if (isDisabled) return selector; return IAlgebraPlugin.handlePluginFee.selector; } + function setPluginFees(uint24 _overrideFee, uint24 _pluginFee) external { + (overrideFee, pluginFee) = (_overrideFee, _pluginFee); + } + + function disablePluginFeeHandle() external { + isDisabled = true; + } + /// @notice The hook called before the state of a pool is initialized /// @param sender The initial msg.sender for the initialize call /// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96 @@ -97,8 +109,9 @@ contract MockPoolPlugin is IAlgebraPlugin, IAlgebraDynamicFeePlugin { bytes calldata data ) external override returns (bytes4, uint24) { emit BeforeModifyPosition(sender, recipient, bottomTick, topTick, desiredLiquidityDelta, data); - if (!Plugins.hasFlag(selectorsDisableConfig, Plugins.BEFORE_POSITION_MODIFY_FLAG)) return (IAlgebraPlugin.beforeModifyPosition.selector, 0); - return (IAlgebraPlugin.defaultPluginConfig.selector, 0); + if (!Plugins.hasFlag(selectorsDisableConfig, Plugins.BEFORE_POSITION_MODIFY_FLAG)) + return (IAlgebraPlugin.beforeModifyPosition.selector, overrideFee); + return (IAlgebraPlugin.defaultPluginConfig.selector, overrideFee); } /// @notice The hook called after a position is modified @@ -132,8 +145,8 @@ contract MockPoolPlugin is IAlgebraPlugin, IAlgebraDynamicFeePlugin { bytes calldata data ) external override returns (bytes4, uint24, uint24) { emit BeforeSwap(sender, recipient, zeroToOne, amountRequired, limitSqrtPrice, withPaymentInAdvance, data); - if (!Plugins.hasFlag(selectorsDisableConfig, Plugins.BEFORE_SWAP_FLAG)) return (IAlgebraPlugin.beforeSwap.selector, 0, 0); - return (IAlgebraPlugin.defaultPluginConfig.selector, 0, 0); + if (!Plugins.hasFlag(selectorsDisableConfig, Plugins.BEFORE_SWAP_FLAG)) return (IAlgebraPlugin.beforeSwap.selector, overrideFee, pluginFee); + return (IAlgebraPlugin.defaultPluginConfig.selector, overrideFee, pluginFee); } /// @notice The hook called after a swap diff --git a/src/core/test/AlgebraPool.spec.ts b/src/core/test/AlgebraPool.spec.ts index 59d9dff2c..2039f2631 100644 --- a/src/core/test/AlgebraPool.spec.ts +++ b/src/core/test/AlgebraPool.spec.ts @@ -2430,6 +2430,96 @@ describe('AlgebraPool', () => { }); }); + describe('#pluginFee', () => { + let poolPlugin : MockPoolPlugin; + + beforeEach('initialize the pool', async () => { + const MockPoolPluginFactory = await ethers.getContractFactory('MockPoolPlugin'); + poolPlugin = (await MockPoolPluginFactory.deploy(await pool.getAddress())) as any as MockPoolPlugin; + await pool.setPlugin(poolPlugin); + await pool.setPluginConfig(255); + await pool.initialize(encodePriceSqrt(1, 1)); + await mint(wallet.address, minTick, maxTick, expandTo18Decimals(1)); + }); + + it('swap fails if plugin fee greater than override fee', async () => { + await poolPlugin.setPluginFees(3000, 4000); + await expect(swapExact0For1(expandTo18Decimals(1), wallet.address)).to.be.revertedWithCustomError(pool, 'incorrectPluginFee'); + }) + + it('swap fails if plugin fee exceeds max value', async () => { + await poolPlugin.setPluginFees(1000001, 4000); + await expect(swapExact0For1(expandTo18Decimals(1), wallet.address)).to.be.revertedWithCustomError(pool, 'incorrectOverrideFee'); + await expect(pool.burn(minTick, maxTick, expandTo18Decimals(1), '0x')).to.be.revertedWithCustomError(pool, 'incorrectOverrideFee'); + }) + + it('swap fails if plugin return incorrect selector', async () => { + await poolPlugin.disablePluginFeeHandle(); + await poolPlugin.setPluginFees(5000, 4000); + await expect(swapExact0For1(expandTo18Decimals(1), wallet.address)).to.be.revertedWithCustomError(pool, 'invalidPluginResponce') ; + }) + + it('works correct on swap', async () => { + await poolPlugin.setPluginFees(5000, 4000); + await swapExact0For1(expandTo18Decimals(1), wallet.address); + await swapExact0For1(expandTo18Decimals(1), wallet.address); + await swapExact1For0(expandTo18Decimals(1), wallet.address); + let pluginFees = await pool.getPluginFeePending(); + expect(pluginFees[0]).to.be.eq(4n * 10n**15n); + expect(pluginFees[1]).to.be.eq(4n * 10n**15n) + }) + + it('works correct on swap, fee is 50%, 75%, 100%', async () => { + await poolPlugin.setPluginFees(500000, 500000); + await swapExact0For1(expandTo18Decimals(1), wallet.address); + await swapExact1For0(expandTo18Decimals(1), wallet.address); + let pluginFees = await pool.getPluginFeePending(); + expect(pluginFees[1]).to.be.eq(expandTo18Decimals(1)/2n); + + await poolPlugin.setPluginFees(750000, 750000); + await swapExact1For0(expandTo18Decimals(1), wallet.address); + pluginFees = await pool.getPluginFeePending(); + expect(pluginFees[1]).to.be.eq(expandTo18Decimals(1)* 125n / 100n); + + await poolPlugin.setPluginFees(1000000, 1000000); + await swapExact1For0(expandTo18Decimals(1), wallet.address); + pluginFees = await pool.getPluginFeePending(); + expect(pluginFees[1]).to.be.eq(expandTo18Decimals(1)* 225n / 100n); + }) + + it('works correct on burn', async () => { + await poolPlugin.setPluginFees(6000, 0); + await pool.burn(minTick, maxTick, expandTo18Decimals(1), '0x') + let pluginFees = await pool.getPluginFeePending(); + expect(pluginFees[0]).to.be.eq(6n * 10n**15n-1n); + expect(pluginFees[1]).to.be.eq(6n * 10n**15n-1n) + }) + + it('fees transfered to plugin', async () => { + await poolPlugin.setPluginFees(5000, 4000); + const pluginBalance0Before = await token0.balanceOf(poolPlugin); + const pluginBalance1Before = await token1.balanceOf(poolPlugin); + await swapExact0For1(expandTo18Decimals(1), wallet.address) + const pluginBalance0After = await token0.balanceOf(poolPlugin); + const pluginBalance1After = await token1.balanceOf(poolPlugin); + expect(pluginBalance0After - pluginBalance0Before).to.be.eq(4n * 10n**15n); + expect(pluginBalance1After - pluginBalance1Before).to.be.eq(0); + }) + + it('works correct with communityFee', async () => { + await poolPlugin.setPluginFees(5000, 4000); + await pool.setCommunityFee(500); + await swapExact0For1(expandTo18Decimals(1), wallet.address); + await swapExact0For1(expandTo18Decimals(1), wallet.address); + const communityFees = await pool.getCommunityFeePending(); + const pluginFees = await pool.getPluginFeePending(); + + expect(communityFees[0]).to.be.eq(expandTo18Decimals(1) * 5n / 10000n); // 0.05% + expect(pluginFees[0]).to.be.eq(4n * 10n**15n); + }) + + }) + describe('PermissionedActions', async () => { describe('#setCommunityFee', () => { beforeEach('initialize the pool', async () => { diff --git a/src/plugin/contracts/test/MockPool.sol b/src/plugin/contracts/test/MockPool.sol index e191229ee..1c2604c58 100644 --- a/src/plugin/contracts/test/MockPool.sol +++ b/src/plugin/contracts/test/MockPool.sol @@ -77,6 +77,11 @@ contract MockPool is IAlgebraPoolActions, IAlgebraPoolPermissionedActions, IAlge revert('not implemented'); } + /// @inheritdoc IAlgebraPoolState + function getPluginFeePending() external pure override returns (uint128, uint128) { + revert('not implemented'); + } + /// @inheritdoc IAlgebraPoolState function fee() external pure returns (uint16) { revert('not implemented');