Skip to content
This repository was archived by the owner on Nov 11, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 115 additions & 106 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dhedge/trading-widget",
"version": "4.4.1",
"version": "4.5.0",
"license": "MIT",
"type": "module",
"main": "dist/index.cjs",
Expand Down
19 changes: 19 additions & 0 deletions src/core-kit/abi/limit-order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ export const LimitOrderAbi = [
name: 'LimitOrderModified',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: 'address',
name: 'user',
type: 'address',
},
{
indexed: false,
internalType: 'uint256',
name: 'destTokenAmountReceived',
type: 'uint256',
},
],
name: 'SettlementOrderExecuted',
type: 'event',
},
{
inputs: [],
name: 'SLIPPAGE_DENOMINATOR',
Expand Down
6 changes: 6 additions & 0 deletions src/core-kit/const/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const TRADING_PANEL_LOG_EVENT = {
BATCH_TRANSACTIONS_CHANGE: 'batch_transactions_change',
CREATE_LIMIT_SELL_ORDER: 'create_limit_sell_order',
OPEN_LIMIT_SELL_VIEW: 'open_limit_sell_view',
LIMIT_ORDER_WITHDRAW: 'limit_order_withdraw',
LIMIT_ORDER_WITHDRAW_DELETE: 'limit_order_withdraw_delete',
}

export const LOG_EVENT_BY_TRANSACTION_ACTION_MAP: Record<
Expand All @@ -38,6 +40,10 @@ export const LOG_EVENT_BY_TRANSACTION_ACTION_MAP: Record<
claim: [TRADING_PANEL_LOG_EVENT.CLAIM],
swap: [TRADING_PANEL_LOG_EVENT.SWAP],
create_limit_sell_order: [TRADING_PANEL_LOG_EVENT.CREATE_LIMIT_SELL_ORDER],
limit_order_withdraw: [TRADING_PANEL_LOG_EVENT.LIMIT_ORDER_WITHDRAW],
delete_limit_order_withdraw: [
TRADING_PANEL_LOG_EVENT.LIMIT_ORDER_WITHDRAW_DELETE,
],
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useTradingPanelPoolConfig } from 'core-kit/hooks/state'
import { useLeveragedWithdrawalChecks } from 'trading-widget/hooks/use-leveraged-withdrawal-checks'

