Skip to content

Commit

Permalink
Merge pull request #134 from cryptoalgebra/integral-v1.2-sliding-fee
Browse files Browse the repository at this point in the history
Integral v1.2 sliding fee
  • Loading branch information
IliaAzhel authored Oct 9, 2024
2 parents 2df0171 + 66396ab commit ec140c1
Show file tree
Hide file tree
Showing 80 changed files with 2,435 additions and 514 deletions.
5 changes: 5 additions & 0 deletions hardhat.base.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ export default {
chainId: 34443,
accounts: [`0x${MNEMONIC || '1000000000000000000000000000000000000000000000000000000000000000'}`],
},
holesky: {
url: `https://ethereum-holesky-rpc.publicnode.com`,
chainId: 17000,
accounts: [`0x${MNEMONIC || '1000000000000000000000000000000000000000000000000000000000000000'}`],
},
blastTestnet: {
url: `https://blast-sepolia.blockpi.network/v1/rpc/public`,
chainId: 168587773,
Expand Down
2 changes: 1 addition & 1 deletion src/core/contracts/AlgebraCommunityVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import './interfaces/vault/IAlgebraCommunityVault.sol';
/// @title Algebra community fee vault
/// @notice Community fee from pools is sent here, if it is enabled
/// @dev Role system is used to withdraw tokens
/// @dev Version: Algebra Integral 1.1
/// @dev Version: Algebra Integral 1.2
contract AlgebraCommunityVault is IAlgebraCommunityVault {
/// @dev The role can be granted in AlgebraFactory
bytes32 public constant COMMUNITY_FEE_WITHDRAWER_ROLE = keccak256('COMMUNITY_FEE_WITHDRAWER');
Expand Down
2 changes: 1 addition & 1 deletion src/core/contracts/AlgebraFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import '@openzeppelin/contracts/security/ReentrancyGuard.sol';

/// @title Algebra factory
/// @notice Is used to deploy pools and its plugins
/// @dev Version: Algebra Integral 1.1
/// @dev Version: Algebra Integral 1.2
contract AlgebraFactory is IAlgebraFactory, Ownable2Step, AccessControlEnumerable, ReentrancyGuard {
/// @inheritdoc IAlgebraFactory
bytes32 public constant override POOLS_ADMINISTRATOR_ROLE = keccak256('POOLS_ADMINISTRATOR'); // it`s here for the public visibility of the value
Expand Down
2 changes: 1 addition & 1 deletion src/core/contracts/AlgebraPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import './interfaces/IAlgebraFactory.sol';

/// @title Algebra concentrated liquidity pool
/// @notice This contract is responsible for liquidity positions, swaps and flashloans
/// @dev Version: Algebra Integral 1.1
/// @dev Version: Algebra Integral 1.2
contract AlgebraPool is AlgebraPoolBase, TickStructure, ReentrancyGuard, Positions, SwapCalculation, ReservesManager {
using SafeCast for uint256;
using SafeCast for uint128;
Expand Down
2 changes: 1 addition & 1 deletion src/core/contracts/AlgebraPoolDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import './AlgebraPool.sol';

/// @title Algebra pool deployer
/// @notice Is used by AlgebraFactory to deploy pools
/// @dev Version: Algebra Integral 1.1
/// @dev Version: Algebra Integral 1.2
contract AlgebraPoolDeployer is IAlgebraPoolDeployer {
/// @dev two storage slots for dense cache packing
bytes32 private cache0;
Expand Down
5 changes: 4 additions & 1 deletion src/core/contracts/test/MockDefaultPluginFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import './MockPoolPlugin.sol';
contract MockDefaultPluginFactory is IAlgebraPluginFactory {
mapping(address => address) public pluginsForPools;

event DataOnPoolCreation(bytes data);

function afterCreatePoolHook(address plugin, address pool, address deployer) external override {}

function beforeCreatePoolHook(address pool, address, address, address, address, bytes calldata) external override returns (address plugin) {
function beforeCreatePoolHook(address pool, address, address, address, address, bytes calldata data) external override returns (address plugin) {
plugin = address(new MockPoolPlugin(pool));
pluginsForPools[pool] = plugin;
emit DataOnPoolCreation(data);
}
}
26 changes: 26 additions & 0 deletions src/core/contracts/test/MockPoolPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import '../interfaces/plugin/IAlgebraPlugin.sol';
import '../interfaces/plugin/IAlgebraDynamicFeePlugin.sol';
import '../interfaces/IAlgebraPool.sol';
import '../libraries/Plugins.sol';
import './TestERC20.sol';

contract MockPoolPlugin is IAlgebraPlugin, IAlgebraDynamicFeePlugin {
address public pool;
Expand Down Expand Up @@ -197,4 +198,29 @@ contract MockPoolPlugin is IAlgebraPlugin, IAlgebraDynamicFeePlugin {
if (!Plugins.hasFlag(selectorsDisableConfig, Plugins.AFTER_FLASH_FLAG)) return IAlgebraPlugin.afterFlash.selector;
return IAlgebraPlugin.defaultPluginConfig.selector;
}

function swap() external {
IAlgebraPool(pool).swap(address(this), true, 10000, 4295128740, '');
}

function algebraSwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata ) external {
require(amount0Delta > 0 || amount1Delta > 0, 'Zero liquidity swap'); // swaps entirely within 0-liquidity regions are not supported

(address token, uint256 amountToPay) = amount0Delta > 0
? (IAlgebraPool(pool).token0(), uint256(amount0Delta))
: (IAlgebraPool(pool).token1(), uint256(amount1Delta));

TestERC20(token).transfer(pool, amountToPay);
}


function mint() external {
IAlgebraPool(pool).mint(address(this), address(this), -60, 60, 1000, '');
}

function algebraMintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes calldata ) external {

if (amount0Owed > 0) TestERC20(IAlgebraPool(pool).token0()).transfer(pool, amount0Owed);
if (amount1Owed > 0) TestERC20(IAlgebraPool(pool).token1()).transfer(pool, amount1Owed);
}
}
4 changes: 2 additions & 2 deletions src/core/package-lock.json

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

2 changes: 1 addition & 1 deletion src/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"publishConfig": {
"access": "public"
},
"version": "1.1.0",
"version": "1.2.0",
"keywords": [
"algebra"
],
Expand Down
7 changes: 7 additions & 0 deletions src/core/test/AlgebraFactory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ describe('AlgebraFactory', () => {
expect(await pool.plugin()).to.be.eq(pluginAddress);
});

it('data passed to defaultPluginFactory', async () => {
await factory.setDefaultPluginFactory(defaultPluginFactory);
const create = factory.createPool(TEST_ADDRESSES[0], TEST_ADDRESSES[1], '0x0200');

await expect(create).to.emit(defaultPluginFactory, 'DataOnPoolCreation').withArgs('0x0200');
});

it('sets vault in pool', async () => {
await createAndCheckPool([TEST_ADDRESSES[0], TEST_ADDRESSES[1]]);

Expand Down
103 changes: 102 additions & 1 deletion src/core/test/AlgebraPool.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
PriceMovementMathTest,
IERC20Minimal,
} from '../typechain';
import { plugin } from '../typechain/contracts/interfaces';

type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;

Expand Down Expand Up @@ -1185,7 +1186,7 @@ describe('AlgebraPool', () => {
await swapExact0For1(expandTo18Decimals(2), other.address);
await expect(pool.burn(-120, 0, expandTo18Decimals(1), '0x'))
.to.emit(pool, 'Burn')
.withArgs(wallet.address, -120, 0, expandTo18Decimals(1), '6017734268818165', 0)
.withArgs(wallet.address, -120, 0, expandTo18Decimals(1),'6017734268818165', 0, 0)
.to.not.emit(token0, 'Transfer')
.to.not.emit(token1, 'Transfer');
await expect(pool.collect(wallet.address, -120, 0, MaxUint128, MaxUint128))
Expand Down Expand Up @@ -2505,6 +2506,18 @@ describe('AlgebraPool', () => {
expect(pluginBalance1After - pluginBalance1Before).to.be.eq(6n * 10n**15n-1n);
})

it('works correct on burn single-sided position', async () => {
await poolPlugin.setPluginFees(0, 6000);
await mint(wallet.address, -120, -60, expandTo18Decimals(1));
await mint(wallet.address, 60, 120, expandTo18Decimals(1));
await pool.burn(minTick, maxTick, expandTo18Decimals(1), '0x')
await pool.burn(-120, -60, expandTo18Decimals(1), '0x')
await pool.burn(60, 120, expandTo18Decimals(1), '0x')
let res = await pool.getPluginFeePending()
expect(res[0]).to.be.eq(17918296827593n);
expect(res[1]).to.be.eq(17918296827593n);
})

it('fees transfered to plugin', async () => {
await poolPlugin.setPluginFees(5000, 4000);
const pluginBalance0Before = await token0.balanceOf(poolPlugin);
Expand All @@ -2516,6 +2529,51 @@ describe('AlgebraPool', () => {
expect(pluginBalance1After - pluginBalance1Before).to.be.eq(0);
})

it('fees transfered to plugin, if comm fee is zero', async () => {
await poolPlugin.setPluginFees(5000, 4000);
await swapExact1For0(expandTo18Decimals(1), wallet.address)
const pluginBalance0Before = await token0.balanceOf(poolPlugin);
const pluginBalance1Before = await token1.balanceOf(poolPlugin);
await pool.advanceTime(86400);
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('fees transfered to plugin, after disable plugin fee and enable comm fee', async () => {
await poolPlugin.setPluginFees(5000, 4000);
await swapExact1For0(expandTo18Decimals(1), wallet.address)
await swapExact0For1(expandTo18Decimals(1), wallet.address)
const pluginBalance0Before = await token0.balanceOf(poolPlugin);
const pluginBalance1Before = await token1.balanceOf(poolPlugin);
await pool.advanceTime(86400);
await poolPlugin.setPluginFees(5000, 0);
await pool.setCommunityFee(100);
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('fees transfered to vault, after disable comm fee and enable plugin fee', async () => {
await pool.setCommunityFee(100);
await swapExact1For0(expandTo18Decimals(1), wallet.address)
await swapExact0For1(expandTo18Decimals(1), wallet.address)
const vaultBalance0Before = await token0.balanceOf(vaultAddress);
const vaultBalance1Before = await token1.balanceOf(vaultAddress);
await pool.advanceTime(86400);
await poolPlugin.setPluginFees(5000, 4000);
await pool.setCommunityFee(0);
await swapExact0For1(expandTo18Decimals(1), wallet.address)
const vaultBalance0After = await token0.balanceOf(vaultAddress);
const vaultBalance1After = await token1.balanceOf(vaultAddress);
expect(vaultBalance0After - vaultBalance0Before).to.be.eq(5n * 10n**13n);
expect(vaultBalance1After - vaultBalance1Before).to.be.eq(0);
})

it('works correct with communityFee', async () => {
await poolPlugin.setPluginFees(1000, 4000);
await pool.setCommunityFee(500);
Expand All @@ -2528,6 +2586,30 @@ describe('AlgebraPool', () => {
expect(pluginFees[0]).to.be.eq(4n * 10n**15n);
})

it('emits an event with plugin fee and override fee on swap', async () => {
await poolPlugin.setPluginFees(4000, 6000);
await expect(swapExact0For1(expandTo18Decimals(1), wallet.address)).to.be.emit(pool, 'Swap').withArgs(
await swapTarget.getAddress(),
wallet.address,
10n**18n,
-497487437185929648n,
39813146992092631956554748913n,
1000000000000000000n,
-13764,
4000,
6000
)
})

it('emits an event with plugin fee and override fee on burn', async () => {
await poolPlugin.setPluginFees(4000, 6000);
await mint(wallet.address, 60, 120, expandTo18Decimals(1));
await expect(pool.burn(60, 120, expandTo18Decimals(1), '0x'))
.to.emit(pool, 'Burn')
.withArgs(wallet.address, 60, 120, expandTo18Decimals(1), '2968464507771288', 0, 6000)

})

})

describe('PermissionedActions', async () => {
Expand Down Expand Up @@ -2898,6 +2980,25 @@ describe('AlgebraPool', () => {
await pool.setPluginConfig(223);
await expect(flash(100, 200, other.address)).not.to.be.emit(poolPlugin, 'AfterFlash');
});

it('before/after swap hook is not called if caller is a plugin,', async () => {
await pool.initialize(encodePriceSqrt(1, 1));
await mint(wallet.address, minTick, maxTick, expandTo18Decimals(1));
await token0.transfer(poolPlugin, expandTo18Decimals(1))
await token1.transfer(poolPlugin, expandTo18Decimals(1))
await expect(poolPlugin.swap()).not.to.be.emit(poolPlugin, 'BeforeSwap');
await expect(poolPlugin.swap()).not.to.be.emit(poolPlugin, 'AfterSwap');
});

it('before/after modify hook is not called if caller is a plugin,', async () => {
await pool.initialize(encodePriceSqrt(1, 1));
await mint(wallet.address, minTick, maxTick, expandTo18Decimals(1));
await token0.transfer(poolPlugin, expandTo18Decimals(1))
await token1.transfer(poolPlugin, expandTo18Decimals(1))
await expect(poolPlugin.mint()).not.to.be.emit(poolPlugin, 'BeforeModifyPosition');
await expect(poolPlugin.mint()).not.to.be.emit(poolPlugin, 'AfterModifyPosition');
});

});

describe('#setPlugin', () => {
Expand Down
10 changes: 5 additions & 5 deletions src/core/test/__snapshots__/AlgebraFactory.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AlgebraFactory #createCustomPool gas [ @skip-on-coverage ] 1`] = `4756512`;
exports[`AlgebraFactory #createCustomPool gas [ @skip-on-coverage ] 1`] = `4752295`;

exports[`AlgebraFactory #createCustomPool gas for second pool [ @skip-on-coverage ] 1`] = `4756512`;
exports[`AlgebraFactory #createCustomPool gas for second pool [ @skip-on-coverage ] 1`] = `4752295`;

exports[`AlgebraFactory #createPool gas [ @skip-on-coverage ] 1`] = `4744315`;
exports[`AlgebraFactory #createPool gas [ @skip-on-coverage ] 1`] = `4740098`;

exports[`AlgebraFactory #createPool gas for second pool [ @skip-on-coverage ] 1`] = `4744315`;
exports[`AlgebraFactory #createPool gas for second pool [ @skip-on-coverage ] 1`] = `4740098`;

exports[`AlgebraFactory factory bytecode size [ @skip-on-coverage ] 1`] = `10699`;

exports[`AlgebraFactory pool bytecode size [ @skip-on-coverage ] 1`] = `22456`;
exports[`AlgebraFactory pool bytecode size [ @skip-on-coverage ] 1`] = `22435`;
Loading

0 comments on commit ec140c1

Please sign in to comment.