diff --git a/README.md b/README.md index a6e3a23..9f2145c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ import { TradingPanelProvider, TradingWidget } from '@dhedge/trading-widget'; - Setup [Wagmi Provider](https://wagmi.sh/react/api/WagmiProvider) on top level or use existing one in your app - Setup [TradingPanelProvider](#tradingpanelprovider) + #### Providing a `getSwapData` callback is mandatory for depositing with off-chain swaps. - Setup [TradingWidget](#tradingwidget) 3. Minimum required config @@ -52,23 +53,22 @@ Top level provider component. Headless part of trading logic. API handles params
actions / Optional General callbacks to interact with 3rd party services -> | name | type | default value | description | -> |-----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|-----------------------------------------------------------------------------------| -> | `onUpdatePoolConfigDepositMethod` | (payload: { address: `Address`; method: `'deposit' \| 'depositWithCustomCooldown'` }) => void | undefined | triggers on deposit method change | -> | `onUpdateSendTokenInput` | (payload: Partial\<{ address: `Address`; symbol: `string`; value: `string`; decimals: `number`; isLoading?: `boolean` }\>) => void | undefined | triggers on send token change | -> | `onUpdateTradingSettings` | (payload: Partial\<{ slippage: `number \| 'auto'`; minSlippage?: `number` isInfiniteAllowance: `boolean`; isMultiAssetWithdrawalEnabled: `boolean`; isMaxSlippageLoading: `boolean` }\>) => void | undefined | triggers on trading settings change | -> | `onSetTradingType` | (payload: `'deposit' \| 'withdraw'`) => void | undefined | triggers on trading type change | -> | `onUpdateTradingMeta` | (payload: Partial\<{ approvingStatus: `'pending' \| 'success'` }\>) => void | undefined | triggers on trading meta change | -> | `onUpdateTradingModal` | (payload: Partial\<{ isOpen: `boolean`; status: `'Success' \| 'None' \| 'Mining' \| 'Wallet'` }\>) => void | undefined | triggers on trading modal change | -> | `onUpdateTransactions` | (payload: AddTransaction \| UpdateTransaction \| RemoveTransaction) => void | undefined | triggers on transaction action change | -> | `onUpdateEntryFee` | (payload: Partial\\>) => void | undefined | triggers on transaction action change | -> | `onTradingSettleError` | (error: `Error`) => void | undefined | triggers on trading settle error | -> | `onTransactionError` | (error: `Error`, action: `TransactionAction` \| `undefined`, chainId?: `ChainId`, txHash?: `Address`) => void | undefined | triggers on transaction error | -> | `onTransactionSuccess` | (data: `WaitForTransactionReceiptReturnType`, action: `TransactionAction` \| `undefined`, link?: `string`) => void | undefined | triggers on transaction success | -> | `onTransactionEstimationError` | (error: `EstimationError`, address: `Address`, chainId?: `ChainId`, account?: `Address`) => void | undefined | triggers on transaction estimation error | -> | `onTokenSelector` | (payload: { isOpen: `boolean`; entity: `'token' \| 'pool'` }) => void | undefined | triggers on token selector change | -> | `onLog` | (eventName: `string`, payload?: `Record`) => void | undefined | triggers on log event | -> | `onSimulateTransaction` | (payload: { chainId: `ChainId`; from: `Address`: to: `Address`; input: `string`; gas: `number`; value?: `string` }) => Promise<{ link?: `string`; simulation: { status: `boolean`; error_message: `string` } } \| null> | undefined | triggers to simulate transaction and get error details after failed tx estimation | +> | name | type | default value | description | +> |---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|------------------------------------------------------------------------------------| +> | `onUpdateSendTokenInput` | (payload: Partial\<{ address: `Address`; symbol: `string`; value: `string`; decimals: `number`; isLoading?: `boolean` }\>) => void | undefined | triggers on send token change | +> | `onUpdateTradingSettings` | (payload: Partial\<{ slippage: `number \| 'auto'`; minSlippage?: `number` isInfiniteAllowance: `boolean`; isMultiAssetWithdrawalEnabled: `boolean`; isMaxSlippageLoading: `boolean` }\>) => void | undefined | triggers on trading settings change | +> | `onSetTradingType` | (payload: `'deposit' \| 'withdraw'`) => void | undefined | triggers on trading type change | +> | `onUpdateTradingMeta` | (payload: Partial\<{ approvingStatus: `'pending' \| 'success'` }\>) => void | undefined | triggers on trading meta change | +> | `onUpdateTradingModal` | (payload: Partial\<{ isOpen: `boolean`; status: `'Success' \| 'None' \| 'Mining' \| 'Wallet'` }\>) => void | undefined | triggers on trading modal change | +> | `onUpdateTransactions` | (payload: AddTransaction \| UpdateTransaction \| RemoveTransaction) => void | undefined | triggers on transaction action change | +> | `onTradingSettleError` | (error: `Error`) => void | undefined | triggers on trading settle error | +> | `onTransactionError` | (error: `Error`, action: `TransactionAction` \| `undefined`, chainId?: `ChainId`, txHash?: `Address`) => void | undefined | triggers on transaction error | +> | `onTransactionSuccess` | (data: `WaitForTransactionReceiptReturnType`, action: `TransactionAction` \| `undefined`, link?: `string`) => void | undefined | triggers on transaction success | +> | `onTransactionEstimationError` | (error: `EstimationError`, address: `Address`, chainId?: `ChainId`, account?: `Address`) => void | undefined | triggers on transaction estimation error | +> | `onTokenSelector` | (payload: { isOpen: `boolean`; entity: `'token' \| 'pool'` }) => void | undefined | triggers on token selector change | +> | `onLog` | (eventName: `string`, payload?: `Record`) => void | undefined | triggers on log event | +> | `onSimulateTransaction` | (payload: { chainId: `ChainId`; from: `Address`: to: `Address`; input: `string`; gas: `number`; value?: `string` }) => Promise<{ link?: `string`; simulation: { status: `boolean`; error_message: `string` } } \| null> | undefined | triggers to simulate transaction and get error details after failed tx estimation | +> | `getSwapData` | ({ signal: `AbortSignal`, variables: { chainId: `number`; sourceAddress: `Address`; destinationAddress: `Address`; walletAddress: `Address`; fromAddress: `Address`; amount: `string`; slippage: `string` } }) => Promise<{ destinationAmount: `string`; txData: `string` ; routerKey: `'ONE_INCH' / 'ONE_INCH_V5' / 'ZERO_X' / 'PARASWAP'` } } \| null> | undefined | provides off chain swap data based on send token value | ###### Source: `packages/trading-widget/src/core-kit/providers/index.tsx` ###### Default values: `undefined` @@ -106,21 +106,23 @@ UI configuration provider. Manages params to configure custom styling, component ##### params -> | name | type | default value | description | -> |-------------------------------------|-----------------------------------------------------------------|-------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| -> | `isGeoBlocked` | `boolean` | `false` | Restricts depositing action button and conditionally renders GeoBlockAlert 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 | -> | `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 for PoolLogic abi trading methods and can be managed in panel settings) | -> | `chainCustomLockTimeMap` | `Record` | `{ [chainId]: '60 minutes' }` | Formatted custom deposit lock time per chain for EasySwapper abi trading methods to be displayed in panel | -> | `stablePrecision` | `number` | `3` | Number of decimals to be displayed in stables (e.g USDC balance) | -> | `defaultPrecision` | `number` | `6` | Number of decimals to be displayed in token values | -> | `stakingChainId` | `number` | `10` (Optimism) | ChainId to be used in staking logic | -> | `termsOfUseAccepted` | `boolean` | `true` | Requires user to confirm terms of use by rendering DepositTermsOfUse component before deposit action | -> | `standalone` | `boolean` | `true` | Handles token selection in SPA mode | -> | `chainConfig` | `Partial>` | `{}` | Sets map of chain `name` and `iconPath` | +> | name | type | default value | description | +> |----------------------------------------|----------------------------------------------------------------|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| +> | `isGeoBlocked` | `boolean` | `false` | Restricts depositing action button and conditionally renders GeoBlockAlert 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 | +> | `defaultWithdrawSlippageScale` | `number[]` | `[0.1, 0.3, 0.5, 1, 1.5, 3]` | Initial withdraw slippage absolute percent. Further adjustments are available in panel settings | +> | `defaultSwapTransactionSlippage` | `number` | `0.3` | Default slippage (%) applied to swap transaction. | +> | `defaultNoSwapMinDepositAmountGap` | `number` | `0.1` | Default gap (%) for min received vault tokens during no swap deposits. | +> | `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 | +> | `stablePrecision` | `number` | `3` | Number of decimals to be displayed in stables (e.g USDC balance) | +> | `defaultPrecision` | `number` | `6` | Number of decimals to be displayed in token values | +> | `stakingChainId` | `number` | `10` (Optimism) | ChainId to be used in staking logic | +> | `termsOfUseAccepted` | `boolean` | `true` | Requires user to confirm terms of use by rendering DepositTermsOfUse component before deposit action | +> | `standalone` | `boolean` | `true` | Handles token selection in SPA mode | +> | `chainConfig` | `Partial>` | `{}` | Sets map of chain `name` and `iconPath` | ##### actions @@ -414,84 +416,82 @@ path: `component.meta[name]` Translation keys -> | name | type | default value | description | -> |-----------------------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| -> | `depositSlippageWarning` | string | Includes entry fee. We recommend 2-3%, but usually it will be < 1%. Slippage may be amplified by the leverage. See the docs for more info. | | -> | `withdrawSlippageWarning` | string | Slippage only applies to single asset withdrawals and withdrawals from vaults with debt positions in Aave. | | -> | `minSlippageWarning` | string | Flexible min slippage value that is likely enough to process the transaction. | | -> | `highSlippageWarning` | string | We recommend using another asset to trade with lower slippage. | | -> | `recommendedMinSlippage` | string | Recommended Min Slippage | | -> | `projectedDailyEarningsTooltip` | string | Projected daily earnings are based on the current APY and may differ from actual earnings. | | -> | `dailyEarnings` | string | Daily Earnings | | -> | `projectedYearlyEarningsTooltip` | string | Projected yearly earnings are based on the current APY and may differ from actual earnings. | | -> | `yearlyEarnings` | string | Yearly Earnings | | -> | `fullReceiveDetails` | string | See full details influencing what you will receive. | | -> | `tradeDetails` | string | Trade details | | -> | `maxSlippage` | string | Max slippage | | -> | `minReceiveAmount` | string | You will receive no less than this amount. | | -> | `minReceived` | string | Minimum Received | | -> | `estimatedMultiAssetFractions` | string | Estimated multi asset fractions | | -> | `infinite` | string | Infinite | | -> | `tokenAllowance` | string | Token Allowance | | -> | `entryFee` | string | Entry Fee | | -> | `entryFeeExplanation` | string | When you deposit, the token takes a small entry fee. This fee helps cover the costs when we rebalance the underlying funds, and it's shared among all token holders. | | -> | `easySwapperEntryFee` | string | Entry fee is charged when a cooldown of {time} is selected. Bypass Entry Fee at trading settings. | | -> | `amountToBeApproved` | string | Amount of {symbol} tokens to be approved. Can be customized in settings. | | -> | `minDepositUsd` | string | Minimum deposit in USD. | | -> | `minDeposit` | string | Minimum Deposit | | -> | `tokensLockTime` | string | Purchased tokens will have a {lockTime} lock. | | -> | `slippageTolerance` | string | Slippage tolerance | | -> | `bypassEntryFee` | string | Bypass Entry Fee | | -> | `entryFeeSwitchWarning` | string | By removing the entry fee, your position is locked for up to {defaultLockTime} instead of the normal {customLockTime}. | | -> | `tokenAmountToApprove` | string | Amount of tokens to be approved. | | -> | `auto` | string | Auto | | -> | `autoSlippageDescription` | string | App is testing different slippage ranges, starting low and increasing until it's likely to pass | | -> | `lengthenLockup` | string | Lengthen lockup to remove entry fee | | -> | `deposit` | string | Buy | | -> | `withdraw` | string | Sell | | -> | `yourBalance` | string | Your Balance | | -> | `max` | string | Max | | -> | `allAssets` | string | All Assets | | -> | `all` | string | All | | -> | `payWith` | string | Pay with | | -> | `buyEstimated` | string | Buy (estimated) | | -> | `sell` | string | Sell | | -> | `receiveEstimated` | string | Receive (estimated) | | -> | `confirmInWallet` | string | Please confirm in wallet | | -> | `pending` | string | Pending... | | -> | `approve` | string | Approve | | -> | `connectWallet` | string | Connect Wallet | | -> | `minimumPurchase` | string | Minimum purchase is ${value} | | -> | `poolIsInactive` | string | {poolSymbol} token is no longer active. Please withdraw from them. | | -> | `poolIsPrivate` | string | This vault is currently private | | -> | `updateOracles` | string | Update Oracles | | -> | `checkingOracles` | string | Checking Oracles | | -> | `confirmMaxSlippage` | string | Confirm {slippagePercentage}% max slippage | | -> | `withdrawalWindowDisabled` | string | You can sell your {tokenSymbol} tokens during withdrawal window period starting from {startTime} | | -> | `withdrawCooldown` | string | You can sell your {tokenSymbol} tokens in {cooldownEndTime} | | -> | `termsOfUse` | string | Terms Of Use | | -> | `termOfUseDepositListTitle` | string | Please know the following before depositing | | -> | `termOfUseDepositAssetSlippage` | string | When exiting, investors receive single asset or the underlying vault assets. Withdraw slippage can be customized in withdraw settings | | -> | `termOfUseDepositBugs` | string | There may be interface bugs on the platform | | -> | `termOfUseDepositDowntime` | string | There may be interface downtime (planned and unplanned) | | -> | `termOfUseDepositAuditRisk` | string | Smart contracts are audited but a risk is still present | | -> | `termOfUseDepositAccept` | string | Accept & Deposit | | -> | `back` | string | Back | | -> | `highSlippage` | string | High Slippage Alert | | -> | `responsibleHighSlippage` | string | By proceeding with this trade, you acknowledge and accept the possibility of experiencing high slippage, resulting in a potential difference between the expected and executed price. | | -> | `highSlippageListTitle` | string | Please consider the following before confirming | | -> | `highSlippageQuoteDiff` | string | Be aware that the final amount of assets you receive may be different from the initially quoted value. | | -> | `highSlippageRisk` | string | Ensure that you understand the risks associated with high slippage and are comfortable proceeding with the trade. | | -> | `confirm` | string | Confirm | | -> | `selectToken` | string | Select Token | | -> | `sendingOrderToWallet` | string | Sending order to your wallet | | -> | `settingUpTx` | string | Setting up transaction | | -> | `updateSynthetixOracles` | string | Updating Synthetix Oracles | | -> | `approveSpending` | string | Approve {symbol} spending | | -> | `pay` | string | Pay | | -> | `multiAssetFractions` | string | multi asset fractions | | -> | `explorer` | string | Explorer | | -> | `as` | string | As | | +> | name | type | default value | description | +> |----------------------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +> | `depositSlippageWarning` | string | Excludes entry fee. Slippage may be amplified by the leverage. See the docs for more info. | | +> | `withdrawSlippageWarning` | string | Slippage only applies to single asset withdrawals and withdrawals from vaults with debt positions in Aave. | | +> | `minSlippageWarning` | string | Flexible min slippage value that is likely enough to process the transaction. | | +> | `highSlippageWarning` | string | We recommend using another asset to trade with lower slippage. | | +> | `recommendedMinSlippage` | string | Recommended Min Slippage | | +> | `projectedDailyEarningsTooltip` | string | Projected daily earnings are based on the current APY and may differ from actual earnings. | | +> | `dailyEarnings` | string | Daily Earnings | | +> | `projectedYearlyEarningsTooltip` | string | Projected yearly earnings are based on the current APY and may differ from actual earnings. | | +> | `yearlyEarnings` | string | Yearly Earnings | | +> | `fullReceiveDetails` | string | See full details influencing what you will receive. | | +> | `tradeDetails` | string | Trade details | | +> | `maxSlippage` | string | Max slippage | | +> | `minReceiveAmount` | string | You will receive no less than this amount. | | +> | `minReceived` | string | Minimum Received | | +> | `estimatedMultiAssetFractions` | string | Estimated multi asset fractions | | +> | `infinite` | string | Infinite | | +> | `tokenAllowance` | string | Token Allowance | | +> | `entryFee` | string | Entry Fee | | +> | `entryFeeExplanation` | string | When you deposit, the token takes a small entry fee. This fee helps cover the costs when we rebalance the underlying funds, and it's shared among all token holders. | | +> | `amountToBeApproved` | string | Amount of {symbol} tokens to be approved. Can be customized in settings. | | +> | `minDepositUsd` | string | Minimum deposit in USD. | | +> | `minDeposit` | string | Minimum Deposit | | +> | `tokensLockTime` | string | Purchased tokens will have a {lockTime} lock. | | +> | `slippageTolerance` | string | Slippage tolerance | | +> | `bypassEntryFee` | string | Bypass Entry Fee | | +> | `tokenAmountToApprove` | string | Amount of tokens to be approved. | | +> | `auto` | string | Auto | | +> | `autoSlippageDescription` | string | App is testing different slippage ranges, starting low and increasing until it's likely to pass | | +> | `lengthenLockup` | string | Lengthen lockup to remove entry fee | | +> | `deposit` | string | Buy | | +> | `withdraw` | string | Sell | | +> | `yourBalance` | string | Your Balance | | +> | `max` | string | Max | | +> | `allAssets` | string | All Assets | | +> | `all` | string | All | | +> | `payWith` | string | Pay with | | +> | `buyEstimated` | string | Buy (estimated) | | +> | `sell` | string | Sell | | +> | `receiveEstimated` | string | Receive (estimated) | | +> | `confirmInWallet` | string | Please confirm in wallet | | +> | `pending` | string | Pending... | | +> | `approve` | string | Approve | | +> | `connectWallet` | string | Connect Wallet | | +> | `minimumPurchase` | string | Minimum purchase is ${value} | | +> | `poolIsInactive` | string | {poolSymbol} token is no longer active. Please withdraw from them. | | +> | `poolIsPrivate` | string | This vault is currently private | | +> | `updateOracles` | string | Update Oracles | | +> | `checkingOracles` | string | Checking Oracles | | +> | `confirmMaxSlippage` | string | Confirm {slippagePercentage}% max slippage | | +> | `withdrawalWindowDisabled` | string | You can sell your {tokenSymbol} tokens during withdrawal window period starting from {startTime} | | +> | `withdrawCooldown` | string | You can sell your {tokenSymbol} tokens in {cooldownEndTime} | | +> | `termsOfUse` | string | Terms Of Use | | +> | `termOfUseDepositListTitle` | string | Please know the following before depositing | | +> | `termOfUseDepositAssetSlippage` | string | When exiting, investors receive single asset or the underlying vault assets. Withdraw slippage can be customized in withdraw settings | | +> | `termOfUseDepositBugs` | string | There may be interface bugs on the platform | | +> | `termOfUseDepositDowntime` | string | There may be interface downtime (planned and unplanned) | | +> | `termOfUseDepositAuditRisk` | string | Smart contracts are audited but a risk is still present | | +> | `termOfUseDepositAccept` | string | Accept & Deposit | | +> | `back` | string | Back | | +> | `highSlippage` | string | High Slippage Alert | | +> | `responsibleHighSlippage` | string | By proceeding with this trade, you acknowledge and accept the possibility of experiencing high slippage, resulting in a potential difference between the expected and executed price. | | +> | `highSlippageListTitle` | string | Please consider the following before confirming | | +> | `highSlippageQuoteDiff` | string | Be aware that the final amount of assets you receive may be different from the initially quoted value. | | +> | `highSlippageRisk` | string | Ensure that you understand the risks associated with high slippage and are comfortable proceeding with the trade. | | +> | `confirm` | string | Confirm | | +> | `selectToken` | string | Select Token | | +> | `sendingOrderToWallet` | string | Sending order to your wallet | | +> | `settingUpTx` | string | Setting up transaction | | +> | `updateSynthetixOracles` | string | Updating Synthetix Oracles | | +> | `approveSpending` | string | Approve {symbol} spending | | +> | `pay` | string | Pay | | +> | `multiAssetFractions` | string | multi asset fractions | | +> | `explorer` | string | Explorer | | +> | `as` | string | As | | ###### Source: `packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.tsx` ###### Default values: `packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.defaults.ts` diff --git a/packages/trading-widget/package.json b/packages/trading-widget/package.json index c776797..1170423 100644 --- a/packages/trading-widget/package.json +++ b/packages/trading-widget/package.json @@ -1,6 +1,6 @@ { "name": "@dhedge/trading-widget", - "version": "1.2.10", + "version": "2.0.0", "type": "module", "main": "index.js", "module": "index.mjs", diff --git a/packages/trading-widget/src/core-kit/abi/easy-swapper-v2.ts b/packages/trading-widget/src/core-kit/abi/easy-swapper-v2.ts new file mode 100644 index 0000000..8acf2ce --- /dev/null +++ b/packages/trading-widget/src/core-kit/abi/easy-swapper-v2.ts @@ -0,0 +1,540 @@ +export const EasySwapperV2Abi = [ + { + inputs: [], + name: 'customCooldown', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'customCooldownDepositsWhitelist', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: '_vaultDepositToken', + type: 'address', + }, + { + internalType: 'uint256', + name: '_depositAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'deposit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + internalType: 'address', + name: '_vaultDepositToken', + type: 'address', + }, + { + internalType: 'uint256', + name: '_depositAmount', + type: 'uint256', + }, + ], + name: 'depositQuote', + outputs: [ + { + internalType: 'uint256', + name: 'expectedAmountReceived', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: '_vaultDepositToken', + type: 'address', + }, + { + internalType: 'uint256', + name: '_depositAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'depositWithCustomCooldown', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + internalType: 'uint256', + name: '_amountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_slippageTolerance', + type: 'uint256', + }, + ], + name: 'initWithdrawal', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'nativeDeposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'nativeDepositWithCustomCooldown', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'swapper', + outputs: [ + { + internalType: 'contract ISwapper', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'weth', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'withdrawalContracts', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'wrappedNativeToken', + outputs: [ + { + internalType: 'contract IWETH', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + components: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { + components: [ + { + internalType: 'bytes32', + name: 'routerKey', + type: 'bytes32', + }, + { + internalType: 'bytes', + name: 'swapData', + type: 'bytes', + }, + ], + internalType: 'struct ISwapper.AggregatorData', + name: 'aggregatorData', + type: 'tuple', + }, + ], + internalType: 'struct ISwapper.SrcTokenSwapDetails', + name: 'srcData', + type: 'tuple', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'destToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'minDestAmount', + type: 'uint256', + }, + ], + internalType: 'struct ISwapper.DestData', + name: 'destData', + type: 'tuple', + }, + ], + internalType: 'struct EasySwapperV2.SingleInSingleOutData', + name: '_swapData', + type: 'tuple', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'zapDeposit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + components: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { + components: [ + { + internalType: 'bytes32', + name: 'routerKey', + type: 'bytes32', + }, + { + internalType: 'bytes', + name: 'swapData', + type: 'bytes', + }, + ], + internalType: 'struct ISwapper.AggregatorData', + name: 'aggregatorData', + type: 'tuple', + }, + ], + internalType: 'struct ISwapper.SrcTokenSwapDetails', + name: 'srcData', + type: 'tuple', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'destToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'minDestAmount', + type: 'uint256', + }, + ], + internalType: 'struct ISwapper.DestData', + name: 'destData', + type: 'tuple', + }, + ], + internalType: 'struct EasySwapperV2.SingleInSingleOutData', + name: '_swapData', + type: 'tuple', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'zapDepositWithCustomCooldown', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + components: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { + components: [ + { + internalType: 'bytes32', + name: 'routerKey', + type: 'bytes32', + }, + { + internalType: 'bytes', + name: 'swapData', + type: 'bytes', + }, + ], + internalType: 'struct ISwapper.AggregatorData', + name: 'aggregatorData', + type: 'tuple', + }, + ], + internalType: 'struct ISwapper.SrcTokenSwapDetails', + name: 'srcData', + type: 'tuple', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'destToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'minDestAmount', + type: 'uint256', + }, + ], + internalType: 'struct ISwapper.DestData', + name: 'destData', + type: 'tuple', + }, + ], + internalType: 'struct EasySwapperV2.SingleInSingleOutData', + name: '_swapData', + type: 'tuple', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'zapNativeDeposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_dHedgeVault', + type: 'address', + }, + { + components: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { + components: [ + { + internalType: 'bytes32', + name: 'routerKey', + type: 'bytes32', + }, + { + internalType: 'bytes', + name: 'swapData', + type: 'bytes', + }, + ], + internalType: 'struct ISwapper.AggregatorData', + name: 'aggregatorData', + type: 'tuple', + }, + ], + internalType: 'struct ISwapper.SrcTokenSwapDetails', + name: 'srcData', + type: 'tuple', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'destToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'minDestAmount', + type: 'uint256', + }, + ], + internalType: 'struct ISwapper.DestData', + name: 'destData', + type: 'tuple', + }, + ], + internalType: 'struct EasySwapperV2.SingleInSingleOutData', + name: '_swapData', + type: 'tuple', + }, + { + internalType: 'uint256', + name: '_expectedAmountReceived', + type: 'uint256', + }, + ], + name: 'zapNativeDepositWithCustomCooldown', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, +] as const diff --git a/packages/trading-widget/src/core-kit/abi/flatcoin-points-module.ts b/packages/trading-widget/src/core-kit/abi/flatcoin-points-module.ts index e465415..690e684 100644 --- a/packages/trading-widget/src/core-kit/abi/flatcoin-points-module.ts +++ b/packages/trading-widget/src/core-kit/abi/flatcoin-points-module.ts @@ -1,4 +1,4 @@ -export const FlatcoinPointsModuleABI = [ +export const FlatcoinPointsModuleAbi = [ { inputs: [ { diff --git a/packages/trading-widget/src/core-kit/abi/index.ts b/packages/trading-widget/src/core-kit/abi/index.ts index b87c77c..3a0892f 100644 --- a/packages/trading-widget/src/core-kit/abi/index.ts +++ b/packages/trading-widget/src/core-kit/abi/index.ts @@ -14,4 +14,5 @@ export { SynthetixV3AssetGuard, SynthetixV3ContractGuard, } from './synthetix-v3' -export { FlatcoinPointsModuleABI } from './flatcoin-points-module' +export { FlatcoinPointsModuleAbi } from './flatcoin-points-module' +export { EasySwapperV2Abi } from './easy-swapper-v2' diff --git a/packages/trading-widget/src/core-kit/const/config.ts b/packages/trading-widget/src/core-kit/const/config.ts index 8841919..fc1e201 100644 --- a/packages/trading-widget/src/core-kit/const/config.ts +++ b/packages/trading-widget/src/core-kit/const/config.ts @@ -4,7 +4,8 @@ import { AaveLendingPoolAbi, DHedgeStakingV2Abi, DhedgeEasySwapperAbi, - FlatcoinPointsModuleABI, + EasySwapperV2Abi, + FlatcoinPointsModuleAbi, PoolFactoryAbi, PoolLogicAbi, PoolManagerLogicAbi, @@ -24,6 +25,10 @@ import { EASY_SWAPPER_ADDRESS_BASE, EASY_SWAPPER_ADDRESS_OPTIMISM, EASY_SWAPPER_ADDRESS_POLYGON, + EASY_SWAPPER_V2_ADDRESS_ARBITRUM, + EASY_SWAPPER_V2_ADDRESS_BASE, + EASY_SWAPPER_V2_ADDRESS_OPTIMISM, + EASY_SWAPPER_V2_ADDRESS_POLYGON, FACTORY_ADDRESS_ARBITRUM, FACTORY_ADDRESS_BASE, FACTORY_ADDRESS_OPTIMISM, @@ -48,6 +53,7 @@ export type ContractId = | 'synthetixV3AssetGuard' | 'synthetixV3Core' | 'flatcoinPointsModule' + | 'easySwapperV2' type ContractsAddressesMap = Readonly< Record @@ -59,6 +65,7 @@ export const contractsAddressesMap: ContractsAddressesMap = { easySwapper: EASY_SWAPPER_ADDRESS_POLYGON, aaveLendingPoolV2: AAVE_LENDING_POOL_V2_ADDRESS_POLYGON, aaveLendingPoolV3: AAVE_LENDING_POOL_V3_ADDRESS_POLYGON, + easySwapperV2: EASY_SWAPPER_V2_ADDRESS_POLYGON, }, [optimism.id]: { factory: FACTORY_ADDRESS_OPTIMISM, @@ -66,18 +73,21 @@ export const contractsAddressesMap: ContractsAddressesMap = { rewardDistribution: REWARD_DISTRIBUTION_ADDRESS_OPTIMISM, stakingV2: STAKING_V2_ADDRESS_OPTIMISM, aaveLendingPoolV3: AAVE_LENDING_POOL_V3_ADDRESS_OPTIMISM, + easySwapperV2: EASY_SWAPPER_V2_ADDRESS_OPTIMISM, }, [arbitrum.id]: { factory: FACTORY_ADDRESS_ARBITRUM, easySwapper: EASY_SWAPPER_ADDRESS_ARBITRUM, aaveLendingPoolV3: AAVE_LENDING_POOL_V3_ADDRESS_ARBITRUM, synthetixV3Core: SYNTHETIX_V3_CORE_ADDRESS_ARBITRUM, + easySwapperV2: EASY_SWAPPER_V2_ADDRESS_ARBITRUM, }, [base.id]: { factory: FACTORY_ADDRESS_BASE, synthetixV3Core: SYNTHETIX_V3_CORE_ADDRESS_BASE, flatcoinPointsModule: FLATCOIN_POINTS_MODULE_ADDRESS_BASE, easySwapper: EASY_SWAPPER_ADDRESS_BASE, + easySwapperV2: EASY_SWAPPER_V2_ADDRESS_BASE, }, } @@ -94,7 +104,8 @@ export const contractsAbisMap: { [id in ContractId]: any } = { poolLogic: PoolLogicAbi, synthetixV3AssetGuard: SynthetixV3AssetGuard, synthetixV3Core: SynthetixV3CoreAbi, - flatcoinPointsModule: FlatcoinPointsModuleABI, + flatcoinPointsModule: FlatcoinPointsModuleAbi, + easySwapperV2: EasySwapperV2Abi, } export const QUERY_KEYS = { diff --git a/packages/trading-widget/src/core-kit/const/contracts/arbitrum.ts b/packages/trading-widget/src/core-kit/const/contracts/arbitrum.ts index 7d46edd..666ef97 100644 --- a/packages/trading-widget/src/core-kit/const/contracts/arbitrum.ts +++ b/packages/trading-widget/src/core-kit/const/contracts/arbitrum.ts @@ -9,3 +9,6 @@ export const AAVE_LENDING_POOL_V3_ADDRESS_ARBITRUM = export const SYNTHETIX_V3_CORE_ADDRESS_ARBITRUM = '0xffffffaEff0B96Ea8e4f94b2253f31abdD875847' + +export const EASY_SWAPPER_V2_ADDRESS_ARBITRUM = + '0xA5679C4272A056Bb83f039961fae7D99C48529F5' diff --git a/packages/trading-widget/src/core-kit/const/contracts/base.ts b/packages/trading-widget/src/core-kit/const/contracts/base.ts index 16a13ea..25bcc87 100644 --- a/packages/trading-widget/src/core-kit/const/contracts/base.ts +++ b/packages/trading-widget/src/core-kit/const/contracts/base.ts @@ -3,6 +3,8 @@ export const SYNTHETIX_V3_CORE_ADDRESS_BASE = '0x32C222A9A159782aFD7529c87FA34b96CA72C696' export const EASY_SWAPPER_ADDRESS_BASE = '0xE10Ed1E5354eEd0F7C9D2e16250ba8996C12db7A' +export const EASY_SWAPPER_V2_ADDRESS_BASE = + '0xf067575Eb60c7587C11e867907AA7284833704d1' export const FLATCOIN_POINTS_MODULE_ADDRESS_BASE = '0x59525b9b23adc475ef91d98dae06b568ba574ce5' diff --git a/packages/trading-widget/src/core-kit/const/contracts/optimism.ts b/packages/trading-widget/src/core-kit/const/contracts/optimism.ts index a51c154..40ffa8c 100644 --- a/packages/trading-widget/src/core-kit/const/contracts/optimism.ts +++ b/packages/trading-widget/src/core-kit/const/contracts/optimism.ts @@ -12,3 +12,6 @@ export const STAKING_V2_ADDRESS_OPTIMISM = export const AAVE_LENDING_POOL_V3_ADDRESS_OPTIMISM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' + +export const EASY_SWAPPER_V2_ADDRESS_OPTIMISM = + '0x2Ed1bd7f66e47113672f3870308b5E867C5bb743' diff --git a/packages/trading-widget/src/core-kit/const/contracts/polygon.ts b/packages/trading-widget/src/core-kit/const/contracts/polygon.ts index f376506..6694f20 100644 --- a/packages/trading-widget/src/core-kit/const/contracts/polygon.ts +++ b/packages/trading-widget/src/core-kit/const/contracts/polygon.ts @@ -9,3 +9,6 @@ export const AAVE_LENDING_POOL_V2_ADDRESS_POLYGON = export const AAVE_LENDING_POOL_V3_ADDRESS_POLYGON = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' + +export const EASY_SWAPPER_V2_ADDRESS_POLYGON = + '0x45b90480D6F643dE2f128db091A357C3c90399f2' diff --git a/packages/trading-widget/src/core-kit/const/default-data.ts b/packages/trading-widget/src/core-kit/const/default-data.ts index 71527cf..6d012fe 100644 --- a/packages/trading-widget/src/core-kit/const/default-data.ts +++ b/packages/trading-widget/src/core-kit/const/default-data.ts @@ -1,10 +1,8 @@ import { formatDuration } from 'date-fns' -import { arbitrum, base, optimism, polygon } from 'wagmi/chains' +import { optimism } from 'wagmi/chains' -import type { ChainId } from 'core-kit/types' import type { PoolConfig } from 'core-kit/types/config.types' -import type { DepositMethodName } from 'core-kit/types/trading-panel.types' -import type { PoolDepositMethodName } from 'core-kit/types/trading.types' +import type { DepositMethodName } from 'core-kit/types/trading.types' import { AddressZero } from './web3' @@ -16,29 +14,6 @@ export const EXTREMELY_SHORT_POLLING_INTERVAL = 15_000 export const DEFAULT_RETRIES_NUMBER = 5 export const DEFAULT_LOCK_TIME = formatDuration({ hours: 24 }) -export const CUSTOM_LOCK_TIME = formatDuration({ minutes: 60 }) - -export const DEFAULT_DEPOSIT_LOCKTIME_MAP: Record< - ChainId, - Record -> = { - [optimism.id]: { - deposit: DEFAULT_LOCK_TIME, - depositWithCustomCooldown: CUSTOM_LOCK_TIME, - }, - [polygon.id]: { - deposit: DEFAULT_LOCK_TIME, - depositWithCustomCooldown: CUSTOM_LOCK_TIME, - }, - [arbitrum.id]: { - deposit: DEFAULT_LOCK_TIME, - depositWithCustomCooldown: CUSTOM_LOCK_TIME, - }, - [base.id]: { - deposit: DEFAULT_LOCK_TIME, - depositWithCustomCooldown: CUSTOM_LOCK_TIME, - }, -} export const EMPTY_POOL_CONFIG: PoolConfig = { address: AddressZero, @@ -51,8 +26,10 @@ export const EMPTY_POOL_CONFIG: PoolConfig = { export const DEFAULT_DEPOSIT_METHOD: DepositMethodName = 'deposit' -export const DEFAULT_WITHDRAW_SLIPPAGE = 3 -export const DEFAULT_DEPOSIT_SLIPPAGE = 0 +export const DEFAULT_WITHDRAW_SLIPPAGE = 3 // % +export const DEFAULT_DEPOSIT_SLIPPAGE = 0 // % +export const DEFAULT_NO_SWAP_MIN_DEPOSIT_AMOUNT_GAP = 0.1 // % +export const DEFAULT_SWAP_TRANSACTION_SLIPPAGE = 0.3 // % export const DEFAULT_WITHDRAW_SLIPPAGE_SCALE = [ 0.1, @@ -71,9 +48,6 @@ export const NATIVE_TOKEN_DEPOSIT_GAS_LIMIT = 4200000 export const GAS_LIMIT_BUFFER_COEFF = 1.25 -export const DEPOSIT_QUOTE_MULTIPLIER_DEFAULT = 0.9997 -export const DEPOSIT_QUOTE_MULTIPLIER_CUSTOM = 0.999 - export const MANAGER_FEE_DENOMINATOR = 10000 export const DEFAULT_PROMISE_TIMEOUT_MS = 13000 diff --git a/packages/trading-widget/src/core-kit/const/index.ts b/packages/trading-widget/src/core-kit/const/index.ts index c364d7a..8dfdd92 100644 --- a/packages/trading-widget/src/core-kit/const/index.ts +++ b/packages/trading-widget/src/core-kit/const/index.ts @@ -10,3 +10,4 @@ export * from './tokens' export * from './synthetix' export * from './links' export * from './flat-money' +export * from './trading' diff --git a/packages/trading-widget/src/core-kit/const/logger.ts b/packages/trading-widget/src/core-kit/const/logger.ts index 3558a9f..38d8340 100644 --- a/packages/trading-widget/src/core-kit/const/logger.ts +++ b/packages/trading-widget/src/core-kit/const/logger.ts @@ -4,7 +4,6 @@ export const TRADING_PANEL_LOG_EVENT = { DEPOSIT: 'deposit', WITHDRAWAL: 'withdrawal', TRADING_SETTINGS_OPENED: 'trading_settings_opened', - DEPOSIT_METHOD_CHANGE: 'deposit_method_change', INFINITE_ALLOWANCE_CHANGE: 'infinite_allowance_change', MULTI_ASSET_WITHDRAWAL_CHANGE: 'multi_asset_withdrawal_change', } diff --git a/packages/trading-widget/src/core-kit/const/tokens/index.ts b/packages/trading-widget/src/core-kit/const/tokens/index.ts index c0356bf..797cfd4 100644 --- a/packages/trading-widget/src/core-kit/const/tokens/index.ts +++ b/packages/trading-widget/src/core-kit/const/tokens/index.ts @@ -1,9 +1,29 @@ -import type { TradingToken } from 'core-kit/types' +import type { ChainId, TradingToken } from 'core-kit/types' -import { BRIDGED_USDC_ARBITRUM, WETH_ARBITRUM } from './arbitrum' -import { WETH_BASE } from './base' -import { BRIDGED_USDC_OPTIMISM, WETH_OPTIMISM } from './optimism' -import { BRIDGED_USDC_POLYGON, WETH_POLYGON } from './polygon' +import { + BRIDGED_USDC_ARBITRUM, + USDC_ARBITRUM, + WBTC_ARBITRUM, + WETH_ARBITRUM, +} from './arbitrum' +import { USDC_BASE, WETH_BASE } from './base' +import { + BRIDGED_USDC_OPTIMISM, + DAI_OPTIMISM, + USDC_OPTIMISM, + USDT_OPTIMISM, + WBTC_OPTIMISM, + WETH_OPTIMISM, +} from './optimism' +import { + BRIDGED_USDC_POLYGON, + DAI_POLYGON, + USDC_POLYGON, + USDT_POLYGON, + WBTC_POLYGON, + WETH_POLYGON, + WMATIC_POLYGON, +} from './polygon' import { DEFAULT_PRECISION } from '../default-data' import { arbitrum, base, optimism, polygon } from '../network' import { AddressZero } from '../web3' @@ -32,3 +52,36 @@ export const WETH_BY_CHAIN_ID: Record = { [polygon.id]: WETH_POLYGON, [arbitrum.id]: WETH_ARBITRUM, } + +export const FALLBACK_ASSETS_MAP: Record< + ChainId, + Record +> = { + [optimism.id]: { + WETH: WETH_OPTIMISM, + USDC: USDC_OPTIMISM, + WBTC: WBTC_OPTIMISM, + USDCe: BRIDGED_USDC_OPTIMISM, + USDT: USDT_OPTIMISM, + DAI: DAI_OPTIMISM, + }, + [polygon.id]: { + WMATIC: WMATIC_POLYGON, + WETH: WETH_POLYGON, + USDC: USDC_POLYGON, + WBTC: WBTC_POLYGON, + USDCe: BRIDGED_USDC_POLYGON, + USDT: USDT_POLYGON, + DAI: DAI_POLYGON, + }, + [arbitrum.id]: { + WETH: WETH_ARBITRUM, + USDC: USDC_ARBITRUM, + WBTC: WBTC_ARBITRUM, + USDCe: BRIDGED_USDC_ARBITRUM, + }, + [base.id]: { + WETH: WETH_BASE, + USDC: USDC_BASE, + }, +} diff --git a/packages/trading-widget/src/core-kit/const/trading.ts b/packages/trading-widget/src/core-kit/const/trading.ts new file mode 100644 index 0000000..0b9a3ce --- /dev/null +++ b/packages/trading-widget/src/core-kit/const/trading.ts @@ -0,0 +1,12 @@ +import type { DepositMethodName } from 'core-kit/types' + +export const EASY_SWAPPER_V2_DEPOSIT_METHODS = { + DEPOSIT: 'deposit', + DEPOSIT_CUSTOM: 'depositWithCustomCooldown', + NATIVE: 'nativeDeposit', + NATIVE_CUSTOM: 'nativeDepositWithCustomCooldown', + ZAP_NATIVE_DEPOSIT: 'zapNativeDeposit', + ZAP_NATIVE_DEPOSIT_CUSTOM: 'zapNativeDepositWithCustomCooldown', + ZAP_DEPOSIT: 'zapDeposit', + ZAP_DEPOSIT_CUSTOM: 'zapDepositWithCustomCooldown', +} satisfies Record diff --git a/packages/trading-widget/src/core-kit/hooks/component/panel.ts b/packages/trading-widget/src/core-kit/hooks/component/panel.ts index 0b0527b..6ff7c61 100644 --- a/packages/trading-widget/src/core-kit/hooks/component/panel.ts +++ b/packages/trading-widget/src/core-kit/hooks/component/panel.ts @@ -1,13 +1,9 @@ import { useInvalidatePoolContractData } from 'core-kit/hooks/pool' -import { - useHandlePoolSwapInfo, - useTradingResultHandling, -} from 'core-kit/hooks/trading' -import { useHandlePoolDepositData } from 'core-kit/hooks/trading/deposit' +import { useTradingResultHandling } from 'core-kit/hooks/trading' +import { useHandlePoolDepositData } from 'core-kit/hooks/trading/deposit-v2' export const useGeneralTradingPanelHandlers = () => { useTradingResultHandling() - useHandlePoolSwapInfo() useHandlePoolDepositData() useInvalidatePoolContractData() } diff --git a/packages/trading-widget/src/core-kit/hooks/component/tab.ts b/packages/trading-widget/src/core-kit/hooks/component/tab.ts index 65ebd2d..ff2cae0 100644 --- a/packages/trading-widget/src/core-kit/hooks/component/tab.ts +++ b/packages/trading-widget/src/core-kit/hooks/component/tab.ts @@ -5,12 +5,12 @@ import { useTradingPanelPoolConfig, useTradingPanelType, } from 'core-kit/hooks/state' -import { usePoolDepositTokens } from 'core-kit/hooks/trading/deposit' +import { useVaultDepositTokens } from 'core-kit/hooks/trading/deposit-v2' import type { TradingPanelType } from 'core-kit/types/trading-panel.types' export const useOnTradingTypeChange = () => { const poolConfig = useTradingPanelPoolConfig() - const [initialDepositToken] = usePoolDepositTokens() + const [initialDepositToken] = useVaultDepositTokens() const setTradingType = useTradingPanelType()[1] const updateSendToken = useSendTokenInput()[1] diff --git a/packages/trading-widget/src/core-kit/hooks/pool/multicall/use-pool.static.ts b/packages/trading-widget/src/core-kit/hooks/pool/multicall/use-pool.static.ts index f220f1b..4a6edf8 100644 --- a/packages/trading-widget/src/core-kit/hooks/pool/multicall/use-pool.static.ts +++ b/packages/trading-widget/src/core-kit/hooks/pool/multicall/use-pool.static.ts @@ -1,8 +1,4 @@ -import { - DhedgeEasySwapperAbi, - PoolFactoryAbi, - PoolLogicAbi, -} from 'core-kit/abi' +import { EasySwapperV2Abi, PoolFactoryAbi, PoolLogicAbi } from 'core-kit/abi' import { AddressZero } from 'core-kit/const' import { useContractReadErrorLogging, @@ -30,22 +26,17 @@ const getContracts = ({ address, chainId }: PoolContractCallParams) => chainId, }, { - address: getContractAddressById('easySwapper', chainId), - abi: DhedgeEasySwapperAbi, - functionName: 'allowedPools', + address: getContractAddressById('easySwapperV2', chainId), + abi: EasySwapperV2Abi, + functionName: 'customCooldownDepositsWhitelist', args: [address], chainId, }, { - address: getContractAddressById('easySwapper', chainId), - abi: DhedgeEasySwapperAbi, - functionName: 'feeNumerator', - chainId, - }, - { - address: getContractAddressById('easySwapper', chainId), - abi: DhedgeEasySwapperAbi, - functionName: 'feeDenominator', + address: getContractAddressById('easySwapperV2', chainId), + abi: EasySwapperV2Abi, + functionName: 'customCooldown', + args: [], chainId, }, ] as const @@ -55,9 +46,8 @@ type Data = MulticallReturnType> const selector = (data: Data) => ({ isPool: data[0].result, poolManagerLogic: data[1].result, - easySwapperAllowedPools: data[2].result, - easySwapperFeeNumerator: data[3].result, - easySwapperFeeDenominator: data[4].result, + isCustomCooldownDepositAllowed: data[2].result, + customCooldown: data[3].result, }) export const usePoolStatic = ({ address, chainId }: PoolContractCallParams) => { diff --git a/packages/trading-widget/src/core-kit/hooks/pool/use-fmed-vested-points.ts b/packages/trading-widget/src/core-kit/hooks/pool/use-fmed-vested-points.ts index 8a58cc1..ea871e7 100644 --- a/packages/trading-widget/src/core-kit/hooks/pool/use-fmed-vested-points.ts +++ b/packages/trading-widget/src/core-kit/hooks/pool/use-fmed-vested-points.ts @@ -1,4 +1,4 @@ -import { FlatcoinPointsModuleABI } from 'core-kit/abi' +import { FlatcoinPointsModuleAbi } from 'core-kit/abi' import { base } from 'core-kit/const' import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' @@ -24,21 +24,21 @@ const getContracts = (vaultAddress: string) => { { address: pointsContractAddress, chainId: FMED_CHAIN_ID, - abi: FlatcoinPointsModuleABI, + abi: FlatcoinPointsModuleAbi, functionName: 'lockedBalance', args: [vaultAddress], }, { address: pointsContractAddress, chainId: FMED_CHAIN_ID, - abi: FlatcoinPointsModuleABI, + abi: FlatcoinPointsModuleAbi, functionName: 'getUnlockTax', args: [vaultAddress], }, { address: pointsContractAddress, chainId: FMED_CHAIN_ID, - abi: FlatcoinPointsModuleABI, + abi: FlatcoinPointsModuleAbi, functionName: 'unlockTime', args: [vaultAddress], }, diff --git a/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.test.ts b/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.test.ts index fef0b2f..d37e98d 100644 --- a/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.test.ts +++ b/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.test.ts @@ -12,7 +12,6 @@ vi.mock('./use-pool-dynamic-contract-data', () => ({ })) vi.mock('core-kit/hooks/state', () => ({ - useTradingPanelEntryFee: vi.fn(), useTradingPanelPoolFallbackData: vi.fn(), })) @@ -30,10 +29,6 @@ describe('usePoolFees', () => { exitFee: '4', }) as ReturnType, ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - 0, - vi.fn(), - ]) vi.mocked(stateHooks.useTradingPanelPoolFallbackData).mockImplementation( () => [{}] as unknown as ReturnType< @@ -54,31 +49,6 @@ describe('usePoolFees', () => { }) }) - it('should call useTradingPanelEntryFee hook', () => { - const address = TEST_ADDRESS - const chainId = optimism.id - - vi.mocked(poolHooks.usePoolDynamicContractData).mockImplementation( - () => - ({ - performanceFee: '1', - streamingFee: '2', - entryFee: '3', - exitFee: '4', - }) as ReturnType, - ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - 0, - vi.fn(), - ]) - - renderHook(() => usePoolFees({ address, chainId })) - - expect(vi.mocked(stateHooks.useTradingPanelEntryFee)).toHaveBeenCalledTimes( - 1, - ) - }) - it('should return performanceFee data', () => { const address = TEST_ADDRESS const chainId = optimism.id @@ -92,10 +62,6 @@ describe('usePoolFees', () => { entryFee: '3', }) as ReturnType, ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - 0, - vi.fn(), - ]) const { result } = renderHook(() => usePoolFees({ address, chainId })) @@ -117,10 +83,6 @@ describe('usePoolFees', () => { entryFee: '3', }) as ReturnType, ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - 0, - vi.fn(), - ]) const { result } = renderHook(() => usePoolFees({ address, chainId })) @@ -129,7 +91,7 @@ describe('usePoolFees', () => { ) }) - it('should return contract entryFee data', () => { + it('should return entryFee data', () => { const address = TEST_ADDRESS const chainId = optimism.id const entryFee = '1' @@ -142,10 +104,6 @@ describe('usePoolFees', () => { entryFee, }) as ReturnType, ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - 0, - vi.fn(), - ]) const { result } = renderHook(() => usePoolFees({ address, chainId })) @@ -154,7 +112,7 @@ describe('usePoolFees', () => { ) }) - it('should return contract exit fee data', () => { + it('should return exit fee data', () => { const address = TEST_ADDRESS const chainId = optimism.id const exitFee = '10' @@ -169,41 +127,12 @@ describe('usePoolFees', () => { }) as ReturnType, ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - 0, - vi.fn(), - ]) - const { result } = renderHook(() => usePoolFees({ address, chainId })) expect(result.current.exitFee).toEqual('0.1%') expect(result.current.exitFeeNumber).toEqual(0.1) }) - it('should return state entryFee data as fallback', () => { - const address = TEST_ADDRESS - const chainId = optimism.id - const entryFee = '0' - const stateFee = 1 - - vi.mocked(poolHooks.usePoolDynamicContractData).mockImplementation( - () => - ({ - performanceFee: '1', - streamingFee: '2', - entryFee, - }) as ReturnType, - ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - stateFee, - vi.fn(), - ]) - - const { result } = renderHook(() => usePoolFees({ address, chainId })) - - expect(result.current.entryFee).toEqual(`${stateFee}%`) - }) - it('should rely on fallback fees', () => { const address = TEST_ADDRESS const chainId = optimism.id @@ -224,10 +153,6 @@ describe('usePoolFees', () => { exitFee: undefined, }) as ReturnType, ) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockImplementation(() => [ - 0, - vi.fn(), - ]) vi.mocked(stateHooks.useTradingPanelPoolFallbackData).mockImplementation( () => [fallbackData] as unknown as ReturnType< diff --git a/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.ts b/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.ts index bd9ae8f..d75ddcf 100644 --- a/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.ts +++ b/packages/trading-widget/src/core-kit/hooks/pool/use-pool-fees.ts @@ -2,10 +2,7 @@ import { useMemo } from 'react' import { MANAGER_FEE_DENOMINATOR } from 'core-kit/const' import { usePoolDynamicContractData } from 'core-kit/hooks/pool' -import { - useTradingPanelEntryFee, - useTradingPanelPoolFallbackData, -} from 'core-kit/hooks/state' +import { useTradingPanelPoolFallbackData } from 'core-kit/hooks/state' import type { Address, ChainId } from 'core-kit/types/web3.types' import { formatNumeratorToPercentage, @@ -23,13 +20,15 @@ export const usePoolFees = ({ address, chainId }: PoolFeesParams) => { const poolFallbackData = isEqualAddress(poolData.address, address) ? poolData : null - const { performanceFee, streamingFee, entryFee, exitFee } = - usePoolDynamicContractData({ address, chainId }) - const [easySwapperEntryFee] = useTradingPanelEntryFee() - const vaultNativeEntryFee = entryFee ?? poolFallbackData?.entryFeeNumerator - const hasVaultNativeEntryFee = - !!vaultNativeEntryFee && +vaultNativeEntryFee > 0 - const vaultExitFee = exitFee ?? poolFallbackData?.exitFeeNumerator ?? '0' + const { + performanceFee, + streamingFee, + entryFee: entryFeeContract, + exitFee: exitFeeContract, + } = usePoolDynamicContractData({ address, chainId }) + const entryFee = + entryFeeContract ?? poolFallbackData?.entryFeeNumerator ?? '0' + const exitFee = exitFeeContract ?? poolFallbackData?.exitFeeNumerator ?? '0' return useMemo( () => ({ @@ -42,32 +41,21 @@ export const usePoolFees = ({ address, chainId }: PoolFeesParams) => { MANAGER_FEE_DENOMINATOR, 2, ), - entryFee: hasVaultNativeEntryFee - ? formatNumeratorToPercentage( - vaultNativeEntryFee, - MANAGER_FEE_DENOMINATOR, - 2, - ) - : `${easySwapperEntryFee}%`, - hasPoolEntryFee: hasVaultNativeEntryFee, - exitFee: formatNumeratorToPercentage( - exitFee ?? poolFallbackData?.exitFeeNumerator ?? '0', + entryFee: formatNumeratorToPercentage( + entryFee, MANAGER_FEE_DENOMINATOR, 2, ), - exitFeeNumber: getPercent(+vaultExitFee, MANAGER_FEE_DENOMINATOR), + exitFee: formatNumeratorToPercentage(exitFee, MANAGER_FEE_DENOMINATOR, 2), + exitFeeNumber: getPercent(+exitFee, MANAGER_FEE_DENOMINATOR), }), [ performanceFee, poolFallbackData?.performanceFeeNumerator, poolFallbackData?.streamingFeeNumerator, - poolFallbackData?.exitFeeNumerator, streamingFee, - hasVaultNativeEntryFee, - vaultNativeEntryFee, - easySwapperEntryFee, + entryFee, exitFee, - vaultExitFee, ], ) } diff --git a/packages/trading-widget/src/core-kit/hooks/state/action.ts b/packages/trading-widget/src/core-kit/hooks/state/action.ts index 8cd4ae7..ca32ec5 100644 --- a/packages/trading-widget/src/core-kit/hooks/state/action.ts +++ b/packages/trading-widget/src/core-kit/hooks/state/action.ts @@ -15,7 +15,6 @@ export const useSetTradingType = () => useTradingPanelActions().setTradingType export const useUpdateTradingMeta = () => useTradingPanelActions().updateTradingMeta -export const useUpdateEntryFee = () => useTradingPanelActions().updateEntryFee export const useUpdateTradingModal = () => useTradingPanelActions().updateTradingModal @@ -41,3 +40,5 @@ export const useTradingPanelLogger = () => useTradingPanelActions().onLog export const useOnSimulateTransaction = () => useTradingPanelActions().onSimulateTransaction + +export const useGetSwapData = () => useTradingPanelActions().getSwapData diff --git a/packages/trading-widget/src/core-kit/hooks/state/index.ts b/packages/trading-widget/src/core-kit/hooks/state/index.ts index 162b5e0..27c108e 100644 --- a/packages/trading-widget/src/core-kit/hooks/state/index.ts +++ b/packages/trading-widget/src/core-kit/hooks/state/index.ts @@ -6,7 +6,6 @@ export { useSetPoolAddress, useUpdateReceiveTokenInput, useUpdateTradingSettings, - useUpdateEntryFee, useOnTransactionError, useOnTransactionSuccess, useOnTransactionEstimationError, @@ -15,23 +14,18 @@ export { useOnSimulateTransaction, useUpdatePoolFallbackData, useOnTradingSettleError, + useGetSwapData, } from './action' export { useTradingPanelPoolAddress, useTradingPanelPoolConfig, - useTradingPanelDepositMethod, useTradingPanelPoolConfigs, useTradingPanelPoolFallbackData, useIsPoolAddress, } from './pool' export { useSendTokenInput, useReceiveTokenInput } from './input' export { useTradingPanelSettings } from './settings' -export { - useTradingPanelMeta, - useTradingPanelApprovingStatus, - useTradingPanelEntryFee, - useTradingPanelLockTime, -} from './meta' +export { useTradingPanelMeta, useTradingPanelApprovingStatus } from './meta' export { useTradingPanelModal } from './modal' export { useTradingPanelType, useIsDepositTradingPanelType } from './type' export { useTradingPanelTransactions } from './transaction' diff --git a/packages/trading-widget/src/core-kit/hooks/state/meta.ts b/packages/trading-widget/src/core-kit/hooks/state/meta.ts index c6c2a8b..59e5d32 100644 --- a/packages/trading-widget/src/core-kit/hooks/state/meta.ts +++ b/packages/trading-widget/src/core-kit/hooks/state/meta.ts @@ -1,15 +1,10 @@ import { useCallback } from 'react' -import { CUSTOM_LOCK_TIME, DEFAULT_DEPOSIT_METHOD } from 'core-kit/const' -import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' import type { TradingPanelActionsState, TradingPanelState, } from 'core-kit/types/state.types' -import { useConfigContextParams } from 'trading-widget/providers/config-provider' - -import { useUpdateEntryFee } from './action' import { useTradingPanelActions, useTradingPanelState } from './context' export const useTradingPanelMeta = (): [ @@ -30,28 +25,3 @@ export const useTradingPanelApprovingStatus = (): [ return [meta.approvingStatus, setApprovingStatus] } - -export const useTradingPanelEntryFee = (): [ - number, - (entryFeeSlice: Partial) => void, -] => { - const { depositParams } = useTradingPanelPoolConfig() - const entryFee = useTradingPanelState().entryFee - const updateEntryFee = useUpdateEntryFee() - - return [ - entryFee[depositParams.method ?? DEFAULT_DEPOSIT_METHOD], - updateEntryFee, - ] -} - -export const useTradingPanelLockTime = (): string => { - const { depositParams, chainId } = useTradingPanelPoolConfig() - const { chainCustomLockTimeMap, defaultLockTime } = useConfigContextParams() - - if (depositParams.method === 'depositWithCustomCooldown') { - return chainCustomLockTimeMap[chainId] ?? CUSTOM_LOCK_TIME - } - - return defaultLockTime -} diff --git a/packages/trading-widget/src/core-kit/hooks/state/pool.ts b/packages/trading-widget/src/core-kit/hooks/state/pool.ts index 5d131c4..dbbdc08 100644 --- a/packages/trading-widget/src/core-kit/hooks/state/pool.ts +++ b/packages/trading-widget/src/core-kit/hooks/state/pool.ts @@ -1,13 +1,12 @@ import { useMemo } from 'react' -import { DEFAULT_DEPOSIT_METHOD, EMPTY_POOL_CONFIG } from 'core-kit/const' +import { EMPTY_POOL_CONFIG } from 'core-kit/const' import { useUpdatePoolFallbackData } from 'core-kit/hooks/state' import type { PoolConfig } from 'core-kit/types/config.types' import type { TradingPanelActionsState, TradingPanelState, } from 'core-kit/types/state.types' -import type { DepositMethodName } from 'core-kit/types/trading-panel.types' import type { Address } from 'core-kit/types/web3.types' import { useTradingPanelActions, useTradingPanelState } from './context' @@ -38,21 +37,6 @@ export const useIsPoolAddress = (address: Address) => { ) } -export const useTradingPanelDepositMethod = (): [ - DepositMethodName, - ( - payload: Pick & - Pick, - ) => void, -] => { - const { - depositParams: { method: depositMethod = DEFAULT_DEPOSIT_METHOD }, - } = useTradingPanelPoolConfig() - const { updatePoolConfigDepositMethod } = useTradingPanelActions() - - return [depositMethod, updatePoolConfigDepositMethod] -} - export const useTradingPanelPoolFallbackData = (): [ TradingPanelState['poolFallbackData'], TradingPanelActionsState['updatePoolFallbackData'], diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/__snapshots__/use-deposit-price-diff.test.ts.snap b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/__snapshots__/use-deposit-price-diff.test.ts.snap new file mode 100644 index 0000000..154eeae --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/__snapshots__/use-deposit-price-diff.test.ts.snap @@ -0,0 +1,5 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`useTradingPriceDiff > should calculate diff excluding entry fee 1`] = `-2`; + +exports[`useTradingPriceDiff > should calculate diff including entry fee 1`] = `-1.01`; diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/index.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/index.ts new file mode 100644 index 0000000..25c9013 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/index.ts @@ -0,0 +1,16 @@ +export { useDeposit } from './use-deposit' +export { useDepositAllowance } from './use-deposit-allowance' +export { useDepositQuote } from './use-deposit-quote' +export { useDepositQuoteContractRead } from './use-deposit-quote-contract-read' +export { useDepositSlippage } from './use-deposit-slippage' +export { useHandlePoolDepositData } from './use-handle-pool-deposit-data' +export { useIsVaultDepositLocked } from './use-is-vault-deposit-locked' +export { useSwapDataBasedOnSendToken } from './use-swap-data-based-on-send-token' +export { useVaultDepositParams } from './use-vault-deposit-params' +export { useVaultDepositTokenAmount } from './use-vault-deposit-token-amount' +export { useVaultDepositTokens } from './use-vault-deposit-tokens' +export { useVaultDepositTransactionArguments } from './use-vault-deposit-transaction-arguments' +export { useDepositLockTime } from './use-deposit-lock-time' +export { useDepositPriceDiff } from './use-deposit-price-diff' +export { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' +export { useMinVaultTokensReceivedAmount } from './use-min-vault-tokens-received-amount' diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-applied-deposit-slippage.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-applied-deposit-slippage.test.ts new file mode 100644 index 0000000..069c1ab --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-applied-deposit-slippage.test.ts @@ -0,0 +1,48 @@ +import { + DEFAULT_DEPOSIT_SLIPPAGE, + DEFAULT_SWAP_TRANSACTION_SLIPPAGE, +} from 'core-kit/const' +import { useTradingPanelSettings } from 'core-kit/hooks/state' +import { renderHook } from 'tests/test-utils' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' + +vi.mock('core-kit/hooks/state', () => ({ + useTradingPanelSettings: vi.fn(), +})) + +vi.mock('./use-is-deposit-with-swap-transaction', () => ({ + useIsDepositWithSwapTransaction: vi.fn(), +})) + +describe('useAppliedDepositSlippage', () => { + it('should return default deposit slippage when slippage is auto and not a deposit with swap transaction', () => { + vi.mocked(useTradingPanelSettings).mockReturnValueOnce([ + { slippage: 'auto' }, + ] as unknown as ReturnType) + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValueOnce(false) + + const { result } = renderHook(() => useAppliedDepositSlippage()) + expect(result.current).toEqual(DEFAULT_DEPOSIT_SLIPPAGE) + }) + + it('should return default swap transaction slippage when slippage is auto and is a deposit with swap transaction', () => { + vi.mocked(useTradingPanelSettings).mockReturnValueOnce([ + { slippage: 'auto' }, + ] as unknown as ReturnType) + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValueOnce(true) + + const { result } = renderHook(() => useAppliedDepositSlippage()) + expect(result.current).toEqual(DEFAULT_SWAP_TRANSACTION_SLIPPAGE) + }) + + it('should return the set slippage when slippage is not auto', () => { + vi.mocked(useTradingPanelSettings).mockReturnValueOnce([ + { slippage: 1 }, + ] as unknown as ReturnType) + + const { result } = renderHook(() => useAppliedDepositSlippage()) + expect(result.current).toEqual(1) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-applied-deposit-slippage.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-applied-deposit-slippage.ts new file mode 100644 index 0000000..5133c3e --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-applied-deposit-slippage.ts @@ -0,0 +1,21 @@ +import { DEFAULT_DEPOSIT_SLIPPAGE } from 'core-kit/const' +import { useTradingPanelSettings } from 'core-kit/hooks/state' + +import { useConfigContextParams } from 'trading-widget/providers/config-provider' + +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' + +export const useAppliedDepositSlippage = () => { + const { defaultSwapTransactionSlippage } = useConfigContextParams() + const [{ slippage }] = useTradingPanelSettings() + const isDepositWithSwapTransaction = useIsDepositWithSwapTransaction() + const isAutoSlippage = slippage === 'auto' + + if (isAutoSlippage) { + return isDepositWithSwapTransaction + ? defaultSwapTransactionSlippage + : DEFAULT_DEPOSIT_SLIPPAGE + } + + return slippage +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-allowance.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-allowance.test.ts similarity index 75% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-allowance.test.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-allowance.test.ts index 1df413d..379b9c3 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-allowance.test.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-allowance.test.ts @@ -3,18 +3,16 @@ import { act } from '@testing-library/react' import { AddressZero, BRIDGED_USDC_OPTIMISM, + base, contractsAddressesMap, - optimism, } from 'core-kit/const' import * as stateHooks from 'core-kit/hooks/state' -import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' import * as allowanceHooks from 'core-kit/hooks/trading/allowance' import { TEST_ADDRESS } from 'tests/mocks' import { renderHook } from 'tests/test-utils' import { useDepositAllowance } from './use-deposit-allowance' -import { useIsEasySwapperTrading } from '../use-is-easy-swapper-trading' vi.mock('core-kit/hooks/state', () => ({ useSendTokenInput: vi.fn(), @@ -38,7 +36,7 @@ vi.mock('core-kit/hooks/web3', () => ({ vi.mock('../use-is-easy-swapper-trading', () => ({ useIsEasySwapperTrading: vi.fn(), })) -const chainId = optimism.id +const chainId = base.id describe('useDepositAllowance', () => { it('should return approve fn and check send token allowance when token is not native', () => { @@ -61,7 +59,6 @@ describe('useDepositAllowance', () => { vi.mocked(allowanceHooks.useApprove).mockImplementationOnce( () => approveMock, ) - vi.mocked(useIsEasySwapperTrading).mockImplementationOnce(() => true) const { result } = renderHook(() => useDepositAllowance()) @@ -69,7 +66,7 @@ describe('useDepositAllowance', () => { expect(allowanceHooks.useCanSpend).toHaveBeenCalledWith({ tokenAddress: sendToken.address, ownerAddress: TEST_ADDRESS, - spenderAddress: contractsAddressesMap[chainId]?.easySwapper, + spenderAddress: contractsAddressesMap[chainId]?.easySwapperV2, rawAmountToSpend: '1000000', chainId, skip: false, @@ -78,7 +75,7 @@ describe('useDepositAllowance', () => { expect(allowanceHooks.useApprove).toHaveBeenCalledWith({ token: sendToken, rawTokenAmount: '1000000', - spenderAddress: contractsAddressesMap[chainId]?.easySwapper, + spenderAddress: contractsAddressesMap[chainId]?.easySwapperV2, }) expect(updateApprovingStatusMock).toHaveBeenCalledTimes(1) expect(updateApprovingStatusMock).toHaveBeenCalledWith('success') @@ -88,7 +85,7 @@ describe('useDepositAllowance', () => { }) it('should not check send token allowance when token is native', () => { - const chainId = optimism.id + const chainId = base.id const sendToken = { symbol: 'ETH', value: '1', @@ -106,7 +103,6 @@ describe('useDepositAllowance', () => { () => ['success', updateApprovingStatusMock], ) vi.mocked(allowanceHooks.useApprove).mockImplementationOnce(() => vi.fn()) - vi.mocked(useIsEasySwapperTrading).mockImplementationOnce(() => true) renderHook(() => useDepositAllowance()) @@ -114,7 +110,7 @@ describe('useDepositAllowance', () => { expect(allowanceHooks.useCanSpend).toHaveBeenCalledWith({ tokenAddress: sendToken.address, ownerAddress: TEST_ADDRESS, - spenderAddress: contractsAddressesMap[chainId]?.easySwapper, + spenderAddress: contractsAddressesMap[chainId]?.easySwapperV2, rawAmountToSpend: '1000', chainId, skip: true, @@ -122,33 +118,4 @@ describe('useDepositAllowance', () => { expect(updateApprovingStatusMock).toHaveBeenCalledTimes(1) expect(updateApprovingStatusMock).toHaveBeenCalledWith(undefined) }) - - it('should use correct contract address to check PoolLogic allowance', () => { - const sendToken = { ...BRIDGED_USDC_OPTIMISM, value: '1', isLoading: false } - - vi.mocked(stateHooks.useSendTokenInput).mockImplementationOnce(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useTradingPanelApprovingStatus).mockImplementationOnce( - () => ['pending', vi.fn()], - ) - vi.mocked(useTradingPanelPoolConfig).mockImplementationOnce( - () => - ({ - address: '0xPool', - chainId: optimism.id, - }) as unknown as ReturnType, - ) - vi.mocked(useIsEasySwapperTrading).mockImplementationOnce(() => false) - - renderHook(() => useDepositAllowance()) - - expect(allowanceHooks.useCanSpend).toHaveBeenCalledWith( - expect.objectContaining({ - spenderAddress: '0xPool', - chainId, - }), - ) - }) }) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-allowance.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-allowance.ts similarity index 68% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-allowance.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-allowance.ts index d28dc2d..cc9a0de 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-allowance.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-allowance.ts @@ -12,32 +12,24 @@ import { useApprove, useCanSpend } from 'core-kit/hooks/trading/allowance' import { useAccount } from 'core-kit/hooks/web3' import { getContractAddressById, isNativeToken } from 'core-kit/utils' -import { useIsEasySwapperTrading } from '../use-is-easy-swapper-trading' - export const useDepositAllowance = () => { - const { account } = useAccount() - const poolConfig = useTradingPanelPoolConfig() + const { account = AddressZero } = useAccount() + const { chainId } = useTradingPanelPoolConfig() const [sendToken] = useSendTokenInput() const updateApprovingStatus = useTradingPanelApprovingStatus()[1] - const isEasySwapperTrading = useIsEasySwapperTrading() + const spenderAddress = getContractAddressById('easySwapperV2', chainId) const rawDepositAmount = new BigNumber(sendToken.value || '0') .shiftedBy(sendToken.decimals) .toFixed(0, BigNumber.ROUND_UP) - const spenderAddress = isEasySwapperTrading - ? getContractAddressById('easySwapper', poolConfig.chainId) - : poolConfig.address - const canSpend = useCanSpend({ tokenAddress: sendToken.address, - ownerAddress: account ?? AddressZero, + ownerAddress: account, spenderAddress, rawAmountToSpend: rawDepositAmount, - chainId: poolConfig.chainId, - skip: - isNativeToken(sendToken.symbol, poolConfig.chainId) || - rawDepositAmount === '0', + chainId, + skip: isNativeToken(sendToken.symbol, chainId) || rawDepositAmount === '0', }) const approve = useApprove({ token: sendToken, diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-lock-time.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-lock-time.test.ts new file mode 100644 index 0000000..92f12ff --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-lock-time.test.ts @@ -0,0 +1,115 @@ +import { expect } from 'vitest' + +import { optimism } from 'core-kit/const' +import { usePoolStatic } from 'core-kit/hooks/pool/multicall' +import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' + +import { renderHook } from 'tests/test-utils' + +import { useDepositLockTime } from './use-deposit-lock-time' +import { useVaultDepositParams } from './use-vault-deposit-params' + +vi.mock('core-kit/hooks/pool/multicall', () => ({ + usePoolStatic: vi.fn(), +})) + +vi.mock('core-kit/hooks/state', () => ({ + useTradingPanelPoolConfig: vi.fn(), +})) + +vi.mock('./use-vault-deposit-params', () => ({ + useVaultDepositParams: vi.fn(), +})) + +describe('useDepositLockTime', () => { + const chainId = optimism.id + + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockImplementation( + () => ({ chainId }) as ReturnType, + ) + + vi.mocked(usePoolStatic).mockImplementation( + () => + ({ data: { customCooldown: 3600n } }) as ReturnType< + typeof usePoolStatic + >, + ) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return lock time for deposit', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'deposit', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('24 hours') + }) + + it('should return lock time for depositWithCustomCooldown ', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'depositWithCustomCooldown', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('60 minutes') + }) + + it('should return lock time for nativeDeposit', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'nativeDeposit', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('24 hours') + }) + + it('should return lock time for nativeDepositWithCustomCooldown', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'nativeDepositWithCustomCooldown', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('60 minutes') + }) + + it('should return lock time for zapDepositWithCustomCooldown', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'zapDepositWithCustomCooldown', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('60 minutes') + }) + + it('should return lock time for zapDeposit', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'zapDeposit', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('24 hours') + }) + + it('should return lock time for zapNativeDeposit', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'zapNativeDeposit', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('24 hours') + }) + + it('should return lock time for zapNativeDepositWithCustomCooldown', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod: 'zapNativeDepositWithCustomCooldown', + } as ReturnType) + + const { result } = renderHook(() => useDepositLockTime()) + expect(result.current).toBe('60 minutes') + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-lock-time.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-lock-time.ts new file mode 100644 index 0000000..7db6769 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-lock-time.ts @@ -0,0 +1,32 @@ +import { formatDuration } from 'date-fns' + +import { usePoolStatic } from 'core-kit/hooks/pool/multicall' +import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' + +import { useConfigContextParams } from 'trading-widget/providers/config-provider' + +import { useVaultDepositParams } from './use-vault-deposit-params' + +export const useDepositLockTime = () => { + const { defaultLockTime } = useConfigContextParams() + const { chainId, address } = useTradingPanelPoolConfig() + const { data: { customCooldown } = {} } = usePoolStatic({ + address, + chainId, + }) + const { depositMethod } = useVaultDepositParams() + + const customLockTime = customCooldown + ? formatDuration({ minutes: Number(customCooldown) / 60 }) + : defaultLockTime + + switch (depositMethod) { + case 'depositWithCustomCooldown': + case 'nativeDepositWithCustomCooldown': + case 'zapDepositWithCustomCooldown': + case 'zapNativeDepositWithCustomCooldown': + return customLockTime + default: + return defaultLockTime + } +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-price-diff.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-price-diff.test.ts new file mode 100644 index 0000000..81b65df --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-price-diff.test.ts @@ -0,0 +1,207 @@ +import { beforeEach } from 'vitest' + +import { optimism } from 'core-kit/const' +import * as poolHooks from 'core-kit/hooks/pool' +import * as stateHooks from 'core-kit/hooks/state' +import * as tradingHooks from 'core-kit/hooks/trading' +import { TEST_ADDRESS } from 'tests/mocks' +import { renderHook } from 'tests/test-utils' + +import { useDepositPriceDiff } from './use-deposit-price-diff' + +vi.mock('core-kit/hooks/pool', () => ({ + usePoolTokenPrice: vi.fn(), + usePoolDynamicContractData: vi.fn(), +})) + +vi.mock('core-kit/hooks/state', () => ({ + useTradingPanelPoolConfig: vi.fn(), + useSendTokenInput: vi.fn(), + useReceiveTokenInput: vi.fn(), +})) + +vi.mock('core-kit/hooks/trading', () => ({ + useAssetPrice: vi.fn(), +})) + +const poolConfig = { address: TEST_ADDRESS, chainId: optimism.id } + +describe('useTradingPriceDiff', () => { + beforeEach(() => { + vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValueOnce( + poolConfig as ReturnType, + ) + }) + + it('should handle zero send input value', () => { + const sendAssetValue = '0' + const receiveAssetValue = '2' + const sendTokenPrice = '1' + const poolTokenPrice = '2' + + expect(Number(sendAssetValue)).toEqual(0) + expect(Number(receiveAssetValue)).not.toEqual(0) + expect(Number(sendTokenPrice)).not.toEqual(0) + expect(Number(poolTokenPrice)).not.toEqual(0) + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValueOnce([ + { value: sendAssetValue }, + ] as unknown as ReturnType) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValueOnce([ + { value: receiveAssetValue }, + ] as unknown as ReturnType) + vi.mocked(poolHooks.usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '0', + } as unknown as ReturnType) + vi.mocked(tradingHooks.useAssetPrice).mockReturnValueOnce(sendTokenPrice) + vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValueOnce(poolTokenPrice) + + const { result } = renderHook(() => useDepositPriceDiff()) + + expect(result.current).toEqual(0) + }) + + it('should handle zero receive input value', () => { + const sendAssetValue = '1' + const receiveAssetValue = '0' + const sendTokenPrice = '1' + const poolTokenPrice = '2' + + expect(Number(sendAssetValue)).not.toEqual(0) + expect(Number(receiveAssetValue)).toEqual(0) + expect(Number(sendTokenPrice)).not.toEqual(0) + expect(Number(poolTokenPrice)).not.toEqual(0) + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValueOnce([ + { value: sendAssetValue }, + ] as unknown as ReturnType) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValueOnce([ + { value: receiveAssetValue }, + ] as unknown as ReturnType) + vi.mocked(poolHooks.usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '0', + } as unknown as ReturnType) + vi.mocked(tradingHooks.useAssetPrice).mockReturnValueOnce(sendTokenPrice) + vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValueOnce(poolTokenPrice) + + const { result } = renderHook(() => useDepositPriceDiff()) + + expect(result.current).toEqual(0) + }) + + it('should handle zero send token price', () => { + const sendAssetValue = '1' + const receiveAssetValue = '1' + const sendTokenPrice = '0' + const poolTokenPrice = '2' + + expect(Number(sendAssetValue)).not.toEqual(0) + expect(Number(receiveAssetValue)).not.toEqual(0) + expect(Number(sendTokenPrice)).toEqual(0) + expect(Number(poolTokenPrice)).not.toEqual(0) + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValueOnce([ + { value: sendAssetValue }, + ] as unknown as ReturnType) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValueOnce([ + { value: receiveAssetValue }, + ] as unknown as ReturnType) + vi.mocked(poolHooks.usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '0', + } as unknown as ReturnType) + vi.mocked(tradingHooks.useAssetPrice).mockReturnValueOnce(sendTokenPrice) + vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValueOnce(poolTokenPrice) + + const { result } = renderHook(() => useDepositPriceDiff()) + + expect(result.current).toEqual(0) + }) + + it('should handle zero receive token price', () => { + const sendAssetValue = '1' + const receiveAssetValue = '1' + const sendTokenPrice = '1' + const poolTokenPrice = '0' + + expect(Number(sendAssetValue)).not.toEqual(0) + expect(Number(receiveAssetValue)).not.toEqual(0) + expect(Number(sendTokenPrice)).not.toEqual(0) + expect(Number(poolTokenPrice)).toEqual(0) + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValueOnce([ + { value: sendAssetValue }, + ] as unknown as ReturnType) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValueOnce([ + { value: receiveAssetValue }, + ] as unknown as ReturnType) + vi.mocked(poolHooks.usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '0', + } as unknown as ReturnType) + vi.mocked(tradingHooks.useAssetPrice).mockReturnValueOnce(sendTokenPrice) + vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValueOnce(poolTokenPrice) + + const { result } = renderHook(() => useDepositPriceDiff()) + + expect(result.current).toEqual(0) + }) + + it('should calculate diff excluding entry fee', () => { + const entryFee = '1' + const sendAssetValue = '100' + const receiveAssetValue = '49' + const sendTokenPrice = '100' + const poolTokenPrice = '200' + + expect(Number(sendAssetValue)).not.toEqual(0) + expect(Number(receiveAssetValue)).not.toEqual(0) + expect(Number(sendTokenPrice)).not.toEqual(0) + expect(Number(poolTokenPrice)).not.toEqual(0) + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValueOnce([ + { value: sendAssetValue }, + ] as unknown as ReturnType) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValueOnce([ + { value: receiveAssetValue }, + ] as unknown as ReturnType) + vi.mocked(poolHooks.usePoolDynamicContractData).mockReturnValueOnce({ + entryFee, + } as unknown as ReturnType) + vi.mocked(tradingHooks.useAssetPrice).mockReturnValue(sendTokenPrice) + vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValue(poolTokenPrice) + + const { result } = renderHook(() => useDepositPriceDiff()) + + expect(result.current).toMatchSnapshot() + }) + + it('should calculate diff including entry fee', () => { + const entryFee = '100' + const sendAssetValue = '100' + const receiveAssetValue = '49' + const sendTokenPrice = '100' + const poolTokenPrice = '200' + + expect(Number(sendAssetValue)).not.toEqual(0) + expect(Number(receiveAssetValue)).not.toEqual(0) + expect(Number(sendTokenPrice)).not.toEqual(0) + expect(Number(poolTokenPrice)).not.toEqual(0) + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValueOnce([ + { value: sendAssetValue }, + ] as unknown as ReturnType) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValueOnce([ + { value: receiveAssetValue }, + ] as unknown as ReturnType) + vi.mocked(poolHooks.usePoolDynamicContractData).mockReturnValueOnce({ + entryFee, + } as unknown as ReturnType) + vi.mocked(tradingHooks.useAssetPrice).mockReturnValue(sendTokenPrice) + vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValue(poolTokenPrice) + + const { result } = renderHook(() => + useDepositPriceDiff({ includesEntryFee: true }), + ) + + expect(result.current).toMatchSnapshot() + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-price-diff.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-price-diff.ts new file mode 100644 index 0000000..92fd23f --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-price-diff.ts @@ -0,0 +1,79 @@ +import BigNumber from 'bignumber.js' +import { useMemo } from 'react' + +import { MANAGER_FEE_DENOMINATOR } from 'core-kit/const' +import { + usePoolDynamicContractData, + usePoolTokenPrice, +} from 'core-kit/hooks/pool' +import { + useReceiveTokenInput, + useSendTokenInput, + useTradingPanelPoolConfig, +} from 'core-kit/hooks/state' +import { useAssetPrice } from 'core-kit/hooks/trading' +import { getConventionalTokenPriceDecimals, getPercent } from 'core-kit/utils' + +type UseDepositPriceDiffProps = + | { + includesEntryFee?: boolean + } + | undefined + +export const useDepositPriceDiff = (props: UseDepositPriceDiffProps = {}) => { + const { address, chainId } = useTradingPanelPoolConfig() + const { entryFee = '0' } = usePoolDynamicContractData({ address, chainId }) + const [sendToken] = useSendTokenInput() + const [receiveToken] = useReceiveTokenInput() + const sendTokenPrice = useAssetPrice({ + address: sendToken.address, + chainId, + }) + const vaultTokenPrice = usePoolTokenPrice({ address, chainId }) + const entryFeeValue = props.includesEntryFee + ? getPercent(+entryFee, MANAGER_FEE_DENOMINATOR) + : 0 + + return useMemo(() => { + const sendAmount = Number(sendToken.value || '0') + const sendAmountBN = new BigNumber(sendAmount) + .times(sendTokenPrice ?? '0') + .times(1 - entryFeeValue / 100) + + const receiveAmount = Number(receiveToken.value || '0') + const receiveAmountBN = new BigNumber(receiveAmount).times( + vaultTokenPrice ?? '0', + ) + + if (sendAmountBN.isZero() || receiveAmountBN.isZero()) { + return 0 + } + + const canBeCompared = sendAmountBN + .decimalPlaces(getConventionalTokenPriceDecimals(sendAmount)) + .comparedTo( + receiveAmountBN.decimalPlaces( + getConventionalTokenPriceDecimals(receiveAmount), + ), + ) + + if (canBeCompared) { + return sendAmountBN.isGreaterThan(0) + ? receiveAmountBN + .dividedBy(sendAmountBN) + .minus(1) + .times(100) + .decimalPlaces(2, BigNumber.ROUND_DOWN) + .toNumber() + : 0 + } + + return 0 + }, [ + entryFeeValue, + receiveToken.value, + sendToken.value, + sendTokenPrice, + vaultTokenPrice, + ]) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote-contract-read.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote-contract-read.test.ts new file mode 100644 index 0000000..f96d671 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote-contract-read.test.ts @@ -0,0 +1,128 @@ +import { act } from '@testing-library/react' +import { expect } from 'vitest' + +import { EasySwapperV2Abi } from 'core-kit/abi' +import { EXTREMELY_SHORT_POLLING_INTERVAL } from 'core-kit/const' +import { + useIsDepositTradingPanelType, + useSendTokenInput, +} from 'core-kit/hooks/state' +import { useDebounce } from 'core-kit/hooks/utils' +import { useReadContract } from 'core-kit/hooks/web3' +import { renderHook } from 'tests/test-utils' + +import { useDepositQuoteContractRead } from './use-deposit-quote-contract-read' +import { useVaultDepositParams } from './use-vault-deposit-params' +import { useVaultDepositTokenAmount } from './use-vault-deposit-token-amount' + +vi.mock('core-kit/hooks/state', () => ({ + useIsDepositTradingPanelType: vi.fn(), + useSendTokenInput: vi.fn(), +})) +vi.mock('core-kit/hooks/utils', () => ({ + useDebounce: vi.fn(), +})) +vi.mock('core-kit/hooks/web3', () => ({ + useContractReadErrorLogging: vi.fn(), + useReadContract: vi.fn(), +})) +vi.mock('./use-vault-deposit-params', () => ({ + useVaultDepositParams: vi.fn(), +})) +vi.mock('./use-vault-deposit-token-amount', () => ({ + useVaultDepositTokenAmount: vi.fn(), +})) + +describe('useDepositQuoteContractRead', () => { + beforeEach(() => { + vi.mocked(useSendTokenInput).mockImplementation( + () => + [{ address: '0x123' }] as unknown as ReturnType< + typeof useSendTokenInput + >, + ) + vi.mocked(useDebounce).mockImplementation((v) => v) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should not make a request when is not deposit type', () => { + vi.mocked(useIsDepositTradingPanelType).mockReturnValueOnce(false) + vi.mocked(useVaultDepositParams).mockReturnValue({ + vaultDepositTokenAddress: '0x1', + depositMethod: 'deposit', + }) + vi.mocked(useVaultDepositTokenAmount).mockReturnValue('100') + + const { rerender } = renderHook(() => + useDepositQuoteContractRead({ address: '0x123', chainId: 1 }), + ) + expect(useReadContract).toHaveBeenCalledWith( + expect.objectContaining({ + chainId: 1, + query: expect.objectContaining({ + enabled: false, + refetchInterval: EXTREMELY_SHORT_POLLING_INTERVAL, + }), + }), + ) + + vi.mocked(useIsDepositTradingPanelType).mockReturnValue(true) + act(() => rerender()) + + expect(useReadContract).toHaveBeenCalledTimes(2) + expect(useReadContract).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + query: expect.objectContaining({ + enabled: true, + }), + }), + ) + + vi.mocked(useVaultDepositTokenAmount).mockReturnValueOnce('') + act(() => rerender()) + expect(useReadContract).toHaveBeenCalledTimes(3) + expect(useReadContract).toHaveBeenNthCalledWith( + 3, + expect.objectContaining({ + query: expect.objectContaining({ + enabled: false, + }), + }), + ) + }) + + it('should make a request when is deposit type', () => { + const address = '0x123' + const vaultDepositTokenAddress = '0x1' + const vaultDepositTokenAmount = '100' + vi.mocked(useIsDepositTradingPanelType).mockReturnValue(true) + vi.mocked(useVaultDepositParams).mockReturnValue({ + vaultDepositTokenAddress, + depositMethod: 'deposit', + }) + vi.mocked(useVaultDepositTokenAmount).mockReturnValue( + vaultDepositTokenAmount, + ) + + renderHook(() => useDepositQuoteContractRead({ address, chainId: 1 })) + + expect(useReadContract).toHaveBeenCalledTimes(1) + expect(useReadContract).toHaveBeenCalledWith( + expect.objectContaining({ + abi: EasySwapperV2Abi, + functionName: 'depositQuote', + args: [ + address, + vaultDepositTokenAddress, + BigInt(vaultDepositTokenAmount), + ], + chainId: 1, + query: expect.objectContaining({ enabled: true }), + }), + ) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote-contract-read.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote-contract-read.ts new file mode 100644 index 0000000..4e124c3 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote-contract-read.ts @@ -0,0 +1,49 @@ +import { keepPreviousData } from '@tanstack/react-query' + +import { EasySwapperV2Abi } from 'core-kit/abi' +import { EXTREMELY_SHORT_POLLING_INTERVAL } from 'core-kit/const' +import { + useIsDepositTradingPanelType, + useSendTokenInput, +} from 'core-kit/hooks/state' +import { useDebounce } from 'core-kit/hooks/utils' +import { + useContractReadErrorLogging, + useReadContract, +} from 'core-kit/hooks/web3' +import type { PoolConfig } from 'core-kit/types/config.types' +import { getContractAddressById } from 'core-kit/utils' + +import { useVaultDepositParams } from './use-vault-deposit-params' +import { useVaultDepositTokenAmount } from './use-vault-deposit-token-amount' + +export const useDepositQuoteContractRead = ({ + address, + chainId, +}: Pick) => { + const [sendToken] = useSendTokenInput() + const isDeposit = useIsDepositTradingPanelType() + const { vaultDepositTokenAddress } = useVaultDepositParams() + + const sendAmount = useVaultDepositTokenAmount() + const debouncedSendAmount = useDebounce(sendAmount, 500) + const hasSendInputValue = !!(debouncedSendAmount && +debouncedSendAmount > 0) + + const quoteResponse = useReadContract({ + address: getContractAddressById('easySwapperV2', chainId), + abi: EasySwapperV2Abi, + functionName: 'depositQuote', + args: [address, vaultDepositTokenAddress, BigInt(sendAmount ?? 0)], + chainId, + query: { + enabled: + isDeposit && hasSendInputValue && !!sendToken.address && !!sendAmount, + refetchInterval: EXTREMELY_SHORT_POLLING_INTERVAL, + placeholderData: keepPreviousData, + }, + }) + + useContractReadErrorLogging(quoteResponse) + + return quoteResponse +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote.test.ts new file mode 100644 index 0000000..df99019 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote.test.ts @@ -0,0 +1,192 @@ +import { act } from '@testing-library/react' + +import { expect } from 'vitest' + +import { optimism } from 'core-kit/const' +import * as stateHooks from 'core-kit/hooks/state' + +import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' +import type { DynamicTradingToken } from 'core-kit/types' +import { renderHook } from 'tests/test-utils' + +import { useDepositQuote } from './use-deposit-quote' +import { useDepositQuoteContractRead } from './use-deposit-quote-contract-read' + +vi.mock('core-kit/hooks/state', () => ({ + useIsDepositTradingPanelType: vi.fn(), + useReceiveTokenInput: vi.fn(), + useSendTokenInput: vi.fn(), + useTradingPanelSettings: vi.fn(), + useTradingPanelPoolConfig: vi.fn(), +})) +vi.mock('core-kit/hooks/utils', () => ({ + useDebounce: vi.fn().mockImplementation((v) => v), +})) + +vi.mock('./use-deposit-quote-contract-read', () => ({ + useDepositQuoteContractRead: vi.fn(), +})) +vi.mock('./use-swap-data-based-on-send-token', () => ({ + useSwapDataBasedOnSendToken: vi.fn().mockReturnValue({}), +})) + +describe('useDepositQuote', () => { + const address = '0x123' + const chainId = optimism.id + const updateSettingsMock = vi.fn() + + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockImplementation( + () => + ({ chainId, address }) as unknown as ReturnType< + typeof useTradingPanelPoolConfig + >, + ) + vi.mocked(stateHooks.useTradingPanelSettings).mockReturnValue([ + {}, + updateSettingsMock, + ] as unknown as ReturnType) + }) + + it('should not update receive token when is not deposit', () => { + const isDeposit = false + const sendToken: DynamicTradingToken = { + symbol: 'USDC', + address: '0x123', + decimals: 6, + value: '100', + isLoading: false, + } + const receiveToken: DynamicTradingToken = { + symbol: 'USDy', + address: '0x111', + decimals: 3, + value: '50', + isLoading: false, + } + const updateReceiveTokenMock = vi.fn() + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValue([ + sendToken, + vi.fn(), + ]) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValue([ + receiveToken, + updateReceiveTokenMock, + ]) + vi.mocked(stateHooks.useIsDepositTradingPanelType).mockReturnValue( + isDeposit, + ) + vi.mocked(useDepositQuoteContractRead).mockReturnValueOnce({ + isFetching: false, + } as ReturnType) + + expect(isDeposit).toBe(false) + + renderHook(() => useDepositQuote()) + + expect(updateReceiveTokenMock).not.toHaveBeenCalled() + }) + + it('should update receive token input based on deposit quote', () => { + const isDeposit = true + const updateReceiveTokenMock = vi.fn() + + const sendToken: DynamicTradingToken = { + symbol: 'USDC', + address: '0x123', + decimals: 6, + value: '100', + isLoading: false, + } + const receiveToken: DynamicTradingToken = { + symbol: 'USDy', + address: '0x111', + decimals: 3, + value: '50', + isLoading: false, + } + + expect(isDeposit).toBe(true) + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValue([ + sendToken, + vi.fn(), + ]) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValue([ + receiveToken, + updateReceiveTokenMock, + ]) + vi.mocked(stateHooks.useIsDepositTradingPanelType).mockReturnValue( + isDeposit, + ) + vi.mocked(useDepositQuoteContractRead).mockReturnValue({ + isFetching: true, + } as ReturnType) + + const { rerender } = renderHook(() => useDepositQuote()) + + expect(updateReceiveTokenMock).toHaveBeenCalledTimes(1) + expect(updateReceiveTokenMock).toHaveBeenCalledWith({ + isLoading: true, + }) + + vi.mocked(useDepositQuoteContractRead).mockReturnValue({ + isFetching: false, + data: 30000n, + } as ReturnType) + + act(() => rerender()) + + expect(updateReceiveTokenMock).toHaveBeenCalledTimes(3) + expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(2, { + value: '30.000', + }) + expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(3, { + isLoading: false, + }) + }) + + it('should reset receive token value and slippage when send token value is 0', () => { + const isDeposit = true + const updateReceiveTokenMock = vi.fn() + + const sendToken: DynamicTradingToken = { + symbol: 'USDC', + address: '0x123', + decimals: 6, + value: '', + isLoading: false, + } + const receiveToken: DynamicTradingToken = { + symbol: 'USDy', + address: '0x111', + decimals: 3, + value: '50', + isLoading: false, + } + + vi.mocked(stateHooks.useSendTokenInput).mockReturnValue([ + sendToken, + vi.fn(), + ]) + vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValue([ + receiveToken, + updateReceiveTokenMock, + ]) + vi.mocked(stateHooks.useIsDepositTradingPanelType).mockReturnValue( + isDeposit, + ) + vi.mocked(useDepositQuoteContractRead).mockReturnValueOnce({ + isFetching: false, + } as ReturnType) + + renderHook(() => useDepositQuote()) + + expect(updateReceiveTokenMock).toHaveBeenCalledTimes(2) + expect(updateReceiveTokenMock).toHaveBeenCalledWith({ isLoading: false }) + expect(updateReceiveTokenMock).toHaveBeenCalledWith({ value: '0' }) + expect(updateSettingsMock).toHaveBeenCalledTimes(1) + expect(updateSettingsMock).toHaveBeenCalledWith({ minSlippage: 0 }) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote.ts new file mode 100644 index 0000000..7b8ae09 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-quote.ts @@ -0,0 +1,72 @@ +import BigNumber from 'bignumber.js' + +import { useEffect } from 'react' + +import { + useIsDepositTradingPanelType, + useReceiveTokenInput, + useSendTokenInput, + useTradingPanelPoolConfig, + useTradingPanelSettings, +} from 'core-kit/hooks/state' +import { useDebounce } from 'core-kit/hooks/utils' + +import { useDepositQuoteContractRead } from './use-deposit-quote-contract-read' +import { useSwapDataBasedOnSendToken } from './use-swap-data-based-on-send-token' + +export const useDepositQuote = () => { + const { address, chainId } = useTradingPanelPoolConfig() + const isDeposit = useIsDepositTradingPanelType() + + const [sendToken] = useSendTokenInput() + const [receiveToken, updateReceiveToken] = useReceiveTokenInput() + const [, updateSettings] = useTradingPanelSettings() + const debouncedSendTokenValue = useDebounce(sendToken.value, 500) + const { isFetching: isSwapDataFetching } = useSwapDataBasedOnSendToken() + const { data: quoteResult, isFetching: isDepositQuoteFetching } = + useDepositQuoteContractRead({ + address, + chainId, + }) + + const isLoading = + isSwapDataFetching || + isDepositQuoteFetching || + sendToken.value !== debouncedSendTokenValue + + useEffect(() => { + if (!isDeposit) { + return + } + if (quoteResult) { + const formattedVal = new BigNumber(quoteResult.toString()) + .shiftedBy(-receiveToken.decimals) + .toFixed(receiveToken.decimals) + + updateReceiveToken({ value: formattedVal }) + } + }, [ + quoteResult, + receiveToken.decimals, + sendToken.address, + updateReceiveToken, + isDeposit, + ]) + + useEffect(() => { + if (!isDeposit) { + return + } + updateReceiveToken({ isLoading }) + }, [isDeposit, isLoading, updateReceiveToken]) + + useEffect(() => { + if (!isDeposit) { + return + } + if (!sendToken.value || sendToken.value === '0') { + updateReceiveToken({ value: '0' }) + updateSettings({ minSlippage: 0 }) + } + }, [updateReceiveToken, updateSettings, sendToken.value, isDeposit]) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-slippage.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-slippage.test.ts similarity index 56% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-slippage.test.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-slippage.test.ts index 17a25df..1fb3d42 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-slippage.test.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-slippage.test.ts @@ -1,24 +1,25 @@ import { act } from '@testing-library/react' import * as stateHooks from 'core-kit/hooks/state' -import * as tradingHooks from 'core-kit/hooks/trading' -import type { DynamicTradingToken, TradingPanelState } from 'core-kit/types' -import { TEST_ADDRESS } from 'tests/mocks' +import type { TradingPanelState } from 'core-kit/types' import { renderHook } from 'tests/test-utils' +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useDepositPriceDiff } from './use-deposit-price-diff' import { useDepositSlippage } from './use-deposit-slippage' vi.mock('core-kit/hooks/state', () => ({ useIsDepositTradingPanelType: vi.fn(), - useSendTokenInput: vi.fn(), useTradingPanelSettings: vi.fn(), })) -vi.mock('core-kit/hooks/trading', () => ({ useTradingPriceDiff: vi.fn() })) +vi.mock('./use-deposit-price-diff', () => ({ useDepositPriceDiff: vi.fn() })) vi.mock('core-kit/hooks/utils', () => ({ useDebounce: vi.fn().mockImplementation((v) => v), })) - +vi.mock('./use-applied-deposit-slippage', () => ({ + useAppliedDepositSlippage: vi.fn(), +})) const updateSettingsMock = vi.fn() describe('useDepositSlippage', () => { @@ -26,42 +27,32 @@ describe('useDepositSlippage', () => { vi.mocked(stateHooks.useIsDepositTradingPanelType).mockImplementation( () => true, ) - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - { - address: TEST_ADDRESS, - value: '1', - } as unknown as DynamicTradingToken, - vi.fn(), - ]) vi.mocked(stateHooks.useTradingPanelSettings).mockImplementation(() => [ {} as unknown as TradingPanelState['settings'], updateSettingsMock, ]) + vi.mocked(useAppliedDepositSlippage).mockReturnValue(0) }) - it('should update deposit slippage', () => { - const receiveAssetInputValue = '123' - - vi.mocked(tradingHooks.useTradingPriceDiff) + it('should update min slippage including deposit slippage', () => { + vi.mocked(useDepositPriceDiff) .mockImplementationOnce(() => 2.12) .mockImplementationOnce(() => -1.13) + .mockImplementationOnce(() => -2) - const { rerender } = renderHook(() => - useDepositSlippage(receiveAssetInputValue), - ) + const { rerender } = renderHook(() => useDepositSlippage()) expect(stateHooks.useIsDepositTradingPanelType).toHaveBeenCalledTimes(1) - expect(stateHooks.useSendTokenInput).toHaveBeenCalledTimes(1) expect(stateHooks.useTradingPanelSettings).toHaveBeenCalledTimes(1) - expect(tradingHooks.useTradingPriceDiff).toHaveBeenCalledTimes(1) - expect(tradingHooks.useTradingPriceDiff).toHaveBeenCalledWith({ - sendAssetAddress: TEST_ADDRESS, - sendAssetValue: '1', - receiveAssetValue: receiveAssetInputValue, - }) + expect(useDepositPriceDiff).toHaveBeenCalledTimes(1) expect(updateSettingsMock).toHaveBeenCalledTimes(1) expect(updateSettingsMock).toHaveBeenCalledWith({ minSlippage: 0 }) act(() => rerender()) expect(updateSettingsMock).toHaveBeenCalledTimes(2) expect(updateSettingsMock).toHaveBeenLastCalledWith({ minSlippage: 1.13 }) + + vi.mocked(useAppliedDepositSlippage).mockReturnValue(1) + act(() => rerender()) + expect(updateSettingsMock).toHaveBeenCalledTimes(3) + expect(updateSettingsMock).toHaveBeenLastCalledWith({ minSlippage: 3 }) }) }) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-slippage.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-slippage.ts new file mode 100644 index 0000000..94fa842 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit-slippage.ts @@ -0,0 +1,30 @@ +import { useEffect } from 'react' + +import { + useIsDepositTradingPanelType, + useTradingPanelSettings, +} from 'core-kit/hooks/state' +import { useDebounce } from 'core-kit/hooks/utils' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useDepositPriceDiff } from './use-deposit-price-diff' + +export const useDepositSlippage = () => { + const isDeposit = useIsDepositTradingPanelType() + const [, updateSettings] = useTradingPanelSettings() + + const depositSlippage = useAppliedDepositSlippage() + const priceDiff = useDepositPriceDiff({ includesEntryFee: true }) + + const priceDiffDebounced = useDebounce(priceDiff - depositSlippage, 100) + + useEffect(() => { + if (isDeposit) { + const minSlippage = + priceDiffDebounced < 0 + ? Math.abs(Number(priceDiffDebounced.toFixed(2))) + : 0 + updateSettings({ minSlippage }) + } + }, [updateSettings, isDeposit, priceDiffDebounced]) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit.test.ts new file mode 100644 index 0000000..aac6243 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit.test.ts @@ -0,0 +1,126 @@ +import { act } from '@testing-library/react' +import { expect } from 'vitest' + +import { BRIDGED_USDC_OPTIMISM, optimism } from 'core-kit/const' + +import { + useReceiveTokenInput, + useSendTokenInput, + useTradingPanelPoolConfig, + useTradingPanelTransactions, +} from 'core-kit/hooks/state' +import { useTradingSettleHandler } from 'core-kit/hooks/trading' +import { useContractFunction } from 'core-kit/hooks/web3' +import type { DynamicTradingToken } from 'core-kit/types' + +import { renderHook } from 'tests/test-utils' + +import { useDeposit } from './use-deposit' +import { useVaultDepositParams } from './use-vault-deposit-params' +import { useVaultDepositTransactionArguments } from './use-vault-deposit-transaction-arguments' + +vi.mock('core-kit/hooks/state', () => ({ + useReceiveTokenInput: vi.fn(), + useTradingPanelPoolConfig: vi.fn(), + useTradingPanelTransactions: vi.fn(), + useSendTokenInput: vi.fn(), +})) + +vi.mock('core-kit/hooks/trading', () => ({ + useTradingSettleHandler: vi.fn(), +})) + +vi.mock('core-kit/hooks/web3', () => ({ + useContractFunction: vi.fn(), +})) + +vi.mock('./use-vault-deposit-params', () => ({ + useVaultDepositParams: vi.fn(), +})) + +vi.mock('./use-vault-deposit-transaction-arguments', () => ({ + useVaultDepositTransactionArguments: vi.fn(), +})) + +describe('useDeposit', () => { + const chainId = optimism.id + const updatePendingTransactionsMock = vi.fn() + const onSettledMock = vi.fn() + const sendMock = vi.fn() + + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockImplementation( + () => ({ chainId }) as ReturnType, + ) + vi.mocked(useTradingPanelTransactions).mockImplementation(() => [ + [], + updatePendingTransactionsMock, + ]) + vi.mocked(useTradingSettleHandler).mockImplementation(() => onSettledMock) + vi.mocked(useContractFunction).mockImplementation( + () => + ({ + send: sendMock, + }) as unknown as ReturnType, + ) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should process deposits', async () => { + const depositMethod = 'depositWithCustomCooldown' + const sendToken = { ...BRIDGED_USDC_OPTIMISM, value: '5', isLoading: false } + const receiveToken = { + symbol: 'USDy', + address: '0x123', + value: '10', + } as unknown as DynamicTradingToken + const depositArguments = ['0x1', '0x2', '1000'] + + vi.mocked(useSendTokenInput).mockImplementationOnce(() => [ + sendToken, + vi.fn(), + ]) + vi.mocked(useReceiveTokenInput).mockImplementationOnce(() => [ + receiveToken, + vi.fn(), + ]) + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + depositMethod, + vaultDepositTokenAddress: '0x123', + }) + vi.mocked(useVaultDepositTransactionArguments).mockReturnValueOnce( + depositArguments, + ) + + const { result } = renderHook(() => useDeposit()) + + expect(useVaultDepositTransactionArguments).toHaveBeenCalledTimes(1) + expect(useVaultDepositTransactionArguments).toHaveBeenCalledWith({ + depositMethod, + vaultDepositTokenAddress: '0x123', + }) + expect(useTradingSettleHandler).toHaveBeenCalledTimes(1) + expect(useTradingSettleHandler).toHaveBeenCalledWith('deposit') + expect(useContractFunction).toHaveBeenCalledTimes(1) + expect(useContractFunction).toHaveBeenCalledWith({ + contractId: 'easySwapperV2', + functionName: depositMethod, + onSettled: onSettledMock, + }) + + await act(async () => await result.current()) + + expect(updatePendingTransactionsMock).toHaveBeenCalledTimes(1) + expect(updatePendingTransactionsMock).toHaveBeenCalledWith({ + type: 'add', + action: 'deposit', + symbol: receiveToken.symbol, + chainId, + }) + expect(sendMock).toHaveBeenCalledTimes(1) + expect(sendMock).toHaveBeenCalledWith(...depositArguments) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit.ts new file mode 100644 index 0000000..96c7a5a --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-deposit.ts @@ -0,0 +1,47 @@ +import { useCallback } from 'react' + +import { + useReceiveTokenInput, + useTradingPanelPoolConfig, + useTradingPanelTransactions, +} from 'core-kit/hooks/state' +import { useTradingSettleHandler } from 'core-kit/hooks/trading' +import { useContractFunction } from 'core-kit/hooks/web3' + +import type { ContractActionFunc } from 'core-kit/types/web3.types' + +import { useVaultDepositParams } from './use-vault-deposit-params' +import { useVaultDepositTransactionArguments } from './use-vault-deposit-transaction-arguments' + +const action = 'deposit' + +export const useDeposit = (): ContractActionFunc => { + const { chainId } = useTradingPanelPoolConfig() + const [receiveToken] = useReceiveTokenInput() + const updatePendingTransactions = useTradingPanelTransactions()[1] + const { depositMethod, vaultDepositTokenAddress } = useVaultDepositParams() + const txArgs = useVaultDepositTransactionArguments({ + depositMethod, + vaultDepositTokenAddress, + }) + + const onSettled = useTradingSettleHandler(action) + + const { send } = useContractFunction({ + contractId: 'easySwapperV2', + functionName: depositMethod, + onSettled, + }) + + return useCallback(async () => { + updatePendingTransactions({ + type: 'add', + action, + symbol: receiveToken.symbol, + chainId, + }) + + console.log('Transaction Arguments:', txArgs) + return send(...txArgs) + }, [updatePendingTransactions, chainId, receiveToken.symbol, send, txArgs]) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-handle-pool-deposit-data.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-handle-pool-deposit-data.test.ts similarity index 86% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-handle-pool-deposit-data.test.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-handle-pool-deposit-data.test.ts index 4c0ef03..01977c1 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-handle-pool-deposit-data.test.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-handle-pool-deposit-data.test.ts @@ -8,7 +8,7 @@ import { TEST_ADDRESS } from 'tests/mocks' import { renderHook } from 'tests/test-utils' import { useHandlePoolDepositData } from './use-handle-pool-deposit-data' -import { usePoolDepositTokens } from './use-pool-deposit-tokens' +import { useVaultDepositTokens } from './use-vault-deposit-tokens' vi.mock('core-kit/hooks/state', () => ({ useSendTokenInput: vi.fn(), @@ -17,8 +17,8 @@ vi.mock('core-kit/hooks/state', () => ({ useTradingPanelPoolFallbackData: vi.fn(), })) -vi.mock('./use-pool-deposit-tokens', () => ({ - usePoolDepositTokens: vi.fn(), +vi.mock('./use-vault-deposit-tokens', () => ({ + useVaultDepositTokens: vi.fn(), })) const updateSendTokenMock = vi.fn() @@ -45,7 +45,7 @@ describe('useHandlePoolDepositData', () => { value: 'test', } - vi.mocked(usePoolDepositTokens).mockImplementation(() => [ + vi.mocked(useVaultDepositTokens).mockImplementation(() => [ initialDepositToken, ]) vi.mocked(stateHooks.useTradingPanelType).mockImplementation(() => [ @@ -57,7 +57,7 @@ describe('useHandlePoolDepositData', () => { expect(stateHooks.useTradingPanelPoolConfig).toHaveBeenCalledTimes(1) expect(stateHooks.useTradingPanelType).toHaveBeenCalledTimes(1) - expect(usePoolDepositTokens).toHaveBeenCalledTimes(1) + expect(useVaultDepositTokens).toHaveBeenCalledTimes(1) expect(updateSendTokenMock).toHaveBeenCalledTimes(1) expect(updateSendTokenMock).toHaveBeenCalledWith({ ...initialDepositToken, @@ -73,7 +73,7 @@ describe('useHandlePoolDepositData', () => { decimals: 6, value: 'value', } - vi.mocked(usePoolDepositTokens).mockImplementation(() => [ + vi.mocked(useVaultDepositTokens).mockImplementation(() => [ initialDepositToken, ]) vi.mocked(stateHooks.useTradingPanelType).mockImplementation(() => [ diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-handle-pool-deposit-data.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-handle-pool-deposit-data.ts similarity index 88% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-handle-pool-deposit-data.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-handle-pool-deposit-data.ts index 0c9cc17..1ec083b 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-handle-pool-deposit-data.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-handle-pool-deposit-data.ts @@ -6,11 +6,11 @@ import { useTradingPanelType, } from 'core-kit/hooks/state' -import { usePoolDepositTokens } from './use-pool-deposit-tokens' +import { useVaultDepositTokens } from './use-vault-deposit-tokens' export const useHandlePoolDepositData = () => { const poolConfig = useTradingPanelPoolConfig() - const [initialDepositToken] = usePoolDepositTokens() + const [initialDepositToken] = useVaultDepositTokens() const updateSendToken = useSendTokenInput()[1] const [type] = useTradingPanelType() diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-custom-cooldown-deposit.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-custom-cooldown-deposit.test.ts new file mode 100644 index 0000000..9216566 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-custom-cooldown-deposit.test.ts @@ -0,0 +1,84 @@ +import { act } from '@testing-library/react' + +import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' +import { TEST_ADDRESS } from 'tests/mocks' +import { renderHook } from 'tests/test-utils' + +import { useIsCustomCooldownDeposit } from './use-is-custom-cooldown-deposit' +import { usePoolDynamicContractData } from '../../pool' +import { usePoolStatic } from '../../pool/multicall' + +vi.mock('core-kit/hooks/pool', () => ({ + usePoolDynamicContractData: vi.fn(), +})) +vi.mock('core-kit/hooks/pool/multicall', () => ({ + usePoolStatic: vi.fn(), +})) +vi.mock('core-kit/hooks/state', () => ({ + useTradingPanelPoolConfig: vi.fn(), +})) + +describe('useIsCustomCooldownDeposit', () => { + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockImplementation( + () => + ({ chainId: 1, address: TEST_ADDRESS }) as ReturnType< + typeof useTradingPanelPoolConfig + >, + ) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return false when entry fee is 0 or custom cooldown deposit is not allowed', () => { + vi.mocked(usePoolStatic).mockReturnValueOnce({ + data: { isCustomCooldownDepositAllowed: false }, + } as ReturnType) + vi.mocked(usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '0', + } as ReturnType) + + const { result, rerender } = renderHook(() => useIsCustomCooldownDeposit()) + + expect(result.current).toBe(false) + + vi.mocked(usePoolStatic).mockReturnValueOnce({ + data: { isCustomCooldownDepositAllowed: true }, + } as ReturnType) + vi.mocked(usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '0', + } as ReturnType) + + act(() => { + rerender() + }) + expect(result.current).toBe(false) + + vi.mocked(usePoolStatic).mockReturnValueOnce({ + data: { isCustomCooldownDepositAllowed: false }, + } as ReturnType) + vi.mocked(usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '100', + } as ReturnType) + + act(() => { + rerender() + }) + expect(result.current).toBe(false) + }) + + it('should return true when entry fee is greater than 0 and custom cooldown deposit is allowed', () => { + vi.mocked(usePoolStatic).mockReturnValueOnce({ + data: { isCustomCooldownDepositAllowed: true }, + } as ReturnType) + vi.mocked(usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '100', + } as ReturnType) + + const { result } = renderHook(() => useIsCustomCooldownDeposit()) + + expect(result.current).toBe(true) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-custom-cooldown-deposit.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-custom-cooldown-deposit.ts new file mode 100644 index 0000000..1c6bc59 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-custom-cooldown-deposit.ts @@ -0,0 +1,15 @@ +import { usePoolDynamicContractData } from 'core-kit/hooks/pool' +import { usePoolStatic } from 'core-kit/hooks/pool/multicall' +import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' + +export const useIsCustomCooldownDeposit = () => { + const { chainId, address } = useTradingPanelPoolConfig() + const { data: { isCustomCooldownDepositAllowed = false } = {} } = + usePoolStatic({ + address, + chainId, + }) + const { entryFee = '0' } = usePoolDynamicContractData({ address, chainId }) + const entryFeeEnabled = +entryFee > 0 + return entryFeeEnabled && isCustomCooldownDepositAllowed +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-deposit-with-swap-transaction.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-deposit-with-swap-transaction.test.ts new file mode 100644 index 0000000..84b1967 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-deposit-with-swap-transaction.test.ts @@ -0,0 +1,44 @@ +import { useSendTokenInput } from 'core-kit/hooks/state' +import { TEST_ADDRESS } from 'tests/mocks' +import { renderHook } from 'tests/test-utils' + +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' +import { useVaultDepositParams } from './use-vault-deposit-params' + +vi.mock('core-kit/hooks/state', () => ({ + useSendTokenInput: vi.fn(), +})) +vi.mock('./use-vault-deposit-params', () => ({ + useVaultDepositParams: vi.fn(), +})) + +describe('useIsDepositWithSwapTransaction', () => { + beforeEach(() => { + vi.mocked(useSendTokenInput).mockImplementation( + () => + [{ address: TEST_ADDRESS }] as unknown as ReturnType< + typeof useSendTokenInput + >, + ) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return true when sendToken address and vaultDepositTokenAddress are not equal', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + vaultDepositTokenAddress: '0x123', + } as unknown as ReturnType) + const { result } = renderHook(() => useIsDepositWithSwapTransaction()) + expect(result.current).toBe(true) + }) + + it('should return false when sendToken address and vaultDepositTokenAddress are equal', () => { + vi.mocked(useVaultDepositParams).mockReturnValueOnce({ + vaultDepositTokenAddress: TEST_ADDRESS, + } as unknown as ReturnType) + const { result } = renderHook(() => useIsDepositWithSwapTransaction()) + expect(result.current).toBe(false) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-deposit-with-swap-transaction.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-deposit-with-swap-transaction.ts new file mode 100644 index 0000000..9961c1d --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-deposit-with-swap-transaction.ts @@ -0,0 +1,11 @@ +import { useSendTokenInput } from 'core-kit/hooks/state' +import { isEqualAddress } from 'core-kit/utils' + +import { useVaultDepositParams } from './use-vault-deposit-params' + +export const useIsDepositWithSwapTransaction = () => { + const [sendToken] = useSendTokenInput() + const { vaultDepositTokenAddress } = useVaultDepositParams() + + return !isEqualAddress(sendToken.address, vaultDepositTokenAddress) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-should-be-whitelisted.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-vault-deposit-locked.test.ts similarity index 89% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-should-be-whitelisted.test.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-vault-deposit-locked.test.ts index bec6e3b..73f69d2 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-should-be-whitelisted.test.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-vault-deposit-locked.test.ts @@ -5,7 +5,7 @@ import * as stateHooks from 'core-kit/hooks/state' import { TEST_ADDRESS } from 'tests/mocks' import { renderHook } from 'tests/test-utils' -import { useShouldBeWhitelisted } from './use-should-be-whitelisted' +import { useIsVaultDepositLocked } from './use-is-vault-deposit-locked' vi.mock('core-kit/hooks/pool', () => ({ useCheckWhitelist: vi.fn(), @@ -13,7 +13,7 @@ vi.mock('core-kit/hooks/pool', () => ({ })) vi.mock('core-kit/hooks/state', () => ({ useTradingPanelPoolConfig: vi.fn() })) -describe('useShouldBeWhitelisted', () => { +describe('useIsVaultDepositLocked', () => { it('should not check whitelisting if vault is not private or deprecated', () => { const isPrivateVault = false const deprecated = false @@ -33,7 +33,7 @@ describe('useShouldBeWhitelisted', () => { ) vi.mocked(poolHooks.useCheckWhitelist).mockImplementationOnce(() => false) - const { result } = renderHook(() => useShouldBeWhitelisted()) + const { result } = renderHook(() => useIsVaultDepositLocked()) expect(poolHooks.usePoolDynamicContractData).toHaveBeenCalledTimes(1) expect(poolHooks.usePoolDynamicContractData).toHaveBeenCalledWith({ @@ -47,7 +47,7 @@ describe('useShouldBeWhitelisted', () => { }) expect(result.current).toEqual({ - shouldBeWhitelisted: false, + isVaultDepositLocked: false, isAccountWhitelisted: false, }) }) @@ -72,7 +72,7 @@ describe('useShouldBeWhitelisted', () => { ) vi.mocked(poolHooks.useCheckWhitelist).mockImplementationOnce(() => true) - const { result } = renderHook(() => useShouldBeWhitelisted()) + const { result } = renderHook(() => useIsVaultDepositLocked()) expect(poolHooks.useCheckWhitelist).toHaveBeenCalledTimes(1) expect(poolHooks.useCheckWhitelist).toHaveBeenCalledWith({ @@ -81,7 +81,7 @@ describe('useShouldBeWhitelisted', () => { }) expect(result.current).toEqual({ - shouldBeWhitelisted: true, + isVaultDepositLocked: true, isAccountWhitelisted: true, }) }) @@ -106,7 +106,7 @@ describe('useShouldBeWhitelisted', () => { ) vi.mocked(poolHooks.useCheckWhitelist).mockImplementationOnce(() => false) - const { result } = renderHook(() => useShouldBeWhitelisted()) + const { result } = renderHook(() => useIsVaultDepositLocked()) expect(poolHooks.useCheckWhitelist).toHaveBeenCalledTimes(1) expect(poolHooks.useCheckWhitelist).toHaveBeenCalledWith({ @@ -115,7 +115,7 @@ describe('useShouldBeWhitelisted', () => { }) expect(result.current).toEqual({ - shouldBeWhitelisted: true, + isVaultDepositLocked: true, isAccountWhitelisted: false, }) }) @@ -140,7 +140,7 @@ describe('useShouldBeWhitelisted', () => { ) vi.mocked(poolHooks.useCheckWhitelist).mockImplementationOnce(() => true) - const { result } = renderHook(() => useShouldBeWhitelisted()) + const { result } = renderHook(() => useIsVaultDepositLocked()) expect(poolHooks.useCheckWhitelist).toHaveBeenCalledWith({ address: TEST_ADDRESS, @@ -148,7 +148,7 @@ describe('useShouldBeWhitelisted', () => { }) expect(result.current).toEqual({ - shouldBeWhitelisted: true, + isVaultDepositLocked: true, isAccountWhitelisted: true, }) }) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-should-be-whitelisted.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-vault-deposit-locked.ts similarity index 71% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-should-be-whitelisted.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-vault-deposit-locked.ts index 5093a8a..ff1ef1a 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-should-be-whitelisted.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-is-vault-deposit-locked.ts @@ -4,18 +4,18 @@ import { } from 'core-kit/hooks/pool' import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' -export const useShouldBeWhitelisted = () => { +export const useIsVaultDepositLocked = () => { const { chainId, address, deprecated } = useTradingPanelPoolConfig() const { isPrivateVault = false } = usePoolDynamicContractData({ address, chainId, }) - const shouldBeWhitelisted = isPrivateVault || deprecated + const isVaultDepositLocked = isPrivateVault || deprecated const isAccountWhitelisted = useCheckWhitelist({ address, chainId, }) - return { shouldBeWhitelisted, isAccountWhitelisted } + return { isVaultDepositLocked, isAccountWhitelisted } } diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-min-vault-tokens-received-amount.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-min-vault-tokens-received-amount.test.ts new file mode 100644 index 0000000..5b291d5 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-min-vault-tokens-received-amount.test.ts @@ -0,0 +1,132 @@ +import { + usePoolDynamicContractData, + usePoolTokenPrice, +} from 'core-kit/hooks/pool' +import { + useReceiveTokenInput, + useSendTokenInput, + useTradingPanelPoolConfig, + useTradingPanelSettings, +} from 'core-kit/hooks/state' +import { useAssetPrice } from 'core-kit/hooks/trading' +import { TEST_ADDRESS } from 'tests/mocks' +import { act, renderHook } from 'tests/test-utils' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' +import { useMinVaultTokensReceivedAmount } from './use-min-vault-tokens-received-amount' + +vi.mock('core-kit/hooks/pool', () => ({ + usePoolDynamicContractData: vi.fn(), + usePoolTokenPrice: vi.fn(), +})) +vi.mock('core-kit/hooks/state', () => ({ + useReceiveTokenInput: vi.fn(), + useSendTokenInput: vi.fn(), + useTradingPanelPoolConfig: vi.fn(), + useTradingPanelSettings: vi.fn(), +})) +vi.mock('core-kit/hooks/trading', () => ({ + useAssetPrice: vi.fn(), +})) +vi.mock('./use-applied-deposit-slippage', () => ({ + useAppliedDepositSlippage: vi.fn(), +})) +vi.mock('./use-is-deposit-with-swap-transaction', () => ({ + useIsDepositWithSwapTransaction: vi.fn(), +})) + +const sendToken = { + address: '0x123', + value: '1', + symbol: 'USDC', + decimals: 3, +} +const sendTokenPrice = '2' +const receiveToken = { + address: '0x456', + value: '2', + symbol: 'DHTP', + decimals: 3, +} +const receiveTokenPrice = '1' + +describe('useMinVaultTokensReceivedAmount', () => { + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockReturnValue([ + { address: TEST_ADDRESS, chainId: 1 }, + ] as unknown as ReturnType) + vi.mocked(useSendTokenInput).mockReturnValue([ + sendToken, + ] as unknown as ReturnType) + vi.mocked(useReceiveTokenInput).mockReturnValue([ + receiveToken, + ] as unknown as ReturnType) + vi.mocked(useAssetPrice).mockReturnValue(sendTokenPrice) + vi.mocked(usePoolTokenPrice).mockReturnValue(receiveTokenPrice) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return the minimum vault tokens received amount for deposit without swap transaction', () => { + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValue(false) + vi.mocked(usePoolDynamicContractData).mockReturnValue({ + entryFee: '1000', + } as ReturnType) + vi.mocked(useTradingPanelSettings).mockReturnValue([ + { slippage: 'auto' }, + ] as unknown as ReturnType) + vi.mocked(useAppliedDepositSlippage).mockReturnValue(0) + + const { result, rerender } = renderHook(() => + useMinVaultTokensReceivedAmount(), + ) + expect(result.current).toBe('1998') + + vi.mocked(useTradingPanelSettings).mockReturnValueOnce([ + { slippage: 0 }, + ] as unknown as ReturnType) + + act(() => rerender()) + expect(result.current).toBe('2000') + }) + + it('should return the minimum vault tokens received amount for deposit with swap transaction and auto slippage', () => { + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValue(true) + vi.mocked(usePoolDynamicContractData).mockReturnValue({ + entryFee: '1000', + } as ReturnType) + vi.mocked(useTradingPanelSettings).mockReturnValue([ + { slippage: 'auto' }, + ] as unknown as ReturnType) + vi.mocked(useAppliedDepositSlippage).mockReturnValue(0.1) + + const { result } = renderHook(() => useMinVaultTokensReceivedAmount()) + expect(result.current).toBe('1998') + }) + + it('should return the minimum vault tokens received amount for deposit with swap transaction and manual slippage', () => { + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValue(true) + vi.mocked(usePoolDynamicContractData).mockReturnValue({ + entryFee: '0', + } as ReturnType) + vi.mocked(useTradingPanelSettings).mockReturnValue([ + { slippage: 0.1 }, + ] as unknown as ReturnType) + vi.mocked(useAppliedDepositSlippage).mockReturnValue(0.1) + + const { result, rerender } = renderHook(() => + useMinVaultTokensReceivedAmount(), + ) + expect(result.current).toBe('1998') + + vi.mocked(usePoolDynamicContractData).mockReturnValueOnce({ + entryFee: '1000', + } as ReturnType) + + act(() => rerender()) + expect(result.current).toBe('1798') + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-min-vault-tokens-received-amount.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-min-vault-tokens-received-amount.ts new file mode 100644 index 0000000..75416ca --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-min-vault-tokens-received-amount.ts @@ -0,0 +1,64 @@ +import BigNumber from 'bignumber.js' + +import { MANAGER_FEE_DENOMINATOR } from 'core-kit/const' +import { + usePoolDynamicContractData, + usePoolTokenPrice, +} from 'core-kit/hooks/pool' +import { + useReceiveTokenInput, + useSendTokenInput, + useTradingPanelPoolConfig, + useTradingPanelSettings, +} from 'core-kit/hooks/state' +import { useAssetPrice } from 'core-kit/hooks/trading' +import { getPercent } from 'core-kit/utils' + +import { useConfigContextParams } from 'trading-widget/providers/config-provider' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' + +export const useMinVaultTokensReceivedAmount = () => { + const { defaultNoSwapMinDepositAmountGap } = useConfigContextParams() + const { address, chainId } = useTradingPanelPoolConfig() + const [sendToken] = useSendTokenInput() + const [receiveToken] = useReceiveTokenInput() + const { entryFee = '0' } = usePoolDynamicContractData({ address, chainId }) + const entryFeeValue = getPercent(+entryFee, MANAGER_FEE_DENOMINATOR) + const [{ slippage }] = useTradingPanelSettings() + const isAutoSlippage = slippage === 'auto' + const depositSlippage = useAppliedDepositSlippage() + const isDepositWithSwapTransaction = useIsDepositWithSwapTransaction() + + const sendTokenPrice = +useAssetPrice({ + address: sendToken.address, + chainId, + }) + const vaultTokenPrice = +usePoolTokenPrice({ address, chainId }) + + if (isDepositWithSwapTransaction) { + const sendValue = + Number(sendToken.value || 0) * sendTokenPrice * (1 - entryFeeValue / 100) + // calculate expected received vault tokens amount excluding entry fee + const expectedReceivedVaultTokensAmount = sendValue / vaultTokenPrice + + // when slippage is manual use expectedReceivedVaultTokensAmount + return new BigNumber( + isAutoSlippage + ? receiveToken.value || '0' + : expectedReceivedVaultTokensAmount, + ) + .shiftedBy(receiveToken.decimals) + .times(1 - depositSlippage / 100) + .toFixed(0) + } + + const noSwapMinValueGap = isAutoSlippage + ? defaultNoSwapMinDepositAmountGap + : depositSlippage + return new BigNumber(receiveToken.value || '0') + .shiftedBy(receiveToken.decimals) + .times(1 - noSwapMinValueGap / 100) + .toFixed(0) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-swap-data-based-on-send-token.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-swap-data-based-on-send-token.test.ts new file mode 100644 index 0000000..fc8d46b --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-swap-data-based-on-send-token.test.ts @@ -0,0 +1,104 @@ +import { base } from 'core-kit/const' +import { + useSendTokenInput, + useTradingPanelPoolConfig, +} from 'core-kit/hooks/state' +import { useSwapDataQuery } from 'core-kit/hooks/trading' +import { useDebounce } from 'core-kit/hooks/utils' +import { useAccount } from 'core-kit/hooks/web3' +import { TEST_ADDRESS } from 'tests/mocks' +import { renderHook } from 'tests/test-utils' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' +import { useSwapDataBasedOnSendToken } from './use-swap-data-based-on-send-token' +import { useVaultDepositParams } from './use-vault-deposit-params' +import { getContractAddressById } from '../../../utils' + +vi.mock('core-kit/hooks/state', () => ({ + useSendTokenInput: vi.fn(), + useTradingPanelPoolConfig: vi.fn(), +})) +vi.mock('core-kit/hooks/trading', () => ({ + useSwapDataQuery: vi.fn(), +})) +vi.mock('core-kit/hooks/utils', () => ({ + useDebounce: vi.fn(), +})) +vi.mock('core-kit/hooks/web3', () => ({ + useAccount: vi.fn(), +})) +vi.mock('./use-applied-deposit-slippage', () => ({ + useAppliedDepositSlippage: vi.fn(), +})) +vi.mock('./use-is-deposit-with-swap-transaction', () => ({ + useIsDepositWithSwapTransaction: vi.fn(), +})) +vi.mock('./use-vault-deposit-params', () => ({ + useVaultDepositParams: vi.fn(), +})) + +describe('useSwapDataBasedOnSendToken', () => { + const account = '0x1' + const sendToken = { + address: '0x123', + value: '1', + symbol: 'USDC', + decimals: 3, + } + const vaultDepositTokenAddress = '0x2' + const slippage = 1 + const chainId = base.id + + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockImplementation( + () => + ({ chainId, address: TEST_ADDRESS }) as ReturnType< + typeof useTradingPanelPoolConfig + >, + ) + vi.mocked(useAccount).mockImplementation( + () => ({ account }) as unknown as ReturnType, + ) + vi.mocked(useSendTokenInput).mockReturnValue([ + sendToken, + ] as unknown as ReturnType) + vi.mocked(useDebounce).mockImplementation((value) => value) + vi.mocked(useVaultDepositParams).mockReturnValue({ + vaultDepositTokenAddress: vaultDepositTokenAddress, + } as unknown as ReturnType) + vi.mocked(useAppliedDepositSlippage).mockReturnValue(slippage) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return swap data when deposit with swap transaction is true', () => { + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValue(true) + renderHook(() => useSwapDataBasedOnSendToken()) + + expect(useSwapDataQuery).toHaveBeenCalledWith( + { + amount: '1000', + chainId, + destinationAddress: vaultDepositTokenAddress, + fromAddress: getContractAddressById('easySwapperV2', chainId), + slippage: '1', + sourceAddress: '0x123', + walletAddress: account, + }, + expect.objectContaining({ enabled: true }), + ) + }) + + it('should not return swap data when deposit with swap transaction is false', () => { + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValue(false) + + renderHook(() => useSwapDataBasedOnSendToken()) + expect(useSwapDataQuery).toHaveBeenCalledWith( + expect.objectContaining({}), + expect.objectContaining({ enabled: false }), + ) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-swap-data-based-on-send-token.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-swap-data-based-on-send-token.ts new file mode 100644 index 0000000..2729374 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-swap-data-based-on-send-token.ts @@ -0,0 +1,46 @@ +import { keepPreviousData } from '@tanstack/react-query' +import BigNumber from 'bignumber.js' + +import { AddressZero, EXTREMELY_SHORT_POLLING_INTERVAL } from 'core-kit/const' +import { + useSendTokenInput, + useTradingPanelPoolConfig, +} from 'core-kit/hooks/state' +import { useSwapDataQuery } from 'core-kit/hooks/trading' +import { useDebounce } from 'core-kit/hooks/utils' +import { useAccount } from 'core-kit/hooks/web3' +import { getContractAddressById } from 'core-kit/utils' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' +import { useVaultDepositParams } from './use-vault-deposit-params' + +export const useSwapDataBasedOnSendToken = () => { + const { account: walletAddress = AddressZero } = useAccount() + const { chainId } = useTradingPanelPoolConfig() + const [sendToken] = useSendTokenInput() + const debouncedSendTokenValue = useDebounce(sendToken.value, 500) + const { vaultDepositTokenAddress } = useVaultDepositParams() + const isDepositWithSwapTransaction = useIsDepositWithSwapTransaction() + const easySwapperV2Address = getContractAddressById('easySwapperV2', chainId) + const slippage = useAppliedDepositSlippage() + + return useSwapDataQuery( + { + sourceAddress: sendToken.address, + destinationAddress: vaultDepositTokenAddress, + amount: new BigNumber(debouncedSendTokenValue) + .shiftedBy(sendToken.decimals) + .toFixed(0), + chainId, + slippage: slippage.toString(), + walletAddress, + fromAddress: easySwapperV2Address, + }, + { + enabled: isDepositWithSwapTransaction && !!debouncedSendTokenValue, + refetchInterval: EXTREMELY_SHORT_POLLING_INTERVAL, + placeholderData: keepPreviousData, + }, + ) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-params.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-params.test.ts new file mode 100644 index 0000000..a2323eb --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-params.test.ts @@ -0,0 +1,141 @@ +import { + EASY_SWAPPER_V2_DEPOSIT_METHODS, + USDC_BASE, + WETH_BASE, + base, +} from 'core-kit/const' +import { usePoolComposition } from 'core-kit/hooks/pool' +import { + useSendTokenInput, + useTradingPanelPoolConfig, +} from 'core-kit/hooks/state' +import { TEST_ADDRESS } from 'tests/mocks' +import { act, renderHook } from 'tests/test-utils' + +import { useIsCustomCooldownDeposit } from './use-is-custom-cooldown-deposit' +import { useVaultDepositParams } from './use-vault-deposit-params' + +vi.mock('core-kit/hooks/pool', () => ({ + usePoolComposition: vi.fn(), +})) +vi.mock('core-kit/hooks/state', () => ({ + useSendTokenInput: vi.fn(), + useTradingPanelPoolConfig: vi.fn(), +})) +vi.mock('./use-is-custom-cooldown-deposit', () => ({ + useIsCustomCooldownDeposit: vi.fn(), +})) + +const nativeDepositToken = { + symbol: 'ETH', + address: '0x4200000000000000000000000000000000000006', +} + +describe('useVaultDepositParams', () => { + const chainId = base.id + + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockImplementation( + () => + ({ chainId, address: TEST_ADDRESS }) as ReturnType< + typeof useTradingPanelPoolConfig + >, + ) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return deposit params for native token deposit with wrapped native token as deposit option in vault composition', () => { + const poolComposition = [ + { tokenName: 'WETH', tokenAddress: '0x123', isDeposit: true }, + ] + vi.mocked(useSendTokenInput).mockReturnValue([ + nativeDepositToken, + ] as unknown as ReturnType) + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(false) + vi.mocked(usePoolComposition).mockReturnValue( + poolComposition as unknown as ReturnType, + ) + + const { result, rerender } = renderHook(() => useVaultDepositParams()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.NATIVE, + ) + + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(true) + act(() => rerender()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.NATIVE_CUSTOM, + ) + }) + + it('should return deposit params for native token deposit without wrapped native token as deposit option in vault composition', () => { + const poolComposition = [ + { tokenName: 'USDC', tokenAddress: '0x123', isDeposit: true }, + ] + vi.mocked(useSendTokenInput).mockReturnValue([ + nativeDepositToken, + ] as unknown as ReturnType) + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(false) + vi.mocked(usePoolComposition).mockReturnValue( + poolComposition as unknown as ReturnType, + ) + + const { result, rerender } = renderHook(() => useVaultDepositParams()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_NATIVE_DEPOSIT, + ) + + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(true) + act(() => rerender()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_NATIVE_DEPOSIT_CUSTOM, + ) + }) + + it('should return deposit params for custom token deposit when deposit token is presented in vault composition', () => { + const poolComposition = [{ tokenName: USDC_BASE.symbol, isDeposit: true }] + vi.mocked(useSendTokenInput).mockReturnValue([ + USDC_BASE, + ] as unknown as ReturnType) + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(false) + vi.mocked(usePoolComposition).mockReturnValue( + poolComposition as unknown as ReturnType, + ) + + const { result, rerender } = renderHook(() => useVaultDepositParams()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.DEPOSIT, + ) + + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(true) + act(() => rerender()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.DEPOSIT_CUSTOM, + ) + }) + + it('should return deposit params for custom token deposit when deposit token is not presented in vault composition', () => { + const poolComposition = [{ tokenName: WETH_BASE.symbol, isDeposit: true }] + vi.mocked(useSendTokenInput).mockReturnValue([ + USDC_BASE, + ] as unknown as ReturnType) + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(false) + vi.mocked(usePoolComposition).mockReturnValue( + poolComposition as unknown as ReturnType, + ) + + const { result, rerender } = renderHook(() => useVaultDepositParams()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_DEPOSIT, + ) + + vi.mocked(useIsCustomCooldownDeposit).mockReturnValueOnce(true) + act(() => rerender()) + expect(result.current.depositMethod).toBe( + EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_DEPOSIT_CUSTOM, + ) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-params.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-params.ts new file mode 100644 index 0000000..420f5f2 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-params.ts @@ -0,0 +1,114 @@ +import { useMemo } from 'react' + +import { + CHAIN_NATIVE_TOKENS, + EASY_SWAPPER_V2_DEPOSIT_METHODS, + FALLBACK_ASSETS_MAP, +} from 'core-kit/const' +import { usePoolComposition } from 'core-kit/hooks/pool' +import { + useSendTokenInput, + useTradingPanelPoolConfig, +} from 'core-kit/hooks/state' +import type { + ChainId, + PoolComposition, + VaultDepositParams, +} from 'core-kit/types' + +import { isEqualAddress, isNativeToken } from 'core-kit/utils' + +import { useIsCustomCooldownDeposit } from './use-is-custom-cooldown-deposit' + +const getVaultDepositTokenAddress = ( + availableDepositOptions: PoolComposition[], + chainId: ChainId, +) => { + if (!availableDepositOptions.length) { + return null + } + const fallbackToken = availableDepositOptions.find( + ({ tokenName, tokenAddress }) => + Object.values(FALLBACK_ASSETS_MAP[chainId] ?? {}).some( + (fallbackToken) => + fallbackToken.symbol === tokenName || + isEqualAddress(fallbackToken.address, tokenAddress), + ), + ) + + return fallbackToken?.tokenAddress ?? availableDepositOptions[0]?.tokenAddress +} + +export const useVaultDepositParams = (): VaultDepositParams => { + const [sendToken] = useSendTokenInput() + const { chainId, address } = useTradingPanelPoolConfig() + const poolComposition = usePoolComposition({ + address, + chainId, + }) + const isCustomCooldownDeposit = useIsCustomCooldownDeposit() + + return useMemo(() => { + const availableDepositOptions = poolComposition.filter( + ({ isDeposit }) => isDeposit, + ) + const isNativeTokenDeposit = isNativeToken(sendToken.symbol, chainId) + + // Step 1: Check if the token is native + if (isNativeTokenDeposit) { + const wrappedNativeTokenInComposition = availableDepositOptions.find( + ({ tokenName }) => + CHAIN_NATIVE_TOKENS[chainId]?.wrappedNativeTokenName === tokenName, + ) + if (wrappedNativeTokenInComposition) { + return { + depositMethod: isCustomCooldownDeposit + ? EASY_SWAPPER_V2_DEPOSIT_METHODS.NATIVE_CUSTOM + : EASY_SWAPPER_V2_DEPOSIT_METHODS.NATIVE, + vaultDepositTokenAddress: + wrappedNativeTokenInComposition.tokenAddress, + } + } + return { + depositMethod: isCustomCooldownDeposit + ? EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_NATIVE_DEPOSIT_CUSTOM + : EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_NATIVE_DEPOSIT, + vaultDepositTokenAddress: + getVaultDepositTokenAddress(availableDepositOptions, chainId) ?? + sendToken.address, + } + } + + const depositTokenPresentedInVault = availableDepositOptions.find( + ({ tokenName, tokenAddress }) => + tokenName === sendToken.symbol || + isEqualAddress(tokenAddress, sendToken.address), + ) + + // Step 2: Check if the token is presented in the vault + if (depositTokenPresentedInVault) { + return { + depositMethod: isCustomCooldownDeposit + ? EASY_SWAPPER_V2_DEPOSIT_METHODS.DEPOSIT_CUSTOM + : EASY_SWAPPER_V2_DEPOSIT_METHODS.DEPOSIT, + vaultDepositTokenAddress: depositTokenPresentedInVault.tokenAddress, + } + } + + // Step 3: Handle custom token deposit + return { + depositMethod: isCustomCooldownDeposit + ? EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_DEPOSIT_CUSTOM + : EASY_SWAPPER_V2_DEPOSIT_METHODS.ZAP_DEPOSIT, + vaultDepositTokenAddress: + getVaultDepositTokenAddress(availableDepositOptions, chainId) ?? + sendToken.address, + } + }, [ + chainId, + isCustomCooldownDeposit, + poolComposition, + sendToken.address, + sendToken.symbol, + ]) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-token-amount.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-token-amount.test.ts new file mode 100644 index 0000000..b9040da --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-token-amount.test.ts @@ -0,0 +1,57 @@ +import BigNumber from 'bignumber.js' + +import { useSendTokenInput } from 'core-kit/hooks/state' +import { useDebounce } from 'core-kit/hooks/utils' +import { renderHook } from 'tests/test-utils' + +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' +import { useSwapDataBasedOnSendToken } from './use-swap-data-based-on-send-token' +import { useVaultDepositTokenAmount } from './use-vault-deposit-token-amount' + +vi.mock('core-kit/hooks/state', () => ({ + useSendTokenInput: vi.fn(), +})) +vi.mock('core-kit/hooks/utils', () => ({ + useDebounce: vi.fn(), +})) +vi.mock('./use-is-deposit-with-swap-transaction', () => ({ + useIsDepositWithSwapTransaction: vi.fn(), +})) +vi.mock('./use-swap-data-based-on-send-token', () => ({ + useSwapDataBasedOnSendToken: vi.fn(), +})) + +describe('useVaultDepositTokenAmount', () => { + const sendToken = { value: '100', decimals: 3 } + const swapDataBasedOnSendTokenDestinationAmount = '100001' + + beforeEach(() => { + vi.mocked(useSendTokenInput).mockReturnValue([ + sendToken, + ] as unknown as ReturnType) + vi.mocked(useSwapDataBasedOnSendToken).mockReturnValue({ + data: { destinationAmount: swapDataBasedOnSendTokenDestinationAmount }, + } as unknown as ReturnType) + vi.mocked(useDebounce).mockImplementation((value) => value) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return destination amount for deposit with swap transaction', () => { + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValueOnce(true) + + const { result } = renderHook(() => useVaultDepositTokenAmount()) + expect(result.current).toBe(swapDataBasedOnSendTokenDestinationAmount) + }) + + it('should return debounced send token value for deposit without swap transaction', () => { + vi.mocked(useIsDepositWithSwapTransaction).mockReturnValueOnce(false) + + const { result } = renderHook(() => useVaultDepositTokenAmount()) + expect(result.current).toBe( + new BigNumber(sendToken.value).shiftedBy(sendToken.decimals).toFixed(0), + ) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-token-amount.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-token-amount.ts new file mode 100644 index 0000000..3032775 --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-token-amount.ts @@ -0,0 +1,20 @@ +import BigNumber from 'bignumber.js' + +import { useSendTokenInput } from 'core-kit/hooks/state' +import { useDebounce } from 'core-kit/hooks/utils' + +import { useIsDepositWithSwapTransaction } from './use-is-deposit-with-swap-transaction' +import { useSwapDataBasedOnSendToken } from './use-swap-data-based-on-send-token' + +export const useVaultDepositTokenAmount = () => { + const [sendToken] = useSendTokenInput() + const debouncedSendTokenValue = useDebounce(sendToken.value, 500) + const isDepositWithSwapTransaction = useIsDepositWithSwapTransaction() + + const { data } = useSwapDataBasedOnSendToken() + return isDepositWithSwapTransaction + ? data?.destinationAmount ?? '0' + : new BigNumber(debouncedSendTokenValue || '0') + .shiftedBy(sendToken.decimals) + .toFixed(0) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-tokens.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-tokens.test.ts similarity index 96% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-tokens.test.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-tokens.test.ts index 35b01eb..5f686b5 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-tokens.test.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-tokens.test.ts @@ -13,7 +13,7 @@ import type { Address, PoolComposition, TradingToken } from 'core-kit/types' import { TEST_ADDRESS } from 'tests/mocks' import { renderHook } from 'tests/test-utils' -import { usePoolDepositTokens } from './use-pool-deposit-tokens' +import { useVaultDepositTokens } from './use-vault-deposit-tokens' vi.mock('core-kit/hooks/state', () => ({ useTradingPanelPoolConfig: vi.fn() })) vi.mock('core-kit/hooks/pool', () => ({ usePoolComposition: vi.fn() })) @@ -24,7 +24,7 @@ vi.mock('core-kit/hooks/web3', () => ({ useContractReadsErrorLogging: vi.fn(), })) -describe('usePoolDepositTokens', () => { +describe('useVaultDepositTokens', () => { it('should return an empty array when there are no deposit tokens and account is not connected', () => { vi.mocked(web3Hooks.useAccount).mockImplementation( () => ({ account: undefined }) as ReturnType, @@ -45,7 +45,7 @@ describe('usePoolDepositTokens', () => { }) as ReturnType, ) - const { result } = renderHook(() => usePoolDepositTokens()) + const { result } = renderHook(() => useVaultDepositTokens()) expect(poolHooks.usePoolComposition).toHaveBeenCalledWith({ address: TEST_ADDRESS, chainId: optimism.id, @@ -101,7 +101,7 @@ describe('usePoolDepositTokens', () => { }) as ReturnType, ) - const { result } = renderHook(() => usePoolDepositTokens()) + const { result } = renderHook(() => useVaultDepositTokens()) expect(result.current).toEqual([ { address: AddressZero, @@ -159,7 +159,7 @@ describe('usePoolDepositTokens', () => { }) as ReturnType, ) - const { result } = renderHook(() => usePoolDepositTokens()) + const { result } = renderHook(() => useVaultDepositTokens()) expect(web3Hooks.useReadContracts).toHaveBeenCalledWith({ contracts: [ @@ -247,7 +247,7 @@ describe('usePoolDepositTokens', () => { }) as ReturnType, ) - const { result } = renderHook(() => usePoolDepositTokens()) + const { result } = renderHook(() => useVaultDepositTokens()) expect(web3Hooks.useReadContracts).toHaveBeenCalledTimes(1) expect(web3Hooks.useReadContracts).toHaveBeenCalledWith({ @@ -331,7 +331,7 @@ describe('usePoolDepositTokens', () => { }) as ReturnType, ) - const { result } = renderHook(() => usePoolDepositTokens()) + const { result } = renderHook(() => useVaultDepositTokens()) expect(result.current).toEqual([ { diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-tokens.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-tokens.ts similarity index 91% rename from packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-tokens.ts rename to packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-tokens.ts index ccaeeba..2ad5ca1 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-tokens.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-tokens.ts @@ -20,18 +20,15 @@ import type { TradingToken } from 'core-kit/types/trading-panel.types' import type { Address } from 'core-kit/types/web3.types' import { normalizeNumber } from 'core-kit/utils' -import { useIsEasySwapperTrading } from '../use-is-easy-swapper-trading' - interface ProductDepositToken extends TradingToken { balance?: number } -export const usePoolDepositTokens = (): TradingToken[] => { +export const useVaultDepositTokens = (): TradingToken[] => { const { address, chainId, depositParams } = useTradingPanelPoolConfig() const { account } = useAccount() const poolComposition = usePoolComposition({ address, chainId }) const isPoolManagerAccount = useIsPoolManagerAccount() - const isEasySwapperTrading = useIsEasySwapperTrading() const depositTokens = useMemo( () => @@ -110,8 +107,8 @@ export const usePoolDepositTokens = (): TradingToken[] => { ...productDepositTokens.filter( ({ symbol }) => symbol !== depositParams.defaultDepositTokenSymbol, ), - // remove native deposits for dHEDGE managers and in SynthetixV3 vaults - ...(isPoolManagerAccount || !isEasySwapperTrading + // remove native deposits for dHEDGE managers + ...(isPoolManagerAccount ? [] : [ { @@ -130,6 +127,5 @@ export const usePoolDepositTokens = (): TradingToken[] => { balances, chainId, depositParams.defaultDepositTokenSymbol, - isEasySwapperTrading, ]) } diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-transaction-arguments.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-transaction-arguments.test.ts new file mode 100644 index 0000000..4cf2deb --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-transaction-arguments.test.ts @@ -0,0 +1,205 @@ +import { act } from '@testing-library/react' + +import { stringToHex } from 'viem' + +import { + useSendTokenInput, + useTradingPanelPoolConfig, +} from 'core-kit/hooks/state' +import type { VaultDepositParams } from 'core-kit/types' +import { TEST_ADDRESS } from 'tests/mocks' +import { renderHook } from 'tests/test-utils' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useMinVaultTokensReceivedAmount } from './use-min-vault-tokens-received-amount' +import { useSwapDataBasedOnSendToken } from './use-swap-data-based-on-send-token' +import { useVaultDepositTokenAmount } from './use-vault-deposit-token-amount' +import { useVaultDepositTransactionArguments } from './use-vault-deposit-transaction-arguments' + +vi.mock('core-kit/hooks/state', () => ({ + useSendTokenInput: vi.fn(), + useTradingPanelPoolConfig: vi.fn(), +})) +vi.mock('./use-applied-deposit-slippage', () => ({ + useAppliedDepositSlippage: vi.fn(), +})) +vi.mock('./use-min-vault-tokens-received-amount', () => ({ + useMinVaultTokensReceivedAmount: vi.fn(), +})) +vi.mock('./use-swap-data-based-on-send-token', () => ({ + useSwapDataBasedOnSendToken: vi.fn(), +})) +vi.mock('./use-vault-deposit-token-amount', () => ({ + useVaultDepositTokenAmount: vi.fn(), +})) + +describe('useVaultDepositTransactionArguments', () => { + const sendToken = { value: '100', decimals: 0, address: '0x123' } + const vaultDepositTokenAmount = '101' + const swapData = { + txData: '0x123123123123123', + routerKey: 'ZERO_X', + destinationAmount: '100', + } + const minVaultTokensReceivedAmount = '50' + const depositSlippage = 1 + beforeEach(() => { + vi.mocked(useTradingPanelPoolConfig).mockImplementation( + () => + ({ chainId: 1, address: TEST_ADDRESS }) as ReturnType< + typeof useTradingPanelPoolConfig + >, + ) + vi.mocked(useSendTokenInput).mockReturnValue([ + sendToken, + ] as unknown as ReturnType) + vi.mocked(useVaultDepositTokenAmount).mockReturnValue( + vaultDepositTokenAmount, + ) + vi.mocked(useSwapDataBasedOnSendToken).mockReturnValue({ + data: swapData, + } as unknown as ReturnType) + vi.mocked(useMinVaultTokensReceivedAmount).mockReturnValue( + minVaultTokensReceivedAmount, + ) + vi.mocked(useAppliedDepositSlippage).mockReturnValue(depositSlippage) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should return arguments for native deposit', () => { + const depositParams: VaultDepositParams = { + depositMethod: 'nativeDeposit', + vaultDepositTokenAddress: '0x111', + } + + const { result, rerender } = renderHook( + ({ depositParams }) => useVaultDepositTransactionArguments(depositParams), + { + initialProps: { depositParams }, + }, + ) + const expectedDepositArguments = [ + TEST_ADDRESS, + minVaultTokensReceivedAmount, + { value: vaultDepositTokenAmount }, + ] + + expect(result.current).toEqual(expectedDepositArguments) + + const customCooldownDepositParams: VaultDepositParams = { + depositMethod: 'nativeDepositWithCustomCooldown', + vaultDepositTokenAddress: '0x111', + } + act(() => rerender({ depositParams: customCooldownDepositParams })) + + expect(result.current).toEqual(expectedDepositArguments) + }) + + it('should return arguments for zap native deposit', () => { + const depositParams: VaultDepositParams = { + depositMethod: 'zapNativeDeposit', + vaultDepositTokenAddress: '0x111', + } + + const { result, rerender } = renderHook( + ({ depositParams }) => useVaultDepositTransactionArguments(depositParams), + { + initialProps: { depositParams }, + }, + ) + + const expectedDepositArguments = [ + TEST_ADDRESS, + [ + [ + sendToken.address, + sendToken.value, + [stringToHex(swapData.routerKey, { size: 32 }), swapData.txData], + ], + [depositParams.vaultDepositTokenAddress, '99'], + ], + minVaultTokensReceivedAmount, + { value: sendToken.value }, + ] + + expect(result.current).toEqual(expectedDepositArguments) + + const customCooldownDepositParams: VaultDepositParams = { + depositMethod: 'zapNativeDepositWithCustomCooldown', + vaultDepositTokenAddress: '0x111', + } + act(() => rerender({ depositParams: customCooldownDepositParams })) + + expect(result.current).toEqual(expectedDepositArguments) + }) + + it('should return arguments for zap deposit', () => { + const depositParams: VaultDepositParams = { + depositMethod: 'zapDeposit', + vaultDepositTokenAddress: '0x111', + } + + const { result, rerender } = renderHook( + ({ depositParams }) => useVaultDepositTransactionArguments(depositParams), + { + initialProps: { depositParams }, + }, + ) + + const expectedDepositArguments = [ + TEST_ADDRESS, + [ + [ + sendToken.address, + sendToken.value, + [stringToHex(swapData.routerKey, { size: 32 }), swapData.txData], + ], + [depositParams.vaultDepositTokenAddress, '99'], + ], + minVaultTokensReceivedAmount, + ] + + expect(result.current).toEqual(expectedDepositArguments) + + const customCooldownDepositParams: VaultDepositParams = { + depositMethod: 'zapDepositWithCustomCooldown', + vaultDepositTokenAddress: '0x111', + } + act(() => rerender({ depositParams: customCooldownDepositParams })) + + expect(result.current).toEqual(expectedDepositArguments) + }) + + it('should return arguments for default deposits', () => { + const depositParams: VaultDepositParams = { + depositMethod: 'deposit', + vaultDepositTokenAddress: '0x111', + } + + const { result, rerender } = renderHook( + ({ depositParams }) => useVaultDepositTransactionArguments(depositParams), + { + initialProps: { depositParams }, + }, + ) + const expectedDepositArguments = [ + TEST_ADDRESS, + depositParams.vaultDepositTokenAddress, + vaultDepositTokenAmount, + minVaultTokensReceivedAmount, + ] + + expect(result.current).toEqual(expectedDepositArguments) + + const customCooldownDepositParams: VaultDepositParams = { + depositMethod: 'depositWithCustomCooldown', + vaultDepositTokenAddress: '0x111', + } + act(() => rerender({ depositParams: customCooldownDepositParams })) + + expect(result.current).toEqual(expectedDepositArguments) + }) +}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-transaction-arguments.tsx b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-transaction-arguments.tsx new file mode 100644 index 0000000..0f2696f --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/deposit-v2/use-vault-deposit-transaction-arguments.tsx @@ -0,0 +1,87 @@ +import BigNumber from 'bignumber.js' +import { useMemo } from 'react' + +import { + useSendTokenInput, + useTradingPanelPoolConfig, +} from 'core-kit/hooks/state' +import type { VaultDepositParams } from 'core-kit/types' + +import { buildZapDepositTransactionArguments } from 'core-kit/utils' + +import { useAppliedDepositSlippage } from './use-applied-deposit-slippage' +import { useMinVaultTokensReceivedAmount } from './use-min-vault-tokens-received-amount' +import { useSwapDataBasedOnSendToken } from './use-swap-data-based-on-send-token' +import { useVaultDepositTokenAmount } from './use-vault-deposit-token-amount' + +export const useVaultDepositTransactionArguments = ({ + depositMethod, + vaultDepositTokenAddress, +}: VaultDepositParams): unknown[] => { + const { address } = useTradingPanelPoolConfig() + const [sendToken] = useSendTokenInput() + const sendTokenAmount = new BigNumber(sendToken.value) + .shiftedBy(sendToken.decimals) + .toFixed(0) + const vaultDepositTokenAmount = useVaultDepositTokenAmount() + const { data: swapData } = useSwapDataBasedOnSendToken() + const minVaultTokensReceivedAmount = useMinVaultTokensReceivedAmount() + const depositSlippage = useAppliedDepositSlippage() + + return useMemo(() => { + const isZapDeposit = + depositMethod === 'zapNativeDeposit' || + depositMethod === 'zapNativeDepositWithCustomCooldown' || + depositMethod === 'zapDeposit' || + depositMethod === 'zapDepositWithCustomCooldown' + const zapDepositArguments = isZapDeposit + ? buildZapDepositTransactionArguments({ + vaultAddress: address, + sendTokenAddress: sendToken.address, + sendTokenAmount, + minVaultTokensReceivedAmount, + vaultDepositTokenAddress, + swapData: swapData?.txData ?? '', + routerKey: swapData?.routerKey, + swapDestinationAmount: swapData?.destinationAmount ?? '0', + swapSlippage: depositSlippage, + }) + : [] + + switch (depositMethod) { + case 'nativeDeposit': + case 'nativeDepositWithCustomCooldown': + return [ + address, + minVaultTokensReceivedAmount, + { value: vaultDepositTokenAmount }, + ] + case 'zapNativeDeposit': + case 'zapNativeDepositWithCustomCooldown': + return [...zapDepositArguments, { value: sendTokenAmount }] + case 'zapDeposit': + case 'zapDepositWithCustomCooldown': + return zapDepositArguments + default: + // deposit, deposit with custom cooldown + return [ + address, + vaultDepositTokenAddress, + vaultDepositTokenAmount, + minVaultTokensReceivedAmount, + ] + } + }, [ + depositMethod, + address, + minVaultTokensReceivedAmount, + vaultDepositTokenAmount, + sendToken.address, + sendTokenAmount, + vaultDepositTokenAddress, + swapData?.txData, + swapData?.routerKey, + swapData?.destinationAmount, + depositSlippage, + ]) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/__snapshots__/use-deposit.test.ts.snap b/packages/trading-widget/src/core-kit/hooks/trading/deposit/__snapshots__/use-deposit.test.ts.snap deleted file mode 100644 index 57f596d..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/__snapshots__/use-deposit.test.ts.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`useDeposit > should process deposits with auto slippage and not native token 1`] = ` -[ - BuyingWithEasyswapperArgs { - "fromTokenAmount": "5000000", - "poolDepositAddress": "0x111", - "receiveAssetAddress": "0x123", - "receiveAssetInputValue": "10", - "sendAssetAddress": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - }, -] -`; - -exports[`useDeposit > should process deposits with auto slippage and not native token 2`] = ` -[ - "0x123", - "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - "5000000", - "0x111", - "10000000000000000000", -] -`; - -exports[`useDeposit > should process deposits with custom slippage, custom cooldown and native token 1`] = ` -[ - BuyingWithNativeAssetArgs { - "fromTokenAmount": "5000000000000000000", - "poolDepositAddress": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - "receiveAssetAddress": "0x123", - "receiveAssetInputValue": "10", - }, -] -`; - -exports[`useDeposit > should process deposits with custom slippage, custom cooldown and native token 2`] = ` -[ - "0x123", - "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - "9985000000000000000", - { - "value": 5000000000000000000n, - }, -] -`; diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/index.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/index.ts deleted file mode 100644 index 4c18197..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { useDeposit } from './use-deposit' -export { useDepositAllowance } from './use-deposit-allowance' -export { useDepositSlippage } from './use-deposit-slippage' -export { useShouldBeWhitelisted } from './use-should-be-whitelisted' -export { useDepositMethodHandler } from './use-deposit-method-handler' -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' diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-method-handler.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-method-handler.test.ts deleted file mode 100644 index 99cc0f8..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-method-handler.test.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { act } from '@testing-library/react' - -import { optimism } from 'core-kit/const' -import * as poolHooks from 'core-kit/hooks/pool' -import { usePoolStatic } from 'core-kit/hooks/pool/multicall' -import * as stateHooks from 'core-kit/hooks/state' -import { useIsPoolManagerAccount } from 'core-kit/hooks/user' -import { TEST_ADDRESS } from 'tests/mocks' -import { renderHook } from 'tests/test-utils' - -import { useDepositMethodHandler } from './use-deposit-method-handler' - -vi.mock('core-kit/hooks/state', () => ({ - useTradingPanelDepositMethod: vi.fn(), - useTradingPanelPoolConfig: vi.fn(), -})) - -vi.mock('core-kit/hooks/pool/multicall', () => ({ - usePoolStatic: vi.fn(), -})) - -vi.mock('core-kit/hooks/user', () => ({ - useIsPoolManagerAccount: vi.fn(), -})) - -vi.mock('core-kit/hooks/pool', () => ({ - usePoolDynamicContractData: vi.fn(), -})) - -describe('useDepositMethodHandler', () => { - beforeEach(() => { - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockImplementation( - () => - ({ - address: TEST_ADDRESS, - chainId: optimism.id, - }) as ReturnType, - ) - - vi.mocked(poolHooks.usePoolDynamicContractData).mockImplementation( - () => - ({ - entryFee: '10', - }) as ReturnType, - ) - }) - - it('should return deposit method, deposit method updater and hasDepositOptions flag when vault is allowed and manager is not vault account', () => { - const setDepositMethodMock = vi.fn() - const isPoolManagerAccount = false - const isEasySwapperAllowedPool = true - const method = 'deposit' - const entryFee = '' - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation( - () => [method, setDepositMethodMock], - ) - vi.mocked(useIsPoolManagerAccount).mockImplementation( - () => isPoolManagerAccount, - ) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { easySwapperAllowedPools: isEasySwapperAllowedPool }, - }) as ReturnType, - ) - vi.mocked(poolHooks.usePoolDynamicContractData).mockImplementation( - () => - ({ - entryFee, - }) as ReturnType, - ) - - const { result } = renderHook(() => useDepositMethodHandler()) - expect(result.current[0]).toBe(method) - expect(result.current[1]).toBeInstanceOf(Function) - expect(result.current[2]).toBe(true) - - act(() => result.current[1]('depositWithCustomCooldown')) - - expect(setDepositMethodMock).toHaveBeenCalledTimes(1) - expect(setDepositMethodMock).toHaveBeenCalledWith({ - address: TEST_ADDRESS, - method: 'depositWithCustomCooldown', - }) - }) - - it('should return hasDepositOptions flag as false when vault is not allowed', () => { - const isPoolManagerAccount = false - const isEasySwapperAllowedPool = false - const method = 'depositWithCustomCooldown' - const setDepositMethodMock = vi.fn() - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation( - () => [method, setDepositMethodMock], - ) - vi.mocked(useIsPoolManagerAccount).mockImplementation( - () => isPoolManagerAccount, - ) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { easySwapperAllowedPools: isEasySwapperAllowedPool }, - }) as ReturnType, - ) - - const { result } = renderHook(() => useDepositMethodHandler()) - expect(result.current[0]).toBe(method) - expect(result.current[2]).toBe(false) - }) - - it('should return hasDepositOptions flag as false when vault is allowed but manager is vault account', () => { - const isPoolManagerAccount = true - const isEasySwapperAllowedPool = true - const method = 'depositWithCustomCooldown' - const setDepositMethodMock = vi.fn() - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation( - () => [method, setDepositMethodMock], - ) - vi.mocked(useIsPoolManagerAccount).mockImplementation( - () => isPoolManagerAccount, - ) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { easySwapperAllowedPools: isEasySwapperAllowedPool }, - }) as ReturnType, - ) - - const { result } = renderHook(() => useDepositMethodHandler()) - expect(result.current[2]).toBe(false) - }) - - it('should return falsy hasDepositOptions flag when entry fee is defined', () => { - const setDepositMethodMock = vi.fn() - const isPoolManagerAccount = false - const isEasySwapperAllowedPool = true - const method = 'deposit' - const entryFee = '1' - - expect(isPoolManagerAccount).toBe(false) - expect(isEasySwapperAllowedPool).toBe(true) - expect(+entryFee).toBeGreaterThan(0) - - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation( - () => [method, setDepositMethodMock], - ) - vi.mocked(useIsPoolManagerAccount).mockImplementation( - () => isPoolManagerAccount, - ) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { easySwapperAllowedPools: isEasySwapperAllowedPool }, - }) as ReturnType, - ) - vi.mocked(poolHooks.usePoolDynamicContractData).mockImplementation( - () => - ({ entryFee }) as ReturnType< - typeof poolHooks.usePoolDynamicContractData - >, - ) - - const { result } = renderHook(() => useDepositMethodHandler()) - expect(result.current[2]).toBe(false) - }) - - it('should return truthy hasDepositOptions flag when entry fee is not defined', () => { - const setDepositMethodMock = vi.fn() - const isPoolManagerAccount = false - const isEasySwapperAllowedPool = true - const method = 'deposit' - const entryFee = '' - - expect(isPoolManagerAccount).toBe(false) - expect(isEasySwapperAllowedPool).toBe(true) - expect(+entryFee).not.toBeGreaterThan(0) - - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation( - () => [method, setDepositMethodMock], - ) - vi.mocked(useIsPoolManagerAccount).mockImplementation( - () => isPoolManagerAccount, - ) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { easySwapperAllowedPools: isEasySwapperAllowedPool }, - }) as ReturnType, - ) - vi.mocked(poolHooks.usePoolDynamicContractData).mockImplementation( - () => - ({ entryFee }) as ReturnType< - typeof poolHooks.usePoolDynamicContractData - >, - ) - - const { result } = renderHook(() => useDepositMethodHandler()) - expect(result.current[2]).toBe(true) - }) -}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-method-handler.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-method-handler.ts deleted file mode 100644 index 7988ff5..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-method-handler.ts +++ /dev/null @@ -1,51 +0,0 @@ -import BigNumber from 'bignumber.js' -import { useCallback, useMemo } from 'react' - -import { usePoolDynamicContractData } from 'core-kit/hooks/pool' -import { usePoolStatic } from 'core-kit/hooks/pool/multicall' -import { - useTradingPanelDepositMethod, - useTradingPanelPoolConfig, -} from 'core-kit/hooks/state' -import { useIsPoolManagerAccount } from 'core-kit/hooks/user' -import type { DepositMethodName } from 'core-kit/types/trading-panel.types' - -export const useDepositMethodHandler = (): [ - DepositMethodName, - (method: DepositMethodName) => void, - boolean, -] => { - const { address, chainId } = useTradingPanelPoolConfig() - const [depositMethod, setDepositMethod] = useTradingPanelDepositMethod() - const isPoolManagerAccount = useIsPoolManagerAccount() - const { data: { easySwapperAllowedPools: isPoolAllowed = false } = {} } = - usePoolStatic({ - address, - chainId, - }) - const { entryFee = '0' } = usePoolDynamicContractData({ - address, - chainId, - }) - - const entryFeeBN = new BigNumber(entryFee) - const hasDepositOptions = - (entryFeeBN.isNaN() || entryFeeBN.isZero()) && - isPoolAllowed && - !isPoolManagerAccount - - const setPoolDepositMethod = useCallback( - (method: DepositMethodName) => { - setDepositMethod({ - address, - method, - }) - }, - [setDepositMethod, address], - ) - - return useMemo( - () => [depositMethod, setPoolDepositMethod, hasDepositOptions], - [depositMethod, setPoolDepositMethod, hasDepositOptions], - ) -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-quote.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-quote.test.ts deleted file mode 100644 index 312c222..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-quote.test.ts +++ /dev/null @@ -1,412 +0,0 @@ -import { act } from '@testing-library/react' -import BigNumber from 'bignumber.js' - -import { expect } from 'vitest' - -import { DhedgeEasySwapperAbi } from 'core-kit/abi' -import { AddressZero, optimism } from 'core-kit/const' -import * as poolHooks from 'core-kit/hooks/pool' -import { usePoolTokenPrice } from 'core-kit/hooks/pool' -import * as stateHooks from 'core-kit/hooks/state' -import { usePoolDepositAssetAddress } from 'core-kit/hooks/trading/deposit' -import { useReadContracts } from 'core-kit/hooks/web3' - -import type { Address, DynamicTradingToken } from 'core-kit/types' -import { TEST_ADDRESS } from 'tests/mocks' -import { renderHook } from 'tests/test-utils' - -import { useDepositQuote } from './use-deposit-quote' -import { useAssetPrice } from '../use-asset-price' -import { useIsEasySwapperTrading } from '../use-is-easy-swapper-trading' - -vi.mock('core-kit/hooks/state', () => ({ - useIsDepositTradingPanelType: vi.fn(), - useReceiveTokenInput: vi.fn(), - useSendTokenInput: vi.fn(), - useTradingPanelPoolFallbackData: vi.fn(), - useTradingPanelSettings: vi.fn().mockImplementation(() => []), - useTradingPanelPoolConfig: vi.fn(), -})) -vi.mock('core-kit/hooks/utils', () => ({ - useDebounce: vi.fn().mockImplementation((v) => v), -})) -vi.mock('core-kit/hooks/web3', () => ({ - useReadContracts: vi.fn(), - useContractReadsErrorLogging: vi.fn(), - useInvalidateOnBlock: vi.fn(), -})) -vi.mock('core-kit/hooks/trading/deposit', () => ({ - usePoolDepositAssetAddress: vi.fn(), -})) -vi.mock('core-kit/hooks/pool', () => ({ - usePoolTokenPrice: vi.fn(), -})) -vi.mock('../use-is-easy-swapper-trading', () => ({ - useIsEasySwapperTrading: vi.fn(), -})) -vi.mock('../use-asset-price', () => ({ - useAssetPrice: vi.fn(), -})) - -describe('useDepositQuote', () => { - it('should update receive token input based on deposit quote with default multiplier', () => { - const isDeposit = true - const sendToken: DynamicTradingToken = { - symbol: 'USDC', - address: '0x123', - decimals: 6, - value: '100', - isLoading: false, - } - const receiveToken: DynamicTradingToken = { - symbol: 'USDy', - address: '0x111', - decimals: 3, - value: '50', - isLoading: false, - } - const updateReceiveTokenMock = vi.fn() - expect(isDeposit).toBe(true) - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useReceiveTokenInput).mockImplementation(() => [ - receiveToken, - updateReceiveTokenMock, - ]) - vi.mocked(stateHooks.useIsDepositTradingPanelType).mockImplementation( - () => isDeposit, - ) - vi.mocked(usePoolDepositAssetAddress).mockImplementation( - () => sendToken.address, - ) - vi.mocked(useReadContracts).mockImplementation( - () => - ({ - data: [{ result: BigInt(100000) }], - }) as ReturnType, - ) - vi.mocked(useIsEasySwapperTrading).mockImplementation(() => true) - - const { rerender } = renderHook(() => - useDepositQuote({ - address: TEST_ADDRESS, - chainId: optimism.id, - depositParams: { customTokens: [] }, - }), - ) - expect(usePoolDepositAssetAddress).toHaveBeenCalledTimes(1) - expect(usePoolDepositAssetAddress).toHaveBeenCalledWith({ - investAssetAddress: sendToken.address, - symbol: sendToken.symbol, - productPoolAddress: TEST_ADDRESS, - chainId: optimism.id, - }) - expect(useReadContracts).toHaveBeenCalledTimes(1) - expect(useReadContracts).toHaveBeenCalledWith({ - contracts: [ - expect.objectContaining({ - abi: DhedgeEasySwapperAbi, - functionName: 'depositQuote', - chainId: optimism.id, - args: [ - TEST_ADDRESS, - sendToken.address, - BigInt( - new BigNumber(sendToken.value) - .shiftedBy(sendToken.decimals) - .toFixed(0), - ), - sendToken.address, - false, - ], - }), - ], - query: expect.objectContaining({ - enabled: true, - }), - }) - expect(updateReceiveTokenMock).toHaveBeenCalledTimes(2) - expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(1, { - isLoading: false, - }) - expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(2, { - value: '99.970', - }) - vi.mocked(useReadContracts).mockImplementationOnce( - () => - ({ - data: [{ result: BigInt(500000) }], - }) as ReturnType, - ) - act(() => rerender()) - expect(updateReceiveTokenMock).toHaveBeenCalledTimes(4) - expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(4, { - value: '499.850', - }) - }) - - it('should update receive token input based on deposit quote with custom multiplier', () => { - const isDeposit = true - const sendToken: DynamicTradingToken = { - symbol: 'USDC', - address: '0x123', - decimals: 6, - value: '100', - isLoading: false, - } - const receiveToken: DynamicTradingToken = { - symbol: 'USDy', - address: '0x111', - decimals: 3, - value: '50', - isLoading: false, - } - const updateReceiveTokenMock = vi.fn() - expect(isDeposit).toBe(true) - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useReceiveTokenInput).mockImplementation(() => [ - receiveToken, - updateReceiveTokenMock, - ]) - vi.mocked(stateHooks.useIsDepositTradingPanelType).mockImplementation( - () => isDeposit, - ) - vi.mocked(usePoolDepositAssetAddress).mockImplementation( - () => AddressZero, // sendToken.address !== poolDepositAssetAddress - ) - vi.mocked(useReadContracts).mockImplementationOnce( - () => - ({ - data: [{ result: BigInt(100000) }], - }) as ReturnType, - ) - - renderHook(() => - useDepositQuote({ - address: TEST_ADDRESS, - chainId: optimism.id, - depositParams: { - method: 'depositWithCustomCooldown', - customTokens: [], - }, - }), - ) - expect(useReadContracts).toHaveBeenCalledWith({ - contracts: [ - expect.objectContaining({ - args: [ - TEST_ADDRESS, - sendToken.address, - BigInt( - new BigNumber(sendToken.value) - .shiftedBy(sendToken.decimals) - .toFixed(0), - ), - AddressZero, - true, - ], - }), - ], - query: expect.objectContaining({ - enabled: true, - }), - }) - expect(updateReceiveTokenMock).toHaveBeenCalledTimes(2) - expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(1, { - isLoading: false, - }) - expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(2, { - value: '99.900', - }) - }) - - it('should not update receive token input when trading type is "withdraw"', () => { - const isDeposit = false - const sendToken: DynamicTradingToken = { - symbol: 'USDC', - address: '0x123', - decimals: 6, - value: '100', - isLoading: false, - } - const receiveToken: DynamicTradingToken = { - symbol: 'USDy', - address: '0x111', - decimals: 3, - value: '50', - isLoading: false, - } - const updateReceiveTokenMock = vi.fn() - expect(isDeposit).toBe(false) - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useReceiveTokenInput).mockImplementation(() => [ - receiveToken, - updateReceiveTokenMock, - ]) - vi.mocked(stateHooks.useIsDepositTradingPanelType).mockImplementation( - () => isDeposit, - ) - vi.mocked(usePoolDepositAssetAddress).mockImplementation( - () => receiveToken.address as Address, - ) - vi.mocked(useReadContracts).mockImplementationOnce( - () => - ({ - data: [{ result: BigInt(100000) }], - }) as ReturnType, - ) - - renderHook(() => - useDepositQuote({ - address: TEST_ADDRESS, - chainId: optimism.id, - depositParams: { customTokens: [] }, - }), - ) - - expect(updateReceiveTokenMock).not.toHaveBeenCalled() - }) - - it('should set receive token value and slippage to 0 when send token value is not defined', () => { - const isDeposit = false - const sendToken: DynamicTradingToken = { - symbol: 'USDC', - address: '0x123', - decimals: 6, - value: '', - isLoading: false, - } - const receiveToken: DynamicTradingToken = { - symbol: 'USDy', - address: '0x111', - decimals: 3, - value: '', - isLoading: false, - } - const updateReceiveTokenMock = vi.fn() - const updateTradingSettingsMock = vi.fn() - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useReceiveTokenInput).mockImplementation(() => [ - receiveToken, - updateReceiveTokenMock, - ]) - vi.mocked(stateHooks.useIsDepositTradingPanelType).mockImplementation( - () => isDeposit, - ) - vi.mocked(stateHooks.useTradingPanelSettings).mockImplementationOnce(() => [ - { - slippage: 'auto', - isInfiniteAllowance: false, - isMultiAssetWithdrawalEnabled: false, - isMaxSlippageLoading: false, - }, - updateTradingSettingsMock, - ]) - vi.mocked(usePoolDepositAssetAddress).mockImplementation( - () => receiveToken.address as Address, - ) - vi.mocked(useReadContracts).mockImplementationOnce( - () => - ({ - data: [{ result: BigInt(100000) }], - }) as ReturnType, - ) - - renderHook(() => - useDepositQuote({ - address: TEST_ADDRESS, - chainId: optimism.id, - depositParams: { customTokens: [] }, - }), - ) - - expect(updateReceiveTokenMock).toHaveBeenCalledTimes(1) - expect(updateReceiveTokenMock).toHaveBeenCalledWith({ value: '0' }) - expect(updateReceiveTokenMock).toHaveBeenCalledTimes(1) - expect(updateTradingSettingsMock).toHaveBeenCalledWith({ minSlippage: 0 }) - }) - - it('should update receive token input for synthetix vault', () => { - const isDeposit = true - const sendToken: DynamicTradingToken = { - symbol: 'USDC', - address: '0x123', - decimals: 6, - value: '100', - isLoading: false, - } - const receiveToken: DynamicTradingToken = { - symbol: 'USDy', - address: '0x111', - decimals: 3, - value: '50', - isLoading: false, - } - const updateReceiveTokenMock = vi.fn() - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useReceiveTokenInput).mockImplementation(() => [ - receiveToken, - updateReceiveTokenMock, - ]) - vi.mocked(stateHooks.useIsDepositTradingPanelType).mockImplementation( - () => isDeposit, - ) - vi.mocked(usePoolDepositAssetAddress).mockImplementation( - () => sendToken.address, - ) - vi.mocked(useReadContracts).mockImplementation( - () => - ({ - data: [{ result: BigInt(100000) }], - }) as ReturnType, - ) - vi.mocked(useIsEasySwapperTrading).mockImplementation(() => false) - vi.mocked(poolHooks.usePoolTokenPrice).mockImplementation(() => '100') - vi.mocked(useAssetPrice).mockImplementation(() => '100') - - renderHook(() => - useDepositQuote({ - address: receiveToken.address, - chainId: optimism.id, - depositParams: { customTokens: [] }, - }), - ) - expect(usePoolTokenPrice).toHaveBeenCalledTimes(1) - expect(usePoolTokenPrice).toHaveBeenCalledWith({ - address: receiveToken.address, - chainId: optimism.id, - disabled: false, - }) - expect(useAssetPrice).toHaveBeenCalledTimes(1) - expect(useAssetPrice).toHaveBeenCalledWith({ - address: sendToken.address, - chainId: optimism.id, - disabled: false, - }) - expect(useReadContracts).toHaveBeenCalledWith( - expect.objectContaining({ - query: expect.objectContaining({ - enabled: false, - }), - }), - ) - expect(updateReceiveTokenMock).toHaveBeenCalledTimes(1) - expect(updateReceiveTokenMock).toHaveBeenNthCalledWith(1, { - value: '100.000', - }) - }) -}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-quote.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-quote.ts deleted file mode 100644 index ff8b088..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-quote.ts +++ /dev/null @@ -1,160 +0,0 @@ -import BigNumber from 'bignumber.js' - -import { useEffect } from 'react' - -import { DhedgeEasySwapperAbi } from 'core-kit/abi' -import { - DEPOSIT_QUOTE_MULTIPLIER_CUSTOM, - DEPOSIT_QUOTE_MULTIPLIER_DEFAULT, - SHORTEN_POLLING_INTERVAL, -} from 'core-kit/const' -import { usePoolTokenPrice } from 'core-kit/hooks/pool' -import { - useIsDepositTradingPanelType, - useReceiveTokenInput, - useSendTokenInput, - useTradingPanelSettings, -} from 'core-kit/hooks/state' -import { usePoolDepositAssetAddress } from 'core-kit/hooks/trading/deposit' -import { useDebounce } from 'core-kit/hooks/utils' -import { - useContractReadsErrorLogging, - useReadContracts, -} from 'core-kit/hooks/web3' -import type { PoolConfig } from 'core-kit/types/config.types' -import { getContractAddressById } from 'core-kit/utils' - -import { useAssetPrice } from '../use-asset-price' -import { useIsEasySwapperTrading } from '../use-is-easy-swapper-trading' - -export const useDepositQuote = ({ - address, - chainId, - depositParams, -}: Pick) => { - const [sendToken] = useSendTokenInput() - const [receiveToken, updateReceiveToken] = useReceiveTokenInput() - const [, updateSettings] = useTradingPanelSettings() - const isDeposit = useIsDepositTradingPanelType() - const isEasySwapperTrading = useIsEasySwapperTrading() - const vaultTokenPrice = usePoolTokenPrice({ - address: receiveToken.address, - chainId, - disabled: isEasySwapperTrading, - }) - const sendTokenPrice = useAssetPrice({ - address: sendToken.address, - chainId, - disabled: isEasySwapperTrading, - }) - const debounceTime = isEasySwapperTrading ? 500 : 0 - const debouncedSendTokenValue = useDebounce(sendToken.value, debounceTime) - const poolDepositAssetAddress = usePoolDepositAssetAddress({ - investAssetAddress: sendToken.address, - symbol: sendToken.symbol, - productPoolAddress: address, - chainId, - }) - - const isSendValueUpdating = sendToken.value !== debouncedSendTokenValue - const hasSendInputValue = !!( - debouncedSendTokenValue && +debouncedSendTokenValue > 0 - ) - const sendAmount = new BigNumber(debouncedSendTokenValue || '0') - .shiftedBy(sendToken.decimals) - .toFixed(0) - - const { data } = useReadContracts({ - contracts: [ - { - address: getContractAddressById('easySwapper', chainId), - abi: DhedgeEasySwapperAbi, - functionName: 'depositQuote', - args: [ - address, - sendToken.address, - BigInt(sendAmount), - poolDepositAssetAddress, - depositParams.method === 'depositWithCustomCooldown', - ], - chainId, - }, - ], - query: { - enabled: - hasSendInputValue && - !!sendToken.address && - !!poolDepositAssetAddress && - isEasySwapperTrading, - refetchInterval: SHORTEN_POLLING_INTERVAL, - }, - }) - - const depositQuote = data?.[0]?.result - useContractReadsErrorLogging(data) - - // Updates received amount for EasySwapper deposits - useEffect(() => { - if (!isDeposit || !isEasySwapperTrading) { - return - } - - const isLoading = - isSendValueUpdating || (!depositQuote && hasSendInputValue) - - updateReceiveToken({ isLoading }) - if (depositQuote) { - const formattedVal = new BigNumber(depositQuote.toString()) - .multipliedBy( - sendToken.address === poolDepositAssetAddress - ? DEPOSIT_QUOTE_MULTIPLIER_DEFAULT - : DEPOSIT_QUOTE_MULTIPLIER_CUSTOM, - ) - .shiftedBy(-receiveToken.decimals) - .toFixed(receiveToken.decimals) - - updateReceiveToken({ value: isLoading ? '0' : formattedVal }) - } - }, [ - isEasySwapperTrading, - isDeposit, - receiveToken.decimals, - hasSendInputValue, - depositQuote, - sendToken.address, - poolDepositAssetAddress, - isSendValueUpdating, - updateReceiveToken, - ]) - - // Updates received amount for PoolLogic deposits - useEffect(() => { - if (!isDeposit || isEasySwapperTrading || !hasSendInputValue) { - return - } - updateReceiveToken({ - value: new BigNumber(sendAmount) - .shiftedBy(-sendToken.decimals) - .multipliedBy(sendTokenPrice) - .dividedBy(vaultTokenPrice) - .toFixed(receiveToken.decimals), - }) - }, [ - isDeposit, - isEasySwapperTrading, - sendAmount, - sendTokenPrice, - updateReceiveToken, - vaultTokenPrice, - sendToken.decimals, - receiveToken.decimals, - hasSendInputValue, - ]) - - useEffect(() => { - if (!sendToken.value) { - updateReceiveToken({ value: '0' }) - updateSettings({ minSlippage: 0 }) - } - }, [updateReceiveToken, updateSettings, sendToken.value]) -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-slippage.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-slippage.ts deleted file mode 100644 index a989bf2..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-slippage.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { useEffect } from 'react' - -import { - useIsDepositTradingPanelType, - useSendTokenInput, - useTradingPanelSettings, -} from 'core-kit/hooks/state' -import { useTradingPriceDiff } from 'core-kit/hooks/trading' -import { useDebounce } from 'core-kit/hooks/utils' - -export const useDepositSlippage = (receiveAssetInputValue: string) => { - const isDeposit = useIsDepositTradingPanelType() - const [sendToken] = useSendTokenInput() - const updateSettings = useTradingPanelSettings()[1] - const tradingPriceDiff = useTradingPriceDiff({ - sendAssetValue: sendToken.value, - sendAssetAddress: sendToken.address, - receiveAssetValue: receiveAssetInputValue, - }) - const priceDiffDebounced = useDebounce(tradingPriceDiff, 100) - - useEffect(() => { - if (isDeposit) { - const minSlippage = - priceDiffDebounced < 0 ? Math.abs(priceDiffDebounced) : 0 - updateSettings({ minSlippage }) - } - }, [updateSettings, isDeposit, priceDiffDebounced]) -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-trading-params.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-trading-params.test.ts deleted file mode 100644 index 346d8e7..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-trading-params.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -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>( - '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, - ) - vi.mocked(stateHooks.useSendTokenInput).mockReturnValue([ - sendToken, - vi.fn(), - ] as ReturnType) - vi.mocked(stateHooks.useReceiveTokenInput).mockReturnValue([ - receiveToken, - vi.fn(), - ] as ReturnType) - vi.mocked(tradingDepositHooks.usePoolDepositAssetAddress).mockReturnValue( - poolDepositAssetAddress, - ) - vi.mocked(stateHooks.useTradingPanelSettings).mockReturnValue([ - { slippage: 'auto' }, - ] as unknown as ReturnType) - }) - - 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) - - 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(), - ) - }) -}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-trading-params.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-trading-params.ts deleted file mode 100644 index f95fa6f..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit-trading-params.ts +++ /dev/null @@ -1,63 +0,0 @@ -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( - () => ({ - sendAssetAddress: sendToken.address, - fromTokenAmount: new BigNumber(sendToken.value || '0'), - receiveAssetAddress, - receiveAssetAmount, - poolDepositAddress: poolDepositAssetAddress, - }), - [ - sendToken.address, - sendToken.value, - receiveAssetAddress, - receiveAssetAmount, - poolDepositAssetAddress, - ], - ) -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit.test.ts deleted file mode 100644 index afc8078..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit.test.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { act } from '@testing-library/react' -import BigNumber from 'bignumber.js' - -import { - AddressZero, - BRIDGED_USDC_OPTIMISM, - DEFAULT_DEPOSIT_SLIPPAGE, - optimism, -} from 'core-kit/const' -import * as stateHooks from 'core-kit/hooks/state' - -import { - useIsEasySwapperTrading, - useTradingSettleHandler, -} from 'core-kit/hooks/trading' -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' -import * as configProviderHooks from 'trading-widget/providers/config-provider' - -import { useDeposit } from './use-deposit' - -vi.mock('trading-widget/providers/config-provider', () => ({ - useConfigContextParams: vi.fn().mockReturnValue({ - defaultDepositSlippage: DEFAULT_DEPOSIT_SLIPPAGE, - }), -})) - -vi.mock('core-kit/hooks/state', () => ({ - useReceiveTokenInput: vi.fn(), - useSendTokenInput: vi.fn(), - useTradingPanelDepositMethod: vi.fn(), - useTradingPanelPoolConfig: vi.fn(), - useTradingPanelSettings: vi.fn(), - useTradingPanelTransactions: vi.fn(), -})) -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(), -})) -const { logTransactionArguments } = vi.hoisted(() => ({ - logTransactionArguments: vi.fn(), -})) -vi.mock('core-kit/utils', async () => { - const actual = - await vi.importActual>('core-kit/utils') - return { - ...actual, - logTransactionArguments, - } -}) -describe('useDeposit', () => { - const chainId = optimism.id - const updatePendingTransactionsMock = vi.fn() - const onSettledMock = vi.fn() - const sendMock = vi.fn() - - beforeEach(() => { - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockImplementation( - () => - ({ chainId }) as ReturnType< - typeof stateHooks.useTradingPanelPoolConfig - >, - ) - vi.mocked(stateHooks.useTradingPanelTransactions).mockImplementation(() => [ - [], - updatePendingTransactionsMock, - ]) - vi.mocked(useTradingSettleHandler).mockImplementation(() => onSettledMock) - vi.mocked(useContractFunction).mockImplementation( - () => - ({ - send: sendMock, - }) as unknown as ReturnType, - ) - vi.mocked(configProviderHooks.useConfigContextParams).mockImplementation( - () => - ({ - defaultDepositSlippage: DEFAULT_DEPOSIT_SLIPPAGE, - }) as unknown as ReturnType< - typeof configProviderHooks.useConfigContextParams - >, - ) - vi.mocked(useIsEasySwapperTrading).mockReturnValue(true) - }) - - afterEach(() => { - vi.restoreAllMocks() - }) - - it('should process deposits with auto slippage and not native token', async () => { - const depositMethod = 'deposit' - const sendToken = { ...BRIDGED_USDC_OPTIMISM, value: '5', isLoading: false } - const receiveToken = { - symbol: 'USDy', - address: '0x123', - value: '10', - } as unknown as DynamicTradingToken - const slippage = 'auto' - const tradingParams = { - poolDepositAddress: '0x111' as Address, - receiveAssetAddress: receiveToken.address, - sendAssetAddress: sendToken.address, - receiveAssetAmount: receiveToken.value, - fromTokenAmount: new BigNumber(sendToken.value), - } - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation( - () => [depositMethod, vi.fn()], - ) - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useReceiveTokenInput).mockImplementation(() => [ - receiveToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useTradingPanelSettings).mockImplementation( - () => - [ - { - slippage, - }, - vi.fn, - ] as unknown as ReturnType, - ) - vi.mocked(useDepositTradingParams).mockImplementation(() => tradingParams) - - const { result } = renderHook(() => useDeposit()) - - expect(useDepositSlippage).toHaveBeenCalledTimes(1) - expect(useDepositSlippage).toHaveBeenCalledWith( - tradingParams.receiveAssetAmount, - ) - expect(useTradingSettleHandler).toHaveBeenCalledTimes(1) - expect(useTradingSettleHandler).toHaveBeenCalledWith('deposit') - - expect(useContractFunction).toHaveBeenCalledTimes(1) - expect(useContractFunction).toHaveBeenCalledWith({ - contractId: 'easySwapper', - functionName: depositMethod, - onSettled: onSettledMock, - }) - - await act(async () => await result.current()) - - expect(updatePendingTransactionsMock).toHaveBeenCalledTimes(1) - expect(updatePendingTransactionsMock).toHaveBeenCalledWith({ - type: 'add', - action: 'deposit', - symbol: receiveToken.symbol, - chainId, - }) - expect(logTransactionArguments).toHaveBeenCalledTimes(1) - expect(logTransactionArguments.mock.calls[0]).toMatchSnapshot() - expect(sendMock).toHaveBeenCalledTimes(1) - expect(sendMock.mock.calls[0]).toMatchSnapshot() - }) - - it('should process deposits with custom slippage, custom cooldown and native token', async () => { - const depositMethod = 'depositWithCustomCooldown' - const sendToken = { - symbol: 'ETH', - decimals: 18, - address: AddressZero, - value: '5', - isLoading: false, - } - const receiveToken = { - symbol: 'USDy', - address: '0x123', - value: '10', - } as unknown as DynamicTradingToken - const slippage = 0.15 - const tradingParams = { - poolDepositAddress: BRIDGED_USDC_OPTIMISM.address, - receiveAssetAddress: receiveToken.address, - sendAssetAddress: sendToken.address, - receiveAssetAmount: receiveToken.value, - fromTokenAmount: new BigNumber(sendToken.value), - } - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockImplementation( - () => [depositMethod, vi.fn()], - ) - vi.mocked(stateHooks.useSendTokenInput).mockImplementation(() => [ - sendToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useReceiveTokenInput).mockImplementation(() => [ - receiveToken, - vi.fn(), - ]) - vi.mocked(stateHooks.useTradingPanelSettings).mockImplementation( - () => - [ - { - slippage, - }, - vi.fn, - ] as unknown as ReturnType, - ) - vi.mocked(useDepositTradingParams).mockImplementation(() => tradingParams) - - const { result } = renderHook(() => useDeposit()) - - expect(useDepositSlippage).toHaveBeenCalledTimes(1) - expect(useDepositSlippage).toHaveBeenCalledWith( - tradingParams.receiveAssetAmount, - ) - expect(useTradingSettleHandler).toHaveBeenCalledTimes(1) - expect(useTradingSettleHandler).toHaveBeenCalledWith('deposit') - - expect(useContractFunction).toHaveBeenCalledTimes(1) - expect(useContractFunction).toHaveBeenCalledWith({ - contractId: 'easySwapper', - functionName: 'depositNativeWithCustomCooldown', - onSettled: onSettledMock, - }) - - await act(async () => await result.current()) - - expect(logTransactionArguments).toHaveBeenCalledTimes(1) - expect(logTransactionArguments.mock.calls[0]).toMatchSnapshot() - expect(sendMock).toHaveBeenCalledTimes(1) - expect(sendMock.mock.calls[0]).toMatchSnapshot() - }) -}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit.ts deleted file mode 100644 index 0c1e1ef..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-deposit.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { useCallback, useMemo } from 'react' - -import { DEFAULT_DEPOSIT_SLIPPAGE } from 'core-kit/const' -import { - useReceiveTokenInput, - useSendTokenInput, - useTradingPanelDepositMethod, - useTradingPanelPoolConfig, - useTradingPanelSettings, - useTradingPanelTransactions, -} from 'core-kit/hooks/state' -import { - useIsEasySwapperTrading, - useTradingSettleHandler, -} from 'core-kit/hooks/trading' -import { - useDepositSlippage, - useDepositTradingParams, -} from 'core-kit/hooks/trading/deposit' -import { useContractFunction } from 'core-kit/hooks/web3' - -import { - BuyingWithEasyswapperArgs, - BuyingWithNativeAssetArgs, - BuyingWithPoolLogicArgs, -} from 'core-kit/models' -import type { ContractActionFunc } from 'core-kit/types/web3.types' -import { - getOrderedTxArgs, - isNativeToken, - logTransactionArguments, -} from 'core-kit/utils' - -const action = 'deposit' - -export const useDeposit = (): ContractActionFunc => { - const poolConfig = useTradingPanelPoolConfig() - const [depositMethod] = useTradingPanelDepositMethod() - const [sendToken] = useSendTokenInput() - const [receiveToken] = useReceiveTokenInput() - const updatePendingTransactions = useTradingPanelTransactions()[1] - const [{ slippage }] = useTradingPanelSettings() - const isEasySwapperDeposit = useIsEasySwapperTrading() - const { - poolDepositAddress, - receiveAssetAddress, - sendAssetAddress, - receiveAssetAmount, - fromTokenAmount, - } = useDepositTradingParams() - - useDepositSlippage(receiveAssetAmount) - - const isDepositNative = - poolConfig.chainId && isEasySwapperDeposit - ? isNativeToken(sendToken.symbol, poolConfig.chainId) - : false - const functionName = isDepositNative - ? depositMethod === 'deposit' - ? 'depositNative' - : 'depositNativeWithCustomCooldown' - : depositMethod - - const onSettled = useTradingSettleHandler(action) - const txArgs = useMemo(() => { - const depositAddress = poolDepositAddress ?? sendAssetAddress - const depositArgs = { - receiveAssetAddress, - fromTokenAmount: fromTokenAmount.shiftedBy(sendToken.decimals).toFixed(0), - poolDepositAddress: depositAddress, - receiveAssetInputValue: receiveAssetAmount, - } - - if (!isEasySwapperDeposit) { - return new BuyingWithPoolLogicArgs({ - ...depositArgs, - fromTokenAddress: sendAssetAddress, - }) - } - - if (isDepositNative) { - return new BuyingWithNativeAssetArgs(depositArgs) - } - - return new BuyingWithEasyswapperArgs({ - ...depositArgs, - sendAssetAddress, - }) - }, [ - fromTokenAmount, - isDepositNative, - isEasySwapperDeposit, - poolDepositAddress, - receiveAssetAddress, - receiveAssetAmount, - sendAssetAddress, - sendToken.decimals, - ]) - const { send } = useContractFunction({ - contractId: isEasySwapperDeposit ? 'easySwapper' : 'poolLogic', - dynamicContractAddress: isEasySwapperDeposit - ? undefined - : receiveToken.address, - functionName, - onSettled, - }) - - return useCallback(async () => { - updatePendingTransactions({ - type: 'add', - action, - symbol: receiveToken.symbol, - chainId: poolConfig.chainId, - }) - - logTransactionArguments(txArgs) - const args: unknown[] = getOrderedTxArgs( - txArgs, - slippage === 'auto' ? DEFAULT_DEPOSIT_SLIPPAGE : slippage, - ) - if (isDepositNative) { - args.push({ value: BigInt(txArgs.fromTokenAmount) }) - } - return send(...args) - }, [ - updatePendingTransactions, - isDepositNative, - poolConfig.chainId, - receiveToken.symbol, - send, - txArgs, - slippage, - ]) -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-asset-address.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-asset-address.test.ts deleted file mode 100644 index 715703a..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-asset-address.test.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { - BRIDGED_USDC_OPTIMISM, - BRIDGED_USDC_POLYGON, - PAXG_POLYGON, - WBTC_OPTIMISM, - WBTC_POLYGON, - WMATIC_POLYGON, - optimism, - polygon, -} from 'core-kit/const' -import * as poolHooks from 'core-kit/hooks/pool' -import type { PoolComposition } from 'core-kit/types' -import { TEST_ADDRESS } from 'tests/mocks' -import { renderHook } from 'tests/test-utils' - -import { usePoolDepositAssetAddress } from './use-pool-deposit-asset-address' - -vi.mock('core-kit/hooks/pool', () => ({ usePoolComposition: vi.fn() })) - -describe('usePoolDepositAssetAddress', () => { - it('should return investAssetAddress when initialInvestToken does not exist', () => { - const investAssetAddress = '0xInvest' - const symbol = 'WETH' - const productPoolAddress = TEST_ADDRESS - const chainId = optimism.id - - vi.mocked(poolHooks.usePoolComposition).mockImplementation(() => []) - - const { result } = renderHook(() => - usePoolDepositAssetAddress({ - investAssetAddress, - chainId, - productPoolAddress, - symbol, - }), - ) - expect(poolHooks.usePoolComposition).toHaveBeenCalledTimes(1) - expect(poolHooks.usePoolComposition).toHaveBeenCalledWith({ - address: productPoolAddress, - chainId, - }) - expect(result.current).toEqual(investAssetAddress) - }) - - it('should return investAssetAddress if initialInvestToken exists and isCustomTokenDeposit is false', () => { - const investAssetAddress = '0xInvest' - const symbol = 'USDC' - const productPoolAddress = TEST_ADDRESS - const chainId = optimism.id - - vi.mocked(poolHooks.usePoolComposition).mockImplementation(() => [ - { - tokenAddress: investAssetAddress, - tokenName: symbol, - isDeposit: true, - } as unknown as PoolComposition, - ]) - - const { result } = renderHook(() => - usePoolDepositAssetAddress({ - investAssetAddress, - chainId, - productPoolAddress, - symbol, - }), - ) - expect(poolHooks.usePoolComposition).toHaveBeenCalledTimes(1) - expect(poolHooks.usePoolComposition).toHaveBeenCalledWith({ - address: productPoolAddress, - chainId, - }) - expect(result.current).toEqual(investAssetAddress) - }) - - it('should return the fallback asset address if initialInvestToken exists, isCustomTokenDeposit is true, and fallback asset symbol is found', () => { - const investAssetAddress = '0xInvest' - const symbol = 'CUSTOM' - const productPoolAddress = TEST_ADDRESS - const chainId = optimism.id - - vi.mocked(poolHooks.usePoolComposition).mockImplementation(() => [ - { - tokenAddress: BRIDGED_USDC_OPTIMISM.address, - tokenName: BRIDGED_USDC_OPTIMISM.symbol, - isDeposit: true, - } as unknown as PoolComposition, - { - tokenAddress: WBTC_OPTIMISM.address, - tokenName: WBTC_OPTIMISM.symbol, - isDeposit: true, - } as unknown as PoolComposition, - ]) - - const { result } = renderHook(() => - usePoolDepositAssetAddress({ - investAssetAddress, - chainId, - productPoolAddress, - symbol, - }), - ) - expect(result.current).toEqual(BRIDGED_USDC_OPTIMISM.address) - }) - - it('should return the fallback asset address if initialInvestToken exists, isCustomTokenDeposit is true, and fallback asset symbol is found (should prefer wrapped native token) #2', () => { - const investAssetAddress = '0xInvest' - const symbol = 'CUSTOM' - const productPoolAddress = TEST_ADDRESS - const chainId = polygon.id - - vi.mocked(poolHooks.usePoolComposition).mockImplementation(() => [ - { - tokenAddress: BRIDGED_USDC_POLYGON.address, - tokenName: BRIDGED_USDC_POLYGON.symbol, - isDeposit: false, - } as unknown as PoolComposition, - { - tokenAddress: WBTC_POLYGON.address, - tokenName: WBTC_POLYGON.symbol, - isDeposit: false, - } as unknown as PoolComposition, - { - tokenAddress: WMATIC_POLYGON.address, - tokenName: WMATIC_POLYGON.symbol, - isDeposit: true, - } as unknown as PoolComposition, - ]) - - const { result } = renderHook(() => - usePoolDepositAssetAddress({ - investAssetAddress, - chainId, - productPoolAddress, - symbol, - }), - ) - expect(result.current).toEqual(WMATIC_POLYGON.address) - }) - - it('should return the initialInvestToken address if initialInvestToken exists, isCustomTokenDeposit is true, and fallback asset symbol is not found', () => { - const investAssetAddress = BRIDGED_USDC_POLYGON.address - const symbol = BRIDGED_USDC_POLYGON.symbol - const productPoolAddress = TEST_ADDRESS - const chainId = polygon.id - - vi.mocked(poolHooks.usePoolComposition).mockImplementation(() => [ - { - tokenAddress: PAXG_POLYGON.address, - tokenName: PAXG_POLYGON.symbol, - isDeposit: true, - } as unknown as PoolComposition, - ]) - - const { result } = renderHook(() => - usePoolDepositAssetAddress({ - investAssetAddress, - chainId, - productPoolAddress, - symbol, - }), - ) - expect(result.current).toEqual(PAXG_POLYGON.address) - }) -}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-asset-address.ts b/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-asset-address.ts deleted file mode 100644 index 8f4a377..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/deposit/use-pool-deposit-asset-address.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { useMemo } from 'react' - -import { - BRIDGED_USDC_ARBITRUM, - BRIDGED_USDC_OPTIMISM, - BRIDGED_USDC_POLYGON, - DAI_OPTIMISM, - DAI_POLYGON, - USDC_ARBITRUM, - USDC_BASE, - USDC_OPTIMISM, - USDC_POLYGON, - USDT_OPTIMISM, - USDT_POLYGON, - WBTC_ARBITRUM, - WBTC_OPTIMISM, - WBTC_POLYGON, - WETH_ARBITRUM, - WETH_BASE, - WETH_OPTIMISM, - WETH_POLYGON, - WMATIC_POLYGON, - arbitrum, - base, - optimism, - polygon, -} from 'core-kit/const' -import { usePoolComposition } from 'core-kit/hooks/pool' -import type { TradingToken } from 'core-kit/types/trading-panel.types' -import type { Address, ChainId } from 'core-kit/types/web3.types' - -const FALLBACK_ASSET_SYMBOLS = [ - 'WMATIC', - 'WETH', - 'USDCe', - 'USDC', - 'USDT', - 'DAI', - 'WBTC', -] -const FALLBACK_ASSETS_ADRESSES_MAP: Record< - ChainId, - Record -> = { - [optimism.id]: { - WETH: WETH_OPTIMISM, - USDC: USDC_OPTIMISM, - USDCe: BRIDGED_USDC_OPTIMISM, - USDT: USDT_OPTIMISM, - DAI: DAI_OPTIMISM, - WBTC: WBTC_OPTIMISM, - }, - [polygon.id]: { - WMATIC: WMATIC_POLYGON, - WETH: WETH_POLYGON, - USDC: USDC_POLYGON, - USDCe: BRIDGED_USDC_POLYGON, - USDT: USDT_POLYGON, - DAI: DAI_POLYGON, - WBTC: WBTC_POLYGON, - }, - [arbitrum.id]: { - WETH: WETH_ARBITRUM, - USDC: USDC_ARBITRUM, - USDCe: BRIDGED_USDC_ARBITRUM, - WBTC: WBTC_ARBITRUM, - }, - [base.id]: { - WETH: WETH_BASE, - USDC: USDC_BASE, - }, -} - -interface PoolDepositAssetAddressParams { - investAssetAddress: Address - symbol: string - productPoolAddress: Address - chainId: ChainId -} - -export const usePoolDepositAssetAddress = ({ - investAssetAddress, - symbol, - productPoolAddress, - chainId, -}: PoolDepositAssetAddressParams): Address => { - const poolComposition = usePoolComposition({ - address: productPoolAddress, - chainId, - }) - const poolInvestTokens = poolComposition.filter(({ isDeposit }) => isDeposit) - const isCustomTokenDeposit = !poolInvestTokens.some( - ({ tokenName }) => tokenName === symbol, - ) - const [initialInvestToken] = poolInvestTokens - - return useMemo
(() => { - if (initialInvestToken) { - if (isCustomTokenDeposit) { - const depositTokens = poolComposition - .filter(({ isDeposit }) => isDeposit) - .map(({ tokenName }) => tokenName) - const fallbackAssetSymbol = FALLBACK_ASSET_SYMBOLS.find((symbol) => { - return depositTokens.includes(symbol) - }) - - // use fallback asset - return fallbackAssetSymbol - ? FALLBACK_ASSETS_ADRESSES_MAP[chainId]?.[fallbackAssetSymbol] - ?.address ?? initialInvestToken.tokenAddress - : initialInvestToken.tokenAddress - } - } - - return investAssetAddress - }, [ - chainId, - investAssetAddress, - isCustomTokenDeposit, - poolComposition, - initialInvestToken, - ]) -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/index.ts b/packages/trading-widget/src/core-kit/hooks/trading/index.ts index 1b65be6..740bc5b 100644 --- a/packages/trading-widget/src/core-kit/hooks/trading/index.ts +++ b/packages/trading-widget/src/core-kit/hooks/trading/index.ts @@ -1,7 +1,5 @@ export { useTradingResultHandling } from './use-trading-result-handling' -export { useHandlePoolSwapInfo } from './use-handle-pool-swap-info' export { useTradingSettleHandler } from './use-trading-settle-handler' -export { useTradingPriceDiff } from './use-trading-price-diff' export { useAssetPrice } from './use-asset-price' export { useRawAssetPrice } from './use-raw-asset-price' export { useIsTradingEnabled } from './use-is-trading-enabled' @@ -12,4 +10,4 @@ export { useMaxSlippagePlaceholder } from './use-max-slippage-placeholder' export { useSynthetixV3OraclesUpdate } from './synthetix-v3/use-synthetix-v3-oracles-update' export { useDepositProjectedEarnings } from './projected-earnings/use-deposit-projected-earnings' export { useProjectedEarningsCore } from './projected-earnings/use-projected-earnings-core' -export { useIsEasySwapperTrading } from './use-is-easy-swapper-trading' +export { useSwapDataQuery } from './use-swap-data-query' diff --git a/packages/trading-widget/src/core-kit/hooks/trading/use-handle-pool-swap-info.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/use-handle-pool-swap-info.test.ts deleted file mode 100644 index be33c3f..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/use-handle-pool-swap-info.test.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { optimism } from 'core-kit/const' -import { usePoolStatic } from 'core-kit/hooks/pool/multicall' -import * as stateHooks from 'core-kit/hooks/state' -import * as userHooks from 'core-kit/hooks/user' - -import { getPercent } from 'core-kit/utils' -import { TEST_ADDRESS } from 'tests/mocks' -import { renderHook } from 'tests/test-utils' - -import { useHandlePoolSwapInfo } from './use-handle-pool-swap-info' - -vi.mock('core-kit/hooks/state', () => ({ - useTradingPanelDepositMethod: vi.fn(), - useTradingPanelEntryFee: vi.fn(), - useTradingPanelPoolConfig: vi.fn(), -})) - -vi.mock('core-kit/hooks/pool/multicall', () => ({ - usePoolStatic: vi.fn(), -})) - -vi.mock('core-kit/hooks/user', () => ({ - useIsPoolManagerAccount: vi.fn(), -})) - -describe('useHandlePoolSwapInfo', () => { - it('should set deposit method as depositWithCustomCooldown', () => { - const address = TEST_ADDRESS - const isPoolManagerAccount = true - const isPoolSwapAllowed = true - const setDepositMethodMock = vi.fn() - - expect(isPoolManagerAccount && isPoolSwapAllowed).toEqual(true) - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue({ - address, - chainId: optimism.id, - } as ReturnType) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { - easySwapperAllowedPools: isPoolSwapAllowed, - easySwapperFeeDenominator: BigInt(2), - easySwapperFeeNumerator: BigInt(1), - }, - }) as ReturnType, - ) - vi.mocked(userHooks.useIsPoolManagerAccount).mockReturnValue( - isPoolManagerAccount, - ) - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockReturnValue([ - 'deposit', - setDepositMethodMock, - ]) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockReturnValue([0, vi.fn()]) - - renderHook(() => useHandlePoolSwapInfo()) - - expect(setDepositMethodMock).toHaveBeenCalledTimes(1) - expect(setDepositMethodMock).toHaveBeenCalledWith({ - address, - method: 'depositWithCustomCooldown', - }) - }) - - it('should skip setting of deposit method as depositWithCustomCooldown', () => { - const address = TEST_ADDRESS - const isPoolManagerAccount = false - const isPoolSwapAllowed = true - const setDepositMethodMock = vi.fn() - - expect(isPoolManagerAccount && isPoolSwapAllowed).toEqual(false) - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue({ - address, - chainId: optimism.id, - } as ReturnType) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { - easySwapperAllowedPools: isPoolSwapAllowed, - easySwapperFeeDenominator: BigInt(2), - easySwapperFeeNumerator: BigInt(1), - }, - }) as ReturnType, - ) - vi.mocked(userHooks.useIsPoolManagerAccount).mockReturnValue( - isPoolManagerAccount, - ) - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockReturnValue([ - 'deposit', - setDepositMethodMock, - ]) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockReturnValue([0, vi.fn()]) - - renderHook(() => useHandlePoolSwapInfo()) - - expect(setDepositMethodMock).toHaveBeenCalledTimes(0) - }) - - it('should update entry fee', () => { - const address = TEST_ADDRESS - const isPoolManagerAccount = true - const isPoolSwapAllowed = true - const feeNumerator = BigInt(1) - const feeDenominator = BigInt(2) - const depositMethod = 'depositWithCustomCooldown' - const updateEntryFeeMock = vi.fn() - - expect(depositMethod).toEqual('depositWithCustomCooldown') - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue({ - address, - chainId: optimism.id, - } as ReturnType) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { - easySwapperAllowedPools: isPoolSwapAllowed, - easySwapperFeeDenominator: feeDenominator, - easySwapperFeeNumerator: feeNumerator, - }, - }) as ReturnType, - ) - vi.mocked(userHooks.useIsPoolManagerAccount).mockReturnValue( - isPoolManagerAccount, - ) - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockReturnValue([ - depositMethod, - vi.fn(), - ]) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockReturnValue([ - 0, - updateEntryFeeMock, - ]) - - renderHook(() => useHandlePoolSwapInfo()) - - expect(updateEntryFeeMock).toHaveBeenCalledTimes(1) - expect(updateEntryFeeMock).toHaveBeenCalledWith({ - depositWithCustomCooldown: getPercent( - Number(feeNumerator), - Number(feeDenominator), - ), - }) - }) - - it('should skip updating entry fee', () => { - const address = TEST_ADDRESS - const isPoolManagerAccount = true - const isPoolSwapAllowed = true - const feeNumerator = BigInt(1) - const feeDenominator = BigInt(2) - const depositMethod = 'deposit' - const updateEntryFeeMock = vi.fn() - - expect(depositMethod).toEqual('deposit') - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue({ - address, - chainId: optimism.id, - } as ReturnType) - vi.mocked(usePoolStatic).mockImplementationOnce( - () => - ({ - data: { - easySwapperAllowedPools: isPoolSwapAllowed, - easySwapperFeeDenominator: feeDenominator, - easySwapperFeeNumerator: feeNumerator, - }, - }) as ReturnType, - ) - vi.mocked(userHooks.useIsPoolManagerAccount).mockReturnValue( - isPoolManagerAccount, - ) - vi.mocked(stateHooks.useTradingPanelDepositMethod).mockReturnValue([ - depositMethod, - vi.fn(), - ]) - vi.mocked(stateHooks.useTradingPanelEntryFee).mockReturnValue([ - 0, - updateEntryFeeMock, - ]) - - renderHook(() => useHandlePoolSwapInfo()) - - expect(updateEntryFeeMock).toHaveBeenCalledTimes(0) - }) -}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/use-handle-pool-swap-info.ts b/packages/trading-widget/src/core-kit/hooks/trading/use-handle-pool-swap-info.ts deleted file mode 100644 index 87b60e4..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/use-handle-pool-swap-info.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { useEffect } from 'react' - -import { usePoolStatic } from 'core-kit/hooks/pool/multicall' -import { - useTradingPanelDepositMethod, - useTradingPanelEntryFee, - useTradingPanelPoolConfig, -} from 'core-kit/hooks/state' -import { useIsPoolManagerAccount } from 'core-kit/hooks/user' -import { getPercent, isBigInt } from 'core-kit/utils' - -export const useHandlePoolSwapInfo = () => { - const { address, chainId } = useTradingPanelPoolConfig() - - const { - data: { - easySwapperFeeDenominator, - easySwapperFeeNumerator, - easySwapperAllowedPools: isPoolSwapAllowed = false, - } = {}, - } = usePoolStatic({ - address, - chainId, - }) - const isPoolManagerAccount = useIsPoolManagerAccount() - - const [depositMethod, setDepositMethod] = useTradingPanelDepositMethod() - const updateEntryFee = useTradingPanelEntryFee()[1] - - useEffect(() => { - if (isPoolManagerAccount && isPoolSwapAllowed) { - setDepositMethod({ address, method: 'depositWithCustomCooldown' }) - } - }, [isPoolManagerAccount, isPoolSwapAllowed, address, setDepositMethod]) - - useEffect(() => { - if ( - isBigInt(easySwapperFeeNumerator) && - isBigInt(easySwapperFeeDenominator) && - isPoolSwapAllowed && - depositMethod === 'depositWithCustomCooldown' - ) { - updateEntryFee({ - depositWithCustomCooldown: getPercent( - Number(easySwapperFeeNumerator), - Number(easySwapperFeeDenominator), - ), - }) - } - }, [ - updateEntryFee, - easySwapperFeeNumerator, - easySwapperFeeDenominator, - depositMethod, - isPoolSwapAllowed, - ]) -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/use-is-easy-swapper-trading.ts b/packages/trading-widget/src/core-kit/hooks/trading/use-is-easy-swapper-trading.ts deleted file mode 100644 index 1eb387c..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/use-is-easy-swapper-trading.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' - -export const useIsEasySwapperTrading = () => { - const poolConfig = useTradingPanelPoolConfig() - - return !poolConfig.usePoolLogicDeposit -} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/use-swap-data-query.ts b/packages/trading-widget/src/core-kit/hooks/trading/use-swap-data-query.ts new file mode 100644 index 0000000..04b95cf --- /dev/null +++ b/packages/trading-widget/src/core-kit/hooks/trading/use-swap-data-query.ts @@ -0,0 +1,26 @@ +import { type UseQueryOptions, useQuery } from '@tanstack/react-query' + +import { useGetSwapData } from 'core-kit/hooks/state' +import type { SwapDataRequest, SwapDataResponse } from 'core-kit/types' + +export const useSwapDataQuery = ( + variables: SwapDataRequest, + options?: Omit< + UseQueryOptions< + SwapDataResponse | null, + Error, + SwapDataResponse | null, + [string, SwapDataRequest] + >, + 'queryKey' | 'queryFn' + >, +) => { + const getSwapData = useGetSwapData() + + return useQuery({ + queryKey: ['getSwapData', variables], + queryFn: async ({ signal, queryKey: [, variables] }) => + getSwapData({ signal, variables }), + ...options, + }) +} diff --git a/packages/trading-widget/src/core-kit/hooks/trading/use-trading-price-diff.test.ts b/packages/trading-widget/src/core-kit/hooks/trading/use-trading-price-diff.test.ts deleted file mode 100644 index a8a8aeb..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/use-trading-price-diff.test.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { optimism } from 'core-kit/const' -import * as poolHooks from 'core-kit/hooks/pool' - -import * as stateHooks from 'core-kit/hooks/state' -import * as tradingHooks from 'core-kit/hooks/trading' -import { TEST_ADDRESS } from 'tests/mocks' -import { renderHook } from 'tests/test-utils' - -import { useTradingPriceDiff } from './use-trading-price-diff' - -vi.mock('core-kit/hooks/pool', () => ({ - usePoolTokenPrice: vi.fn(), -})) - -vi.mock('core-kit/hooks/state', () => ({ - useTradingPanelPoolConfig: vi.fn(), -})) - -vi.mock('./use-asset-price', () => ({ - useAssetPrice: vi.fn(), -})) - -describe('useTradingPriceDiff', () => { - it('should handle zero send input value', () => { - const sendAssetAddress = TEST_ADDRESS - const sendAssetValue = '0' - const receiveAssetValue = '2' - const sendTokenPrice = '1' - const poolTokenPrice = '2' - const poolConfig = { address: TEST_ADDRESS, chainId: optimism.id } - - expect(Number(sendAssetValue)).toEqual(0) - expect(Number(receiveAssetValue)).not.toEqual(0) - expect(Number(sendTokenPrice)).not.toEqual(0) - expect(Number(poolTokenPrice)).not.toEqual(0) - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue( - poolConfig as ReturnType, - ) - vi.mocked(tradingHooks.useAssetPrice).mockReturnValue(sendTokenPrice) - vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValue(poolTokenPrice) - - const { result } = renderHook(() => - useTradingPriceDiff({ - sendAssetAddress, - sendAssetValue, - receiveAssetValue, - }), - ) - - expect(result.current).toEqual(0) - }) - - it('should handle zero receive input value', () => { - const sendAssetAddress = TEST_ADDRESS - const sendAssetValue = '1' - const receiveAssetValue = '0' - const sendTokenPrice = '1' - const poolTokenPrice = '2' - const poolConfig = { address: TEST_ADDRESS, chainId: optimism.id } - - expect(Number(sendAssetValue)).not.toEqual(0) - expect(Number(receiveAssetValue)).toEqual(0) - expect(Number(sendTokenPrice)).not.toEqual(0) - expect(Number(poolTokenPrice)).not.toEqual(0) - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue( - poolConfig as ReturnType, - ) - vi.mocked(tradingHooks.useAssetPrice).mockReturnValue(sendTokenPrice) - vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValue(poolTokenPrice) - - const { result } = renderHook(() => - useTradingPriceDiff({ - sendAssetAddress, - sendAssetValue, - receiveAssetValue, - }), - ) - - expect(result.current).toEqual(0) - }) - - it('should handle zero send token price', () => { - const sendAssetAddress = TEST_ADDRESS - const sendAssetValue = '1' - const receiveAssetValue = '1' - const sendTokenPrice = '0' - const poolTokenPrice = '2' - const poolConfig = { address: TEST_ADDRESS, chainId: optimism.id } - - expect(Number(sendAssetValue)).not.toEqual(0) - expect(Number(receiveAssetValue)).not.toEqual(0) - expect(Number(sendTokenPrice)).toEqual(0) - expect(Number(poolTokenPrice)).not.toEqual(0) - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue( - poolConfig as ReturnType, - ) - vi.mocked(tradingHooks.useAssetPrice).mockReturnValue(sendTokenPrice) - vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValue(poolTokenPrice) - - const { result } = renderHook(() => - useTradingPriceDiff({ - sendAssetAddress, - sendAssetValue, - receiveAssetValue, - }), - ) - - expect(result.current).toEqual(0) - }) - - it('should handle zero receive token price', () => { - const sendAssetAddress = TEST_ADDRESS - const sendAssetValue = '1' - const receiveAssetValue = '1' - const sendTokenPrice = '1' - const poolTokenPrice = '0' - const poolConfig = { address: TEST_ADDRESS, chainId: optimism.id } - - expect(Number(sendAssetValue)).not.toEqual(0) - expect(Number(receiveAssetValue)).not.toEqual(0) - expect(Number(sendTokenPrice)).not.toEqual(0) - expect(Number(poolTokenPrice)).toEqual(0) - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue( - poolConfig as ReturnType, - ) - vi.mocked(tradingHooks.useAssetPrice).mockReturnValue(sendTokenPrice) - vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValue(poolTokenPrice) - - const { result } = renderHook(() => - useTradingPriceDiff({ - sendAssetAddress, - sendAssetValue, - receiveAssetValue, - }), - ) - - expect(result.current).toEqual(0) - }) - - it('should calculate diff', () => { - const sendAssetAddress = TEST_ADDRESS - const sendAssetValue = '100' - const receiveAssetValue = '200' - const sendTokenPrice = '300' - const poolTokenPrice = '400' - const poolConfig = { address: TEST_ADDRESS, chainId: optimism.id } - - expect(Number(sendAssetValue)).not.toEqual(0) - expect(Number(receiveAssetValue)).not.toEqual(0) - expect(Number(sendTokenPrice)).not.toEqual(0) - expect(Number(poolTokenPrice)).not.toEqual(0) - - vi.mocked(stateHooks.useTradingPanelPoolConfig).mockReturnValue( - poolConfig as ReturnType, - ) - vi.mocked(tradingHooks.useAssetPrice).mockReturnValue(sendTokenPrice) - vi.mocked(poolHooks.usePoolTokenPrice).mockReturnValue(poolTokenPrice) - - const { result } = renderHook(() => - useTradingPriceDiff({ - sendAssetAddress, - sendAssetValue, - receiveAssetValue, - }), - ) - - expect(result.current).toMatchSnapshot() - }) -}) diff --git a/packages/trading-widget/src/core-kit/hooks/trading/use-trading-price-diff.ts b/packages/trading-widget/src/core-kit/hooks/trading/use-trading-price-diff.ts deleted file mode 100644 index 67d424b..0000000 --- a/packages/trading-widget/src/core-kit/hooks/trading/use-trading-price-diff.ts +++ /dev/null @@ -1,63 +0,0 @@ -import BigNumber from 'bignumber.js' -import { useMemo } from 'react' - -import { usePoolTokenPrice } from 'core-kit/hooks/pool' -import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' -import type { Address } from 'core-kit/types/web3.types' -import { getConventionalTokenPriceDecimals } from 'core-kit/utils' - -import { useAssetPrice } from './use-asset-price' - -interface UseTradingPriceDiffVariables { - sendAssetAddress: Address - sendAssetValue: string - receiveAssetValue: string -} - -export const useTradingPriceDiff = ({ - sendAssetAddress, - sendAssetValue, - receiveAssetValue, -}: UseTradingPriceDiffVariables) => { - const { address, chainId } = useTradingPanelPoolConfig() - const sendTokenPrice = useAssetPrice({ - address: sendAssetAddress, - chainId, - }) - const poolTokenPrice = usePoolTokenPrice({ address, chainId }) - - return useMemo(() => { - const sendValue = Number(sendAssetValue || '0') - const receiveValue = Number(receiveAssetValue || '0') - - const sendAmount = new BigNumber(sendValue).times(sendTokenPrice ?? '0') - const receiveAmount = new BigNumber(receiveValue).times( - poolTokenPrice ?? '0', - ) - - if (sendAmount.isZero() || receiveAmount.isZero()) { - return 0 - } - - const canBeCompared = sendAmount - .decimalPlaces(getConventionalTokenPriceDecimals(sendValue)) - .comparedTo( - receiveAmount.decimalPlaces( - getConventionalTokenPriceDecimals(receiveValue), - ), - ) - - if (canBeCompared) { - return sendAmount.isGreaterThan(0) - ? receiveAmount - .dividedBy(sendAmount) - .minus(1) - .times(100) - .decimalPlaces(2, BigNumber.ROUND_DOWN) - .toNumber() - : 0 - } - - return 0 - }, [sendTokenPrice, poolTokenPrice, sendAssetValue, receiveAssetValue]) -} diff --git a/packages/trading-widget/src/core-kit/models/buying-with-easyswapper-args.ts b/packages/trading-widget/src/core-kit/models/buying-with-easyswapper-args.ts deleted file mode 100644 index 2a8273e..0000000 --- a/packages/trading-widget/src/core-kit/models/buying-with-easyswapper-args.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Address, ContractCallArgs } from 'core-kit/types/web3.types' - -interface BuyingWithEasyswapperArgsProps { - receiveAssetAddress: Address - sendAssetAddress: Address - fromTokenAmount: string - poolDepositAddress: Address - receiveAssetInputValue: string -} - -export class BuyingWithEasyswapperArgs implements ContractCallArgs { - readonly receiveAssetAddress: Address - readonly sendAssetAddress: Address - readonly fromTokenAmount: string - readonly poolDepositAddress: Address - readonly receiveAssetInputValue: string - - constructor(props: BuyingWithEasyswapperArgsProps) { - this.receiveAssetAddress = props.receiveAssetAddress - this.sendAssetAddress = props.sendAssetAddress - this.fromTokenAmount = props.fromTokenAmount - this.poolDepositAddress = props.poolDepositAddress - this.receiveAssetInputValue = props.receiveAssetInputValue - } - - getOrderedArgs(minReturnAmount: string) { - return [ - this.receiveAssetAddress, - this.sendAssetAddress, - this.fromTokenAmount, - this.poolDepositAddress, - minReturnAmount, - ] - } -} diff --git a/packages/trading-widget/src/core-kit/models/buying-with-native-asset-args.ts b/packages/trading-widget/src/core-kit/models/buying-with-native-asset-args.ts deleted file mode 100644 index 1811e9f..0000000 --- a/packages/trading-widget/src/core-kit/models/buying-with-native-asset-args.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Address, ContractCallArgs } from 'core-kit/types/web3.types' - -interface BuyingWithNativeAssetArgsProps { - receiveAssetAddress: Address - poolDepositAddress: Address - fromTokenAmount: string - receiveAssetInputValue: string -} - -export class BuyingWithNativeAssetArgs implements ContractCallArgs { - readonly receiveAssetAddress: Address - readonly fromTokenAmount: string - readonly poolDepositAddress: Address - readonly receiveAssetInputValue: string - - constructor(props: BuyingWithNativeAssetArgsProps) { - this.receiveAssetAddress = props.receiveAssetAddress - this.fromTokenAmount = props.fromTokenAmount - this.poolDepositAddress = props.poolDepositAddress - this.receiveAssetInputValue = props.receiveAssetInputValue - } - - getOrderedArgs(minReturnAmount: string) { - return [this.receiveAssetAddress, this.poolDepositAddress, minReturnAmount] - } -} diff --git a/packages/trading-widget/src/core-kit/models/buying-with-pool-logic-args.ts b/packages/trading-widget/src/core-kit/models/buying-with-pool-logic-args.ts deleted file mode 100644 index 79e73b0..0000000 --- a/packages/trading-widget/src/core-kit/models/buying-with-pool-logic-args.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Address, ContractCallArgs } from 'core-kit/types/web3.types' - -interface BuyingWithPoolLogicArgsProps { - fromTokenAmount: string - fromTokenAddress: Address - receiveAssetInputValue: string -} - -export class BuyingWithPoolLogicArgs implements ContractCallArgs { - readonly fromTokenAddress: Address - readonly fromTokenAmount: string - readonly receiveAssetInputValue: string - - constructor(props: BuyingWithPoolLogicArgsProps) { - this.fromTokenAmount = props.fromTokenAmount - this.fromTokenAddress = props.fromTokenAddress - this.receiveAssetInputValue = props.receiveAssetInputValue - } - - getOrderedArgs() { - return [this.fromTokenAddress, this.fromTokenAmount] - } -} diff --git a/packages/trading-widget/src/core-kit/models/index.ts b/packages/trading-widget/src/core-kit/models/index.ts index 118ab4b..78403a1 100644 --- a/packages/trading-widget/src/core-kit/models/index.ts +++ b/packages/trading-widget/src/core-kit/models/index.ts @@ -1,5 +1,2 @@ -export { BuyingWithEasyswapperArgs } from './buying-with-easyswapper-args' -export { BuyingWithNativeAssetArgs } from './buying-with-native-asset-args' -export { BuyingWithPoolLogicArgs } from './buying-with-pool-logic-args' export { DefaultSellingParams } from './default-selling-params' export { EstimationError } from './estimation-error' diff --git a/packages/trading-widget/src/core-kit/providers/index.tsx b/packages/trading-widget/src/core-kit/providers/index.tsx index d82eff5..c563e9b 100644 --- a/packages/trading-widget/src/core-kit/providers/index.tsx +++ b/packages/trading-widget/src/core-kit/providers/index.tsx @@ -8,7 +8,7 @@ import { TRADING_LOG_EVENT_PARAM, TRADING_PANEL_LOG_EVENT, } from 'core-kit/const' -import type { PoolConfig, PoolFallbackData } from 'core-kit/types/config.types' +import type { PoolFallbackData } from 'core-kit/types/config.types' import type { TradingPanelAction, TradingPanelActionsState, @@ -73,11 +73,6 @@ export const getDefaultTradingPanelState = ( meta: { ...config?.meta, }, - entryFee: { - deposit: 0, - depositWithCustomCooldown: 0.1, - ...config?.entryFee, - }, modal: { isOpen: false, status: 'None', @@ -106,10 +101,8 @@ export const TradingPanelActionsContext = updateReceiveTokenInput: noop, updateTradingSettings: noop, updateTradingMeta: noop, - updateEntryFee: noop, updateTradingModal: noop, updateTransactions: noop, - updatePoolConfigDepositMethod: noop, updatePoolFallbackData: noop, onTradingSettleError: noop, onTransactionError: noop, @@ -118,6 +111,7 @@ export const TradingPanelActionsContext = onTokenSelector: noop, onLog: noop, onSimulateTransaction: () => Promise.resolve(null), + getSwapData: () => Promise.resolve(null), }) const createReducerWithLogger = @@ -134,20 +128,6 @@ const createReducerWithLogger = ...state, type: action.payload, } - case 'UPDATE_POOL_CONFIG_DEPOSIT_METHOD': - return { - ...state, - poolConfigMap: { - ...state.poolConfigMap, - [action.payload.address]: { - ...state.poolConfigMap[action.payload.address], - depositParams: { - ...state.poolConfigMap[action.payload.address]?.depositParams, - method: action.payload.method, - }, - }, - }, - } case 'UPDATE_SEND_TOKEN_INPUT': return { ...state, @@ -187,15 +167,6 @@ const createReducerWithLogger = }, } } - case 'UPDATE_ENTRY_FEE': { - return { - ...state, - entryFee: { - ...state.entryFee, - ...action.payload, - }, - } - } case 'UPDATE_TRADING_MODAL': { return { ...state, @@ -291,7 +262,6 @@ export const TradingPanelProvider: FC< initialState, actions: { onSetPoolAddress, - onUpdatePoolConfigDepositMethod, onUpdateSendTokenInput, onUpdateReceiveTokenInput, onUpdateTradingSettings, @@ -299,7 +269,6 @@ export const TradingPanelProvider: FC< onUpdateTradingMeta, onUpdateTradingModal, onUpdateTransactions, - onUpdateEntryFee, onTransactionError, onTransactionSuccess, onTransactionEstimationError, @@ -307,6 +276,7 @@ export const TradingPanelProvider: FC< onLog, onSimulateTransaction, onTradingSettleError, + getSwapData, }, }) => { const [state, dispatch] = useReducer( @@ -362,14 +332,6 @@ export const TradingPanelProvider: FC< [onUpdateTradingMeta], ) - const updateEntryFee = useCallback( - (payload: Partial) => { - dispatch({ type: 'UPDATE_ENTRY_FEE', payload }) - onUpdateEntryFee?.(payload) - }, - [onUpdateEntryFee], - ) - const updateTradingModal = useCallback( (payload: Partial) => { dispatch({ type: 'UPDATE_TRADING_MODAL', payload }) @@ -386,17 +348,6 @@ export const TradingPanelProvider: FC< [onUpdateTransactions], ) - const updatePoolConfigDepositMethod = useCallback( - ( - payload: Pick & - Pick, - ) => { - dispatch({ type: 'UPDATE_POOL_CONFIG_DEPOSIT_METHOD', payload }) - onUpdatePoolConfigDepositMethod?.(payload) - }, - [onUpdatePoolConfigDepositMethod], - ) - const updatePoolFallbackData = useCallback((payload: PoolFallbackData) => { dispatch({ type: 'UPDATE_POOL_FALLBACK_DATA', payload }) }, []) @@ -405,14 +356,12 @@ export const TradingPanelProvider: FC< () => ({ setPoolAddress, setTradingType, - updatePoolConfigDepositMethod, updateTradingSettings, updateSendTokenInput, updateReceiveTokenInput, updateTradingMeta, updateTradingModal, updateTransactions, - updateEntryFee, updatePoolFallbackData, onTransactionError, onTransactionSuccess, @@ -421,18 +370,17 @@ export const TradingPanelProvider: FC< onLog, onSimulateTransaction, onTradingSettleError, + getSwapData, }), [ setPoolAddress, setTradingType, - updatePoolConfigDepositMethod, updateTradingSettings, updateSendTokenInput, updateReceiveTokenInput, updateTradingMeta, updateTradingModal, updateTransactions, - updateEntryFee, updatePoolFallbackData, onTransactionError, onTransactionSuccess, @@ -441,6 +389,7 @@ export const TradingPanelProvider: FC< onLog, onSimulateTransaction, onTradingSettleError, + getSwapData, ], ) diff --git a/packages/trading-widget/src/core-kit/types/config.types.ts b/packages/trading-widget/src/core-kit/types/config.types.ts index f9c5c43..274099c 100644 --- a/packages/trading-widget/src/core-kit/types/config.types.ts +++ b/packages/trading-widget/src/core-kit/types/config.types.ts @@ -1,7 +1,6 @@ import type { PoolComposition } from 'core-kit/types/pool.types' import type { ApyCurrency, - DepositMethodName, TradingToken, WithdrawTradingToken, } from 'core-kit/types/trading-panel.types' @@ -12,16 +11,13 @@ export interface PoolConfig { symbol: string chainId: ChainId depositParams: { - method?: DepositMethodName customTokens: TradingToken[] defaultDepositTokenSymbol?: string } withdrawParams: { - method?: string customTokens: WithdrawTradingToken[] } deprecated?: boolean - usePoolLogicDeposit?: boolean } export interface PoolFallbackData { diff --git a/packages/trading-widget/src/core-kit/types/state.types.ts b/packages/trading-widget/src/core-kit/types/state.types.ts index 7d63da1..626c4ee 100644 --- a/packages/trading-widget/src/core-kit/types/state.types.ts +++ b/packages/trading-widget/src/core-kit/types/state.types.ts @@ -2,7 +2,6 @@ import type { EstimationError } from 'core-kit/models' import type { PoolConfig, PoolFallbackData } from 'core-kit/types/config.types' import type { - DepositMethodName, DynamicTradingToken, PendingTransaction, TokenSelectorPayload, @@ -12,6 +11,10 @@ import type { TransactionAction, UpdateTransactionsArguments, } from 'core-kit/types/trading-panel.types' +import type { + SwapDataRequest, + SwapDataResponse, +} from 'core-kit/types/trading.types' import type { Address, ChainId, @@ -42,7 +45,6 @@ export interface TradingPanelState { sendToken: DynamicTradingToken receiveToken: DynamicTradingToken } - entryFee: Record meta: { approvingStatus?: 'pending' | 'success' } @@ -56,10 +58,6 @@ export interface TradingPanelState { export interface TradingPanelSetters { setPoolAddress: (payload: TradingPanelState['poolAddress']) => void - updatePoolConfigDepositMethod: ( - payload: Pick & - Pick, - ) => void updateSendTokenInput: (payload: Partial) => void updateReceiveTokenInput: (payload: Partial) => void updateTradingSettings: ( @@ -67,7 +65,6 @@ export interface TradingPanelSetters { ) => void setTradingType: (payload: TradingPanelState['type']) => void updateTradingMeta: (payload: Partial) => void - updateEntryFee: (payload: Partial) => void updateTradingModal: (payload: Partial) => void updateTransactions: (payload: UpdateTransactionsArguments) => void updatePoolFallbackData: (payload: PoolFallbackData) => void @@ -75,13 +72,11 @@ export interface TradingPanelSetters { export interface CallbackConfig { onSetPoolAddress: TradingPanelSetters['setPoolAddress'] - onUpdatePoolConfigDepositMethod: TradingPanelSetters['updatePoolConfigDepositMethod'] onUpdateSendTokenInput: TradingPanelSetters['updateSendTokenInput'] onUpdateReceiveTokenInput: TradingPanelSetters['updateReceiveTokenInput'] onUpdateTradingSettings: TradingPanelSetters['updateTradingSettings'] onSetTradingType: TradingPanelSetters['setTradingType'] onUpdateTradingMeta: TradingPanelSetters['updateTradingMeta'] - onUpdateEntryFee: TradingPanelSetters['updateEntryFee'] onUpdateTradingModal: TradingPanelSetters['updateTradingModal'] onUpdateTransactions: TradingPanelSetters['updateTransactions'] onTradingSettleError: (error: Error) => void @@ -107,6 +102,10 @@ export interface CallbackConfig { onSimulateTransaction: ( params: SimulateTransactionParams, ) => Promise + getSwapData: (args: { + signal: AbortSignal + variables: SwapDataRequest + }) => Promise } export type TradingPanelAction = @@ -118,11 +117,6 @@ export type TradingPanelAction = type: 'SET_TRADING_TYPE' payload: TradingPanelState['type'] } - | { - type: 'UPDATE_POOL_CONFIG_DEPOSIT_METHOD' - payload: Pick & - Pick - } | { type: 'UPDATE_SEND_TOKEN_INPUT' payload: Partial @@ -139,10 +133,6 @@ export type TradingPanelAction = type: 'UPDATE_TRADING_META' payload: Partial } - | { - type: 'UPDATE_ENTRY_FEE' - payload: Partial - } | { type: 'UPDATE_TRADING_MODAL' payload: Partial @@ -154,7 +144,7 @@ export type TradingPanelAction = | { type: 'UPDATE_POOL_FALLBACK_DATA'; payload: PoolFallbackData } export interface TradingPanelContextConfig { - actions: Partial + actions: Partial & Pick initialState?: Partial } @@ -168,4 +158,5 @@ export type TradingPanelActionsState = TradingPanelSetters & { onTokenSelector: CallbackConfig['onTokenSelector'] | undefined onLog: CallbackConfig['onLog'] | undefined onSimulateTransaction: CallbackConfig['onSimulateTransaction'] | undefined + getSwapData: CallbackConfig['getSwapData'] } diff --git a/packages/trading-widget/src/core-kit/types/trading-panel.types.ts b/packages/trading-widget/src/core-kit/types/trading-panel.types.ts index 22ead5f..32635b2 100644 --- a/packages/trading-widget/src/core-kit/types/trading-panel.types.ts +++ b/packages/trading-widget/src/core-kit/types/trading-panel.types.ts @@ -45,8 +45,6 @@ export type TransactionAction = | 'approve' | 'oraclesUpdate' -export type DepositMethodName = 'deposit' | 'depositWithCustomCooldown' - export type WithdrawMethodName = 'withdraw' | 'withdrawSUSD' | 'withdrawSafe' export type SwapEntity = 'token' | 'pool' diff --git a/packages/trading-widget/src/core-kit/types/trading.types.ts b/packages/trading-widget/src/core-kit/types/trading.types.ts index 1aba332..bb7525e 100644 --- a/packages/trading-widget/src/core-kit/types/trading.types.ts +++ b/packages/trading-widget/src/core-kit/types/trading.types.ts @@ -1,11 +1,6 @@ import type { BigNumber } from 'bignumber.js' -import type { - BuyingWithEasyswapperArgs, - BuyingWithNativeAssetArgs, - BuyingWithPoolLogicArgs, - DefaultSellingParams, -} from 'core-kit/models' +import type { DefaultSellingParams } from 'core-kit/models' import type { Address, ChainId } from 'core-kit/types/web3.types' export interface TradingParams { @@ -27,10 +22,35 @@ export type ChainNativeTokenMap = { } } -export type PoolDepositMethodName = 'deposit' | 'depositWithCustomCooldown' +export type TxArgs = DefaultSellingParams -export type TxArgs = - | BuyingWithEasyswapperArgs - | BuyingWithNativeAssetArgs - | DefaultSellingParams - | BuyingWithPoolLogicArgs +export interface SwapDataResponse { + destinationAmount: string + txData: string + routerKey: 'ONE_INCH' | 'ZERO_X' | 'PARASWAP' | 'ONE_INCH_V5' +} + +export interface SwapDataRequest { + chainId: number + sourceAddress: Address + destinationAddress: Address + walletAddress: Address + fromAddress: Address + amount: string + slippage: string +} + +export interface VaultDepositParams { + depositMethod: DepositMethodName + vaultDepositTokenAddress: Address +} + +export type DepositMethodName = + | 'deposit' + | 'depositWithCustomCooldown' + | 'nativeDeposit' + | 'nativeDepositWithCustomCooldown' + | 'zapNativeDeposit' + | 'zapNativeDepositWithCustomCooldown' + | 'zapDeposit' + | 'zapDepositWithCustomCooldown' diff --git a/packages/trading-widget/src/core-kit/utils/transaction.ts b/packages/trading-widget/src/core-kit/utils/transaction.ts index 9af91d1..0e80bed 100644 --- a/packages/trading-widget/src/core-kit/utils/transaction.ts +++ b/packages/trading-widget/src/core-kit/utils/transaction.ts @@ -1,5 +1,8 @@ import BigNumber from 'bignumber.js' +import type { Address } from 'viem' +import { stringToHex } from 'viem' + import type { TxArgs } from 'core-kit/types/trading.types' import { shiftBy } from './number' @@ -57,3 +60,33 @@ export const getSlippageToleranceForWithdrawSafe = ( return slippageToUse.multipliedBy(100).toFixed(0) } + +export const buildZapDepositTransactionArguments = ({ + vaultAddress, + swapData, + sendTokenAddress, + sendTokenAmount, + vaultDepositTokenAddress, + minVaultTokensReceivedAmount, + routerKey = 'ONE_INCH', + swapDestinationAmount, + swapSlippage, +}: { + vaultAddress: Address + swapData: string + sendTokenAddress: Address + sendTokenAmount: string + vaultDepositTokenAddress: Address + minVaultTokensReceivedAmount: string + routerKey: string | undefined + swapDestinationAmount: string + swapSlippage: number +}) => { + const minDestinationAmount = new BigNumber(swapDestinationAmount) + .multipliedBy(1 - swapSlippage / 100) + .toFixed(0) + const aggregatorData = [stringToHex(routerKey, { size: 32 }), swapData] + const srcData = [sendTokenAddress, sendTokenAmount, aggregatorData] + const destData = [vaultDepositTokenAddress, minDestinationAmount] + return [vaultAddress, [srcData, destData], minVaultTokensReceivedAmount] +} diff --git a/packages/trading-widget/src/examples/simple-example.tsx b/packages/trading-widget/src/examples/simple-example.tsx index 5c6f8bb..d3ffd21 100644 --- a/packages/trading-widget/src/examples/simple-example.tsx +++ b/packages/trading-widget/src/examples/simple-example.tsx @@ -20,7 +20,6 @@ const SYNTHETIX_BASE: PoolConfig = { withdrawParams: { customTokens: [], }, - usePoolLogicDeposit: true, } const SYNTHETIX_ARBITRUM: PoolConfig = { @@ -33,7 +32,6 @@ const SYNTHETIX_ARBITRUM: PoolConfig = { withdrawParams: { customTokens: [], }, - usePoolLogicDeposit: true, } const SIMPLE_INITIAL_STATE: TradingPanelContextConfig['initialState'] = { @@ -83,6 +81,7 @@ const SIMPLE_ACTIONS: TradingPanelContextConfig['actions'] = { onSetTradingType: args, }) }, + getSwapData: async () => Promise.resolve(null), } const SIMPLE_WIDGET_CONFIG: ProvidersProps = { diff --git a/packages/trading-widget/src/index.ts b/packages/trading-widget/src/index.ts index e97cd2b..6af1aa6 100644 --- a/packages/trading-widget/src/index.ts +++ b/packages/trading-widget/src/index.ts @@ -48,8 +48,6 @@ export { EASY_SWAPPER_ADDRESS_ARBITRUM, DHEDGE_SYNTHETIX_V3_VAULT_ADDRESSES, DHEDGE_SYNTHETIX_V3_ASSETS_MAP, - DEPOSIT_QUOTE_MULTIPLIER_CUSTOM, - DEPOSIT_QUOTE_MULTIPLIER_DEFAULT, DEFAULT_DEPOSIT_SLIPPAGE, DEFAULT_WITHDRAW_SLIPPAGE, DEFAULT_WITHDRAW_SLIPPAGE_SCALE, @@ -58,9 +56,7 @@ export { DEFAULT_DEPOSIT_SLIPPAGE_SCALE, DEFAULT_DEPOSIT_METHOD, DEFAULT_PROMISE_TIMEOUT_MS, - DEFAULT_DEPOSIT_LOCKTIME_MAP, DEFAULT_LOCK_TIME, - CUSTOM_LOCK_TIME, DAI_POLYGON, DAI_OPTIMISM, BRIDGED_USDC_POLYGON, @@ -107,13 +103,7 @@ export { TRADING_LOG_EVENT_PARAM, TRADING_PANEL_LOG_EVENT, } from './core-kit/const' -export { - BuyingWithPoolLogicArgs, - BuyingWithEasyswapperArgs, - BuyingWithNativeAssetArgs, - DefaultSellingParams, - EstimationError, -} from './core-kit/models' +export { DefaultSellingParams, EstimationError } from './core-kit/models' export type { SendEstimationResult, ChainId, @@ -147,7 +137,6 @@ export type { PublicClient, WalletClient, DepositMethodName, - PoolDepositMethodName, WithdrawMethodName, OracleAdapter, PendingTransaction, @@ -173,6 +162,8 @@ export type { UseReadContractsParameters, UseWriteContractParameters, WaitForTransactionReceiptReturnType, + SwapDataRequest, + SwapDataResponse, } from './core-kit/types' export { formatNumberToLimitedDecimals, @@ -216,10 +207,6 @@ export { encodeFunctionData, } from './core-kit/utils' -export { - useGeneralTradingPanelHandlers, - useOnTradingTypeChange, -} from './core-kit/hooks/component' export { usePoolDynamicContractData, useInvalidatePoolContractData, @@ -252,9 +239,6 @@ export { useReceiveTokenInput, useSendTokenInput, useTradingPanelApprovingStatus, - useTradingPanelDepositMethod, - useTradingPanelEntryFee, - useTradingPanelLockTime, useTradingPanelLogger, useTradingPanelMeta, useTradingPanelModal, @@ -265,7 +249,6 @@ export { useTradingPanelPoolConfigs, useTradingPanelSettings, useTradingPanelTransactions, - useUpdateEntryFee, useTradingPanelType, useUpdatePoolFallbackData, useUpdateReceiveTokenInput, @@ -280,43 +263,18 @@ export { useAssetPrice, useDepositProjectedEarnings, useSynthetixV3OraclesUpdate, - useHandlePoolSwapInfo, useHandleTrade, useIsTradingEnabled, useRawAssetPrice, useTradingResultHandling, useMaxSlippagePlaceholder, useMinReceiveText, - useTradingPriceDiff, useTradingSettleHandler, - useIsEasySwapperTrading, } from './core-kit/hooks/trading' export { - useDeposit, - useDepositAllowance, - useDepositQuote, - useDepositSlippage, - useDepositMethodHandler, - useHandlePoolDepositData, - usePoolDepositAssetAddress, - usePoolDepositTokens, - useShouldBeWhitelisted, - useDepositTradingParams, -} from './core-kit/hooks/trading/deposit' -export { - useWithdraw, - useWithdrawAllowance, - useWithdrawQuote, - useWithdrawSlippage, - useIsMultiAssetWithdraw, - useWithdrawTypeHandler, - useWithdrawTradingParams, -} from './core-kit/hooks/trading/withdraw' -export { - useApprove, - useCanSpend, - useTokenAllowanceHandler, -} from './core-kit/hooks/trading/allowance' + useVaultDepositTokens, + useDepositLockTime, +} from './core-kit/hooks/trading/deposit-v2' export { useIsInsufficientBalance, useUserTokenBalance, diff --git a/packages/trading-widget/src/tests/mocks.ts b/packages/trading-widget/src/tests/mocks.ts index bcc8d00..c7cfea0 100644 --- a/packages/trading-widget/src/tests/mocks.ts +++ b/packages/trading-widget/src/tests/mocks.ts @@ -11,7 +11,6 @@ export const ETHY_OPTIMISM_POOL_MOCK: PoolConfig = { symbol: 'ETHy', address: '0xb2cfb909e8657c0ec44d3dd898c1053b87804755', depositParams: { - method: 'depositWithCustomCooldown', customTokens: [SUSD_OPTIMISM], }, withdrawParams: { @@ -30,6 +29,9 @@ export const POOL_CONFIG_MAP_MOCK: Record = { [ETHY_OPTIMISM_POOL_MOCK.address]: ETHY_OPTIMISM_POOL_MOCK, } -export const CALLBACK_CONFIG_MOCK: Partial = {} +export const CALLBACK_CONFIG_MOCK: Partial & + Pick = { + getSwapData: async () => Promise.resolve(null), +} export const TEST_ADDRESS: Address = '0xTest' diff --git a/packages/trading-widget/src/trading-widget/components/deposit/button/trade-button/trade-button.hooks.ts b/packages/trading-widget/src/trading-widget/components/deposit/button/trade-button/trade-button.hooks.ts index 72b88e4..26fd3fd 100644 --- a/packages/trading-widget/src/trading-widget/components/deposit/button/trade-button/trade-button.hooks.ts +++ b/packages/trading-widget/src/trading-widget/components/deposit/button/trade-button/trade-button.hooks.ts @@ -1,5 +1,5 @@ import { useHandleTrade } from 'core-kit/hooks/trading' -import { useDeposit } from 'core-kit/hooks/trading/deposit' +import { useDeposit } from 'core-kit/hooks/trading/deposit-v2' import { useConfigContextActions, diff --git a/packages/trading-widget/src/trading-widget/components/deposit/button/valid-deposit-button/valid-deposit-button.hooks.ts b/packages/trading-widget/src/trading-widget/components/deposit/button/valid-deposit-button/valid-deposit-button.hooks.ts index 4dfbc25..2b58b6c 100644 --- a/packages/trading-widget/src/trading-widget/components/deposit/button/valid-deposit-button/valid-deposit-button.hooks.ts +++ b/packages/trading-widget/src/trading-widget/components/deposit/button/valid-deposit-button/valid-deposit-button.hooks.ts @@ -9,9 +9,8 @@ import { import { useSynthetixV3OraclesUpdate } from 'core-kit/hooks/trading' import { useDepositAllowance, - useShouldBeWhitelisted, -} from 'core-kit/hooks/trading/deposit' - + useIsVaultDepositLocked, +} from 'core-kit/hooks/trading/deposit-v2' import { useHighSlippageCheck, useUserVaultBalance } from 'trading-widget/hooks' export const useValidDepositButton = () => { @@ -19,7 +18,8 @@ export const useValidDepositButton = () => { const [receiveToken] = useReceiveTokenInput() const [sendToken] = useSendTokenInput() - const { shouldBeWhitelisted, isAccountWhitelisted } = useShouldBeWhitelisted() + const { isVaultDepositLocked, isAccountWhitelisted } = + useIsVaultDepositLocked() const poolTokenPrice = usePoolTokenPrice({ address, chainId }) const { minDepositUSD } = usePoolManagerLogicData(address, chainId) const poolBalance = useUserVaultBalance(address) @@ -43,7 +43,7 @@ export const useValidDepositButton = () => { return { requiresMinDeposit, - requiresWhitelist: shouldBeWhitelisted && !isAccountWhitelisted, + requiresWhitelist: isVaultDepositLocked && !isAccountWhitelisted, requiresApprove: !canSpend, requiresUpdate: needToBeUpdated && !!sendToken.value, requiresHighSlippageConfirm, diff --git a/packages/trading-widget/src/trading-widget/components/deposit/input-group/input-group.hooks.ts b/packages/trading-widget/src/trading-widget/components/deposit/input-group/input-group.hooks.ts index 01e9e53..3607777 100644 --- a/packages/trading-widget/src/trading-widget/components/deposit/input-group/input-group.hooks.ts +++ b/packages/trading-widget/src/trading-widget/components/deposit/input-group/input-group.hooks.ts @@ -7,7 +7,8 @@ import { useTradingPanelPoolConfig, useTradingPanelSettings, } from 'core-kit/hooks/state' -import { useAssetPrice, useTradingPriceDiff } from 'core-kit/hooks/trading' +import { useAssetPrice } from 'core-kit/hooks/trading' +import { useDepositPriceDiff } from 'core-kit/hooks/trading/deposit-v2' import { useUserTokenBalance } from 'core-kit/hooks/user' const useSendToken = () => { @@ -43,11 +44,7 @@ export const useDepositInputGroup = () => { const sendToken = useSendToken() const receiveToken = useReceiveToken() const log = useTradingPanelLogger() - const tradingPriceDiff = useTradingPriceDiff({ - sendAssetAddress: sendToken.address, - sendAssetValue: sendToken.value, - receiveAssetValue: receiveToken.value, - }) + const tradingPriceDiff = useDepositPriceDiff() const [{ minSlippage }] = useTradingPanelSettings() const handleInputChange = (value: string) => { diff --git a/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.hooks.ts b/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.hooks.ts index ddd3230..873544c 100644 --- a/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.hooks.ts +++ b/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.hooks.ts @@ -1,62 +1,47 @@ import BigNumber from 'bignumber.js' -import { CUSTOM_LOCK_TIME } from 'core-kit/const' -import { - usePoolFees, - usePoolManagerLogicData, - usePoolTokenPrice, -} from 'core-kit/hooks/pool' +import { DEFAULT_PRECISION } from 'core-kit/const' +import { usePoolFees, usePoolManagerLogicData } from 'core-kit/hooks/pool' import { useReceiveTokenInput, useSendTokenInput, useTradingPanelApprovingStatus, - useTradingPanelLockTime, useTradingPanelPoolConfig, useTradingPanelSettings, } from 'core-kit/hooks/state' +import { useDepositProjectedEarnings } from 'core-kit/hooks/trading' import { - useAssetPrice, - useDepositProjectedEarnings, -} from 'core-kit/hooks/trading' -import { formatToUsd } from 'core-kit/utils' + useDepositLockTime, + useIsDepositWithSwapTransaction, + useMinVaultTokensReceivedAmount, +} from 'core-kit/hooks/trading/deposit-v2' +import { formatNumberToLimitedDecimals, formatToUsd } from 'core-kit/utils' import { useGetSlippagePlaceholder, useGetThemeTypeBySlippage, } from 'trading-widget/hooks' -import { useConfigContextParams } from 'trading-widget/providers/config-provider' import { useTranslationContext } from 'trading-widget/providers/translation-provider' import { THEME_TYPE } from 'trading-widget/types' export const useDepositTransactionDisclosure = () => { const t = useTranslationContext() - const { chainCustomLockTimeMap } = useConfigContextParams() const [approvingStatus] = useTradingPanelApprovingStatus() const [{ slippage, minSlippage, isInfiniteAllowance, isMaxSlippageLoading }] = useTradingPanelSettings() const isAutoSlippage = slippage === 'auto' + const minReceivedVaultTokensAmount = useMinVaultTokensReceivedAmount() const [receiveToken] = useReceiveTokenInput() const [sendToken] = useSendTokenInput() const { address, chainId } = useTradingPanelPoolConfig() - const sendTokenPrice = - useAssetPrice({ - address: sendToken.address, - chainId, - disabled: isAutoSlippage, - }) ?? '' - const receiveAssetPrice = - usePoolTokenPrice({ - address: receiveToken.address, - chainId, - disabled: isAutoSlippage, - }) ?? '' - const { entryFee, hasPoolEntryFee } = usePoolFees({ address, chainId }) + const { entryFee } = usePoolFees({ address, chainId }) const { minDepositUSD } = usePoolManagerLogicData(address, chainId) const projectedEarnings = useDepositProjectedEarnings() - const lockTime = useTradingPanelLockTime() + const lockTime = useDepositLockTime() + const showMinimumReceivedAmount = useIsDepositWithSwapTransaction() const minDeposit = minDepositUSD ? formatToUsd({ value: minDepositUSD, minimumFractionDigits: 0 }) @@ -74,32 +59,17 @@ export const useDepositTransactionDisclosure = () => { themeType === THEME_TYPE.DEFAULT ? t.depositSlippageWarning : t.highSlippageWarning - const customLockTime = chainCustomLockTimeMap[chainId] ?? CUSTOM_LOCK_TIME - - const getMinReceiveText = () => { - if (isAutoSlippage) { - return `${new BigNumber(receiveToken.value || 0).toFixed( - 4, - )} ${receiveToken.symbol.toUpperCase()}` - } - const expectedReceiveTokenAmount = new BigNumber(sendToken.value || '0') - .multipliedBy(sendTokenPrice) - .dividedBy(receiveAssetPrice) - const receiveTokenAmountAfterSlippage = - expectedReceiveTokenAmount.isFinite() - ? expectedReceiveTokenAmount.times(1 - slippage / 100).toFixed(4) - : '0' - - return `${receiveTokenAmountAfterSlippage} ${receiveToken.symbol.toUpperCase()}` - } const tokenAllowance = isInfiniteAllowance ? t.infinite : `${new BigNumber(sendToken.value || '0').toFixed(4)} ${sendToken.symbol}` - const entryFeeTooltipText = hasPoolEntryFee - ? t.entryFeeExplanation - : t.easySwapperEntryFee.replace('{time}', customLockTime) + const minReceivedVaultTokens = formatNumberToLimitedDecimals( + new BigNumber(minReceivedVaultTokensAmount) + .shiftedBy(-DEFAULT_PRECISION) + .toFixed(), + 4, + ) return { projectedEarnings, @@ -107,13 +77,14 @@ export const useDepositTransactionDisclosure = () => { slippageTooltipText, isMaxSlippageLoading, slippagePlaceholder, - minReceive: getMinReceiveText(), + minReceive: `${minReceivedVaultTokens} ${receiveToken.symbol.toUpperCase()}`, allowanceRequired: !approvingStatus, tokenAllowance, sendTokenSymbol: sendToken.symbol, entryFee, - entryFeeTooltipText, + entryFeeTooltipText: t.entryFeeExplanation, minDeposit, lockTime, + showMinimumReceivedAmount, } } diff --git a/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.tsx b/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.tsx index 91cb82a..9656c03 100644 --- a/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.tsx +++ b/packages/trading-widget/src/trading-widget/components/deposit/meta/transaction-disclosure/transaction-disclosure.tsx @@ -30,6 +30,7 @@ export const DepositTransactionOverviewDisclosure = () => { entryFeeTooltipText, minDeposit, lockTime, + showMinimumReceivedAmount, } = useDepositTransactionDisclosure() const staticItems: TransactionDisclosureItemProps[] = showEarnings @@ -73,12 +74,15 @@ export const DepositTransactionOverviewDisclosure = () => { ), }, - { + ] + + if (showMinimumReceivedAmount) { + items.push({ tooltipText: t.minReceiveAmount, label: t.minReceived, value: minReceive, - }, - ] + }) + } if (allowanceRequired) { items.push({ diff --git a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-fee-switch/deposit-fee-switch.hooks.ts b/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-fee-switch/deposit-fee-switch.hooks.ts deleted file mode 100644 index 46dd5e2..0000000 --- a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-fee-switch/deposit-fee-switch.hooks.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { TRADING_PANEL_LOG_EVENT } from 'core-kit/const' -import { useTradingPanelLogger } from 'core-kit/hooks/state' -import { useDepositMethodHandler } from 'core-kit/hooks/trading/deposit' - -export const useDepositFeeSwitch = () => { - const [depositMethod, setDepositMethod, hasOptions] = - useDepositMethodHandler() - const log = useTradingPanelLogger() - - const handleChange = (enabled: boolean) => { - setDepositMethod(enabled ? 'depositWithCustomCooldown' : 'deposit') - log?.(TRADING_PANEL_LOG_EVENT.DEPOSIT_METHOD_CHANGE) - } - - return { - defaultEnabled: depositMethod === 'depositWithCustomCooldown', - disabled: !hasOptions, - onChange: handleChange, - } -} diff --git a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-fee-switch/deposit-fee-switch.tsx b/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-fee-switch/deposit-fee-switch.tsx deleted file mode 100644 index 409a253..0000000 --- a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-fee-switch/deposit-fee-switch.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Switch } from 'trading-widget/components/common' - -import { useTranslationContext } from 'trading-widget/providers/translation-provider' - -import { useDepositFeeSwitch } from './deposit-fee-switch.hooks' -import { useDepositSettings } from '../deposit-settings/deposit-settings.hooks' - -export const DepositFeeSwitch = () => { - const t = useTranslationContext() - const { defaultEnabled, disabled, onChange } = useDepositFeeSwitch() - const { customLockTime } = useDepositSettings() - - return ( - - ) -} diff --git a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-settings/deposit-settings.hooks.ts b/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-settings/deposit-settings.hooks.ts deleted file mode 100644 index 5223496..0000000 --- a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-settings/deposit-settings.hooks.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CUSTOM_LOCK_TIME } from 'core-kit/const' -import { usePoolFees } from 'core-kit/hooks/pool' -import { useTradingPanelPoolConfig } from 'core-kit/hooks/state' - -import { useIsEasySwapperTrading } from 'core-kit/hooks/trading/use-is-easy-swapper-trading' -import { useConfigContextParams } from 'trading-widget/providers/config-provider' - -export const useDepositSettings = () => { - const { chainCustomLockTimeMap, defaultLockTime } = useConfigContextParams() - const { address, chainId } = useTradingPanelPoolConfig() - const { hasPoolEntryFee } = usePoolFees({ address, chainId }) - const isEasySwapperTrading = useIsEasySwapperTrading() - const customLockTime = chainCustomLockTimeMap[chainId] ?? CUSTOM_LOCK_TIME - - return { - customLockTime, - defaultLockTime, - hasPoolEntryFee, - isEasySwapperTrading, - } -} diff --git a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-settings/deposit-settings.tsx b/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-settings/deposit-settings.tsx index 5845930..4faac63 100644 --- a/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-settings/deposit-settings.tsx +++ b/packages/trading-widget/src/trading-widget/components/deposit/settings/deposit-settings/deposit-settings.tsx @@ -7,17 +7,8 @@ import { } from 'trading-widget/components/widget/widget-settings' import { useTranslationContext } from 'trading-widget/providers/translation-provider' -import { useDepositSettings } from './deposit-settings.hooks' -import { DepositFeeSwitch } from '../deposit-fee-switch/deposit-fee-switch' - export const DepositSettings: FC = () => { const t = useTranslationContext() - const { - customLockTime, - defaultLockTime, - hasPoolEntryFee, - isEasySwapperTrading, - } = useDepositSettings() return ( <> @@ -27,16 +18,6 @@ export const DepositSettings: FC = () => { > - {isEasySwapperTrading && !hasPoolEntryFee && ( - - - - )} { - const poolConfig = useTradingPanelPoolConfig() - useDepositQuote(poolConfig) + useDepositQuote() + useDepositSlippage() } diff --git a/packages/trading-widget/src/trading-widget/components/widget/widget-overlay/token-select-overlay/token-select-overlay.hooks.ts b/packages/trading-widget/src/trading-widget/components/widget/widget-overlay/token-select-overlay/token-select-overlay.hooks.ts index 872c4c4..968e863 100644 --- a/packages/trading-widget/src/trading-widget/components/widget/widget-overlay/token-select-overlay/token-select-overlay.hooks.ts +++ b/packages/trading-widget/src/trading-widget/components/widget/widget-overlay/token-select-overlay/token-select-overlay.hooks.ts @@ -7,7 +7,7 @@ import { useTradingPanelSettings, useTradingPanelType, } from 'core-kit/hooks/state' -import { usePoolDepositTokens } from 'core-kit/hooks/trading/deposit' +import { useVaultDepositTokens } from 'core-kit/hooks/trading/deposit-v2' import { useIsPoolManagerAccount } from 'core-kit/hooks/user' import type { TradingPanelActionsState, TradingToken } from 'core-kit/types' import { useOverlayHandlers } from 'trading-widget/providers/overlay-provider' @@ -27,7 +27,7 @@ const useTokens = (): { const [receiveToken, updateReceiveToken] = useReceiveTokenInput() const poolConfig = useTradingPanelPoolConfig() - const depositTokens = usePoolDepositTokens() + const depositTokens = useVaultDepositTokens() const withdrawTokens = poolConfig.withdrawParams.customTokens return useMemo( diff --git a/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.defaults.ts b/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.defaults.ts index fbd8ec1..ff9807e 100644 --- a/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.defaults.ts +++ b/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.defaults.ts @@ -2,8 +2,9 @@ import { useCallback } from 'react' import { injected } from 'wagmi/connectors' import { - CUSTOM_LOCK_TIME, DEFAULT_LOCK_TIME, + DEFAULT_NO_SWAP_MIN_DEPOSIT_AMOUNT_GAP, + DEFAULT_SWAP_TRANSACTION_SLIPPAGE, DEFAULT_WITHDRAW_SLIPPAGE_SCALE, arbitrum, base, @@ -24,12 +25,8 @@ export const DEFAULT_CONFIG_PARAMS: ConfigProviderParams = { depositQuoteDiffErrorThreshold: 3, defaultWithdrawSlippageScale: DEFAULT_WITHDRAW_SLIPPAGE_SCALE, defaultLockTime: DEFAULT_LOCK_TIME, - chainCustomLockTimeMap: { - [arbitrum.id]: CUSTOM_LOCK_TIME, - [optimism.id]: CUSTOM_LOCK_TIME, - [polygon.id]: CUSTOM_LOCK_TIME, - [base.id]: CUSTOM_LOCK_TIME, - }, + defaultNoSwapMinDepositAmountGap: DEFAULT_NO_SWAP_MIN_DEPOSIT_AMOUNT_GAP, + defaultSwapTransactionSlippage: DEFAULT_SWAP_TRANSACTION_SLIPPAGE, stablePrecision: 3, defaultPrecision: 6, stakingChainId: optimism.id, diff --git a/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.types.ts b/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.types.ts index 2c94702..4c2f94e 100644 --- a/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.types.ts +++ b/packages/trading-widget/src/trading-widget/providers/config-provider/config-provider.types.ts @@ -6,8 +6,9 @@ export interface ConfigProviderParams { depositQuoteDiffWarningThreshold: number depositQuoteDiffErrorThreshold: number defaultWithdrawSlippageScale: number[] + defaultSwapTransactionSlippage: number + defaultNoSwapMinDepositAmountGap: number defaultLockTime: string - chainCustomLockTimeMap: Record stablePrecision: number defaultPrecision: number stakingChainId: ChainId diff --git a/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.defaults.ts b/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.defaults.ts index e41ee46..43c3302 100644 --- a/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.defaults.ts +++ b/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.defaults.ts @@ -2,7 +2,7 @@ import type { TranslationMap } from './translation-provider.types' export const DEFAULT_TRANSLATION_DATA: TranslationMap = { depositSlippageWarning: - 'Includes entry fee. We recommend 2-3%, but usually it will be < 1%. Slippage may be amplified by the leverage. See the docs for more info.', + 'Excludes entry fee. Slippage may be amplified by the leverage. See the docs for more info.', withdrawSlippageWarning: 'Slippage only applies to single asset withdrawals and withdrawals from vaults with debt positions in Aave.', minSlippageWarning: @@ -28,8 +28,6 @@ export const DEFAULT_TRANSLATION_DATA: TranslationMap = { exitFee: 'Exit fee', entryFeeExplanation: "Entry fee is charged in vault's tokens.", exitFeeExplanation: "Exit fee is charged in vault's tokens.", - easySwapperEntryFee: - 'Entry fee is charged when a cooldown of {time} is selected. Bypass entry fee at trading settings.', amountToBeApproved: 'Amount of {symbol} tokens to be approved. Can be customized in settings.', minDepositUsd: 'Minimum deposit in USD.', @@ -37,8 +35,6 @@ export const DEFAULT_TRANSLATION_DATA: TranslationMap = { tokensLockTime: 'Purchased tokens will have a {lockTime} lock.', slippageTolerance: 'Slippage tolerance', reduceLockupTime: 'Reduce lockup time', - entryFeeSwitchWarning: - 'Your position will be locked for up to {customLockTime} instead of the normal {defaultLockTime}.', toggleTokenApprovalAmount: 'Toggle between exact and infinite token approval.', auto: 'Auto', diff --git a/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.types.ts b/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.types.ts index 8129c2f..12676f5 100644 --- a/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.types.ts +++ b/packages/trading-widget/src/trading-widget/providers/translation-provider/translation-provider.types.ts @@ -20,14 +20,12 @@ export type TranslationMap = { entryFeeExplanation: string exitFee: string exitFeeExplanation: string - easySwapperEntryFee: string amountToBeApproved: string minDepositUsd: string minDeposit: string tokensLockTime: string slippageTolerance: string reduceLockupTime: string - entryFeeSwitchWarning: string toggleTokenApprovalAmount: string auto: string autoSlippageDescription: string