From 92f114cdff412d7772c3a7c4f2911ec88824c466 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Wed, 17 Sep 2025 15:28:55 +0300 Subject: [PATCH 01/34] fix seetings btn and slippage input --- .../common/components/Modals/SettingsModalContent.tsx | 7 ++++++- .../features/swap-new/useCases/AssetSwap/TopBarActions.tsx | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 9044666c02..b76ca91770 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -197,9 +197,14 @@ const SlippageInput = ({ selectedSlippage, setSelectedSlippage, inputRef }) => { setSelectedSlippage(e.target.value)} + onChange={e => { + const raw = e.target.value; + const clean = raw.replace(/[^0-9.]/g, ''); + setSelectedSlippage(clean); + }} style={{ border: 'none', outline: 'none', diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx index c861161af2..fdf58aac50 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx @@ -1,4 +1,4 @@ -import { Stack, useTheme } from '@mui/material'; +import { Box, Stack, useTheme } from '@mui/material'; import { useStrings } from '../../common/hooks/useStrings'; import Tabs from '../../../../../components/common/tabs/Tabs'; import { Icons, IconWrapper } from '../../../../components'; @@ -45,7 +45,9 @@ export const TopBarActions = () => { - + + + ); From e01aa40bc529c084a397ce06110ea46d3f962466 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Wed, 17 Sep 2025 15:55:11 +0300 Subject: [PATCH 02/34] force to one decimal --- .../components/Modals/SettingsModalContent.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index b76ca91770..59702a383c 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -201,8 +201,17 @@ const SlippageInput = ({ selectedSlippage, setSelectedSlippage, inputRef }) => { placeholder="0" value={selectedSlippage} onChange={e => { - const raw = e.target.value; - const clean = raw.replace(/[^0-9.]/g, ''); + let raw = e.target.value; + let clean = raw.replace(/[^0-9.]/g, ''); + const parts = clean.split('.'); + if (parts.length > 2) { + clean = parts[0] + '.' + parts[1]; + } + + if (parts[1] && parts[1].length > 1) { + clean = parts[0] + '.' + parts[1].slice(0, 1); + } + setSelectedSlippage(clean); }} style={{ From 51c268406fe883e3990a59c1241e9c7c25afd0e8 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Wed, 17 Sep 2025 15:55:19 +0300 Subject: [PATCH 03/34] force one decimal --- .../swap-new/common/components/Modals/SettingsModalContent.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 59702a383c..c55079e037 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -207,11 +207,9 @@ const SlippageInput = ({ selectedSlippage, setSelectedSlippage, inputRef }) => { if (parts.length > 2) { clean = parts[0] + '.' + parts[1]; } - if (parts[1] && parts[1].length > 1) { clean = parts[0] + '.' + parts[1].slice(0, 1); } - setSelectedSlippage(clean); }} style={{ From a5ab5b294e3796f64789657ceb61e5398eb83b3a Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Thu, 18 Sep 2025 13:29:15 +0300 Subject: [PATCH 04/34] fixes --- .../portfolio/common/components/TokenInfoIcon.tsx | 4 ++-- .../swap-new/common/components/AssetInfoInRow.tsx | 9 +++++++++ .../common/components/Modals/SelectAssetFrom.tsx | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/portfolio/common/components/TokenInfoIcon.tsx b/packages/yoroi-extension/app/UI/features/portfolio/common/components/TokenInfoIcon.tsx index ed13dd74bf..5c51875c56 100644 --- a/packages/yoroi-extension/app/UI/features/portfolio/common/components/TokenInfoIcon.tsx +++ b/packages/yoroi-extension/app/UI/features/portfolio/common/components/TokenInfoIcon.tsx @@ -33,10 +33,10 @@ export const TokenInfoIcon = ({ info, size = 'lg', imageStyle }: TokenInfoIconPr height: 64, }); - if (!info?.id || uri === undefined) { + if (!info?.id || uri === undefined || fallback) { return ( - + ); } diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx index 62553c9b6c..4b2d14902c 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx @@ -8,6 +8,7 @@ import { useModal } from '../../../../components/modals/ModalContext'; import TokenInfoModal from './Modals/TokenInfoModal'; import { AssetDirectionType } from '../types'; import { ASSET_DIRECTION_IN } from '../constants'; +import { SelectAssetTo } from './Modals/SelectAssetTo'; interface AssetInfoInRowProps { token: any; @@ -59,6 +60,14 @@ export const AssetInfoInRow = React.memo( content: , height: '624px', width: '612px', + handleBack: () => { + openModal({ + title: `SWAP TO`, + content: , + height: '624px', + width: '612px', + }); + }, }); }; diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SelectAssetFrom.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SelectAssetFrom.tsx index 07b16d9453..63246a71fd 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SelectAssetFrom.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SelectAssetFrom.tsx @@ -108,7 +108,7 @@ export const SelectAssetFrom = () => { primaryTokenInfo={primaryTokenInfo} token={{ decimals: asset.info.numberOfDecimals, - name: asset.info.ticker ?? asset.info.name, + name: asset.info.name ?? asset.info.ticker, id: asset.info.id, formatedAmount: asset.formatedAmount, quantity: asset.quantity, From 49b4ff11f764b7fa58baea584380e9e571766c0a Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Thu, 18 Sep 2025 18:34:32 +0300 Subject: [PATCH 05/34] update dispatch --- .../common/components/ErrorMessage.tsx | 4 ++-- .../swap-new/module/SwapContextProvider.tsx | 24 +++++++++---------- .../useCases/AssetSwap/EstimateSummary.tsx | 4 ++-- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/ErrorMessage.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/ErrorMessage.tsx index 6178ac1e26..3ec9be21ec 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/ErrorMessage.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/ErrorMessage.tsx @@ -2,10 +2,10 @@ import { useSwapRevamp } from '../../module/SwapContextProvider'; import { Stack, Typography } from '@mui/material'; export const ErrorMessage = () => { - const { swapForm } = useSwapRevamp(); + const { swapForm, isLimitOptionsLoading } = useSwapRevamp(); const message = swapForm.tokenOutInput.error; - if (!message) { + if (!message || isLimitOptionsLoading) { return null; } return ( diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index c99290c298..262d410bda 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -95,7 +95,7 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => action({ type: 'SlippageInputChanged', value: swapManager.settings.slippage }); }, [swapManager.settings.slippage]); - const { data: limitOptions } = useQuery( + const { data: limitOptions, isLoading: isLimitOptionsLoading } = useQuery( [ 'useSwapLimitOptions', 'mainet', @@ -131,18 +131,10 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => useEffect(() => { const value = limitOptions?.defaultProtocol; - if (value !== undefined && state.selectedProtocol.isTouched === false && state.selectedProtocol.value !== value) { - action({ type: 'ProtocolChanged', value }); - } else { - const current = limitOptions?.options.find(p => p.protocol === state.selectedProtocol.value); - if (state.selectedProtocol.isTouched === true && current === undefined) { - action({ type: 'ProtocolChanged', value }); - } - } + action({ type: 'ProtocolChanged', value }); const wantedPrice = limitOptions?.wantedPrice; - if (wantedPrice !== undefined && wantedPrice > 0 && state.selectedProtocol.value === limitOptions?.defaultProtocol) - action({ type: 'WantedPriceInputChanged', value: String(wantedPrice) }); + action({ type: 'WantedPriceInputChanged', value: String(wantedPrice) }); }, [ limitOptions?.defaultProtocol, limitOptions?.options, @@ -176,15 +168,18 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => ) return; setIsEstimateOrderLoading(true); + swapManager.api .estimate({ slippage: state.slippageInput.value, tokenIn: state.tokenInInput.tokenId, tokenOut: state.tokenOutInput.tokenId, - ...(state.lastInputTouched === ASSET_DIRECTION_IN + ...(state.lastInputTouched === 'in' ? { amountIn: Number(state.tokenInInput.value), - ...(state.orderType === 'limit' && { wantedPrice: Number(state.wantedPrice) }), + ...(state.orderType === 'limit' && { + wantedPrice: Number(state.wantedPrice), + }), } : { amountOut: Number(state.tokenOutInput.value), @@ -264,6 +259,7 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => explorer, createOrder: create, isCreateOrderLoading, + isLimitOptionsLoading, isEstimateOrderLoading, limitOptions, swapManager, @@ -578,6 +574,7 @@ export type SwapContext = SwapState & { loadingTokenList: boolean; isCreateOrderLoading: boolean; isEstimateOrderLoading: boolean; + isLimitOptionsLoading: boolean; explorer: { tokenInfo: { name: string; baseUrl: string } }; swapManager: any; }; @@ -604,6 +601,7 @@ const SwapContext = createContext({ loadingTokenList: false, isCreateOrderLoading: false, isEstimateOrderLoading: false, + isLimitOptionsLoading: false, explorer: { tokenInfo: { name: '', baseUrl: '' } }, swapManager: {}, }); diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx index 55f6527ae1..92d7759ff5 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx @@ -10,7 +10,7 @@ import { LimitDexRouteTable } from '../../common/components/Modals/LimitDexRoute export const EstimateSummary = () => { const strings = useStrings(); const { atoms }: any = useTheme(); - const { swapForm, tokenInfos, primaryTokenInfo, isEstimateOrderLoading } = useSwapRevamp(); + const { swapForm, tokenInfos, primaryTokenInfo, isEstimateOrderLoading, isLimitOptionsLoading } = useSwapRevamp(); const { openModal } = useModal(); const tokenInInfo = tokenInfos.get(swapForm.tokenInInput.tokenId ?? undefinedToken); @@ -19,7 +19,7 @@ export const EstimateSummary = () => { const tokenOutTicker = tokenOutInfo?.ticker ?? tokenOutInfo?.name ?? '-'; const isLimitOrder = swapForm.orderType === 'limit'; - if (isEstimateOrderLoading) { + if (isEstimateOrderLoading || isLimitOptionsLoading) { return ( {Array.from({ length: 4 }).map((_, index) => ( From 8b1d67d82ce1af6fd16298450b89de2ab6b794c4 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Thu, 18 Sep 2025 18:41:35 +0300 Subject: [PATCH 06/34] add constant --- .../app/UI/features/swap-new/module/SwapContextProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index 262d410bda..acf1cc93b3 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -174,7 +174,7 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => slippage: state.slippageInput.value, tokenIn: state.tokenInInput.tokenId, tokenOut: state.tokenOutInput.tokenId, - ...(state.lastInputTouched === 'in' + ...(state.lastInputTouched === ASSET_DIRECTION_IN ? { amountIn: Number(state.tokenInInput.value), ...(state.orderType === 'limit' && { From 2b11d4a041294691aa9fcddf0935fe667d754ee1 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Fri, 19 Sep 2025 13:34:00 +0300 Subject: [PATCH 07/34] add cancel order tx review implementation --- .../useCases/SwapOrders.tsx/SwapOrders.tsx | 97 ++++++++++++------- 1 file changed, 62 insertions(+), 35 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx index 5898d376cd..0edb6d44db 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx @@ -5,13 +5,16 @@ import { fail, maybe } from '../../../../../coreUtils'; import ExplorableHashContainer from '../../../../../containers/widgets/ExplorableHashContainer'; import { truncateAddressShort } from '../../../../../utils/formatters'; -import { Box, Button, Typography } from '@mui/material'; +import { Box, Typography } from '@mui/material'; import { Portfolio, Swap } from '@yoroi/types'; import AssetPair from './AssetPair'; import { useIntl } from 'react-intl'; import { useSwapRevamp } from '../../module/SwapContextProvider'; import { useStrings } from '../../common/hooks/useStrings'; import { ProtocolAvatar } from '../../common/components/ProtocolAvatar/ProtocolAvatar'; +import { LoadingButton } from '@mui/lab'; +import { useTxReviewModal } from '../../../transaction-review/module/ReviewTxProvider'; +import { TransactionResult } from '../../../transaction-review/common/types'; type Column = { name: ColumnValueOrGetter; @@ -155,36 +158,11 @@ export const SwapOrders = (props: Props) => { order={order} defaultTokenInfo={primaryTokenInfo} selectedExplorer={selectedExplorer} - handleCancel={async () => console.log('handleCancel')} openOrdersOnly /> ))} - {/* {cancellationState && ( - ({ - formattedFee: tx.formattedFee, - returnValues: tx.formattedReturn, - }))} - onReorgConfirm={handleReorgConfirm} - onCancelOrder={handleCancelConfirm} - onDialogClose={() => setCancellationState(null)} - defaultTokenInfo={defaultTokenInfo} - getTokenInfo={genLookupOrFail(tokenInfoStore.tokenInfo)} - selectedExplorer={selectedExplorer} - submissionError={null} - walletType={wallet.type} - hwWalletError={null} - /> - )} */} - {/* {!showCompletedOrders && openOrdersLoading && } - {showCompletedOrders && completedOrdersLoading && } - {!openOrdersLoading && isDisplayOpenOrdersEmpty && } - {!completedOrdersLoading && isDisplayCompletedOrdersEmpty && } */} ); }; @@ -193,13 +171,11 @@ interface OrderRowProps { order: Swap.Order; defaultTokenInfo: Portfolio.Token.Info; selectedExplorer: any; - handleCancel?: () => Promise; openOrdersOnly?: boolean; } -const OrderRow = ({ order, defaultTokenInfo, selectedExplorer, openOrdersOnly = false, handleCancel }: OrderRowProps) => { +const OrderRow = ({ order, defaultTokenInfo, selectedExplorer, openOrdersOnly = false }: OrderRowProps) => { const tokenName = (token?: Portfolio.Token.Info) => token?.ticker ?? token?.name ?? token?.id ?? defaultTokenInfo.ticker; - const strings = useStrings(); const intl = useIntl(); const { tokenInfos } = useSwapRevamp(); const tokenOut = tokenInfos.get(order.tokenOut); @@ -211,7 +187,6 @@ const OrderRow = ({ order, defaultTokenInfo, selectedExplorer, openOrdersOnly = const price = roundedPrice !== '0' ? roundedPrice : priceCalc.toFixed(6); const priceStr = `1 ${tokenName(tokenIn)} = ${price} ${tokenName(tokenOut)}`; - const amountOutStr = `${Number(amountOut.toFixed(tokenOut?.decimals ?? 0))} ${tokenName(tokenOut)}`; const totalStr = `${order.amountIn} ${tokenName(tokenIn)}`; @@ -235,12 +210,64 @@ const OrderRow = ({ order, defaultTokenInfo, selectedExplorer, openOrdersOnly = {truncateAddressShort(order.updateTxHash)} - {maybe(handleCancel, f => ( - - - - ))} + {openOrdersOnly && } ); }; + +const OrderCancelation = ({ order }: { order: Swap.Order }) => { + const [loading, setIsLoading] = useState(false); + const { openTxReviewModal, startLoadingTxReview, showTxResultModal, closeTxReviewModal } = useTxReviewModal(); + const strings = useStrings(); + const { swapManager, stores } = useSwapRevamp(); + const wallet = stores.wallets.selectedOrFail; + const handleCancel = async order => { + setIsLoading(true); + const response = await swapManager.api.cancel({ order }); + setIsLoading(false); + if (response.value.data.cbor !== undefined) { + openTxReviewModal({ + modalView: 'transactionReview', + submitTx: passswordInput => { + handleSubmitTransaction(passswordInput, response.value.data.cbor); + }, + cborTx: response.value.data.cbor, + }); + } + }; + + const handleSubmitTransaction = async (passswordInput, cancelTxCbor) => { + try { + startLoadingTxReview(); + try { + const { signedTxHex: signedCancelTx } = await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ + wallet, + transactionHex: cancelTxCbor, + password: passswordInput, + }); + const signedTransactionHexes: any = signedCancelTx != null ? [signedCancelTx, signedCancelTx] : [signedCancelTx]; + await stores.substores.ada.swapStore.executeTransactionHexes({ + wallet, + signedTransactionHexes, + }); + showTxResultModal(TransactionResult.SUCCESS); + } catch (error) { + console.warn('Failed to submit transaction', error); + showTxResultModal(TransactionResult.FAIL); + } finally { + closeTxReviewModal(); + } + } catch (error) { + console.warn('Failed to sign transaction', error); + showTxResultModal(TransactionResult.FAIL); + } + }; + return ( + + handleCancel(order)}> + {strings.cancel} + + + ); +}; From 5e434c8d26830456a7e80d0cfc3cfb51e9f25fae Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Fri, 19 Sep 2025 14:13:13 +0300 Subject: [PATCH 08/34] fix condition --- .../swap-new/common/components/Modals/SettingsModalContent.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index c55079e037..91a9df09f0 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -210,6 +210,8 @@ const SlippageInput = ({ selectedSlippage, setSelectedSlippage, inputRef }) => { if (parts[1] && parts[1].length > 1) { clean = parts[0] + '.' + parts[1].slice(0, 1); } + if (clean !== '' && Number(clean) > 75) return; + setSelectedSlippage(clean); }} style={{ From f0ef5027d42d48d003fb423b2a994b7b2c60ca53 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 23 Sep 2025 15:06:46 +0300 Subject: [PATCH 09/34] add refresh, fix state update --- .../Modals/SettingsModalContent.tsx | 2 +- .../swap-new/module/SwapContextProvider.tsx | 32 ++++++++++++------- .../useCases/AssetSwap/EstimateSummary.tsx | 2 +- .../useCases/AssetSwap/TopBarActions.tsx | 8 ++++- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 91a9df09f0..4fc648122a 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -31,7 +31,7 @@ export const SettingsModalContent = () => { }; const applyChanges = async () => { - await swapForm.action({ type: SwapAction.ProtocolChanged, value: routingPreferance }); + await swapForm.action({ type: SwapAction.ProtocolSelected, value: routingPreferance }); await swapForm.action({ type: SwapAction.SlippageInputChanged, value: Number(selectedSlippage) }); await swapManager.assignSettings({ slippage: Number(selectedSlippage), diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index acf1cc93b3..2d11408837 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -129,19 +129,27 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => }, }); - useEffect(() => { - const value = limitOptions?.defaultProtocol; - action({ type: 'ProtocolChanged', value }); +useEffect(() => { + const value = limitOptions?.defaultProtocol; + if (value !== undefined && state.selectedProtocol.isTouched === false && state.selectedProtocol.value !== value) { - const wantedPrice = limitOptions?.wantedPrice; - action({ type: 'WantedPriceInputChanged', value: String(wantedPrice) }); - }, [ - limitOptions?.defaultProtocol, - limitOptions?.options, - limitOptions?.wantedPrice, - state.selectedProtocol.isTouched, - state.selectedProtocol.value, - ]); + action({ type: 'ProtocolChanged', value }); + } else { + const current = limitOptions?.options.find(p => p.protocol === state.selectedProtocol.value); + if (current === undefined) { + action({ type: 'ProtocolChanged', value }); + } + } + + const wantedPrice = limitOptions?.wantedPrice; + action({ type: 'WantedPriceInputChanged', value: String(wantedPrice) }); +}, [ + limitOptions?.defaultProtocol, + limitOptions?.options, + limitOptions?.wantedPrice, + state.selectedProtocol.isTouched, + state.selectedProtocol.value, +]); useEffect(() => { const normalizeId = (id?: string | null) => (id === '.' ? '' : id); diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx index 92d7759ff5..3dc70336f7 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx @@ -56,7 +56,7 @@ export const EstimateSummary = () => { label={strings.routeLabel} tooltip={strings.routePath} value={ - + {protocol} } diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx index fdf58aac50..2ae7b2406c 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx @@ -27,6 +27,10 @@ export const TopBarActions = () => { }); }; + const onRefresh = () => { + swapForm.action({ type: 'Refresh' }); + }; + return ( { /> - + + + From 6f431f43fddce16d5d418639e55a05c0670d2621 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Fri, 26 Sep 2025 16:54:42 +0300 Subject: [PATCH 10/34] refactor context reducer --- .../swap-new/common/components/LimitInput.tsx | 2 +- .../components/Modals/LimitDexRouteTable.tsx | 4 +- .../Modals/SettingsModalContent.tsx | 37 +- .../swap-new/common/hooks/useStrings.tsx | 6 +- .../swap-new/module/SwapContextProvider.tsx | 341 +++++++++++------- .../swap-new/useCases/AssetSwap/AssetSwap.tsx | 10 +- .../useCases/AssetSwap/TopBarActions.tsx | 6 +- .../useCases/SwapOrders.tsx/SwapOrders.tsx | 16 +- .../app/i18n/locales/id-ID.json | 2 +- 9 files changed, 248 insertions(+), 176 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/LimitInput.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/LimitInput.tsx index 1519d0aa4d..e713ce9759 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/LimitInput.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/LimitInput.tsx @@ -8,7 +8,7 @@ export const LimitInput = () => { const { swapForm, tokenInfos } = useSwapRevamp(); const tokenInputInfo = tokenInfos.get(swapForm.tokenOutInput?.tokenId); - if (swapForm.estimate === undefined || swapForm.orderType === MARKET_ORDER) { + if (swapForm.orderType === MARKET_ORDER) { return null; } diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx index dcc894e060..314689d5d7 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx @@ -1,5 +1,5 @@ import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, Box } from '@mui/material'; -import { SwapAction, useSwapRevamp } from '../../../module/SwapContextProvider'; +import { SwapActionType, useSwapRevamp } from '../../../module/SwapContextProvider'; import { useModal } from '../../../../../components/modals/ModalContext'; import { useStrings } from '../../hooks/useStrings'; @@ -46,7 +46,7 @@ export const LimitDexRouteTable = () => { { - swapForm.action({ type: SwapAction.ProtocolSelected, value: row.protocol }); + swapForm.action({ type: SwapActionType.ProtocolSelected, value: row.protocol }); closeModal(); }} sx={{ diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 4fc648122a..8b3740f1ad 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -2,7 +2,7 @@ import { Box, Button, Stack, Typography, styled, useTheme } from '@mui/material' import React, { useState, useRef, useEffect } from 'react'; import { useStrings } from '../../hooks/useStrings'; import { Switch } from '../../../../../components/Switch/Switch'; -import { SwapAction, useSwapRevamp } from '../../../module/SwapContextProvider'; +import { SwapActionType, useSwapRevamp } from '../../../module/SwapContextProvider'; import { useModal } from '../../../../../components/modals/ModalContext'; import { DEX_ROUTING } from '../../constants'; @@ -11,8 +11,7 @@ const defaultSlippages = ['0', '0.1', '0.5', '1', '2', '3', '5', '10']; export const SettingsModalContent = () => { const { swapManager, swapForm } = useSwapRevamp(); const { closeModal } = useModal(); - - const [routingPreferance, setRoutingPreferance] = useState(swapForm.selectedProtocol.value || DEX_ROUTING.AUTO); + const [routingPreference, setRoutingPreference] = useState(swapManager.settings.routingPreference); const [selectedSlippage, setSelectedSlippage] = useState(swapForm.slippageInput.value || 1); const [isManualSlippage, setIsManualSlippage] = useState(!defaultSlippages.includes(String(selectedSlippage))); const inputRef = useRef(null); @@ -31,11 +30,11 @@ export const SettingsModalContent = () => { }; const applyChanges = async () => { - await swapForm.action({ type: SwapAction.ProtocolSelected, value: routingPreferance }); - await swapForm.action({ type: SwapAction.SlippageInputChanged, value: Number(selectedSlippage) }); + await swapForm.action({ type: SwapActionType.ProtocolSelected, value: routingPreference }); + await swapForm.action({ type: SwapActionType.SlippageInputChanged, value: Number(selectedSlippage) }); await swapManager.assignSettings({ slippage: Number(selectedSlippage), - routingPreferance: [routingPreferance], + routingPreference: [routingPreference], }); closeModal(); }; @@ -58,9 +57,9 @@ export const SettingsModalContent = () => { )} - {strings.routingPreferance} + {strings.routingPreference} - + {/* @ts-ignore */} @@ -101,32 +100,32 @@ const SlipageOptions = ({ setIsManualSlippage, setSelectedSlippage, isManualSlip ); }; -const RoutingPreferance = ({ setRoutingPreferance, routingPreferance }) => { +const RoutingPreference = ({ setRoutingPreference, routingPreference }) => { const strings = useStrings(); - const autoSelected = routingPreferance === DEX_ROUTING.AUTO; + const autoSelected = routingPreference === DEX_ROUTING.AUTO; const dexHunter = - routingPreferance === DEX_ROUTING.AUTO || - routingPreferance === DEX_ROUTING.DEXHUNTER || - routingPreferance === DEX_ROUTING.BOTH; + routingPreference === DEX_ROUTING.AUTO || + routingPreference === DEX_ROUTING.DEXHUNTER || + routingPreference === DEX_ROUTING.BOTH; const muesliswap = - routingPreferance === DEX_ROUTING.AUTO || - routingPreferance === DEX_ROUTING.MUESLISWAP || - routingPreferance === DEX_ROUTING.BOTH; + routingPreference === DEX_ROUTING.AUTO || + routingPreference === DEX_ROUTING.MUESLISWAP || + routingPreference === DEX_ROUTING.BOTH; const handleDexHunterToggle = (e: React.ChangeEvent) => { const checked = e.target.checked; - setRoutingPreferance(checked ? DEX_ROUTING.DEXHUNTER : DEX_ROUTING.MUESLISWAP); + setRoutingPreference(checked ? DEX_ROUTING.DEXHUNTER : DEX_ROUTING.MUESLISWAP); }; const handleMuesliswapToggle = (e: React.ChangeEvent) => { const checked = e.target.checked; - setRoutingPreferance(checked ? DEX_ROUTING.MUESLISWAP : DEX_ROUTING.DEXHUNTER); + setRoutingPreference(checked ? DEX_ROUTING.MUESLISWAP : DEX_ROUTING.DEXHUNTER); }; const handleAutoChange = (e: React.ChangeEvent) => { const checked = e.target.checked; - setRoutingPreferance(checked ? DEX_ROUTING.AUTO : DEX_ROUTING.BOTH); + setRoutingPreference(checked ? DEX_ROUTING.AUTO : DEX_ROUTING.BOTH); }; return ( diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx index 6d8f6b17c2..3d99c36055 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx @@ -80,8 +80,8 @@ export const messages = Object.freeze( id: 'swap.manual', defaultMessage: '!!!Slippage tolerance', }, - routingPreferance: { - id: 'swap.routingPreferance', + routingPreference: { + id: 'swap.routingPreference', defaultMessage: '!!!Slippage tolerance', }, autoLabel: { @@ -187,7 +187,7 @@ export const useStrings = () => { slippageInputInfo: intl.formatMessage(messages.slippageInputInfo), manualLabel: intl.formatMessage(messages.manualLabel), applyLabel: intl.formatMessage(messages.applyLabel), - routingPreferance: intl.formatMessage(messages.routingPreferance), + routingPreference: intl.formatMessage(messages.routingPreference), autoLabel: intl.formatMessage(messages.autoLabel), slippageToleranceHigh: intl.formatMessage(messages.slippageToleranceHigh), swapLabel: intl.formatMessage(messages.swapLabel), diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index 2d11408837..447004a18c 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -51,6 +51,8 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => const { getInputs } = useGetInputs(selectedWallet?.utxos || []); + // const allUtxosAddresses = selectedWallet?.utxos.map(utxo => utxo.address); + const [state, action] = useReducer(swapReducer, defaultState); useEffect(() => { @@ -77,6 +79,15 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => }); }, [stakingKey, primaryTokenInfo, partners]); + const { data: orders = [], refetch: refetchOrders } = useQuery({ + queryKey: ['useSwapOrders', stakingKey, swapManager.settings.routingPreference], + queryFn: async () => { + const res = await swapManager.api.orders(); + if (isRight(res)) return res.value.data; + return []; + }, + }); + const { data: { tokenInfos = new Map(), tokenInfoList = [] } = {}, isLoading: loadingTokenList } = useSyncedTokenInfos({ swapManager, tokenManager, @@ -87,7 +98,7 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => useEffect(() => { if (tokenOutId) { - action({ type: SwapAction.TokenOutIdChanged, value: tokenOutId }); + action({ type: SwapActionType.TokenOutIdChanged, value: tokenOutId as Portfolio.Token.Id }); } }, [tokenOutId]); @@ -95,6 +106,8 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => action({ type: 'SlippageInputChanged', value: swapManager.settings.slippage }); }, [swapManager.settings.slippage]); + const estimateReqIdRef = useRef(0); + const { data: limitOptions, isLoading: isLimitOptionsLoading } = useQuery( [ 'useSwapLimitOptions', @@ -120,36 +133,27 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => } ); - const { data: orders = [], refetch: refetchOrders } = useQuery({ - queryKey: ['useSwapOrders', stakingKey, swapManager.settings.routingPreference], - queryFn: async () => { - const res = await swapManager.api.orders(); - if (isRight(res)) return res.value.data; - return []; - }, - }); - -useEffect(() => { - const value = limitOptions?.defaultProtocol; - if (value !== undefined && state.selectedProtocol.isTouched === false && state.selectedProtocol.value !== value) { - - action({ type: 'ProtocolChanged', value }); - } else { - const current = limitOptions?.options.find(p => p.protocol === state.selectedProtocol.value); - if (current === undefined) { + useEffect(() => { + const value = limitOptions?.defaultProtocol; + if (value !== undefined && state.selectedProtocol.isTouched === false && state.selectedProtocol.value !== value) { action({ type: 'ProtocolChanged', value }); + } else { + const current = limitOptions?.options.find(p => p.protocol === state.selectedProtocol.value); + if (current === undefined) { + action({ type: 'ProtocolChanged', value }); + } } - } - - const wantedPrice = limitOptions?.wantedPrice; - action({ type: 'WantedPriceInputChanged', value: String(wantedPrice) }); -}, [ - limitOptions?.defaultProtocol, - limitOptions?.options, - limitOptions?.wantedPrice, - state.selectedProtocol.isTouched, - state.selectedProtocol.value, -]); + + const wantedPrice = limitOptions?.wantedPrice; + if (wantedPrice !== undefined && wantedPrice > 0 && state.selectedProtocol.value === limitOptions?.defaultProtocol) + action({ type: 'WantedPriceInputChanged', value: String(wantedPrice) }); + }, [ + limitOptions?.defaultProtocol, + limitOptions?.options, + limitOptions?.wantedPrice, + state.selectedProtocol.isTouched, + state.selectedProtocol.value, + ]); useEffect(() => { const normalizeId = (id?: string | null) => (id === '.' ? '' : id); @@ -167,7 +171,7 @@ useEffect(() => { useEffect(() => { if (!state.needsNewEstimate) return; - action({ type: SwapAction.EstimateError, value: { message: '', status: 0, responseData: null } }); + action({ type: SwapActionType.EstimateError, value: { message: '', status: 0, responseData: null } }); if ( state.tokenInInput.tokenId === undefined || @@ -176,6 +180,7 @@ useEffect(() => { ) return; setIsEstimateOrderLoading(true); + const reqId = ++estimateReqIdRef.current; swapManager.api .estimate({ @@ -196,16 +201,44 @@ useEffect(() => { protocol: state.selectedProtocol.value, }) .then(response => { + console.log('response from estimate: ', response); + if (reqId !== estimateReqIdRef.current) return; + if (isLeft(response)) { - action({ type: SwapAction.EstimateError, value: response.error }); + action({ type: SwapActionType.EstimateError, value: response.error }); } else { - action({ type: SwapAction.EstimateResponse, value: response.value.data }); + console.log('response.value.data', response.value.data); + action({ type: SwapActionType.EstimateResponse, value: response.value.data }); } }) + .catch(() => { + if (reqId !== estimateReqIdRef.current) return; + action({ + type: SwapActionType.EstimateError, + value: { + status: -1, + message: 'Failed to estimate swap. Please try again.', + responseData: {}, + }, + }); + }) .finally(() => { setIsEstimateOrderLoading(false); }); - }, [state, swapManager.api]); + }, [ + state.needsNewEstimate, + state.tokenInInput.tokenId, + state.tokenOutInput.tokenId, + state.tokenInInput.value, + state.tokenOutInput.value, + state.slippageInput.value, + state.lastInputTouched, + state.orderType, + state.wantedPrice, + state.selectedProtocol.value, + swapManager.api, + action, + ]); const create = useCallback(async () => { if (state.tokenInInput.tokenId === undefined || state.tokenOutInput.tokenId === undefined) return; @@ -219,6 +252,16 @@ useEffect(() => { const amountsIn = { [state.tokenInInput.tokenId]: String(quantityIn) }; const inputs = await getInputs(amountsIn); + console.log('Created Order', { + tokenIn: state.tokenInInput.tokenId, + tokenOut: state.tokenOutInput.tokenId, + amountIn: Number(state.tokenInInput.value), + ...(state.orderType === 'limit' ? { wantedPrice: Number(state.wantedPrice) } : { slippage: state.slippageInput.value }), + blockedProtocols: [], + protocol: state.selectedProtocol.value, + inputs: inputs, + }); + swapManager.api .create({ tokenIn: state.tokenInInput.tokenId, @@ -227,14 +270,15 @@ useEffect(() => { ...(state.orderType === 'limit' ? { wantedPrice: Number(state.wantedPrice) } : { slippage: state.slippageInput.value }), blockedProtocols: [], protocol: state.selectedProtocol.value, - inputs, + inputs: inputs, }) .then(response => { + console.log('response from create order: ', response); setIsCreateOrderLoading(false); if (isLeft(response)) { - action({ type: SwapAction.CreateError, value: response.error }); + action({ type: SwapActionType.CreateError, value: response.error }); } else { - action({ type: SwapAction.CreateResponse, value: response.value.data }); + action({ type: SwapActionType.CreateResponse, value: response.value.data }); } }); }, [ @@ -284,45 +328,53 @@ useEffect(() => { export const useSwapRevamp = () => useContext(SwapContext) ?? console.log('useSwapRevamp: needs to be wrapped in a SwapContextProvider'); -const swapReducer = (state: SwapState, action: SwapAction) => { +export const swapReducer = (state: SwapState, action: SwapAction) => { return produce(state, draft => { draft.needsNewEstimate = true; draft.lastInputTouched = ASSET_DIRECTION_IN; switch (action.type) { - case SwapAction.ChangeOrderType: + case SwapActionType.ChangeOrderType: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.orderType = action.value; break; - case SwapAction.TokenInInputTouched: + case SwapActionType.TokenInInputTouched: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.tokenInInput.isTouched = true; draft.tokenInInput.value = ''; draft.tokenInInput.error = null; break; - case SwapAction.TokenOutInputTouched: + case SwapActionType.TokenOutInputTouched: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.tokenOutInput.isTouched = true; draft.tokenOutInput.value = ''; draft.tokenOutInput.error = null; break; - case SwapAction.TokenInIdChanged: - if ('value' in action) { - draft.tokenInInput.tokenId = action.value; - draft.selectedProtocol.isTouched = false; - draft.wantedPrice = ''; - } + case SwapActionType.TokenInIdChanged: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; + draft.tokenInInput.tokenId = action.value; + draft.selectedProtocol.isTouched = false; + draft.wantedPrice = ''; break; - case SwapAction.TokenOutIdChanged: - if ('value' in action) { - draft.tokenOutInput.tokenId = action.value; - draft.selectedProtocol.isTouched = false; - draft.wantedPrice = ''; - } + case SwapActionType.TokenOutIdChanged: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; + draft.tokenOutInput.tokenId = action.value; + draft.selectedProtocol.isTouched = false; + draft.wantedPrice = ''; break; - case SwapAction.TokenInAmountChanged: + case SwapActionType.TokenInAmountChanged: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.tokenInInput.value = parseNumber(action.value); if (action.value === '' || action.value === '0') { draft.tokenOutInput.value = '0'; @@ -331,7 +383,8 @@ const swapReducer = (state: SwapState, action: SwapAction) => { } break; - case SwapAction.TokenOutAmountChanged: + case SwapActionType.TokenOutAmountChanged: + draft.needsNewEstimate = true; draft.lastInputTouched = 'out'; draft.tokenOutInput.value = parseNumber(action.value); if (action.value === '' || action.value === '0') { @@ -341,28 +394,40 @@ const swapReducer = (state: SwapState, action: SwapAction) => { } break; - case SwapAction.TokenInErrorChanged: + case SwapActionType.TokenInErrorChanged: + draft.needsNewEstimate = false; draft.lastInputTouched = state.lastInputTouched; draft.tokenInInput.error = action.value; - draft.needsNewEstimate = false; + if (action.value !== null) { + draft.canSwap = false; + } break; - case SwapAction.TokenOutErrorChanged: + case SwapActionType.TokenOutErrorChanged: + draft.needsNewEstimate = false; draft.lastInputTouched = state.lastInputTouched; draft.tokenOutInput.error = action.value; - draft.needsNewEstimate = false; + if (action.value !== null) { + draft.canSwap = false; + } break; - case SwapAction.SlippageInputChanged: + case SwapActionType.SlippageInputChanged: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.slippageInput.value = action.value; break; - case SwapAction.WantedPriceInputChanged: + case SwapActionType.WantedPriceInputChanged: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.wantedPrice = parseNumber(action.value); if (Number(draft.wantedPrice) === 0) draft.needsNewEstimate = false; break; - case SwapAction.SwitchTouched: + case SwapActionType.SwitchTouched: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.tokenOutInput.isTouched = state.tokenInInput.isTouched; draft.tokenOutInput.tokenId = state.tokenInInput.tokenId; draft.tokenOutInput.value = ''; @@ -376,64 +441,78 @@ const swapReducer = (state: SwapState, action: SwapAction) => { draft.wantedPrice = ''; break; - case SwapAction.ProtocolSelected: + case SwapActionType.ProtocolSelected: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.selectedProtocol.isTouched = true; draft.selectedProtocol.value = action.value; break; - case SwapAction.ProtocolChanged: + case SwapActionType.ProtocolChanged: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.selectedProtocol.isTouched = false; draft.selectedProtocol.value = action.value; break; - case SwapAction.Refresh: + case SwapActionType.Refresh: + draft.needsNewEstimate = true; draft.lastInputTouched = state.lastInputTouched; draft.tokenInInput.error = null; draft.tokenOutInput.error = null; + draft.canSwap = false; break; - case SwapAction.ResetAmounts: + case SwapActionType.ResetAmounts: + draft.needsNewEstimate = true; + draft.lastInputTouched = 'in'; draft.tokenInInput.value = ''; draft.tokenOutInput.value = ''; draft.tokenInInput.error = null; draft.tokenOutInput.error = null; + draft.canSwap = false; break; - case SwapAction.ResetForm: + case SwapActionType.ResetForm: Object.assign(draft, defaultState); break; - case SwapAction.EstimateResponse: - draft.lastInputTouched = state.lastInputTouched; + case SwapActionType.EstimateResponse: draft.needsNewEstimate = false; + draft.lastInputTouched = state.lastInputTouched; draft.estimate = action.value; draft.tokenOutInput.error = null; - draft.canSwap = true; + // Only enable swap if there are no input errors + draft.canSwap = state.tokenInInput.error === null; - if (state.lastInputTouched === ASSET_DIRECTION_IN) { + if (state.lastInputTouched === 'in') { draft.tokenOutInput.value = String(action.value.totalOutputWithoutSlippage ?? 0); } else { draft.tokenInInput.value = String(action.value.totalInput ?? 0); } break; - case SwapAction.EstimateError: + case SwapActionType.EstimateError: draft.needsNewEstimate = false; + draft.lastInputTouched = 'in'; draft.estimate = undefined; draft.tokenOutInput.error = action.value.message; draft.canSwap = false; break; - case SwapAction.CreateResponse: + case SwapActionType.CreateResponse: draft.needsNewEstimate = false; + draft.lastInputTouched = 'in'; draft.createTx = action.value; break; - case SwapAction.CreateError: + case SwapActionType.CreateError: draft.needsNewEstimate = false; + draft.lastInputTouched = 'in'; draft.createTx = undefined; draft.tokenOutInput.error = action.value.message; + draft.canSwap = false; break; default: @@ -442,7 +521,7 @@ const swapReducer = (state: SwapState, action: SwapAction) => { }); }; -export const SwapAction = { +export const SwapActionType = { ChangeOrderType: 'ChangeOrderType', TokenInInputTouched: 'TokenInInputTouched', TokenOutInputTouched: 'TokenOutInputTouched', @@ -466,35 +545,62 @@ export const SwapAction = { CreateError: 'CreateError', } as const; -type SwapActionValueMap = { - ChangeOrderType: 'limit' | 'market'; - TokenInInputTouched: undefined; - TokenOutInputTouched: undefined; - TokenInIdChanged: any; - TokenOutIdChanged: any; - TokenInAmountChanged: string; - TokenOutAmountChanged: string; - TokenInErrorChanged: string | null; - TokenOutErrorChanged: string | null; - WantedPriceInputChanged: string; - SlippageInputChanged: number; - SwitchTouched: undefined; - ProtocolSelected: Swap.Protocol; - ProtocolChanged: Swap.Protocol | undefined; - Refresh: undefined; - ResetAmounts: undefined; - ResetForm: undefined; - EstimateResponse: Swap.EstimateResponse; - EstimateError: Api.ResponseError; - CreateResponse: Swap.CreateResponse; - CreateError: Api.ResponseError; -}; +type SwapAction = + | { type: typeof SwapActionType.ChangeOrderType; value: 'limit' | 'market' } + | { type: typeof SwapActionType.TokenInInputTouched } + | { type: typeof SwapActionType.TokenOutInputTouched } + | { type: typeof SwapActionType.TokenInIdChanged; value: Portfolio.Token.Id } + | { type: typeof SwapActionType.TokenOutIdChanged; value: Portfolio.Token.Id } + | { type: typeof SwapActionType.TokenInAmountChanged; value: string } + | { type: typeof SwapActionType.TokenOutAmountChanged; value: string } + | { type: typeof SwapActionType.TokenInErrorChanged; value: string | null } + | { type: typeof SwapActionType.TokenOutErrorChanged; value: string | null } + | { type: typeof SwapActionType.WantedPriceInputChanged; value: string } + | { type: typeof SwapActionType.SlippageInputChanged; value: number } + | { type: typeof SwapActionType.SwitchTouched } + | { type: typeof SwapActionType.ProtocolSelected; value: Swap.Protocol } + | { + type: typeof SwapActionType.ProtocolChanged; + value: Swap.Protocol | undefined; + } + | { type: typeof SwapActionType.Refresh } + | { type: typeof SwapActionType.ResetAmounts } + | { type: typeof SwapActionType.ResetForm } + | { type: typeof SwapActionType.EstimateResponse; value: Swap.EstimateResponse } + | { type: typeof SwapActionType.EstimateError; value: Api.ResponseError } + | { type: typeof SwapActionType.CreateResponse; value: Swap.CreateResponse } + | { type: typeof SwapActionType.CreateError; value: Api.ResponseError }; -export type SwapAction = { - [K in keyof SwapActionValueMap]: SwapActionValueMap[K] extends undefined - ? { type: K } - : { type: K; value: SwapActionValueMap[K] }; -}[keyof SwapActionValueMap]; +type SwapState = { + needsNewEstimate: boolean; + orderType: 'market' | 'limit'; + lastInputTouched: 'in' | 'out'; + tokenInInput: { + isTouched: boolean; + tokenId?: Portfolio.Token.Id; + disabled: boolean; + error: string | null; + value: string; + }; + tokenOutInput: { + isTouched: boolean; + tokenId?: Portfolio.Token.Id; + disabled: boolean; + error: string | null; + value: string; + }; + slippageInput: { + value: number; + }; + selectedProtocol: { + isTouched: boolean; + value?: Swap.Protocol; + }; + wantedPrice: string; + canSwap: boolean; + estimate?: Swap.EstimateResponse; + createTx?: Swap.CreateResponse; +}; const defaultState: SwapState = Object.freeze({ needsNewEstimate: false, @@ -529,37 +635,6 @@ const defaultState: SwapState = Object.freeze({ cancelError: undefined, } as const); -type SwapState = { - needsNewEstimate: boolean; - orderType: MarketOrderType; - lastInputTouched: AssetDirectionType; - tokenInInput: { - isTouched: boolean; - tokenId?: Portfolio.Token.Id; - disabled: boolean; - error: string | null; - value: string; - }; - tokenOutInput: { - isTouched: boolean; - tokenId?: Portfolio.Token.Id; - disabled: boolean; - error: string | null; - value: string; - }; - slippageInput: { - value: number; - }; - selectedProtocol: { - isTouched: boolean; - value?: Swap.Protocol; - }; - wantedPrice: string; - canSwap: boolean; - estimate?: Swap.EstimateResponse; - createTx?: Swap.CreateResponse; -}; - export type SwapContext = SwapState & { isLoading: boolean; limitOptions?: Swap.LimitOptionsResponse; diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx index 8d65840988..4c7124d79e 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx @@ -9,7 +9,7 @@ import { SwitchAssets } from '../../common/components/SwitchAssets'; import { SelectAssetTo } from '../../common/components/Modals/SelectAssetTo'; import { AssetDirectionType } from '../../common/types'; import { ASSET_DIRECTION_IN, ASSET_DIRECTION_OUT, MARKET_ORDER } from '../../common/constants'; -import { SwapAction, useSwapRevamp } from '../../module/SwapContextProvider'; +import { SwapActionType, useSwapRevamp } from '../../module/SwapContextProvider'; import { useEffect } from 'react'; import { useTxReviewModal } from '../../../transaction-review/module/ReviewTxProvider'; import { ErrorMessage } from '../../common/components/ErrorMessage'; @@ -33,7 +33,6 @@ export const AssetSwap = () => { width: '612px', }); }; - // @ts-ignore const handleSubmitTransaction = async password => { // @ts-ignore @@ -41,7 +40,7 @@ export const AssetSwap = () => { wallet, swapState: swapForm, }); - + console.log('unisgnedTxRequest', unisgnedTxRequest); try { await stores.transactionProcessingStore.adaSendAndRefresh({ wallet, @@ -53,7 +52,7 @@ export const AssetSwap = () => { } catch (e) { showTxResultModal(TransactionResult.FAIL); } finally { - swapForm.action({ type: SwapAction.ResetForm }); + swapForm.action({ type: SwapActionType.ResetForm }); closeTxReviewModal(); } }; @@ -90,6 +89,7 @@ export const AssetSwap = () => { onClick={() => { createOrder(); }} + disabled={!swapForm.canSwap} loading={isCreateOrderLoading} > {swapForm.orderType === MARKET_ORDER ? strings.swapLabel : strings.placeOrder} @@ -104,3 +104,5 @@ const Content = styled(Stack)(({ theme }: any) => ({ margin: '0 auto', height: '100%', })); + + diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx index 2ae7b2406c..3344e7a294 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/TopBarActions.tsx @@ -4,7 +4,7 @@ import Tabs from '../../../../../components/common/tabs/Tabs'; import { Icons, IconWrapper } from '../../../../components'; import { useModal } from '../../../../components/modals/ModalContext'; import { SettingsModalContent } from '../../common/components/Modals/SettingsModalContent'; -import { SwapAction, useSwapRevamp } from '../../module/SwapContextProvider'; +import { SwapActionType, useSwapRevamp } from '../../module/SwapContextProvider'; import { LIMIT_ORDER, MARKET_ORDER } from '../../common/constants'; export const TopBarActions = () => { @@ -39,9 +39,9 @@ export const TopBarActions = () => { isActive: swapForm?.orderType === type, onClick: () => { if (type === LIMIT_ORDER) { - swapForm.action({ type: SwapAction.ChangeOrderType, value: LIMIT_ORDER }); + swapForm.action({ type: SwapActionType.ChangeOrderType, value: LIMIT_ORDER }); } else { - swapForm.action({ type: SwapAction.ChangeOrderType, value: MARKET_ORDER }); + swapForm.action({ type: SwapActionType.ChangeOrderType, value: MARKET_ORDER }); } }, }))} diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx index 0edb6d44db..8b88a50a3a 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx @@ -241,16 +241,12 @@ const OrderCancelation = ({ order }: { order: Swap.Order }) => { try { startLoadingTxReview(); try { - const { signedTxHex: signedCancelTx } = await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ - wallet, - transactionHex: cancelTxCbor, - password: passswordInput, - }); - const signedTransactionHexes: any = signedCancelTx != null ? [signedCancelTx, signedCancelTx] : [signedCancelTx]; - await stores.substores.ada.swapStore.executeTransactionHexes({ - wallet, - signedTransactionHexes, - }); + await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ + wallet, + transactionHex: cancelTxCbor, + password: passswordInput, + }); + showTxResultModal(TransactionResult.SUCCESS); } catch (error) { console.warn('Failed to submit transaction', error); diff --git a/packages/yoroi-extension/app/i18n/locales/id-ID.json b/packages/yoroi-extension/app/i18n/locales/id-ID.json index 796cf15b7f..b107674397 100644 --- a/packages/yoroi-extension/app/i18n/locales/id-ID.json +++ b/packages/yoroi-extension/app/i18n/locales/id-ID.json @@ -578,7 +578,7 @@ "swap.txSubmitted": "Transaksi dikirim", "swap.txFailed": "Transaksi gagal", "swap.txId": "ID transaksi", - "swap.routingPreferance": "Pilihan rute", + "swap.routingPreference": "Pilihan rute", "swap.checkTx": "Periksa transaksi ini daftar transaksi", "swap.txNotProcessed": "Transaksi Anda tidak diproses karena masalah teknis", "swap.goToTxs": "Ke transaksi", From e6bac2c68889cc2a402f57fa39fdb2e3cc25f18d Mon Sep 17 00:00:00 2001 From: Denis Nebytov Date: Mon, 29 Sep 2025 13:25:30 +0300 Subject: [PATCH 11/34] fix string --- .../app/UI/features/swap-new/common/hooks/useStrings.tsx | 2 +- packages/yoroi-extension/app/i18n/locales/en-US.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx index 3d99c36055..4fb89d6f3e 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx @@ -82,7 +82,7 @@ export const messages = Object.freeze( }, routingPreference: { id: 'swap.routingPreference', - defaultMessage: '!!!Slippage tolerance', + defaultMessage: '!!!Routing preference', }, autoLabel: { id: 'swap.auto', diff --git a/packages/yoroi-extension/app/i18n/locales/en-US.json b/packages/yoroi-extension/app/i18n/locales/en-US.json index ffc8236e85..4f58fd7340 100644 --- a/packages/yoroi-extension/app/i18n/locales/en-US.json +++ b/packages/yoroi-extension/app/i18n/locales/en-US.json @@ -578,7 +578,7 @@ "swap.txSubmitted": "Transaction submitted", "swap.txFailed": "Transaction failed", "swap.txId": "Transaction ID", - "swap.routingPreferance": "Routing preference", + "swap.routingPreference": "Routing preference", "swap.checkTx": "Check this transaction in the list of wallet transactions", "swap.txNotProcessed": "Your transaction has not been processed properly due to technical issues", "swap.goToTxs": "Go to transactions", From 25f0ae23e59c4ee6e14a6ce1857ae69047071554 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 15:14:57 +0300 Subject: [PATCH 12/34] fix route --- .../components/Modals/DexRouteTable.tsx | 4 +- .../components/Modals/LimitDexRouteTable.tsx | 3 +- .../Modals/SettingsModalContent.tsx | 6 +- .../ProtocolAvatar/ProtocolAvatar.tsx | 56 ++++++++++++++++--- .../swap-new/common/hooks/useStrings.tsx | 2 +- .../useCases/AssetSwap/EstimateSummary.tsx | 5 +- 6 files changed, 60 insertions(+), 16 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/DexRouteTable.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/DexRouteTable.tsx index a815a24108..38cbb376e5 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/DexRouteTable.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/DexRouteTable.tsx @@ -1,4 +1,5 @@ import { Typography, Stack } from '@mui/material'; +import { ProtocolAvatar } from '../ProtocolAvatar/ProtocolAvatar'; type DexRoute = { id: string; @@ -23,8 +24,7 @@ export const DexRouteTable = ({ data }: Props) => { return ( - {/* {row.logo} */} - {row.protocol} + {((100 * (row.expectedOutputWithoutSlippage ?? 0)) / total).toFixed(2)} % diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx index 314689d5d7..9583a4a2d5 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/LimitDexRouteTable.tsx @@ -2,6 +2,7 @@ import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typog import { SwapActionType, useSwapRevamp } from '../../../module/SwapContextProvider'; import { useModal } from '../../../../../components/modals/ModalContext'; import { useStrings } from '../../hooks/useStrings'; +import { ProtocolAvatar } from '../ProtocolAvatar/ProtocolAvatar'; export const LimitDexRouteTable = () => { const strings = useStrings(); @@ -62,7 +63,7 @@ export const LimitDexRouteTable = () => { > - {row.protocol} + diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 8b3740f1ad..331f75f3a4 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -11,6 +11,7 @@ const defaultSlippages = ['0', '0.1', '0.5', '1', '2', '3', '5', '10']; export const SettingsModalContent = () => { const { swapManager, swapForm } = useSwapRevamp(); const { closeModal } = useModal(); + const [routingPreference, setRoutingPreference] = useState(swapManager.settings.routingPreference); const [selectedSlippage, setSelectedSlippage] = useState(swapForm.slippageInput.value || 1); const [isManualSlippage, setIsManualSlippage] = useState(!defaultSlippages.includes(String(selectedSlippage))); @@ -34,7 +35,7 @@ export const SettingsModalContent = () => { await swapForm.action({ type: SwapActionType.SlippageInputChanged, value: Number(selectedSlippage) }); await swapManager.assignSettings({ slippage: Number(selectedSlippage), - routingPreference: [routingPreference], + routingPreference: routingPreference, }); closeModal(); }; @@ -57,7 +58,7 @@ export const SettingsModalContent = () => { )} - {strings.routingPreference} + {strings.routingPreferance} @@ -113,6 +114,7 @@ const RoutingPreference = ({ setRoutingPreference, routingPreference }) => { routingPreference === DEX_ROUTING.MUESLISWAP || routingPreference === DEX_ROUTING.BOTH; + console.log('OPTIONSSS', { autoSelected, dexHunter, muesliswap }); const handleDexHunterToggle = (e: React.ChangeEvent) => { const checked = e.target.checked; setRoutingPreference(checked ? DEX_ROUTING.DEXHUNTER : DEX_ROUTING.MUESLISWAP); diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/ProtocolAvatar/ProtocolAvatar.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/ProtocolAvatar/ProtocolAvatar.tsx index 789f2f1a37..a06b4147d5 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/ProtocolAvatar/ProtocolAvatar.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/ProtocolAvatar/ProtocolAvatar.tsx @@ -1,8 +1,9 @@ import { getDexUrlByProtocol } from '@yoroi/swap'; import { Swap } from '@yoroi/types'; +import { Box, Link, Typography } from '@mui/material'; + import { ProtocolIcon } from '../ProtocolIcon/ProtocolIcon'; -import { Link, Typography } from '@mui/material'; type Props = { protocol: Swap.Protocol; @@ -11,21 +12,58 @@ type Props = { preventOpenLink?: boolean; }; -export const ProtocolAvatar = ({ protocol, append = '' }: Props) => { - const formattedName = `${protocol.charAt(0).toUpperCase()}${protocol.slice(1).replace(/-/, ' ')}${append}`; +export const ProtocolAvatar = ({ protocol, append = '', onPress, preventOpenLink = false }: Props) => { + const formattedName = `${protocol.charAt(0).toUpperCase()}${protocol.slice(1).replace(/-/g, ' ')}${append}`; + + const content = ( + <> + + + {formattedName} + + + ); + + if (preventOpenLink) { + return ( + + {content} + + ); + } return ( - - - - {formattedName} - + {content} ); }; diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx index 4fb89d6f3e..af01e15680 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx @@ -187,7 +187,7 @@ export const useStrings = () => { slippageInputInfo: intl.formatMessage(messages.slippageInputInfo), manualLabel: intl.formatMessage(messages.manualLabel), applyLabel: intl.formatMessage(messages.applyLabel), - routingPreference: intl.formatMessage(messages.routingPreference), + routingPreferance: intl.formatMessage(messages.routingPreferance), autoLabel: intl.formatMessage(messages.autoLabel), slippageToleranceHigh: intl.formatMessage(messages.slippageToleranceHigh), swapLabel: intl.formatMessage(messages.swapLabel), diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx index 3dc70336f7..5564b34b65 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/EstimateSummary.tsx @@ -6,6 +6,7 @@ import { undefinedToken } from '../../common/constants'; import { useModal } from '../../../../components/modals/ModalContext'; import { DexRouteTable } from '../../common/components/Modals/DexRouteTable'; import { LimitDexRouteTable } from '../../common/components/Modals/LimitDexRouteTable'; +import { ProtocolAvatar } from '../../common/components/ProtocolAvatar/ProtocolAvatar'; export const EstimateSummary = () => { const strings = useStrings(); @@ -57,7 +58,9 @@ export const EstimateSummary = () => { tooltip={strings.routePath} value={ - {protocol} + + + } /> From fe2c251bafb0e76089d076b867982e0fc54bf8f9 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 15:17:24 +0300 Subject: [PATCH 13/34] fix typo --- .../swap-new/common/components/Modals/SettingsModalContent.tsx | 2 +- .../app/UI/features/swap-new/common/hooks/useStrings.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 331f75f3a4..3173fb2bcf 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -58,7 +58,7 @@ export const SettingsModalContent = () => { )} - {strings.routingPreferance} + {strings.routingPreference} diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx index af01e15680..4fb89d6f3e 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx @@ -187,7 +187,7 @@ export const useStrings = () => { slippageInputInfo: intl.formatMessage(messages.slippageInputInfo), manualLabel: intl.formatMessage(messages.manualLabel), applyLabel: intl.formatMessage(messages.applyLabel), - routingPreferance: intl.formatMessage(messages.routingPreferance), + routingPreference: intl.formatMessage(messages.routingPreference), autoLabel: intl.formatMessage(messages.autoLabel), slippageToleranceHigh: intl.formatMessage(messages.slippageToleranceHigh), swapLabel: intl.formatMessage(messages.swapLabel), From dc61f33d4a2b5159311fa78e0ca715b4e51c379d Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 15:18:53 +0300 Subject: [PATCH 14/34] fix format --- .../features/swap-new/useCases/AssetSwap/AssetSwap.tsx | 2 -- .../swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx index 4c7124d79e..9ce7c22d29 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx @@ -104,5 +104,3 @@ const Content = styled(Stack)(({ theme }: any) => ({ margin: '0 auto', height: '100%', })); - - diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx index 8b88a50a3a..c5051f9705 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx @@ -241,11 +241,11 @@ const OrderCancelation = ({ order }: { order: Swap.Order }) => { try { startLoadingTxReview(); try { - await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ - wallet, - transactionHex: cancelTxCbor, - password: passswordInput, - }); + await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ + wallet, + transactionHex: cancelTxCbor, + password: passswordInput, + }); showTxResultModal(TransactionResult.SUCCESS); } catch (error) { From edceb061ae516a5be9988896a7c7072a4c1c0786 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 15:19:39 +0300 Subject: [PATCH 15/34] removed console.log --- .../swap-new/common/components/Modals/SettingsModalContent.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 3173fb2bcf..cad43aba0e 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -114,7 +114,6 @@ const RoutingPreference = ({ setRoutingPreference, routingPreference }) => { routingPreference === DEX_ROUTING.MUESLISWAP || routingPreference === DEX_ROUTING.BOTH; - console.log('OPTIONSSS', { autoSelected, dexHunter, muesliswap }); const handleDexHunterToggle = (e: React.ChangeEvent) => { const checked = e.target.checked; setRoutingPreference(checked ? DEX_ROUTING.DEXHUNTER : DEX_ROUTING.MUESLISWAP); From 3bddbfe2d7882ce4a4ef2735a07aa2701daff890 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 15:20:57 +0300 Subject: [PATCH 16/34] remove console.log --- .../swap-new/module/SwapContextProvider.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index 447004a18c..02b4c51595 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -201,13 +201,11 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => protocol: state.selectedProtocol.value, }) .then(response => { - console.log('response from estimate: ', response); if (reqId !== estimateReqIdRef.current) return; if (isLeft(response)) { action({ type: SwapActionType.EstimateError, value: response.error }); } else { - console.log('response.value.data', response.value.data); action({ type: SwapActionType.EstimateResponse, value: response.value.data }); } }) @@ -252,16 +250,6 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => const amountsIn = { [state.tokenInInput.tokenId]: String(quantityIn) }; const inputs = await getInputs(amountsIn); - console.log('Created Order', { - tokenIn: state.tokenInInput.tokenId, - tokenOut: state.tokenOutInput.tokenId, - amountIn: Number(state.tokenInInput.value), - ...(state.orderType === 'limit' ? { wantedPrice: Number(state.wantedPrice) } : { slippage: state.slippageInput.value }), - blockedProtocols: [], - protocol: state.selectedProtocol.value, - inputs: inputs, - }); - swapManager.api .create({ tokenIn: state.tokenInInput.tokenId, @@ -273,7 +261,6 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => inputs: inputs, }) .then(response => { - console.log('response from create order: ', response); setIsCreateOrderLoading(false); if (isLeft(response)) { action({ type: SwapActionType.CreateError, value: response.error }); From 2814a34b9b5d02dc5f64a33c38b9d8945c339783 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 15:53:18 +0300 Subject: [PATCH 17/34] fix parsing number --- .../app/UI/features/swap-new/module/SwapContextProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index 02b4c51595..bb3ffabba1 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -680,6 +680,6 @@ const parseNumber = (text: string) => !Number.isNaN(Number(text.replace(',', '.'))) ? text .replace(',', '.') - .replace(/^0+(.+)/, '$1') + .replace(/^0+(?=\d|\.)/, '0') .replace(/^\.$/, '0.') - : '0'; + : '0'; \ No newline at end of file From 30f845825ac64c4ba993da1c9403edec228c2b71 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 18:00:27 +0300 Subject: [PATCH 18/34] fix format --- .../app/UI/features/swap-new/module/SwapContextProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index bb3ffabba1..11af649c66 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -682,4 +682,4 @@ const parseNumber = (text: string) => .replace(',', '.') .replace(/^0+(?=\d|\.)/, '0') .replace(/^\.$/, '0.') - : '0'; \ No newline at end of file + : '0'; From c697a88fc06160f5cd277ae2ae65929e5c819762 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 29 Sep 2025 18:49:16 +0300 Subject: [PATCH 19/34] fix imports --- .../app/UI/features/swap-new/module/SwapContextProvider.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index 11af649c66..c76a26d2a6 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -23,7 +23,6 @@ import { useSyncedTokenInfos } from '../common/hooks/useTokensInfo'; import { isLeft, isRight } from '@yoroi/common'; import { useGetInputs } from '../common/helpers'; import { ASSET_DIRECTION_IN } from '../common/constants'; -import { AssetDirectionType, MarketOrderType } from '../common/types'; export const convertBech32ToHex = async (bech32Address: string) => { return await RustModule.WalletV4.Address.from_bech32(bech32Address).to_hex(); From 875efa33db8ff4cf1811ff681a913d3263a1c4c2 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 12:24:21 +0300 Subject: [PATCH 20/34] refactor cip30 implementation --- .../UI/features/swap-new/common/helpers.ts | 182 +++++++++++------- .../swap-new/module/SwapContextProvider.tsx | 18 +- 2 files changed, 112 insertions(+), 88 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts b/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts index 83167b8cab..c555f41bf2 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts @@ -1,88 +1,122 @@ import { RustModule } from '../../../../api/ada/lib/cardanoCrypto/rustLoader'; export const normalizeTokenId = (id?: string | null) => (id === '' ? '.' : id); -export const useGetInputs = (walletUtxos: any[]) => { - const getInputs = async (amounts: { [tokenId: string]: string }) => { - try { - const tokenId = Object.keys(amounts)[0]; - if (tokenId === undefined) { - throw new Error('No tokenId provided in amounts'); - } - const requiredAmount = BigInt(Number(amounts[tokenId])); - - const matching = walletUtxos - .map(utxo => { - const token = utxo.output.tokens.find(t => { - return tokenId === '.' ? t.Token.Metadata.ticker === 'ADA' : t.Token.Identifier === tokenId; - }); - - return token - ? { - utxo, - amount: BigInt(token.TokenList.Amount), - } - : null; - }) - .filter(Boolean) - .sort((a, b) => (a!.amount > b!.amount ? -1 : 1)) as { - utxo: any; - amount: bigint; - }[]; - - const selected: any[] = []; - let total = BigInt(0); - - for (const { utxo, amount } of matching) { - selected.push(utxo); - total += amount; - if (total >= requiredAmount) break; - } +type WalletUtxo = { + address: string; // raw address bytes (hex) + output: { + Transaction: { Hash: string }; // 64-hex + UtxoTransactionOutput: { OutputIndex: number }; + tokens?: Array<{ + Token: { + Identifier: string; // '.' for ADA, or `${policyId}.${assetNameHex}` + Metadata: { ticker?: string; policyId?: string; assetName?: string }; + }; + TokenList: { Amount: string }; // decimal string + }>; + inlineDatumCborHex?: string; + datumHashHex?: string; + scriptRefCborHex?: string; + }; +}; - if (total < requiredAmount) { - throw new Error('Not enough balance'); +const isHex = (s: string) => /^[0-9a-f]*$/i.test(s); +const isHex64 = (s: string) => /^[0-9a-f]{64}$/i.test(s); +const hexToBytes = (hex: string): Uint8Array => { + if (!isHex(hex) || hex.length % 2 !== 0) throw new Error('Invalid hex'); + const out = new Uint8Array(hex.length / 2); + for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.substr(i * 2, 2), 16); + return out; +}; +const bytesToHex = (bytes: Uint8Array): string => { + let hex = ''; + // @ts-ignore + for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, '0'); + return hex; +}; +const looksLikeTUSO = (hex: string) => + typeof hex === 'string' && /^[0-9a-f]+$/i.test(hex) && hex.toLowerCase().startsWith('82825820'); // 82 [input,output] / 82 [hash,index] / 58 20 (32-byte hash) + +export const useGetInputs = (walletUtxos: WalletUtxo[]) => { + // encode one UTxO -> CBOR hex TUSO + const encodeUtxo = (u: WalletUtxo): string => { + const { WalletV4 } = RustModule; + + const input = WalletV4.TransactionInput.new( + WalletV4.TransactionHash.from_hex(u.output.Transaction.Hash), + u.output.UtxoTransactionOutput.OutputIndex + ); + + const addr = WalletV4.Address.from_bytes(hexToBytes(u.address)); + + const value = WalletV4.Value.new(WalletV4.BigNum.from_str('0')); + const ma = WalletV4.MultiAsset.new(); + let lovelaceSet = false; + + for (const t of u.output.tokens ?? []) { + const amt = WalletV4.BigNum.from_str(t.TokenList.Amount); + const isAda = t.Token.Identifier === '.' || (t.Token.Metadata?.ticker ?? '').toUpperCase() === 'ADA'; + + if (isAda) { + value.set_coin(amt); + lovelaceSet = true; + } else { + const policyId = t.Token.Metadata?.policyId; + const assetNameHex = t.Token.Metadata?.assetName; + if (!policyId || !assetNameHex) continue; + const policy = WalletV4.ScriptHash.from_hex(policyId); + const assets = ma.get(policy) ?? WalletV4.Assets.new(); + assets.insert(WalletV4.AssetName.new(hexToBytes(assetNameHex)), amt); + ma.insert(policy, assets); } + } - const inputs = await Promise.all( - selected.map(async u => { - const txHash = u.output.Transaction.Hash; - const index = u.output.UtxoTransactionOutput.OutputIndex; - - const receiver = await RustModule.WalletV4.Address.from_bytes(Buffer.from(u.address, 'hex')).to_bech32(); - - const input = RustModule.WalletV4.TransactionInput.new(RustModule.WalletV4.TransactionHash.from_hex(txHash), index); - - const value = RustModule.WalletV4.Value.new(RustModule.WalletV4.BigNum.from_str('0')); - - for (const token of u.output.tokens) { - const amt = RustModule.WalletV4.BigNum.from_str(token.TokenList.Amount); - - if (token.Token.Metadata.ticker === 'ADA') { - value.set_coin(amt); - } else { - const policyId = RustModule.WalletV4.ScriptHash.from_hex(token.Token.Metadata.policyId); - const assetName = RustModule.WalletV4.AssetName.new(Buffer.from(token.Token.Metadata.assetName, 'hex')); + if (!lovelaceSet) value.set_coin(WalletV4.BigNum.from_str('0')); + if (ma.len() > 0) value.set_multiasset(ma); - const multiasset = value.multiasset() || RustModule.WalletV4.MultiAsset.new(); - const assets = multiasset.get(policyId) || RustModule.WalletV4.Assets.new(); - assets.insert(assetName, amt); - multiasset.insert(policyId, assets); - value.set_multiasset(multiasset); - } - } + const out = WalletV4.TransactionOutput.new(addr, value); - const output = RustModule.WalletV4.TransactionOutput.new(RustModule.WalletV4.Address.from_bech32(receiver), value); + if (u.output.inlineDatumCborHex) { + out.set_datum(WalletV4.Datum.new_data(WalletV4.PlutusData.from_bytes(hexToBytes(u.output.inlineDatumCborHex)))); + } else if (u.output.datumHashHex) { + out.set_datum(WalletV4.Datum.new_data_hash(WalletV4.DataHash.from_bytes(hexToBytes(u.output.datumHashHex)))); + } + if (u.output.scriptRefCborHex) { + out.set_script_ref(WalletV4.ScriptRef.from_bytes(hexToBytes(u.output.scriptRefCborHex))); + } - const utxo = RustModule.WalletV4.TransactionUnspentOutput.new(input, output); - return Buffer.from(utxo.to_bytes()).toString('hex'); - }) - ); + const tuso = WalletV4.TransactionUnspentOutput.new(input, out); + const hex = bytesToHex(tuso.to_bytes()); + if (!looksLikeTUSO(hex)) throw new Error(`Not a full TransactionUnspentOutput: ${hex.slice(0, 10)}…`); + return hex; + }; - return inputs; - } catch { - console.warn('Failed to get inputs'); - return []; + // dedupe + validate by (txHash#index) + const sanitize = (list: WalletUtxo[]) => { + const seen = new Set(); + const out: WalletUtxo[] = []; + for (const u of list) { + const txh = u.output?.Transaction?.Hash; + const idx = u.output?.UtxoTransactionOutput?.OutputIndex; + if (!txh || typeof idx !== 'number' || !isHex64(txh)) continue; + const key = `${txh}#${idx}`; + if (seen.has(key)) continue; + seen.add(key); + out.push(u); } + // stable order + out.sort( + (a, b) => + a.output.Transaction.Hash.localeCompare(b.output.Transaction.Hash) || + a.output.UtxoTransactionOutput.OutputIndex - b.output.UtxoTransactionOutput.OutputIndex + ); + return out; + }; + + // returns ALL UTXOs as TUSO CBOR hex + const getInputs = async (): Promise => { + const utxos = sanitize(walletUtxos); + return utxos.map(encodeUtxo); }; return { getInputs }; -}; +}; \ No newline at end of file diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index c76a26d2a6..c2d80d9996 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -22,7 +22,7 @@ import { tokenManagers } from '../../portfolio/common/helpers/build-token-manage import { useSyncedTokenInfos } from '../common/hooks/useTokensInfo'; import { isLeft, isRight } from '@yoroi/common'; import { useGetInputs } from '../common/helpers'; -import { ASSET_DIRECTION_IN } from '../common/constants'; +import { ASSET_DIRECTION_IN, USDA_TOKEN_ID } from '../common/constants'; export const convertBech32ToHex = async (bech32Address: string) => { return await RustModule.WalletV4.Address.from_bech32(bech32Address).to_hex(); @@ -48,10 +48,7 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => const tokenOutInputRef = useRef(null); const tokenInInputRef = useRef(null); - const { getInputs } = useGetInputs(selectedWallet?.utxos || []); - - // const allUtxosAddresses = selectedWallet?.utxos.map(utxo => utxo.address); - + const { getInputs } = useGetInputs(selectedWallet?.utxos ?? []); const [state, action] = useReducer(swapReducer, defaultState); useEffect(() => { @@ -239,15 +236,8 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => const create = useCallback(async () => { if (state.tokenInInput.tokenId === undefined || state.tokenOutInput.tokenId === undefined) return; - setIsCreateOrderLoading(true); - - const tokenInInfo = tokenInfos.get(state.tokenInInput.tokenId); - const quantityIn = - Number(state.tokenInInput.value) * - 10 ** (state.tokenInInput.tokenId === '.' ? primaryTokenInfo.decimals : tokenInInfo?.decimals); - const amountsIn = { [state.tokenInInput.tokenId]: String(quantityIn) }; - const inputs = await getInputs(amountsIn); + const inputs = await getInputs(); swapManager.api .create({ @@ -601,7 +591,7 @@ const defaultState: SwapState = Object.freeze({ }, tokenOutInput: { isTouched: true, - tokenId: undefined, + tokenId: USDA_TOKEN_ID, disabled: false, error: null, value: '', From 64d63f35a9a6d4fc5f5d060e10601c2205f1ef5f Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 12:25:38 +0300 Subject: [PATCH 21/34] update cancel order --- .../useCases/SwapOrders.tsx/SwapOrders.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx index c5051f9705..c46621d8b1 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx @@ -241,11 +241,17 @@ const OrderCancelation = ({ order }: { order: Swap.Order }) => { try { startLoadingTxReview(); try { - await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ - wallet, - transactionHex: cancelTxCbor, - password: passswordInput, - }); + const { signedTxHex: signedCancelTx } = await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ + wallet, + transactionHex: cancelTxCbor, + password: passswordInput, + }); + + const signedTransactionHexes: any = [signedCancelTx]; + await stores.substores.ada.swapStore.executeTransactionHexes({ + wallet, + signedTransactionHexes, + }); showTxResultModal(TransactionResult.SUCCESS); } catch (error) { From e66c03330c9a565441886a696da4813d49fac2fe Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 12:25:57 +0300 Subject: [PATCH 22/34] fix asset input --- .../swap-new/common/components/AssetInput.tsx | 28 +++++++------------ .../Modals/SettingsModalContent.tsx | 7 +++-- .../UI/features/swap-new/common/constants.ts | 1 + .../swap-new/common/hooks/useTokensInfo.ts | 4 --- .../swap-new/useCases/AssetSwap/AssetSwap.tsx | 2 +- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInput.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInput.tsx index 33482515cd..7b7a1deff7 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInput.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInput.tsx @@ -73,27 +73,18 @@ export const AssetInput: React.FC = ({ direction, onAssetSelect } const assetInputName = React.useMemo(() => { - if (direction === ASSET_DIRECTION_IN) { - return tokenInputInfo?.ticker ? tokenInputInfo?.name : primaryTokenInfo.name; + if (direction === ASSET_DIRECTION_OUT && !touched) { + return 'Select token'; } - if (direction === ASSET_DIRECTION_OUT) { - if (!touched) { - return 'Select token'; - } - return tokenInput.tokenId === '.' ? primaryTokenInfo.name : (tokenInputInfo?.ticker ?? tokenInputInfo?.name); - } - return undefined; - }, [direction, tokenInputInfo]); + + return tokenInput.tokenId === '.' || tokenInput.tokenId === '' + ? primaryTokenInfo.name + : (tokenInputInfo?.ticker ?? tokenInputInfo?.name); + }, [direction, tokenInputInfo, swapForm.tokenInInput.tokenId, swapForm.tokenOutInput.tokenId]); const AssetIdForIcon = React.useMemo(() => { - if (direction === ASSET_DIRECTION_IN) { - return tokenInput.tokenId ?? tokenInputInfo?.id; - } - if (direction === ASSET_DIRECTION_OUT) { - return tokenInput.tokenId === '.' ? primaryTokenInfo.id : tokenInputInfo?.id; - } - return undefined; - }, [direction, tokenInputInfo, tokenInput]); + return tokenInput.tokenId === '.' || tokenInput.tokenId === '' ? '.' : tokenInputInfo?.id; + }, [direction, tokenInputInfo, swapForm.tokenInInput.tokenId, swapForm.tokenOutInput.tokenId]); const focusInput = () => { if (inputRef?.current) { @@ -220,6 +211,7 @@ const Wrapper = styled(Box, { }`, backgroundColor: direction === ASSET_DIRECTION_IN ? 'transparent' : theme.palette.ds.bg_color_contrast_min, height: '132px', + width: '506px', '&:hover': { borderColor: !hasError && theme.palette.ds.el_gray_max, diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index cad43aba0e..f26e65a142 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -31,11 +31,14 @@ export const SettingsModalContent = () => { }; const applyChanges = async () => { - await swapForm.action({ type: SwapActionType.ProtocolSelected, value: routingPreference }); + await swapForm.action({ + type: SwapActionType.ProtocolSelected, + value: routingPreference === DEX_ROUTING.BOTH ? DEX_ROUTING.AUTO : routingPreference, + }); await swapForm.action({ type: SwapActionType.SlippageInputChanged, value: Number(selectedSlippage) }); await swapManager.assignSettings({ slippage: Number(selectedSlippage), - routingPreference: routingPreference, + routingPreference: routingPreference === DEX_ROUTING.BOTH ? DEX_ROUTING.AUTO : routingPreference, }); closeModal(); }; diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/constants.ts b/packages/yoroi-extension/app/UI/features/swap-new/common/constants.ts index 8f5a4f8857..a48e87fd7a 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/constants.ts +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/constants.ts @@ -11,6 +11,7 @@ export const MARKET_ORDER = 'market'; export const LIMIT_ORDER = 'limit'; export const undefinedToken: Portfolio.Token.Id = '.unknown'; +export const USDA_TOKEN_ID = 'fe7c786ab321f41c654ef6c1af7b3250a613c24e4213e0425a7ae456.55534441'; export const DEX_ROUTING = { AUTO: 'auto', diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useTokensInfo.ts b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useTokensInfo.ts index d86461d613..10537acf77 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useTokensInfo.ts +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useTokensInfo.ts @@ -22,10 +22,6 @@ export const useSyncedTokenInfos = ({ queryKey: ['syncedTokenInfos', networkId, primaryTokenInfo.id, ...excludedTokens], queryFn: async () => { - // Hardcoded muesliswap because dexhunter is broken at the moment - await swapManager.assignSettings({ - routingPreference: 'muesliswap', - }); const res = await swapManager.api.tokens(); if (!isRight(res)) return { tokenIds: [], tokenInfosArray: [] }; diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx index 9ce7c22d29..75ba1c6ca1 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx @@ -40,7 +40,7 @@ export const AssetSwap = () => { wallet, swapState: swapForm, }); - console.log('unisgnedTxRequest', unisgnedTxRequest); + try { await stores.transactionProcessingStore.adaSendAndRefresh({ wallet, From d48615bb4d235b59979a96d299b9a35b721b3198 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 14:35:26 +0300 Subject: [PATCH 23/34] fix crash on review inputs --- .../transaction-review/common/TokenItem.tsx | 14 +++++++++---- .../ReferenceInputs/ReferenceInputsTab.tsx | 5 ++++- .../useCases/ReviewTx/UTxOs/UTxOsTab.tsx | 20 +++++++++---------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/transaction-review/common/TokenItem.tsx b/packages/yoroi-extension/app/UI/features/transaction-review/common/TokenItem.tsx index 60fcc9ff0f..b0142ad839 100644 --- a/packages/yoroi-extension/app/UI/features/transaction-review/common/TokenItem.tsx +++ b/packages/yoroi-extension/app/UI/features/transaction-review/common/TokenItem.tsx @@ -39,15 +39,21 @@ const getTokenName = (tokenInfo: any): string => { export const TokenItem: React.FC = ({ isSent = true, isPrimary, tokenInfo, quantity }: TokenItemProps) => { const decimals = getDecimals(tokenInfo); const tokenName = getTokenName(tokenInfo); - const value = new BigNumber(quantity).shiftedBy(-decimals).toString(); if (isSent) { const primaryColor = isPrimary ? 'ds.white_static' : 'ds.text_primary_medium'; const primaryBackground = isPrimary ? 'ds.primary_500' : 'ds.primary_100'; return ( - + - {value} {tokenName} + {value} {tokenName || tokenInfo?.ticker} ); @@ -58,7 +64,7 @@ export const TokenItem: React.FC = ({ isSent = true, isPrimary, return ( - {value} {tokenName} + {value} {tokenName || tokenInfo?.ticker} ); diff --git a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/ReferenceInputs/ReferenceInputsTab.tsx b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/ReferenceInputs/ReferenceInputsTab.tsx index d299d19383..a8d2131a8d 100644 --- a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/ReferenceInputs/ReferenceInputsTab.tsx +++ b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/ReferenceInputs/ReferenceInputsTab.tsx @@ -4,7 +4,10 @@ import { Inputs } from '../UTxOs/UTxOsTab'; export const ReferenceInputsTab = ({ referenceInputs }) => { return ( - + ); }; diff --git a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx index 7cceeb0dd6..d9236f8c9f 100644 --- a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx +++ b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx @@ -17,8 +17,8 @@ interface Asset { // TODO Define the type for an individual input interface InputData { address: string; - txHash: string; - txIndex: number; + tx_hash: string; + tx_index: number; assets: Asset[]; } @@ -62,7 +62,7 @@ export const Inputs: React.FC = ({ inputs }) => { content={ {inputs.map(input => ( - + ))} } @@ -101,10 +101,10 @@ const Input: React.FC = ({ input }: any) => { if (!input.assets.length) return null; return input.assets.map(asset => ( )); }; @@ -127,14 +127,14 @@ const Input: React.FC = ({ input }: any) => { - {input.txHash} + {input.txHash || input.tx_hash} - {`#${input.txIndex}`} + {`#${input.txIndex || input.tx_index}`} - + From 87bf1eeb028f51af9dfe6d878458830b28e15046 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:11:35 +0300 Subject: [PATCH 24/34] Update packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx Co-authored-by: Amin Limbada --- .../swap-new/common/components/Modals/SettingsModalContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index cad43aba0e..4a6eed8c7a 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -35,7 +35,7 @@ export const SettingsModalContent = () => { await swapForm.action({ type: SwapActionType.SlippageInputChanged, value: Number(selectedSlippage) }); await swapManager.assignSettings({ slippage: Number(selectedSlippage), - routingPreference: routingPreference, + routingPreference, }); closeModal(); }; From 75792575bc33c4cb497a856fc915999fdb91518a Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:11:52 +0300 Subject: [PATCH 25/34] Update packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx Co-authored-by: Amin Limbada --- .../common/components/Modals/SettingsModalContent.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 4a6eed8c7a..6a8434b8f1 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -106,9 +106,7 @@ const RoutingPreference = ({ setRoutingPreference, routingPreference }) => { const autoSelected = routingPreference === DEX_ROUTING.AUTO; const dexHunter = - routingPreference === DEX_ROUTING.AUTO || - routingPreference === DEX_ROUTING.DEXHUNTER || - routingPreference === DEX_ROUTING.BOTH; +[DEX_ROUTING.AUTO,DEX_ROUTING.DEXHUNTER,DEX_ROUTING.BOTH].includes(routingPreference); const muesliswap = routingPreference === DEX_ROUTING.AUTO || routingPreference === DEX_ROUTING.MUESLISWAP || From f0fc8ca7e0cc6533169e9d35d407f0443674eb1d Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:12:43 +0300 Subject: [PATCH 26/34] removed unused code --- .../app/UI/features/swap-new/module/SwapContextProvider.tsx | 2 -- .../app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index c76a26d2a6..7d347dd066 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -50,8 +50,6 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => const { getInputs } = useGetInputs(selectedWallet?.utxos || []); - // const allUtxosAddresses = selectedWallet?.utxos.map(utxo => utxo.address); - const [state, action] = useReducer(swapReducer, defaultState); useEffect(() => { diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx index 9ce7c22d29..75ba1c6ca1 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/AssetSwap/AssetSwap.tsx @@ -40,7 +40,7 @@ export const AssetSwap = () => { wallet, swapState: swapForm, }); - console.log('unisgnedTxRequest', unisgnedTxRequest); + try { await stores.transactionProcessingStore.adaSendAndRefresh({ wallet, From 42eb0d1d94c03321252f866a07ec7fb5f427ef5d Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:14:19 +0300 Subject: [PATCH 27/34] add const --- .../app/UI/features/swap-new/module/SwapContextProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx index 7d347dd066..b5ac687130 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx @@ -133,11 +133,11 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) => useEffect(() => { const value = limitOptions?.defaultProtocol; if (value !== undefined && state.selectedProtocol.isTouched === false && state.selectedProtocol.value !== value) { - action({ type: 'ProtocolChanged', value }); + action({ type: SwapActionType.ProtocolChanged, value }); } else { const current = limitOptions?.options.find(p => p.protocol === state.selectedProtocol.value); if (current === undefined) { - action({ type: 'ProtocolChanged', value }); + action({ type: SwapActionType.ProtocolChanged, value }); } } From d6f8d4a2696b959b2a6d176495fae3bf3cf55aa9 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:30:09 +0300 Subject: [PATCH 28/34] refactor and extract to fnc --- .../Modals/SettingsModalContent.tsx | 19 ++++--------- .../UI/features/swap-new/common/helpers.ts | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index 6a8434b8f1..9e28858429 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -5,6 +5,7 @@ import { Switch } from '../../../../../components/Switch/Switch'; import { SwapActionType, useSwapRevamp } from '../../../module/SwapContextProvider'; import { useModal } from '../../../../../components/modals/ModalContext'; import { DEX_ROUTING } from '../../constants'; +import { sanitizeSlippageInput } from '../../helpers'; const defaultSlippages = ['0', '0.1', '0.5', '1', '2', '3', '5', '10']; @@ -105,8 +106,7 @@ const RoutingPreference = ({ setRoutingPreference, routingPreference }) => { const strings = useStrings(); const autoSelected = routingPreference === DEX_ROUTING.AUTO; - const dexHunter = -[DEX_ROUTING.AUTO,DEX_ROUTING.DEXHUNTER,DEX_ROUTING.BOTH].includes(routingPreference); + const dexHunter = [DEX_ROUTING.AUTO, DEX_ROUTING.DEXHUNTER, DEX_ROUTING.BOTH].includes(routingPreference); const muesliswap = routingPreference === DEX_ROUTING.AUTO || routingPreference === DEX_ROUTING.MUESLISWAP || @@ -199,18 +199,9 @@ const SlippageInput = ({ selectedSlippage, setSelectedSlippage, inputRef }) => { placeholder="0" value={selectedSlippage} onChange={e => { - let raw = e.target.value; - let clean = raw.replace(/[^0-9.]/g, ''); - const parts = clean.split('.'); - if (parts.length > 2) { - clean = parts[0] + '.' + parts[1]; - } - if (parts[1] && parts[1].length > 1) { - clean = parts[0] + '.' + parts[1].slice(0, 1); - } - if (clean !== '' && Number(clean) > 75) return; - - setSelectedSlippage(clean); + const next = sanitizeSlippageInput(e.target.value, { max: 75, maxDecimals: 1 }); + if (next === null) return; + setSelectedSlippage(next); }} style={{ border: 'none', diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts b/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts index 83167b8cab..f884fa4669 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts @@ -86,3 +86,30 @@ export const useGetInputs = (walletUtxos: any[]) => { return { getInputs }; }; + +export function sanitizeSlippageInput( + raw: string, + { max = 75, maxDecimals = 1 }: { max?: number; maxDecimals?: number } = {} +): string | null { + let clean = (raw ?? '').replace(/[^0-9.]/g, ''); + + // keep only the first dot + let parts = clean.split('.'); + if (parts.length > 2) { + clean = `${parts[0]}.${parts[1]}`; + parts = clean.split('.'); // re-split after modifying + } + + // limit decimals + const decimals = parts[1] ?? ''; + if (decimals.length > maxDecimals) { + clean = `${parts[0]}.${decimals.slice(0, maxDecimals)}`; + } + + // enforce max (ignore change if over) + if (clean !== '' && !Number.isNaN(Number(clean)) && Number(clean) > max) { + return null; + } + + return clean; +} \ No newline at end of file From 1799ae562e8050f5367696820961848281a67037 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:31:50 +0300 Subject: [PATCH 29/34] add string --- .../features/swap-new/common/components/AssetInfoInRow.tsx | 4 +++- .../app/UI/features/swap-new/common/hooks/useStrings.tsx | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx index 4b2d14902c..4fb03c9978 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInfoInRow.tsx @@ -9,6 +9,7 @@ import TokenInfoModal from './Modals/TokenInfoModal'; import { AssetDirectionType } from '../types'; import { ASSET_DIRECTION_IN } from '../constants'; import { SelectAssetTo } from './Modals/SelectAssetTo'; +import { useStrings } from '../hooks/useStrings'; interface AssetInfoInRowProps { token: any; @@ -35,6 +36,7 @@ export const AssetInfoInRow = React.memo( direction, }: AssetInfoInRowProps) => { const { atoms }: any = useTheme(); + const strings = useStrings(); const isPrimary = token.id === '-' || token.id === ''; const tokenPrice = secondaryToken24Activity?.[1]?.price?.close ?? 1; const decimals = isPrimary ? primaryTokenInfo.decimals : token.decimals; @@ -62,7 +64,7 @@ export const AssetInfoInRow = React.memo( width: '612px', handleBack: () => { openModal({ - title: `SWAP TO`, + title: strings.swapToLabel, content: , height: '624px', width: '612px', diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx index 4fb89d6f3e..9ef3fc9b5a 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useStrings.tsx @@ -63,6 +63,10 @@ export const messages = Object.freeze( id: 'swap.slippage', defaultMessage: '!!!Slippage', }, + swapToLabel: { + id: 'swap.swapToLabel', + defaultMessage: '!!!Swap to', + }, slippageInfo: { id: 'swap.slippageInfo', defaultMessage: @@ -205,6 +209,7 @@ export const useStrings = () => { ordersCompletedLabel: intl.formatMessage(messages.ordersCompletedLabel), openOrdersLabel: intl.formatMessage(messages.openOrdersLabel), cancel: intl.formatMessage(messages.cancel), + swapToLabel: intl.formatMessage(messages.swapToLabel), numYourAssets: num => intl.formatMessage(messages.numYourAssets, { num }), }).current; }; From 47df64dc62d277b239bcee89ed18269ab5d3f336 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:32:48 +0300 Subject: [PATCH 30/34] fix format --- .../yoroi-extension/app/UI/features/swap-new/common/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts b/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts index f884fa4669..633075c279 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts @@ -112,4 +112,4 @@ export function sanitizeSlippageInput( } return clean; -} \ No newline at end of file +} From c796e13258057fe06014f406d6d53165a943168b Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 30 Sep 2025 15:52:46 +0300 Subject: [PATCH 31/34] fix close bracket --- .../swap-new/common/components/Modals/SettingsModalContent.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx index e3f967f843..a77adfb3cc 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx @@ -40,6 +40,7 @@ export const SettingsModalContent = () => { await swapManager.assignSettings({ slippage: Number(selectedSlippage), routingPreference: routingPreference === DEX_ROUTING.BOTH ? DEX_ROUTING.AUTO : routingPreference, + }); closeModal(); }; From 0c9f3538e36721300ed5189d8cfc35628157080d Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Fri, 3 Oct 2025 15:21:07 +0200 Subject: [PATCH 32/34] update address on receiver --- .../common/hooks/useFormattedTx.tsx | 2 +- .../useCases/ReviewTx/UTxOs/UTxOsTab.tsx | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/transaction-review/common/hooks/useFormattedTx.tsx b/packages/yoroi-extension/app/UI/features/transaction-review/common/hooks/useFormattedTx.tsx index 654301d715..f4e238de81 100644 --- a/packages/yoroi-extension/app/UI/features/transaction-review/common/hooks/useFormattedTx.tsx +++ b/packages/yoroi-extension/app/UI/features/transaction-review/common/hooks/useFormattedTx.tsx @@ -41,7 +41,7 @@ export const useFormattedTx = (data: TransactionBody): FormattedTx => { const formatInputs = (inputUtxos, allAssetList, networkId, primaryTokenInfo, walletAddresses): any => { return inputUtxos.map(utxo => { - const address = utxo?.receiver; + const address = utxo?.receiver || utxo?.address; const { resolvedAddress, paymentCredKind } = resolveAddress(address); const rewardAddress = address !== null && paymentCredKind === CredKind.Key ? deriveAddress(address, networkId) : null; diff --git a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx index d9236f8c9f..03ea711df5 100644 --- a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx +++ b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx @@ -17,8 +17,10 @@ interface Asset { // TODO Define the type for an individual input interface InputData { address: string; - tx_hash: string; - tx_index: number; + tx_hash?: string; + tx_index?: number; + txHash?: string; + txIndex?: number; assets: Asset[]; } @@ -38,7 +40,7 @@ interface OutputProps { export const UTxOsTab: any = ({ tx }) => { const { primaryTokenInfo } = useTxReviewModal(); - + console.log('tx in UTxOsTab', tx); return ( @@ -62,7 +64,7 @@ export const Inputs: React.FC = ({ inputs }) => { content={ {inputs.map(input => ( - + ))} } @@ -101,7 +103,7 @@ const Input: React.FC = ({ input }: any) => { if (!input.assets.length) return null; return input.assets.map(asset => ( = ({ input }: any) => { - {`#${input.txIndex || input.tx_index}`} + {`#${input?.txIndex ?? input?.tx_index}`} From ff988a8972df56cafdcc50739ca63a85e408f237 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Fri, 3 Oct 2025 15:33:20 +0200 Subject: [PATCH 33/34] remove console.log --- .../transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx index 03ea711df5..ab81e61d3b 100644 --- a/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx +++ b/packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/UTxOs/UTxOsTab.tsx @@ -40,7 +40,6 @@ interface OutputProps { export const UTxOsTab: any = ({ tx }) => { const { primaryTokenInfo } = useTxReviewModal(); - console.log('tx in UTxOsTab', tx); return ( From e1bf1f0e17baf6fa323ad45c78d40893e6cae672 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Mon, 6 Oct 2025 19:07:34 +0300 Subject: [PATCH 34/34] fix format, update package --- .../useCases/SwapOrders.tsx/SwapOrders.tsx | 20 +++++++++---------- packages/yoroi-extension/package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx index c46621d8b1..52ba64f39d 100644 --- a/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx +++ b/packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx @@ -241,17 +241,17 @@ const OrderCancelation = ({ order }: { order: Swap.Order }) => { try { startLoadingTxReview(); try { - const { signedTxHex: signedCancelTx } = await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ - wallet, - transactionHex: cancelTxCbor, - password: passswordInput, - }); + const { signedTxHex: signedCancelTx } = await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({ + wallet, + transactionHex: cancelTxCbor, + password: passswordInput, + }); - const signedTransactionHexes: any = [signedCancelTx]; - await stores.substores.ada.swapStore.executeTransactionHexes({ - wallet, - signedTransactionHexes, - }); + const signedTransactionHexes: any = [signedCancelTx]; + await stores.substores.ada.swapStore.executeTransactionHexes({ + wallet, + signedTransactionHexes, + }); showTxResultModal(TransactionResult.SUCCESS); } catch (error) { diff --git a/packages/yoroi-extension/package.json b/packages/yoroi-extension/package.json index ebf70a5752..d0eb75a60b 100644 --- a/packages/yoroi-extension/package.json +++ b/packages/yoroi-extension/package.json @@ -169,7 +169,7 @@ "@yoroi/portfolio": "1.0.3", "@yoroi/resolver": "2.0.2", "@yoroi/staking": "^1.6.0", - "@yoroi/swap": "6.0.2", + "@yoroi/swap": "7.0.0", "@yoroi/types": "6.0.0", "assert": "2.1.0", "async-await-queue": "2.1.4",