feat(lp-sdk): add LP gas-estimation helpers - #642
Conversation
Introduces @uniswap/lp-sdk, a cross-version package (router-sdk pattern) with helpers that let clients estimate the real gas cost of LP flows instead of reserving a hardcoded native-token buffer: - pickPreEstimateIndependentAmount: picks the larger capped wallet balance as the independent simulation amount (null when both zero) - getV2/getV3/getV4AddLiquidityGasEstimateTransactions: build the ordered approval + create/increase transaction lists for eth_estimateGas, reusing the existing v2/v3/v4 calldata builders Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Bzp1ZmbwPvLbyKSuaRv2X
|
● Reviewed · against Note Approved. Adds AssessmentSelf-contained new package with no changes to existing SDKs, so blast radius is limited to consumers of the new helpers. The v3/v4 approval-sufficiency thresholds now match what each position manager actually pulls — v4 checks against Iteration history · 2 reviews2026-07-14 04:43 UTC · ✅ approved · 0 findings ·
|
There was a problem hiding this comment.
Note
✅ Approved — see full review in the sticky comment ↑
Graphite Automations"Request reviewers once CI passes on sdks monorepo" took an action on this PR • (07/14/26)3 reviewers were added to this PR based on Siyu Jiang (See-You John)'s automation. |
V4PositionManager settles up to mintAmountsWithSlippage (amount0Max/ amount1Max), so an allowance between the desired amounts and the maximums must still produce an approval transaction. v3 keeps the mintAmounts threshold: its manager pulls at most amount0Desired, and its mintAmountsWithSlippage are lower-bound minimums. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Bzp1ZmbwPvLbyKSuaRv2X
Requested by Bruno Nunes · Slack thread
Description
Before: when a user taps "Max" on a native-token input in an LP flow, web reserves a hardcoded 0.015 ETH as a gas buffer — too much on cheap chains, potentially too little during fee spikes. A backend RPC stack was drafted to compute a real estimate server-side (#7487, #7490, #7492, #7493, building on #7208), but per the Slack discussion the logic belongs in the SDK so the frontend can estimate directly instead of adding new backend RPCs. This PR supersedes that stack.
After: clients call SDK helpers that return the full ordered transaction list for an LP flow — required ERC-20/Permit2 approvals plus the create/increase position transaction — and run
eth_estimateGasover it with their own clients, summing the results into a real gas buffer.How: this adds a new cross-version package,
@uniswap/lp-sdk(per Bruno's "one for liquidity" call in the thread; named to avoid confusion with the existingliquidity-launcher-sdk), following therouter-sdkpattern:workspace:*deps onsdk-core+v2/v3/v4-sdk, three-tsconfig tsc build,bun test, changesets. It exports:pickPreEstimateIndependentAmount(balance0, balance1)— pure port of the backend'spickPreEstimateIndependent(#7487) minus the RPC reads: caps each wallet balance at 10^(decimals + 3) raw units, returns the larger side as the independent simulation amount,nullwhen both are zero.getV3AddLiquidityGasEstimateTransactions(params)— approvals to theNonfungiblePositionManager+ the mint/increase tx viaNonfungiblePositionManager.addCallParameters(mint vs increase selected bytokenId,createPoolsupported).getV4AddLiquidityGasEstimateTransactions(params)— ERC-20 approvals to Permit2,Permit2.approvegrants to the v4 position manager, + the mint/increase tx viaV4PositionManager.addCallParameters.getV2AddLiquidityGasEstimateTransactions(params)— approvals to the v2 router +addLiquidity/addLiquidityETH.Helpers are chain-agnostic and make no network calls: they take pool/pair entities, the picked independent amount, and optional allowance state as inputs, and return
{ to, calldata, value }tuples. Omitted allowances are treated as zero, so the default output is the pessimistic (all-approvals) estimate. Position transactions reuse the existing SDK calldata builders — the same ones the backend liquidity service calls — so estimates match the transactions users actually sign.Parity notes vs the backend liquidity service
Places where the helpers intentionally differ from the backend BLs (
CreatePositionBL/CreateClassicPositionBL/IncreasePositionBLandbuildCheckedApprovalPreCalls):deadlineis used both as the new approval's expiration and as the reference time when deciding whether an existing Permit2 allowance still counts. No material gas difference.resetApprovalTokenslist; the SDK is chain-agnostic, so callers flagrequiresResetper token instead.computeEffectiveSlippage(solves the max slippage that fits the user's native balance when the 0.05% default inflatesvaluepast it) is not ported — callers can pass an explicitslippageTolerance. Slippage defaults otherwise match the backend: 2.5%, and 0.05% for native v4 pools.v2-sdk'sRouterhas no add-liquidity builder, so the helper encodesaddLiquidity/addLiquidityETHagainst the canonical V2Router02 ABI — byte-identical to the backend's etherspopulateTransactionoutput.mintAmountsWithSlippage) thatV4PositionManagermay settle; v3 compares againstmintAmounts, which is the exactamount0Desired/amount1Desiredupper bound the v3 manager pulls (v3'smintAmountsWithSlippageare lower-bound minimums, not maximums). The backend compares against the pre-slippage desired amounts in both cases — the v4 check here is intentionally stricter so a borderline allowance can't drop a required approval from the estimate.Position.fromAmount0/1and then recomputes liquidity withmaxLiquidityForAmountsover both amounts; the helpers callPosition.fromAmount0/1directly. Same math, same result.includeApprovalSimulationpreflight calls.deadline.How Has This Been Tested?
Unit tests (
bun test, 25 tests): balance-cap edge cases (both zero → null, cap at 10^(decimals+3), larger-side selection, tie → token0, native balances), approval inclusion/skipping per allowance state, approve(0) resets, Permit2 approval expiry vs deadline, native-side handling (value attached, approval skipped), mint vs increase, borderline allowances between v4's desired and slippage-maximum amounts, and byte-equality of position calldata againstNonfungiblePositionManager.addCallParameters/V4PositionManager.addCallParameters/ V2Router02 ABI encoding.bun run g:build,g:lint, andg:check:deps:mismatchpass locally.Are there any breaking changes?
No. New package only — no changes to existing SDKs.
@uniswap/lp-sdkstarts at 0.x with aminorchangeset.(Optional) Feedback Focus
@uniswap/lp-sdkundersdks/lp-sdk) — decided in the Slack thread, flagging for visibility.TokenAllowanceInput/Permit2AllowanceInput): raw allowances in, helper decides which approvals to include. Alternative was caller-computed booleans.(Optional) Follow Ups
computeEffectiveSlippagefor native v4 "Max" flows if estimate/actual drift matters there.sdks/lp-sdk/(left out to keep this PR reviewable by the default owners; needs a team decision on ownership).