Skip to content

Commit

Permalink
Merge pull request #70 from dhedge/fix/deposit-slippage
Browse files Browse the repository at this point in the history
fix: apply correct manual slippage during depositing
  • Loading branch information
dimlbc authored Aug 1, 2024
2 parents cca4924 + 0d0799e commit 0640007
Show file tree
Hide file tree
Showing 23 changed files with 413 additions and 359 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ UI configuration provider. Manages params to configure custom styling, component
> | `isSanctioned` | `boolean` | `false` | Restricts depositing action button and conditionally renders SanctionedAlert component |
> | `depositQuoteDiffWarningThreshold` | `number` | `1` | Deposit slippage absolute percent value warning threshold, Affects styling to warn user |
> | `depositQuoteDiffErrorThreshold` | `number` | `3` | Deposit slippage absolute percent value error threshold, Affects styling to warn user |
> | `defaultDepositSlippage` | `number` | `0` | Initial deposit slippage absolute percent. Further adjustments are available in panel settings |
> | `defaultDepositSlippageScale` | `number[]` | `[0]` | Initial deposit slippage absolute percent. Further adjustments are available in panel settings |
> | `defaultWithdrawSlippageScale` | `number[]` | `[0.1, 0.3, 0.5, 1, 1.5, 3]` | Initial withdraw slippage absolute percent. Further adjustments are available in panel settings |
> | `defaultLockTime` | `string` | `'24 hours'` | Formatted default deposit lock time to be displayed in panel (Long lockup period is used to bypass entry fee and can be managed in panel settings) |
> | `customLockTime` | `string` | `'15 minutes'` | Formatted custom deposit lock time alternative to be displayed in panel |
Expand Down
2 changes: 1 addition & 1 deletion packages/trading-widget/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dhedge/trading-widget",
"version": "1.2.1",
"version": "1.2.2",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { useDepositQuote } from './use-deposit-quote'
export { usePoolDepositAssetAddress } from './use-pool-deposit-asset-address'
export { usePoolDepositTokens } from './use-pool-deposit-tokens'
export { useHandlePoolDepositData } from './use-handle-pool-deposit-data'
export { useDepositTradingParams } from './use-deposit-trading-params'
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import BigNumber from 'bignumber.js'
import { beforeEach } from 'vitest'

import { DEFAULT_PRECISION, optimism } from 'core-kit/const'
import { usePoolTokenPrice } from 'core-kit/hooks/pool'
import * as stateHooks from 'core-kit/hooks/state'
import * as tradingDepositHooks from 'core-kit/hooks/trading/deposit'

import { useAssetPrice } from 'core-kit/hooks/trading/use-asset-price'
import type { TradingToken } from 'core-kit/types'
import { TEST_ADDRESS } from 'tests/mocks'
import { renderHook } from 'tests/test-utils'

import { useDepositTradingParams } from './use-deposit-trading-params'

vi.mock('core-kit/hooks/state', async () => {
const actual = await vi.importActual<Record<string, unknown>>(
'core-kit/hooks/state',
)
return {
...actual,
useReceiveTokenInput: vi.fn(),
useSendTokenInput: vi.fn(),
useTradingPanelPoolConfig: vi.fn(),
useTradingPanelSettings: vi.fn(),
}
})

vi.mock('core-kit/hooks/trading/deposit', () => ({
usePoolDepositAssetAddress: vi.fn(),
}))

vi.mock('core-kit/hooks/pool', () => ({
usePoolTokenPrice: vi.fn(),
}))
vi.mock('core-kit/hooks/trading/use-asset-price', () => ({
useAssetPrice: vi.fn(),
}))

