Skip to content

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

ZaK3939
Copy link
Contributor

@ZaK3939 ZaK3939 commented May 31, 2025

  • 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

minting position example
Copy link

vercel bot commented May 31, 2025

@ZaK3939 is attempting to deploy a commit to the Uniswap Team on Vercel.

A member of the Team first needs to authorize it.

@ZaK3939 ZaK3939 changed the title docs: v4-sdk: minting position example docs: v4-sdk: minting/fetching position example May 31, 2025
@ZaK3939 ZaK3939 changed the title docs: v4-sdk: minting/fetching position example docs: v4-sdk: minting/fetching position and collecting fee example Jun 2, 2025
@ZaK3939 ZaK3939 changed the title docs: v4-sdk: minting/fetching position and collecting fee example docs: v4-sdk: minting/fetching/adding/removing position and collecting fee example Jun 2, 2025
Comment on lines +83 to +92
// 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)
}
Copy link
Collaborator

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

Comment on lines +163 to +173
// 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
);
Copy link
Collaborator

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
Copy link
Collaborator

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

Comment on lines +406 to +419
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(),
});
Copy link
Collaborator

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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Comment on lines +197 to +214
#### 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 }
}
```
Copy link
Collaborator

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

Comment on lines +252 to +253
functionName: 'multicall',
args: [[calldata]],
Copy link
Collaborator

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.
Copy link
Collaborator

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..

Copy link
Collaborator

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

Comment on lines +208 to +210
// Create currency amounts
const amount0Currency = CurrencyAmount.fromRawAmount(positionDetails.token0, amount0)
const amount1Currency = CurrencyAmount.fromRawAmount(positionDetails.token1, amount1)
Copy link
Collaborator

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)

ocandocrypto and others added 2 commits June 11, 2025 23:53
Co-authored-by: saucepoint <98790946+saucepoint@users.noreply.github.com>
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