Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/custom_pool_periphery'
Browse files Browse the repository at this point in the history
  • Loading branch information
IliaAzhel committed Jul 15, 2024
2 parents 5604a56 + 70f15b0 commit b4ba508
Show file tree
Hide file tree
Showing 62 changed files with 938 additions and 311 deletions.
7 changes: 5 additions & 2 deletions src/farming/contracts/FarmingCenter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ contract FarmingCenter is IFarmingCenter, IPositionFollower, Multicall {
bytes32 _eternalIncentiveId = deposits[tokenId];
if (_eternalIncentiveId != bytes32(0)) {
address tokenOwner = nonfungiblePositionManager.ownerOf(tokenId);
(, , , , , , uint128 liquidity, , , , ) = nonfungiblePositionManager.positions(tokenId);
(, , , , , , , uint128 liquidity, , , , ) = nonfungiblePositionManager.positions(tokenId);

IncentiveKey memory key = incentiveKeys[_eternalIncentiveId];

Expand Down Expand Up @@ -140,6 +140,9 @@ contract FarmingCenter is IFarmingCenter, IPositionFollower, Multicall {
require(msg.sender == address(eternalFarming), 'Only farming can call this');
require(virtualPool != address(0), 'Zero address as virtual pool');
pool = IAlgebraPool(plugin.pool());
require(address(pool) == PoolAddress.computeAddress(algebraPoolDeployer, PoolAddress.PoolKey(pool.token0(), pool.token1())), 'Invalid pool');
require(
address(pool) == PoolAddress.computeAddress(algebraPoolDeployer, PoolAddress.PoolKey(address(0), pool.token0(), pool.token1())),
'Invalid pool'
);
}
}
7 changes: 5 additions & 2 deletions src/farming/contracts/libraries/NFTPositionInfo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ library NFTPositionInfo {
) internal view returns (IAlgebraPool pool, int24 tickLower, int24 tickUpper, uint128 liquidity) {
address token0;
address token1;
(, , token0, token1, tickLower, tickUpper, liquidity, , , , ) = nonfungiblePositionManager.positions(tokenId);
address pluginDeployer;
(, , token0, token1, pluginDeployer, tickLower, tickUpper, liquidity, , , , ) = nonfungiblePositionManager.positions(tokenId);

pool = IAlgebraPool(PoolAddress.computeAddress(address(deployer), PoolAddress.PoolKey({token0: token0, token1: token1})));
pool = IAlgebraPool(
PoolAddress.computeAddress(address(deployer), PoolAddress.PoolKey({deployer: pluginDeployer, token0: token0, token1: token1}))
);
}
}
50 changes: 50 additions & 0 deletions src/farming/package-lock.json

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