export const useIsLimitOrderWithdraw = () => {
const { pricingAsset, onDemandWithdrawalEnabled } =
useTradingPanelPoolConfig()
const { requiresLeveragedCollateralLiquidity } =
useLeveragedWithdrawalChecks()

return (
requiresLeveragedCollateralLiquidity &&
!!pricingAsset &&
!!onDemandWithdrawalEnabled
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AddressZero } from 'core-kit/const'
import { useTradingPanelPoolConfig } from 'core-kit/hooks/state'
import { useLimitOrderWithdrawAmount } from 'core-kit/hooks/trading/limit-order-withdraw/use-limit-order-withdraw-amount'
import { useAccount, useTokenAllowance } from 'core-kit/hooks/web3'
import { getContractAddressById } from 'core-kit/utils'

export const useIsLimitWithdrawOrderApproved = () => {
const { account = AddressZero } = useAccount()
const { address: vaultAddress, chainId } = useTradingPanelPoolConfig()
const limitOrderAddress = getContractAddressById('limitOrder', chainId)
const vaultAmount = useLimitOrderWithdrawAmount()

const { data: allowance } = useTokenAllowance({
tokenAddress: vaultAddress,
ownerAddress: account,
spenderAddress: limitOrderAddress,
chainId,
})

return allowance ? vaultAmount.lte(allowance.toString()) : false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import BigNumber from 'bignumber.js'

import { useSendTokenInput } from 'core-kit/hooks/state'

export const useLimitOrderWithdrawAmount = () => {
const [sendToken] = useSendTokenInput()

return new BigNumber(sendToken.value || '0').shiftedBy(sendToken.decimals)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useCallback } from 'react'

import {
useTradingPanelPoolConfig,
useTradingPanelTransactions,
} from 'core-kit/hooks/state'
import { useTradingSettleHandler } from 'core-kit/hooks/trading'
import { useContractFunction } from 'core-kit/hooks/web3'

const action = 'delete_limit_order_withdraw'

export const useLimitOrderWithdrawDeleteTransaction = () => {
const { address: vaultAddress, symbol, chainId } = useTradingPanelPoolConfig()
const updatePendingTransactions = useTradingPanelTransactions()[1]
const onSettled = useTradingSettleHandler(action)

const { send } = useContractFunction({
onSettled,
contractId: 'limitOrder',
functionName: 'deleteLimitOrder',
})

return useCallback(async () => {
updatePendingTransactions({
type: 'add',
action,
symbol,
chainId,
})

return send(vaultAddress)
}, [chainId, send, symbol, updatePendingTransactions, vaultAddress])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { useCallback } from 'react'

import { AddressZero, MaxUint256 } from 'core-kit/const'
import {
useTradingPanelPoolConfig,
useTradingPanelTransactions,
} from 'core-kit/hooks/state'
import { useTradingSettleHandler } from 'core-kit/hooks/trading'
import { useLimitOrderWithdrawAmount } from 'core-kit/hooks/trading/limit-order-withdraw/use-limit-order-withdraw-amount'
import { useAccount, useContractFunction } from 'core-kit/hooks/web3'
import type { UseWriteContractParameters } from 'core-kit/types/web3.types'
import { useUserLimitOrder } from 'limit-orders/hooks/use-user-limit-order'

const action = 'limit_order_withdraw'

export const useLimitOrderWithdrawTransaction = (txCallback: () => void) => {
const { account = AddressZero } = useAccount()
const {
address: vaultAddress,
chainId,
pricingAsset,
symbol,
} = useTradingPanelPoolConfig()
const updatePendingTransactions = useTradingPanelTransactions()[1]
const onTransactionSettle = useTradingSettleHandler(action)

const onSettled = useCallback<
Required<Required<UseWriteContractParameters>['mutation']>['onSettled']
>(
(...args) => {
onTransactionSettle(...args)
txCallback()
},
[onTransactionSettle, txCallback],
)

const vaultAmount = useLimitOrderWithdrawAmount()

const { data: limitOrder } = useUserLimitOrder({
userAddress: account,
vaultAddress,
chainId,
})
const isModifyTransaction = !!limitOrder
const { send } = useContractFunction({
onSettled,
contractId: 'limitOrder',
functionName: isModifyTransaction ? 'modifyLimitOrder' : 'createLimitOrder',
})

return useCallback(async () => {
updatePendingTransactions({
type: 'add',
action,
symbol,
chainId,
})

const lowerLimitPriceD18 = BigInt(0)
const upperLimitPriceD18 = MaxUint256

const args = [
BigInt(vaultAmount.toFixed()),
lowerLimitPriceD18,
upperLimitPriceD18,
account,
vaultAddress,
pricingAsset?.address,
]

return send(args)
}, [
updatePendingTransactions,
symbol,
chainId,
vaultAmount,
account,
vaultAddress,
pricingAsset?.address,
send,
])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useState } from 'react'

import { MaxUint256 } from 'core-kit/const'
import {
useTradingPanelPoolConfig,
useTradingPanelTransactions,
} from 'core-kit/hooks/state'
import { useTradingSettleHandler } from 'core-kit/hooks/trading'
import { useContractFunction } from 'core-kit/hooks/web3'
import { getContractAddressById } from 'core-kit/utils'

const action = 'approve'

export const useLimitWithdrawApproveTransaction = () => {
const { address: vaultAddress, chainId, symbol } = useTradingPanelPoolConfig()
const [isLoading, setIsLoading] = useState(false)
const limitOrderAddress = getContractAddressById('limitOrder', chainId)
const updatePendingTransactions = useTradingPanelTransactions()[1]
const onApproveSettled = useTradingSettleHandler(action)

const { send } = useContractFunction({
contractId: 'erc20',
dynamicContractAddress: vaultAddress,
functionName: 'approve',
onSettled(...args) {
setIsLoading(false)
onApproveSettled(...args)
},
})

const approveLimitOrder = async () => {
updatePendingTransactions({
type: 'add',
action,
symbol,
chainId,
})

setIsLoading(true)
send(limitOrderAddress, MaxUint256)
}

return {
approveLimitOrder,
isApprovePending: isLoading,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useMemo } from 'react'

import { AddressZero, DEFAULT_PRECISION, MaxUint256 } from 'core-kit/const'
import { useTradingPanelPoolConfig } from 'core-kit/hooks/state'
import { useAccount } from 'core-kit/hooks/web3'
import { formatUnits } from 'core-kit/utils'
import { useUserLimitOrder } from 'limit-orders/hooks/use-user-limit-order'

export const usePendingLimitOrderWithdraw = () => {
const { account = AddressZero } = useAccount()
const { address: vaultAddress, chainId } = useTradingPanelPoolConfig()
const { data: limitOrder } = useUserLimitOrder({
userAddress: account,
vaultAddress,
chainId,
})

return useMemo(() => {
const hasPendingLimitOrderWithdraw =
!!limitOrder &&
limitOrder.stopLossPriceD18 === BigInt(0) &&
limitOrder.takeProfitPriceD18 === MaxUint256

const pendingLimitOrderWithdrawAmount = hasPendingLimitOrderWithdraw
? formatUnits(limitOrder.amountD18, DEFAULT_PRECISION)
: '0'

return {
hasPendingLimitOrderWithdraw,
pendingLimitOrderWithdrawAmount,
}
}, [limitOrder])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
useOnTransactionEstimationError,
useSendTokenInput,
useTradingPanelModal,
useTradingPanelPoolConfig,
useTradingPanelTransactions,
} from 'core-kit/hooks/state'
import { useAccount } from 'core-kit/hooks/web3'
import { EstimationError } from 'core-kit/models'
import type { ContractActionFunc } from 'core-kit/types/web3.types'
import { useOverlayDispatchContext } from 'trading-widget/providers/overlay-provider'
import { useTranslationContext } from 'trading-widget/providers/translation-provider'
import { OVERLAY } from 'trading-widget/types'

interface UseHandleLimitOrderWithdrawProps {
limitOrderHandler: ContractActionFunc
action: 'limit_order_withdraw' | 'delete_limit_order_withdraw'
}

export const useHandleLimitOrderWithdraw = ({
limitOrderHandler,
action,
}: UseHandleLimitOrderWithdrawProps) => {
const t = useTranslationContext()
const dispatch = useOverlayDispatchContext()
const { account } = useAccount()
const poolConfig = useTradingPanelPoolConfig()
const [sendToken] = useSendTokenInput()
const updateTradingModal = useTradingPanelModal()[1]
const updatePendingTransactions = useTradingPanelTransactions()[1]
const onTransactionEstimationError = useOnTransactionEstimationError()
const isDeleteAction = action === 'delete_limit_order_withdraw'

const handleLimitOrderWithdraw = async () => {
const chainId = poolConfig.chainId

updateTradingModal({
isOpen: true,
status: 'Wallet',
action,
link: '',
sendTokens: isDeleteAction ? [] : [sendToken],
receiveTokens: null,
meta: {},
})

try {
await limitOrderHandler()
} catch (error) {
if (error instanceof EstimationError) {
dispatch({
type: 'MERGE_OVERLAY',
payload: {
type: OVERLAY.ERROR_NOTIFICATION,
isOpen: true,
meta: {
error: error.message,
},
},
})

onTransactionEstimationError?.(
error,
poolConfig.address,
chainId,
account,
)
}
updateTradingModal({
isOpen: false,
status: 'None',
link: '',
sendTokens: null,
receiveTokens: null,
meta: {},
})
updatePendingTransactions({ type: 'remove', status: 'fail' })
}
}

return {
label: isDeleteAction ? t.delete : t.withdrawAction,
handleLimitOrderWithdraw,
}
}
Loading