const poolConfig = {
address: TEST_ADDRESS,
chainId: optimism.id,
withdrawParams: {
customTokens: [
{
address: TEST_ADDRESS,
method: 'withdraw',
intermediateToken: {
address: TEST_ADDRESS,
symbol: 'symbol',
value: '1',
decimals: DEFAULT_PRECISION,
},
},
],
},
}
const sendToken: TradingToken = {
address: TEST_ADDRESS,
symbol: 'send_symbol',
value: '1',
decimals: DEFAULT_PRECISION,
}
const receiveToken: TradingToken = {
address: TEST_ADDRESS,
symbol: 'receive_symbol',
value: '1',
decimals: DEFAULT_PRECISION,
}
const poolDepositAssetAddress = TEST_ADDRESS

describe('useDepositTradingParams', () => {
beforeEach(() => {
vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue(
poolConfig as ReturnType<typeof stateHooks.useTradingPanelPoolConfig>,
)
vi.mocked(stateHooks.useSendTokenInput).mockReturnValue([
sendToken,
vi.fn(),
] as ReturnType<typeof stateHooks.useSendTokenInput>)
vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValue([
receiveToken,
vi.fn(),
] as ReturnType<typeof stateHooks.useReceiveTokenInput>)
vi.mocked(tradingDepositHooks.usePoolDepositAssetAddress).mockReturnValue(
poolDepositAssetAddress,
)
vi.mocked(stateHooks.useTradingPanelSettings).mockReturnValue([
{ slippage: 'auto' },
] as unknown as ReturnType<typeof stateHooks.useTradingPanelSettings>)
})

it('should get receiveAssetAddress from receiveToken.address for depositing', () => {
const { result } = renderHook(() => useDepositTradingParams())

expect(result.current.receiveAssetAddress).toEqual(receiveToken.address)
})

it('should get poolDepositAddress from usePoolDepositAssetAddress', () => {
const { result } = renderHook(() => useDepositTradingParams())

expect(result.current.poolDepositAddress).toEqual(poolDepositAssetAddress)
})

it('should calculate receiveAssetAmount correctly when slippage is auto', () => {
const { result } = renderHook(() => useDepositTradingParams())

expect(result.current.receiveAssetAmount).toEqual(receiveToken.value)
})

it('should calculate receiveAssetAmount correctly when slippage is manual', () => {
vi.mocked(stateHooks.useTradingPanelSettings).mockReturnValue([
{ slippage: 0.1 },
] as unknown as ReturnType<typeof stateHooks.useTradingPanelSettings>)

vi.mocked(usePoolTokenPrice).mockReturnValue('1')
vi.mocked(useAssetPrice).mockReturnValue('10')

const { result } = renderHook(() => useDepositTradingParams())

expect(usePoolTokenPrice).toHaveBeenCalledWith({
address: TEST_ADDRESS,
chainId: optimism.id,
disabled: false,
})
expect(useAssetPrice).toHaveBeenCalledWith({
address: TEST_ADDRESS,
chainId: optimism.id,
disabled: false,
})
expect(result.current.receiveAssetAmount).toEqual(
new BigNumber(sendToken.value)
.multipliedBy('10')
.dividedBy('1')
.toFixed(),
)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import BigNumber from 'bignumber.js'
import { useMemo } from 'react'

import { usePoolTokenPrice } from 'core-kit/hooks/pool'
import {
useReceiveTokenInput,
useSendTokenInput,
useTradingPanelPoolConfig,
useTradingPanelSettings,
} from 'core-kit/hooks/state'
import { usePoolDepositAssetAddress } from 'core-kit/hooks/trading/deposit'
import { useAssetPrice } from 'core-kit/hooks/trading/use-asset-price'
import type { TradingParams } from 'core-kit/types/trading.types'

export const useDepositTradingParams = (): TradingParams => {
const { address, chainId } = useTradingPanelPoolConfig()
const [{ slippage }] = useTradingPanelSettings()
const isAutoSlippage = slippage === 'auto'

const [sendToken] = useSendTokenInput()
const sendTokenPrice =
useAssetPrice({
address: sendToken.address,
chainId,
disabled: isAutoSlippage,
}) ?? ''

const [receiveToken] = useReceiveTokenInput()
const receiveAssetAddress = receiveToken.address
const receiveAssetPrice =
usePoolTokenPrice({ address, chainId, disabled: isAutoSlippage }) ?? ''

const poolDepositAssetAddress = usePoolDepositAssetAddress({
investAssetAddress: sendToken.address,
symbol: sendToken.symbol,
productPoolAddress: address,
chainId,
})
const manualSlippageReceiveAssetAmount = new BigNumber(sendToken.value || '0')
.multipliedBy(sendTokenPrice)
.dividedBy(receiveAssetPrice)
.toFixed()
const receiveAssetAmount = isAutoSlippage
? receiveToken.value
: manualSlippageReceiveAssetAmount

return useMemo<TradingParams>(
() => ({
sendAssetAddress: sendToken.address,
fromTokenAmount: new BigNumber(sendToken.value || '0'),
receiveAssetAddress,
receiveAssetAmount,
poolDepositAddress: poolDepositAssetAddress,
}),
[
sendToken.address,
sendToken.value,
receiveAssetAddress,
receiveAssetAmount,
poolDepositAssetAddress,
],
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import {
import * as stateHooks from 'core-kit/hooks/state'

import {
useTradingParams,
useIsEasySwapperTrading,
useTradingSettleHandler,
} from 'core-kit/hooks/trading'
import { useDepositSlippage } from 'core-kit/hooks/trading/deposit'
import {
useDepositSlippage,
useDepositTradingParams,
} from 'core-kit/hooks/trading/deposit'
import { useContractFunction } from 'core-kit/hooks/web3'
import type { Address, DynamicTradingToken } from 'core-kit/types'
import { renderHook } from 'tests/test-utils'
Expand All @@ -38,9 +41,11 @@ vi.mock('core-kit/hooks/state', () => ({
vi.mock('core-kit/hooks/trading', () => ({
useTradingSettleHandler: vi.fn(),
useTradingParams: vi.fn(),
useIsEasySwapperTrading: vi.fn(),
}))
vi.mock('core-kit/hooks/trading/deposit', () => ({
useDepositSlippage: vi.fn(),
useDepositTradingParams: vi.fn(),
}))
vi.mock('core-kit/hooks/web3', () => ({
useContractFunction: vi.fn(),
Expand Down Expand Up @@ -88,6 +93,7 @@ describe('useDeposit', () => {
typeof configProviderHooks.useConfigContextParams
>,
)
vi.mocked(useIsEasySwapperTrading).mockReturnValue(true)
})

afterEach(() => {
Expand All @@ -107,7 +113,7 @@ describe('useDeposit', () => {
poolDepositAddress: '0x111' as Address,
receiveAssetAddress: receiveToken.address,
sendAssetAddress: sendToken.address,
receiveAssetInputValue: receiveToken.value,
receiveAssetAmount: receiveToken.value,
fromTokenAmount: new BigNumber(sendToken.value),
}
vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation(
Expand All @@ -130,13 +136,13 @@ describe('useDeposit', () => {
vi.fn,
] as unknown as ReturnType<typeof stateHooks.useTradingPanelSettings>,
)
vi.mocked(useTradingParams).mockImplementation(() => tradingParams)
vi.mocked(useDepositTradingParams).mockImplementation(() => tradingParams)

const { result } = renderHook(() => useDeposit())

expect(useDepositSlippage).toHaveBeenCalledTimes(1)
expect(useDepositSlippage).toHaveBeenCalledWith(
tradingParams.receiveAssetInputValue,
tradingParams.receiveAssetAmount,
)
expect(useTradingSettleHandler).toHaveBeenCalledTimes(1)
expect(useTradingSettleHandler).toHaveBeenCalledWith('deposit')
Expand Down Expand Up @@ -182,7 +188,7 @@ describe('useDeposit', () => {
poolDepositAddress: BRIDGED_USDC_OPTIMISM.address,
receiveAssetAddress: receiveToken.address,
sendAssetAddress: sendToken.address,
receiveAssetInputValue: receiveToken.value,
receiveAssetAmount: receiveToken.value,
fromTokenAmount: new BigNumber(sendToken.value),
}
vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation(
Expand All @@ -205,13 +211,13 @@ describe('useDeposit', () => {
vi.fn,
] as unknown as ReturnType<typeof stateHooks.useTradingPanelSettings>,
)
vi.mocked(useTradingParams).mockImplementation(() => tradingParams)
vi.mocked(useDepositTradingParams).mockImplementation(() => tradingParams)

const { result } = renderHook(() => useDeposit())

expect(useDepositSlippage).toHaveBeenCalledTimes(1)
expect(useDepositSlippage).toHaveBeenCalledWith(
tradingParams.receiveAssetInputValue,
tradingParams.receiveAssetAmount,
)
expect(useTradingSettleHandler).toHaveBeenCalledTimes(1)
expect(useTradingSettleHandler).toHaveBeenCalledWith('deposit')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useMemo } from 'react'

import { DEFAULT_DEPOSIT_SLIPPAGE } from 'core-kit/const'
import {
useReceiveTokenInput,
useSendTokenInput,
Expand All @@ -9,10 +10,13 @@ import {
useTradingPanelTransactions,
} from 'core-kit/hooks/state'
import {
useTradingParams,
useIsEasySwapperTrading,
useTradingSettleHandler,
} from 'core-kit/hooks/trading'
import { useDepositSlippage } from 'core-kit/hooks/trading/deposit'
import {
useDepositSlippage,
useDepositTradingParams,
} from 'core-kit/hooks/trading/deposit'
import { useContractFunction } from 'core-kit/hooks/web3'

import {
Expand All @@ -27,10 +31,6 @@ import {
logTransactionArguments,
} from 'core-kit/utils'

import { useConfigContextParams } from 'trading-widget/providers/config-provider'

import { useIsEasySwapperTrading } from '../use-is-easy-swapper-trading'

const action = 'deposit'

export const useDeposit = (): ContractActionFunc => {
Expand All @@ -45,12 +45,11 @@ export const useDeposit = (): ContractActionFunc => {
poolDepositAddress,
receiveAssetAddress,
sendAssetAddress,
receiveAssetInputValue,
receiveAssetAmount,
fromTokenAmount,
} = useTradingParams()
const { defaultDepositSlippage } = useConfigContextParams()
} = useDepositTradingParams()

useDepositSlippage(receiveAssetInputValue)
useDepositSlippage(receiveAssetAmount)

const isDepositNative =
poolConfig.chainId && isEasySwapperDeposit
Expand All @@ -69,7 +68,7 @@ export const useDeposit = (): ContractActionFunc => {
receiveAssetAddress,
fromTokenAmount: fromTokenAmount.shiftedBy(sendToken.decimals).toFixed(0),
poolDepositAddress: depositAddress,
receiveAssetInputValue,
receiveAssetInputValue: receiveAssetAmount,
}

if (!isEasySwapperDeposit) {
Expand All @@ -93,7 +92,7 @@ export const useDeposit = (): ContractActionFunc => {
isEasySwapperDeposit,
poolDepositAddress,
receiveAssetAddress,
receiveAssetInputValue,
receiveAssetAmount,
sendAssetAddress,
sendToken.decimals,
])
Expand All @@ -117,7 +116,7 @@ export const useDeposit = (): ContractActionFunc => {
logTransactionArguments(txArgs)
const args: unknown[] = getOrderedTxArgs(
txArgs,
slippage === 'auto' ? defaultDepositSlippage : slippage,
slippage === 'auto' ? DEFAULT_DEPOSIT_SLIPPAGE : slippage,
)
if (isDepositNative) {
args.push({ value: BigInt(txArgs.fromTokenAmount) })
Expand All @@ -131,6 +130,5 @@ export const useDeposit = (): ContractActionFunc => {
send,
txArgs,
slippage,
defaultDepositSlippage,
])
}
Loading

0 comments on commit 0640007

Please sign in to comment.