5 changes: 3 additions & 2 deletions src/farming/test/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Wallet, MaxUint256, Interface } from 'ethers';
import { blockTimestamp, BNe18, FeeAmount, getCurrentTick, maxGas, encodePath, arrayWrap, getMinTick, getMaxTick } from '../shared/index';
import { blockTimestamp, BNe18, FeeAmount, getCurrentTick, maxGas, encodePath, arrayWrap, getMinTick, getMaxTick, ZERO_ADDRESS } from '../shared/index';
import _ from 'lodash';
import { TestERC20, INonfungiblePositionManager, AlgebraEternalFarming, IAlgebraPool, TestIncentiveId, FarmingCenter } from '../../typechain';
import abi from '../../artifacts/contracts/farmings/EternalVirtualPool.sol/EternalVirtualPool.json';
Expand Down Expand Up @@ -343,7 +343,7 @@ export class HelperCommands {
const erc20Helper = new ERC20Helper();
await erc20Helper.ensureBalancesAndApprovals(actor, [tok0, tok1], amountIn, await this.router.getAddress());

const path = encodePath(MAKE_TICK_GO_UP ? [tok1Address, tok0Address] : [tok0Address, tok1Address]);
const path = encodePath(MAKE_TICK_GO_UP ? [tok1Address, ZERO_ADDRESS, tok0Address] : [tok0Address, ZERO_ADDRESS, tok1Address]);

await this.router.connect(actor).exactInput(
{
Expand Down Expand Up @@ -410,6 +410,7 @@ export class HelperCommands {
deadline: MaxUint256,
tokenIn: zto ? tok0Address : tok1Address,
tokenOut: zto ? tok1Address : tok0Address,
deployer: ZERO_ADDRESS,
amountIn: 2n ** 128n - 1n,
amountOutMinimum: 0,
limitSqrtPrice: priceAtTarget,
Expand Down
7 changes: 4 additions & 3 deletions src/farming/test/shared/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
TestIncentiveId,
FarmingCenter,
} from '../../typechain';
import { FeeAmount, encodePriceSqrt, MAX_GAS_LIMIT } from '../shared';
import { FeeAmount, encodePriceSqrt, MAX_GAS_LIMIT, ZERO_ADDRESS } from '../shared';
import { ActorFixture } from './actors';
import { IBasePluginV1Factory, IAlgebraBasePluginV1 } from '@cryptoalgebra/integral-base-plugin/typechain';

Expand Down Expand Up @@ -182,6 +182,7 @@ export const mintPosition = async (
{
token0: mintParams.token0,
token1: mintParams.token1,
deployer: ZERO_ADDRESS,
tickLower: mintParams.tickLower,
tickUpper: mintParams.tickUpper,
recipient: mintParams.recipient,
Expand Down Expand Up @@ -272,9 +273,9 @@ export const algebraFixture: () => Promise<AlgebraFixtureType> = async () => {

const fee = FeeAmount.MEDIUM;

await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], encodePriceSqrt(1, 1));
await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1));

await nft.createAndInitializePoolIfNecessary(tokens[1], tokens[2], encodePriceSqrt(1, 1));
await nft.createAndInitializePoolIfNecessary(tokens[1], tokens[2], ZERO_ADDRESS, encodePriceSqrt(1, 1));

const pool01 = await factory.poolByPair(tokens[0], tokens[1]);

Expand Down
3 changes: 2 additions & 1 deletion src/farming/test/unit/EternalFarms.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1898,7 +1898,7 @@ describe('unit/EternalFarms', () => {

await erc20Helper.ensureBalancesAndApprovals(lpUser0, [token0, token1], amountDesired, await context.nft.getAddress());

await context.nft.createAndInitializePoolIfNecessary(token0, token1, encodePriceSqrt(1, 1));
await context.nft.createAndInitializePoolIfNecessary(token0, token1, ZERO_ADDRESS, encodePriceSqrt(1, 1));

const poolAddress = await context.factory.poolByPair(token0, token1);

Expand Down Expand Up @@ -1958,6 +1958,7 @@ describe('unit/EternalFarms', () => {
const swapData = {
tokenIn: tokenReentrant,
tokenOut: context.token1,
deployer: ZERO_ADDRESS,
amountIn: 10,
amountOutMinimum: 0,
recipient: lpUser0.address,
Expand Down
4 changes: 2 additions & 2 deletions src/farming/test/unit/__snapshots__/EternalFarms.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

exports[`unit/EternalFarms #claimReward when requesting the full amount has gas cost [ @skip-on-coverage ] 1`] = `60772`;

exports[`unit/EternalFarms #enterFarming works and has gas cost [ @skip-on-coverage ] 1`] = `494839`;
exports[`unit/EternalFarms #enterFarming works and has gas cost [ @skip-on-coverage ] 1`] = `498891`;

exports[`unit/EternalFarms #exitFarming after end time works and has gas cost [ @skip-on-coverage ] 1`] = `169695`;
exports[`unit/EternalFarms #exitFarming after end time works and has gas cost [ @skip-on-coverage ] 1`] = `171745`;
11 changes: 7 additions & 4 deletions src/periphery/contracts/NonfungiblePositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ contract NonfungiblePositionManager is
address operator,
address token0,
address token1,
address deployer,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
Expand All @@ -130,6 +131,7 @@ contract NonfungiblePositionManager is
position.operator,
poolKey.token0,
poolKey.token1,
poolKey.deployer,
tickLower,
tickUpper,
liquidity,
Expand All @@ -156,6 +158,7 @@ contract NonfungiblePositionManager is
AddLiquidityParams({
token0: params.token0,
token1: params.token1,
deployer: params.deployer,
recipient: address(this),
tickLower: params.tickLower,
tickUpper: params.tickUpper,
Expand All @@ -178,7 +181,7 @@ contract NonfungiblePositionManager is
// idempotent set
uint80 poolId = _cachePoolKey(
address(pool),
PoolAddress.PoolKey({token0: params.token0, token1: params.token1})
PoolAddress.PoolKey({deployer: params.deployer, token0: params.token0, token1: params.token1})
);

_positions[tokenId] = Position({
Expand Down Expand Up @@ -268,6 +271,7 @@ contract NonfungiblePositionManager is
AddLiquidityParams({
token0: poolKey.token0,
token1: poolKey.token1,
deployer: poolKey.deployer,
tickLower: tickLower,
tickUpper: tickUpper,
amount0Desired: params.amount0Desired,
Expand Down Expand Up @@ -409,7 +413,7 @@ contract NonfungiblePositionManager is
/// @inheritdoc INonfungiblePositionManager
function burn(uint256 tokenId) external payable override isAuthorizedForToken(tokenId) {
Position storage position = _positions[tokenId];
require(position.liquidity | position.tokensOwed0 | position.tokensOwed1 == 0, 'Not cleared');
require(position.liquidity | position.tokensOwed0 | position.tokensOwed1 == 0);

delete _positions[tokenId];
delete tokenFarmedIn[tokenId];
Expand All @@ -424,7 +428,7 @@ contract NonfungiblePositionManager is
) external payable override isAuthorizedForToken(tokenId) {
address newValue;
if (approve) {
require(farmingAddress == farmingCenter, 'Invalid farming address');
require(farmingAddress == farmingCenter);
newValue = farmingAddress;
}
farmingApprovals[tokenId] = newValue;
Expand All @@ -450,7 +454,6 @@ contract NonfungiblePositionManager is
function setFarmingCenter(address newFarmingCenter) external override {
require(IAlgebraFactory(factory).hasRoleOrOwner(NONFUNGIBLE_POSITION_MANAGER_ADMINISTRATOR_ROLE, msg.sender));
farmingCenter = newFarmingCenter;
emit FarmingCenter(newFarmingCenter);
}

/// @inheritdoc IERC721Metadata
Expand Down
19 changes: 15 additions & 4 deletions src/periphery/contracts/NonfungibleTokenPositionDescriptor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,25 @@ contract NonfungibleTokenPositionDescriptor is INonfungibleTokenPositionDescript
INonfungiblePositionManager positionManager,
uint256 tokenId
) external view override returns (string memory) {
(, , address token0, address token1, int24 tickLower, int24 tickUpper, , , , , ) = positionManager.positions(
tokenId
);
(
,
,
address token0,
address token1,
address deployer,
int24 tickLower,
int24 tickUpper,
,
,
,
,

) = positionManager.positions(tokenId);

IAlgebraPool pool = IAlgebraPool(
PoolAddress.computeAddress(
positionManager.poolDeployer(),
PoolAddress.PoolKey({token0: token0, token1: token1})
PoolAddress.PoolKey({deployer: deployer, token0: token0, token1: token1})
)
);

Expand Down
50 changes: 29 additions & 21 deletions src/periphery/contracts/SwapRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ contract SwapRouter is
) PeripheryImmutableState(_factory, _WNativeToken, _poolDeployer) {}

/// @dev Returns the pool for the given token pair. The pool contract may or may not exist.
function getPool(address tokenA, address tokenB) private view returns (IAlgebraPool) {
return IAlgebraPool(PoolAddress.computeAddress(poolDeployer, PoolAddress.getPoolKey(tokenA, tokenB)));
function getPool(address deployer, address tokenA, address tokenB) private view returns (IAlgebraPool) {
return IAlgebraPool(PoolAddress.computeAddress(poolDeployer, PoolAddress.getPoolKey(deployer, tokenA, tokenB)));
}

struct SwapCallbackData {
Expand All @@ -57,8 +57,8 @@ contract SwapRouter is
function algebraSwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata _data) external override {
require(amount0Delta > 0 || amount1Delta > 0, 'Zero liquidity swap'); // swaps entirely within 0-liquidity regions are not supported
SwapCallbackData memory data = abi.decode(_data, (SwapCallbackData));
(address tokenIn, address tokenOut) = data.path.decodeFirstPool();
CallbackValidation.verifyCallback(poolDeployer, tokenIn, tokenOut);
(address tokenIn, address deployer, address tokenOut) = data.path.decodeFirstPool();
CallbackValidation.verifyCallback(poolDeployer, deployer, tokenIn, tokenOut);

(bool isExactInput, uint256 amountToPay) = amount0Delta > 0
? (tokenIn < tokenOut, uint256(amount0Delta))
Expand Down Expand Up @@ -87,11 +87,11 @@ contract SwapRouter is
) private returns (uint256 amountOut) {
if (recipient == address(0)) recipient = address(this); // allow swapping to the router address with address 0

(address tokenIn, address tokenOut) = data.path.decodeFirstPool();
(address tokenIn, address deployer, address tokenOut) = data.path.decodeFirstPool();

bool zeroToOne = tokenIn < tokenOut;

(int256 amount0, int256 amount1) = getPool(tokenIn, tokenOut).swap(
(int256 amount0, int256 amount1) = getPool(deployer, tokenIn, tokenOut).swap(
recipient,
zeroToOne,
amountIn.toInt256(),
Expand All @@ -112,7 +112,10 @@ contract SwapRouter is
params.amountIn,
params.recipient,
params.limitSqrtPrice,
SwapCallbackData({path: abi.encodePacked(params.tokenIn, params.tokenOut), payer: msg.sender})
SwapCallbackData({
path: abi.encodePacked(params.tokenIn, params.deployer, params.tokenOut),
payer: msg.sender
})
);
require(amountOut >= params.amountOutMinimum, 'Too little received');
}
Expand Down Expand Up @@ -155,23 +158,24 @@ contract SwapRouter is
ExactInputSingleParams calldata params
) external payable override checkDeadline(params.deadline) returns (uint256 amountOut) {
SwapCallbackData memory data = SwapCallbackData({
path: abi.encodePacked(params.tokenIn, params.tokenOut),
path: abi.encodePacked(params.tokenIn, params.deployer, params.tokenOut),
payer: msg.sender
});
address recipient = params.recipient == address(0) ? address(this) : params.recipient;

bool zeroToOne = params.tokenIn < params.tokenOut;

(int256 amount0, int256 amount1) = getPool(params.tokenIn, params.tokenOut).swapWithPaymentInAdvance(
msg.sender,
recipient,
zeroToOne,
params.amountIn.toInt256(),
params.limitSqrtPrice == 0
? (zeroToOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1)
: params.limitSqrtPrice,
abi.encode(data)
);
(int256 amount0, int256 amount1) = getPool(params.deployer, params.tokenIn, params.tokenOut)
.swapWithPaymentInAdvance(
msg.sender,
recipient,
zeroToOne,
params.amountIn.toInt256(),
params.limitSqrtPrice == 0
? (zeroToOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1)
: params.limitSqrtPrice,
abi.encode(data)
);

amountOut = uint256(-(zeroToOne ? amount1 : amount0));

Expand All @@ -187,11 +191,11 @@ contract SwapRouter is
) private returns (uint256 amountIn) {
if (recipient == address(0)) recipient = address(this); // allow swapping to the router address with address 0

(address tokenOut, address tokenIn) = data.path.decodeFirstPool();
(address tokenOut, address deployer, address tokenIn) = data.path.decodeFirstPool();

bool zeroToOne = tokenIn < tokenOut;

(int256 amount0Delta, int256 amount1Delta) = getPool(tokenIn, tokenOut).swap(
(int256 amount0Delta, int256 amount1Delta) = getPool(deployer, tokenIn, tokenOut).swap(
recipient,
zeroToOne,
-amountOut.toInt256(),
Expand Down Expand Up @@ -219,7 +223,10 @@ contract SwapRouter is
params.amountOut,
params.recipient,
params.limitSqrtPrice,
SwapCallbackData({path: abi.encodePacked(params.tokenOut, params.tokenIn), payer: msg.sender})
SwapCallbackData({
path: abi.encodePacked(params.tokenOut, params.deployer, params.tokenIn),
payer: msg.sender
})
);

require(amountIn <= params.amountInMaximum, 'Too much requested');
Expand All @@ -232,6 +239,7 @@ contract SwapRouter is
) external payable override checkDeadline(params.deadline) returns (uint256 amountIn) {
// it's okay that the payer is fixed to msg.sender here, as they're only paying for the "final" exact output
// swap, which happens first, and subsequent swaps are paid for within nested callback frames

exactOutputInternal(
params.amountOut,
params.recipient,
Expand Down
Loading

0 comments on commit b4ba508

Please sign in to comment.