Skip to content

Commit

Permalink
fix: proportional slippage (#424)
Browse files Browse the repository at this point in the history
* fix: proportional slippage

* use proper slippage in useAddLiquiditySteps

* fix: use defaultProportionalSlippagePercentage var

* fix: bufferPercentage prop calculation

* fix: add default 0.01 slippage for proportional adds

* fix: change default slippage for boosted proportional adds

* chore: Update conditional

---------

Co-authored-by: Gareth Fuller <[email protected]>
  • Loading branch information
agualis and garethfuller authored Jan 15, 2025
1 parent f003816 commit 3b59129
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { useModalWithPoolRedirect } from '../../useModalWithPoolRedirect'
import { getPoolActionableTokens, isV3NotSupportingWethIsEth } from '../../pool.helpers'
import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsProvider'
import { isUnbalancedAddErrorMessage } from '@repo/lib/shared/utils/error-filters'
import { getDefaultProportionalSlippagePercentage } from '@repo/lib/shared/utils/slippage'
import { ApiToken } from '@repo/lib/modules/tokens/token.types'

export type UseAddLiquidityResponse = ReturnType<typeof _useAddLiquidity>
Expand All @@ -45,11 +46,17 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
const [acceptPoolRisks, setAcceptPoolRisks] = useState(false)
const [wethIsEth, setWethIsEth] = useState(false)
const [totalUSDValue, setTotalUSDValue] = useState('0')
// Used when the user explicitly choses proportional input mode
const [wantsProportional, setWantsProportional] = useState(false)
const [proportionalSlippage, setProportionalSlippage] = useState<string>('0')

const { pool, refetch: refetchPool, isLoading } = usePool()

/* wantsProportional is true when:
- the pool requires proportional input
- the user selected the proportional tab
*/
const [wantsProportional, setWantsProportional] = useState(requiresProportionalInput(pool))
const [proportionalSlippage, setProportionalSlippage] = useState<string>(
getDefaultProportionalSlippagePercentage(pool)
)

const { getNativeAssetToken, getWrappedNativeAssetToken, isLoadingTokenPrices } = useTokens()
const { isConnected } = useUserAccount()
const { hasValidationErrors } = useTokenInputsValidation()
Expand All @@ -68,8 +75,7 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
const chain = pool.chain
const nativeAsset = getNativeAssetToken(chain)
const wNativeAsset = getWrappedNativeAssetToken(chain)
const isForcedProportionalAdd = requiresProportionalInput(pool)
const slippage = isForcedProportionalAdd ? proportionalSlippage : userSlippage
const slippage = wantsProportional ? proportionalSlippage : userSlippage
const tokens = getPoolActionableTokens(pool)

function setInitialHumanAmountsIn() {
Expand Down Expand Up @@ -156,7 +162,7 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
const hasQuoteContext = !!simulationQuery.data

async function refetchQuote() {
if (isForcedProportionalAdd) {
if (wantsProportional) {
/*
This is the only edge-case where the SDK needs pool onchain data from the frontend
(calculateProportionalAmounts uses pool.dynamicData.totalShares in its parameters)
Expand Down Expand Up @@ -221,8 +227,6 @@ export function _useAddLiquidity(urlTxHash?: Hash) {
hasQuoteContext,
addLiquidityTxSuccess,
slippage,
proportionalSlippage,
isForcedProportionalAdd,
wantsProportional,
referenceAmountAddress,
setWantsProportional,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ import { ApiToken } from '@repo/lib/modules/tokens/token.types'

// small wrapper to prevent out of context error
export function AddLiquidityForm() {
const { validTokens, proportionalSlippage } = useAddLiquidity()
const { validTokens, slippage, wantsProportional } = useAddLiquidity()

const bufferPercentage = wantsProportional ? slippage : '0'

return (
<TokenBalancesProvider bufferPercentage={proportionalSlippage} extTokens={validTokens}>
<TokenBalancesProvider bufferPercentage={bufferPercentage} extTokens={validTokens}>
<AddLiquidityMainForm />
</TokenBalancesProvider>
)
Expand All @@ -87,7 +89,6 @@ function AddLiquidityMainForm() {
nativeAsset,
wNativeAsset,
previewModalDisclosure,
proportionalSlippage,
slippage,
setProportionalSlippage,
setWantsProportional,
Expand Down Expand Up @@ -192,11 +193,12 @@ function AddLiquidityMainForm() {
<CardHeader>
<HStack justify="space-between" w="full">
<span>Add liquidity</span>
{requiresProportionalInput(pool) || wantsProportional ? (
{wantsProportional ? (
<ProportionalTransactionSettings
pool={pool}
setSlippage={setProportionalSlippage}
size="sm"
slippage={proportionalSlippage}
slippage={slippage}
/>
) : (
<TransactionSettings size="sm" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class ProportionalBoostedAddLiquidityV3 implements AddLiquidityHandler {
...constructBaseBuildCallInput({
humanAmountsIn,
sdkQueryOutput: queryOutput.sdkQueryOutput,
slippagePercent: slippagePercent,
slippagePercent,
pool: this.helpers.pool,
}),
protocolVersion: 3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TwammAddLiquidityHandler } from './TwammAddLiquidity.handler'
import { UnbalancedAddLiquidityV2Handler } from './UnbalancedAddLiquidityV2.handler'
import { AddLiquidityHandler } from './AddLiquidity.handler'
import { NestedAddLiquidityV2Handler } from './NestedAddLiquidityV2.handler'
import { requiresProportionalInput, supportsNestedActions } from '../../LiquidityActionHelpers'
import { supportsNestedActions } from '../../LiquidityActionHelpers'
import { ProportionalAddLiquidityHandler } from './ProportionalAddLiquidity.handler'
import { isBoosted, isV3Pool } from '../../../pool.helpers'
import { ProportionalAddLiquidityHandlerV3 } from './ProportionalAddLiquidityV3.handler'
Expand Down Expand Up @@ -41,7 +41,7 @@ export function selectAddLiquidityHandler(
return new BoostedUnbalancedAddLiquidityV3Handler(pool)
}

if (requiresProportionalInput(pool) || wantsProportional) {
if (wantsProportional) {
if (isV3Pool(pool)) {
return new ProportionalAddLiquidityHandlerV3(pool)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useRelayerMode } from '@repo/lib/modules/relayer/useRelayerMode'
import { useTokenApprovalSteps } from '@repo/lib/modules/tokens/approvals/useTokenApprovalSteps'
import { getSpenderForAddLiquidity } from '@repo/lib/modules/tokens/token.helpers'
import { useSignRelayerStep } from '@repo/lib/modules/transactions/transaction-steps/useSignRelayerStep'
import { useUserSettings } from '@repo/lib/modules/user/settings/UserSettingsProvider'
import { useMemo } from 'react'
import { usePool } from '../../PoolProvider'
import { requiresPermit2Approval } from '../../pool.helpers'
Expand All @@ -24,10 +23,10 @@ export function useAddLiquiditySteps({
handler,
humanAmountsIn,
simulationQuery,
slippage,
}: AddLiquidityStepsParams) {
const { pool, chainId, chain } = usePool()
const shouldBatchTransactions = useShouldBatchTransactions(pool)
const { slippage } = useUserSettings()
const relayerMode = useRelayerMode(pool)
const shouldSignRelayerApproval = useShouldSignRelayerApproval(chainId, relayerMode)

Expand Down
11 changes: 9 additions & 2 deletions packages/lib/modules/user/settings/TransactionSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { fNum } from '@repo/lib/shared/utils/numbers'
import { AlertTriangle, Settings } from 'react-feather'
import { CurrencySelect } from './CurrencySelect'
import { SlippageInput } from './UserSettings'
import { getDefaultProportionalSlippagePercentage } from '@repo/lib/shared/utils/slippage'
import { Pool } from '../../pool/PoolProvider'

export function TransactionSettings(props: ButtonProps) {
const { slippage, setSlippage } = useUserSettings()
Expand Down Expand Up @@ -62,15 +64,19 @@ export function TransactionSettings(props: ButtonProps) {
interface ProportionalTransactionSettingsProps extends ButtonProps {
slippage: string
setSlippage: (value: string) => void
pool: Pool
}

export function ProportionalTransactionSettings({
slippage,
setSlippage,
pool,
...props
}: ProportionalTransactionSettingsProps) {
const { isOpen, onOpen, onClose } = useDisclosure()

const defaultProportionalSlippagePercentage = getDefaultProportionalSlippagePercentage(pool)

return (
<Popover isLazy isOpen={isOpen} onClose={onClose} placement="bottom-end">
<PopoverTrigger>
Expand Down Expand Up @@ -104,8 +110,9 @@ export function ProportionalTransactionSettings({
<PopoverArrow />
<PopoverBody>
<Text fontSize="sm" fontWeight="500" lineHeight="18px" variant="secondary">
Slippage is set to 0 by default for forced proportional actions to reduce
dust left over. If you need to set slippage higher than 0 it will
Slippage is set to {defaultProportionalSlippagePercentage} by default for
forced proportional actions to reduce dust left over. If you need to set
slippage higher than {defaultProportionalSlippagePercentage} it will
effectively lower the amount of tokens you can add in the form below. Then,
if slippage occurs, the transaction can take the amount of tokens you
specified + slippage from your token balance.
Expand Down
15 changes: 15 additions & 0 deletions packages/lib/shared/utils/slippage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import { HumanAmount } from '@balancer/sdk'
import { bn, fNum } from './numbers'
import { Pool } from '@repo/lib/modules/pool/PoolProvider'

export function getDefaultProportionalSlippagePercentage(pool: Pool) {
/*
We use this small slippage percentage by default for boosted proportional adds because SDK addLiquidityBoosted queries are not 100% precise.
The error is ~1000 wei, which is negligible on 18 decimal tokens but not as much on 6 decimals tokens (this is a SC limitation).
Using 0.01% is big enough to prevent tx simulation errors in all types of boosted proportional adds while keeping the dust amount small.
*/
const defaultBoostedProportionalSlippagePercentage = '0.01'
const defaultProportionalSlippagePercentage = '0'

return pool.hasErc4626 || pool.hasNestedErc4626
? defaultBoostedProportionalSlippagePercentage
: defaultProportionalSlippagePercentage
}

export function slippageDiffLabel(actualAmount: HumanAmount, expectedAmount: HumanAmount) {
if (!expectedAmount) return ''
Expand Down

0 comments on commit 3b59129

Please sign in to comment.