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

<WIP> feat: off-chain farming #41

Closed
wants to merge 4 commits into from
Closed

Conversation

chef-omelette
Copy link
Contributor

@chef-omelette chef-omelette commented May 9, 2024

this PR is mainly to solve the missing fee problem when users are not managing positions through PCS official NonfungiblePositionManager
see https://www.notion.so/pancakeswap/in-house-v4-off-chain-farming-53dca6e8877f4ca9ad20cdd91d2382ce?pvs=4#5302191e85a34787880a6c245e610c81

incur some gas cost

  1. for ModifyLiquidity event to have two extra parameters feesOwed0/1
  2. for modifyLiquidity function to have an extra storage write positionKeys when a positionKey is first time added

CLPosition.Info storage position = self.positions.get(params.owner, params.tickLower, params.tickUpper);
if (position.liquidity == 0 && position.feeGrowthInside0LastX128 == 0 && position.feeGrowthInside1LastX128 == 0)
{
self.positionKeys.push(PositionKey(params.owner, params.tickLower, params.tickUpper));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we consider doing this off-chain ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the same page, why are we doing this on-chain? the PR description doesn't explain this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it, let me explain it in today's v4 sync

feeGrowthInside1LastX128: info.feeGrowthInside1LastX128
});
}

Copy link
Collaborator

@chefburger chefburger May 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

( correct if i am wrong ) So i guess what u want here is basically an array to keep track of all non-empty position, so that can do:

for i = 0 to length - 1:
    gather and calc farming info for each position 

But why not just listen the event ModifyLiquidity in a off-chain manner, and commit update to db instead

event ModifyLiquidity(
      PoolId indexed id,
      address indexed sender,
      int24 tickLower,
      int24 tickUpper,
      int256 liquidityDelta,
      int128 feesOwed0,
      int128 feesOwed1
  );

params.tickLower,
params.tickUpper,
params.liquidityDelta,
feeDelta.amount0(),
Copy link
Collaborator

@ChefMist ChefMist May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this? if the intend is to know the feeDelta, either

1/ when simulate modifyLiqudiity, it returns feeDelta

2/ or calculate this value off-chain, via:
a. get the liquidity, feeGrowthInside0LastX128 and feeGrowthInside1LastX128 for this position via poolManager.getPosition(poolId, owner, tickLower, tickUpper)

b. get the global fee growth feeGrowthGlobal1X128/feeGrowthGlobal1X128 via poolmanager.pools(poolId)

calculate feeDelta by doing the math with those value. ref: https://github.com/pancakeswap/pancake-v4-core/blob/main/src/pool-cl/libraries/CLPosition.sol#L72-L77

Copy link
Contributor Author

@chef-omelette chef-omelette May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for 1/
yes actually the steps 1&2 in the my notion docs is to simulate modifyLiquidity and get feeDelta results
however for step 3, since unlike NonfungiblePositionManager, there are no tokensOwed states for each position in v4-core, we need to somehow record the feesOwed when there are modifyLiquidity(collect) invoked within the epoch

for 2/
that's a more complicated way just as I proposed in my previous version
besides, this method will still require extra event params like feeGrowthInside

also the contract needs to do the computation no matter there is off-chain farming or not, so I don't think emitting the feeDelta results alongside will incur like a unacceptable cost

@@ -70,6 +76,7 @@ library CLPool {
mapping(int24 => Tick.Info) ticks;
mapping(int16 => uint256) tickBitmap;
mapping(bytes32 => CLPosition.Info) positions;
PositionKey[] positionKeys;
Copy link
Collaborator

@chefburger chefburger May 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, have u guys ever heard of an attack vector that is based on unlimited sized array. Given that:

  1. Pushing element into array doesn't cost much in our case (consider addLiquidity 1 to a new range or through new addr)
  2. Array elements are laid linearly in evm storage which means the slot position of a given element will be just a few slots away from current one (unlike for mapping it's hash basically so slot allocation is in fact random)

If a new element's slot position hits exactly a existing contract variable for example address _owner, hacker could manipulate that value through constantly push array until they get that position

I cant remember where did i see it and not sure if this is feasible. Just thought it is worth to point out as reference

@chef-omelette chef-omelette changed the title <WIP> off-chain farming <WIP> feat: off-chain farming May 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants