-
Notifications
You must be signed in to change notification settings - Fork 612
docs: v4-sdk: minting/fetching/adding/removing position and collecting fee example #992
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
base: main
Are you sure you want to change the base?
Conversation
minting position example
@ZaK3939 is attempting to deploy a commit to the Uniswap Team on Vercel. A member of the Team first needs to authorize it. |
// Initialize Currency objects based on token info | ||
let tokenA: Currency | ||
let tokenB: Currency | ||
|
||
// Convert token info to SDK Currency objects | ||
if (tokenAInfo.isNative) { | ||
tokenA = Ether.onChain(chainId) | ||
} else { | ||
tokenA = new Token(chainId, tokenAInfo.address, tokenAInfo.decimals, tokenAInfo.symbol) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this type safe? tokenA is Currency but its being assigned Token?
also it feels really weird to define TokenInfo which gets "typed" back into Token. why not just inline the definitions to reduce lines of code/confusion
// Create Pool instance with the fetched data | ||
const pool = new Pool( | ||
token0, | ||
token1, | ||
fee, | ||
tickSpacing, | ||
hookAddress, // Pass the hook address from above | ||
sqrtPriceX96Current.toString(), // Convert bigint to string for SDK | ||
currentLiquidity.toString(), // Convert bigint to string for SDK | ||
currentTick, // Current tick from slot0 | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
im surprised the Pool object requires current state like spot price and liquidity. have you double checked that this is accurate?
} else { | ||
// For custom range, calculate based on percentage around current tick | ||
// tickRange is the percentage range (e.g., 5%) | ||
const tickRangeAmount = Math.floor((tickRange / 100) * 10000) // Convert percentage to tick count |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the 10_000 multiplier is confusing, and possibly inaccurate. to do a tick-range that is "+/- 5% of the spot price" requires using sqrtPriceX96 math. i.e. taking currentTick * 1.05
is NOT equal to 5% price increase
lets just simplifying the guide and use a fixed offset of 500 ticks
const [, , nonce] = (await publicClient.readContract({ | ||
account: getWalletAccount(), | ||
address: PERMIT2_ADDRESS, | ||
abi: PERMIT2_ABI, | ||
functionName: 'allowance', | ||
args: [userAddress, tokenBInfo.address, POSITION_MANAGER_ADDRESS], | ||
})) as [bigint, bigint, bigint]; | ||
|
||
permitDetails.push({ | ||
token: tokenBInfo.address, | ||
amount: (2n ** 160n - 1n).toString(), | ||
expiration: deadline.toString(), | ||
nonce: nonce.toString(), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can the nonce be the same here because its a batch permit? also surprised this isnt wrapped via an SDK
|
||
#### Step 4: Current Fee Growth Values Retrieval | ||
|
||
**Read the current fee growth in the pool for the position's range:** To compute how much fees are unclaimed, we need the **current** fee growth inside the range and compare it to the last snapshot. We could manually fetch global fee growth and subtract out-of-range values, but `StateView` provides a convenience: `getFeeGrowthInside(poolId, tickLower, tickUpper)` will calculate the up-to-date fee growth inside that tick range for each token. This function reads the latest pool state (including global fee growth) and subtracts the parts outside the range. It accounts for any new trades that happened since the last snapshot. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets link getFeeGrowthInside documentation: https://docs.uniswap.org/contracts/v4/reference/periphery/interfaces/IStateView#getfeegrowthinside
#### Comprehensive Fee Analysis | ||
|
||
```typescript | ||
function performComprehensiveFeeAnalysis( | ||
liquidity, | ||
feeGrowthInside0Current, | ||
feeGrowthInside1Current, | ||
feeGrowthInside0Last, | ||
feeGrowthInside1Last | ||
) { | ||
// Apply three methods sequentially | ||
const unclaimed = calculateUnclaimedFeesV4(/*...*/) | ||
const lifetime = calculateLifetimeFeesV4(/*...*/) | ||
const collectedEstimate = calculateCollectedFeesEstimate(lifetime, unclaimed) | ||
|
||
return { unclaimed, lifetime, collectedEstimate } | ||
} | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uncertain on the usefulness of this snippet
functionName: 'multicall', | ||
args: [[calldata]], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we sure we want to use multicall and not just modifyLiquidities directly?
|
||
**What this guide will cover:** | ||
|
||
1. **Setting up liquidity operations** – Preparing to add/remove liquidity from v4 positions, including fetching position details, handling native ETH vs ERC20 tokens, and configuring Permit2 for gasless approvals. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont recall gasless signature approvals working with Position Manager..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
always thought you had to approve Permit2, and then on permit2 approve posm as a spender
// Create currency amounts | ||
const amount0Currency = CurrencyAmount.fromRawAmount(positionDetails.token0, amount0) | ||
const amount1Currency = CurrencyAmount.fromRawAmount(positionDetails.token1, amount1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we document whether these are the "net new" tokens added to the position, or the "desired underlying amounts" (after the liquidity has been added)
Co-authored-by: saucepoint <98790946+saucepoint@users.noreply.github.com>
This PR adds a detailed developer guide for minting/fetching liquidity positions and collect fee in Uniswap v4 using the v4-sdk.
What's Added
New Documentation: [v4/guides/liquidity/01-minting-position.md],[v4/guides/liquidity/02-fetching-positions.md],[v4/guides/liquidity/03-collecting-fee.md],[v4/guides/liquidity/04-adding-removing-liq.md]
For collecting Fee. i just checked by this snippet.
https://gist.github.com/ZaK3939/571b6e2021d6c7d50d53b6e6b0ef250b