From 413d8e5168bc0b0e64012856f0e8a00388473e82 Mon Sep 17 00:00:00 2001 From: Sven Date: Wed, 12 Feb 2025 10:42:56 +0800 Subject: [PATCH] fix bug & opt dex (#3303) * fix bugs * fix bug * hide swap v2 --- .../src/layouts/config-nav-dashboard.tsx | 14 +- .../trade/components/select-token-pair.tsx | 142 ++--- .../sections/trade/components/token-pair.tsx | 6 +- .../src/sections/trade/components/types.ts | 9 +- .../sections/trade/hooks/use-all-liquidity.ts | 1 - .../trade/hooks/use-owner-liquidity.ts | 2 + .../sections/trade/hooks/use-token-pair.ts | 99 ++++ .../liquidity/list/all_liquidity_list.tsx | 7 +- .../trade/liquidity/list/farm-row-item.tsx | 55 +- .../trade/liquidity/list/farm_list.tsx | 70 +-- .../list/owner-liquidity-row-item.tsx | 4 +- .../liquidity/list/owner_liquidity_list.tsx | 2 +- .../sections/trade/swap-v2/confirm-modal.tsx | 245 ++++---- .../src/sections/trade/swap-v2/view.tsx | 553 +++++++++--------- .../src/sections/trade/swap/confirm-modal.tsx | 10 +- .../src/sections/trade/swap/view.tsx | 5 +- infra/rooch-portal-v2/src/utils/number.ts | 4 +- 17 files changed, 637 insertions(+), 591 deletions(-) create mode 100644 infra/rooch-portal-v2/src/sections/trade/hooks/use-token-pair.ts diff --git a/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx b/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx index 8da026fc12..a157d96c66 100644 --- a/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx +++ b/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx @@ -70,18 +70,18 @@ export const navData = [ noAddressRequired: true, }, // temporary disable swap, when the swap v2 is all good, will remove this path - // { - // title: 'Swap', - // path: paths.dashboard.swap, - // icon: , - // noAddressRequired: true, - // }, { title: 'Swap', - path: paths.dashboard['swap-v2'], + path: paths.dashboard.swap, icon: , noAddressRequired: true, }, + // { + // title: 'Swap', + // path: paths.dashboard['swap-v2'], + // icon: , + // noAddressRequired: true, + // }, ], }, /** diff --git a/infra/rooch-portal-v2/src/sections/trade/components/select-token-pair.tsx b/infra/rooch-portal-v2/src/sections/trade/components/select-token-pair.tsx index d077a5cae8..d97255b710 100644 --- a/infra/rooch-portal-v2/src/sections/trade/components/select-token-pair.tsx +++ b/infra/rooch-portal-v2/src/sections/trade/components/select-token-pair.tsx @@ -19,10 +19,9 @@ import { toDust, fromDust, formatByIntl } from 'src/utils/number'; import { toast } from 'src/components/snackbar'; -import type { TradeCoinType } from './types'; +import { useTokenPair } from '../hooks/use-token-pair'; type TokenType = { - id: string; type: string; name: string; }; @@ -35,27 +34,29 @@ type TokenPairType = { interface SelectTokenPairProps { onLoading: (status: boolean) => void; - onCallback: (x?: TradeCoinType, y?: TradeCoinType) => void; + onCallback: ( + x?: { amount: string } & BalanceInfoView, + y?: { amount: string } & BalanceInfoView + ) => void; } export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPairProps) { const client = useRoochClient(); const dex = useNetworkVariable('dex'); const currentAddress = useCurrentAddress(); + const { tokenPairs } = useTokenPair(); const [loading, setLoading] = useState(false); - const [x, setX] = useState(); + const [x, setX] = useState(); const [xValue, setXValue] = useState(''); const [xCount, setXCount] = useState(''); const [xRatio, setXRation] = useState(0); - const [y, setY] = useState(); + const [y, setY] = useState(); const [x2y, setX2y] = useState(true); const [yValue, setYValue] = useState(''); const [yCount, setYCount] = useState(''); - // map - const [tokenPair, setTokenPair] = useState>(); - const { data } = useRoochClientQuery( + const { data: balances } = useRoochClientQuery( 'getBalances', { owner: currentAddress?.toStr() || '', @@ -68,69 +69,13 @@ export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPa // map const assetsMap = useMemo(() => { const assetsMap = new Map(); - data?.data.forEach((i) => { + balances?.data.forEach((i) => { assetsMap.set(i.coin_type, { ...i, }); }); return assetsMap; - }, [data]); - - useEffect(() => { - client - .queryObjectStates({ - filter: { - object_type: `${dex.address}::swap::TokenPair`, - }, - }) - .then((result) => { - const pair: TokenPairType[] = result.data.map((item) => { - const xView = item.decoded_value!.value.balance_x as AnnotatedMoveStructView; - let xType = xView.type.replace('0x2::object::Object<0x3::coin_store::CoinStore<', ''); - xType = xType.replace('>>', ''); - const xName = xType.split('::'); - const yView = item.decoded_value!.value.balance_y as AnnotatedMoveStructView; - let yType = yView.type.replace('0x2::object::Object<0x3::coin_store::CoinStore<', ''); - yType = yType.replace('>>', ''); - const yName = yType.split('::'); - return { - x2y: true, - x: { - id: xView.value.id as string, - type: xType, - name: xName[xName.length - 1].replace('>>', ''), - }, - y: { - id: yView.value.id as string, - type: yType, - name: yName[yName.length - 1].replace('>>', ''), - }, - }; - }); - - const pairMap = new Map(); - pair.forEach((p) => { - const key = p.x.name; - if (!pairMap.has(key)) { - pairMap.set(key, []); - } - pairMap.get(key)!.push(p); - - const key1 = p.y.name; - if (!pairMap.has(key1)) { - pairMap.set(key1, []); - } - pairMap.get(key1)!.push({ - x2y: false, - x: p.y, - y: p.x, - }); - }); - - // Update the state - setTokenPair(pairMap); - }); - }, [client, dex]); + }, [balances]); const fetchY = useCallback(async () => { if (xCount === '' || xCount === '0' || !x || !y) { @@ -139,11 +84,14 @@ export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPa try { setLoading(true); - const fixdXCount = toDust(xCount.replaceAll(',', ''), assetsMap?.get(x.type)?.decimals || 0); + const fixdXCount = toDust( + xCount.replaceAll(',', ''), + assetsMap?.get(x.coin_type)?.decimals || 0 + ); const result = await client.executeViewFunction({ target: `${dex.address}::router::get_amount_out`, args: [Args.u64(fixdXCount)], - typeArgs: [x.type, y.type], + typeArgs: [x.coin_type, y.coin_type], }); if (result.vm_status !== 'Executed') { @@ -151,27 +99,19 @@ export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPa } const yCount = result.return_values![0].decoded_value as string; - const fixdYCount = fromDust(yCount, assetsMap?.get(y.type)?.decimals || 0); + const fixdYCount = fromDust(yCount, assetsMap?.get(y.coin_type)?.decimals || 0); setYCount(formatByIntl(fixdYCount.toString())); - const xCoin = assetsMap?.get(x.type)!; - const yCoin = assetsMap?.get(y.type); + const xCoin = assetsMap?.get(x.coin_type)!; + const yCoin = assetsMap?.get(y.coin_type); onCallback( { - balance: xCoin.fixedBalance, - type: xCoin.coin_type, - icon: xCoin.icon_url || undefined, - symbol: xCoin.symbol, + ...x, amount: xCount.replaceAll(',', ''), - decimal: xCoin.decimals, }, { - balance: yCoin?.fixedBalance || 0, - type: yCoin?.coin_type || y.type, - icon: yCoin?.icon_url || undefined, - symbol: yCoin?.symbol || y.name, + ...y, amount: fixdYCount.toString(), - decimal: yCoin?.decimals || 0, // TODO: fix } ); } catch (e) { @@ -203,7 +143,7 @@ export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPa setY(oldX); setYValue(oldXValue); - const xbalance = assetsMap?.get(oldY.type)!.fixedBalance || 0; + const xbalance = assetsMap?.get(oldY.coin_type)!.fixedBalance || 0; if (xRatio !== 0) { setXCount(formatByIntl(xbalance * xRatio)); } else if (Number(xCount) > xbalance) { @@ -227,22 +167,24 @@ export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPa label="X" onChange={(e: SelectChangeEvent) => { const s = e.target.value; - const {x} = tokenPair!.get(s)![0]; + const x = tokenPairs!.get(s)?.x; setX(x); setXValue(e.target.value); setY(undefined); setYValue(''); setYCount(''); if (xRatio !== 0) { - setXCount(((assetsMap?.get(x!.type)!.fixedBalance || 0) * xRatio).toString()); + setXCount(formatByIntl((assetsMap?.get(x!.coin_type)?.fixedBalance || 0) * xRatio)); } }} > - {tokenPair && - [...tokenPair.entries()].map(([key, pairs]) => ( + {tokenPairs && + [...tokenPairs.entries()].map(([key, pairs]) => ( {key} : - {formatByIntl(assetsMap?.get(pairs[0].x.type)?.fixedBalance || 0)} + + {formatByIntl(assetsMap?.get(pairs.x.coin_type)?.fixedBalance || 0, '0')} + ))} @@ -260,7 +202,7 @@ export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPa if (/^\d*\.?\d*$/.test(value) === false) { return; } - const xBalance = assetsMap?.get(x!.type)!.fixedBalance || 0; + const xBalance = assetsMap?.get(x!.coin_type)!.fixedBalance || 0; if (xRatio !== 0) { if (value !== (xBalance * xRatio).toString()) { setXRation(0); @@ -281,7 +223,7 @@ export default function SelectTokenPair({ onLoading, onCallback }: SelectTokenPa - {[0.25, 0.5, 0.75, x?.name === 'RGas' ? 0.99 : 1].map((item, index) => ( + {[0.25, 0.5, 0.75, x?.symbol === 'RGAS' ? 0.99 : 1].map((item, index) => ( + + + Staked LP:{' '} + {formatByIntl(fromDust(staked, coinInfo?.decimals || 0).toString())} + + + diff --git a/infra/rooch-portal-v2/src/sections/trade/liquidity/list/farm_list.tsx b/infra/rooch-portal-v2/src/sections/trade/liquidity/list/farm_list.tsx index f580c8bdd4..655dc1b881 100644 --- a/infra/rooch-portal-v2/src/sections/trade/liquidity/list/farm_list.tsx +++ b/infra/rooch-portal-v2/src/sections/trade/liquidity/list/farm_list.tsx @@ -1,5 +1,5 @@ import { useMemo, useState } from 'react'; -import { useRoochClientQuery } from '@roochnetwork/rooch-sdk-kit'; +import { useCurrentAddress, useRoochClientQuery } from '@roochnetwork/rooch-sdk-kit'; import { Card, Table, TableBody } from '@mui/material'; @@ -11,7 +11,7 @@ import TableSkeleton from 'src/components/skeleton/table-skeleton'; import { TableNoData, TableHeadCustom } from 'src/components/table'; import FarmRowItem from './farm-row-item'; -import AddStakeModal from './add-stake-modal'; +import AddSrakeModal from './add-stake-modal'; import AddLiquidityModal from './add-liquidity-modal'; import { useAllLiquidity } from '../../hooks/use-all-liquidity'; import { useOwnerLiquidity } from '../../hooks/use-owner-liquidity'; @@ -19,8 +19,7 @@ import { useOwnerLiquidity } from '../../hooks/use-owner-liquidity'; import type { FarmRowItemType } from './farm-row-item'; const headerLabel = [ - { id: 'lp', label: 'LP', maxWidth: 100 }, - { id: 'harvest_index', label: 'Harvest Index' }, + { id: 'lp', label: 'LP' }, { id: 'release_per_second', label: 'Release Per Second' }, { id: 'asset_total_weight', label: 'Asset Total Weight' }, { id: 'endtime', label: 'Endtime' }, @@ -28,6 +27,7 @@ const headerLabel = [ ]; export default function FarmList() { + const currentAddress = useCurrentAddress(); const dex = useNetworkVariable('dex'); const [openStakeModal, setOpenStakeModal] = useState(false); const [openAddLiquidityModal, setOpenAddLiquidityModal] = useState(false); @@ -41,37 +41,41 @@ export default function FarmList() { }, }); + console.log(farms); + const resolvedFarms = useMemo(() => { if (!farms) { return []; } - return farms.data.map((item) => { - const view = item.decoded_value!.value; - const types = item.object_type - .replace(`${dex.address}::liquidity_incentive::FarmingAsset<`, '') - .trim() - .split(','); - const x = { - type: types[0].trim(), - name: types[0].split('::')[2].trim(), - }; - const y = { - type: types[1].trim(), - name: types[1].split('::')[2].trim(), - }; - return { - id: item.id, - alive: view.alive as boolean, - endtime: view.end_time as number, - assetTotalWeight: view.asset_total_weight as number, - harvestIndex: view.harvest_index as number, - releasePerSecond: view.release_per_second as number, - x, - y, - reward: types[2].replaceAll('>', '').trim(), - liquidity: lpTokens.find((item) => item.x.type === x.type && item.y.type === y.type), - }; - }); + const now = Date.now() / 1000; + return farms.data + .map((item) => { + const view = item.decoded_value!.value; + const types = item.object_type + .replace(`${dex.address}::liquidity_incentive::FarmingAsset<`, '') + .trim() + .split(','); + const x = { + type: types[0].trim(), + name: types[0].split('::')[2].trim(), + }; + const y = { + type: types[1].trim(), + name: types[1].split('::')[2].trim(), + }; + return { + id: item.id, + alive: view.alive as boolean, + endtime: view.end_time as number, + assetTotalWeight: view.asset_total_weight as number, + releasePerSecond: view.release_per_second as number, + x, + y, + reward: types[2].replaceAll('>', '').trim(), + liquidity: lpTokens.find((item) => item.x.type === x.type && item.y.type === y.type), + }; + }) + .filter((item) => item.endtime > now); }, [farms, lpTokens, dex.address]); const handleOpenStakeModal = (row: FarmRowItemType) => { @@ -115,7 +119,7 @@ export default function FarmList() { selectRow={selectedRow} /> ))} - + )} @@ -123,7 +127,7 @@ export default function FarmList() { {selectedRow && ( - - + diff --git a/infra/rooch-portal-v2/src/sections/trade/liquidity/list/owner_liquidity_list.tsx b/infra/rooch-portal-v2/src/sections/trade/liquidity/list/owner_liquidity_list.tsx index 00f0731e7a..08b5acd8b8 100644 --- a/infra/rooch-portal-v2/src/sections/trade/liquidity/list/owner_liquidity_list.tsx +++ b/infra/rooch-portal-v2/src/sections/trade/liquidity/list/owner_liquidity_list.tsx @@ -72,7 +72,7 @@ export default function OwnerLiquidityList() { onOpenRemoveModal={handleRemoveModal} /> ))} - + )} diff --git a/infra/rooch-portal-v2/src/sections/trade/swap-v2/confirm-modal.tsx b/infra/rooch-portal-v2/src/sections/trade/swap-v2/confirm-modal.tsx index ee54a22e7a..a89d8f8a62 100644 --- a/infra/rooch-portal-v2/src/sections/trade/swap-v2/confirm-modal.tsx +++ b/infra/rooch-portal-v2/src/sections/trade/swap-v2/confirm-modal.tsx @@ -38,133 +38,134 @@ export default function SwapConfirmModal({ toCoin: TradeCoinType; slippage: number; }) { - const dex = useNetworkVariable('dex'); - const { mutateAsync, isPending } = useSignAndExecuteTransaction(); + return <>; + // const dex = useNetworkVariable('dex'); + // const { mutateAsync, isPending } = useSignAndExecuteTransaction(); - const handleSwap = () => { - console.log(fromCoin, toCoin); - if (!fromCoin || !toCoin) { - return; - } - const tx = new Transaction(); - const fixedFromCoinAmount = toDust(fromCoin.amount, fromCoin.decimal); - const fixedToCoinAmount = toDust(toCoin.amount, toCoin.decimal); + // const handleSwap = () => { + // console.log(fromCoin, toCoin); + // if (!fromCoin || !toCoin) { + // return; + // } + // const tx = new Transaction(); + // const fixedFromCoinAmount = toDust(fromCoin.amount, fromCoin.decimal); + // const fixedToCoinAmount = toDust(toCoin.amount, toCoin.decimal); - const finalToCoinAmount = - slippage !== 0 - ? bigNumberToBigInt( - BigNumber(fixedToCoinAmount.toString()).minus( - BigNumber(fixedToCoinAmount.toString()).multipliedBy(BigNumber(slippage)) - ) - ) - : fixedToCoinAmount; - tx.callFunction({ - target: `${dex.address}::router::swap_with_exact_input`, - args: [Args.u64(fixedFromCoinAmount), Args.u64(finalToCoinAmount)], - typeArgs: [fromCoin.type, toCoin.type], - }); + // const finalToCoinAmount = + // slippage !== 0 + // ? bigNumberToBigInt( + // BigNumber(fixedToCoinAmount.toString()).minus( + // BigNumber(fixedToCoinAmount.toString()).multipliedBy(BigNumber(slippage)) + // ) + // ) + // : fixedToCoinAmount; + // tx.callFunction({ + // target: `${dex.address}::router::swap_with_exact_input`, + // args: [Args.u64(fixedFromCoinAmount), Args.u64(finalToCoinAmount)], + // typeArgs: [fromCoin.type, toCoin.type], + // }); - mutateAsync({ transaction: tx }) - .then((result) => { - if (result.execution_info.status.type === 'executed') { - toast.success('swap success'); - } else { - toast.error('swap failed'); - } - }) - .catch((e: any) => { - console.log(e); - toast.error('swap failed'); - }) - .finally(() => { - onClose(); - }); - }; + // mutateAsync({ transaction: tx }) + // .then((result) => { + // if (result.execution_info.status.type === 'executed') { + // toast.success('swap success'); + // } else { + // toast.error('swap failed'); + // } + // }) + // .catch((e: any) => { + // console.log(e); + // toast.error('swap failed'); + // }) + // .finally(() => { + // onClose(); + // }); + // }; - return ( - - Swap Confirm + // return ( + // + // Swap Confirm - - - - - - - - - - {' '} - - {fNumber(fromCoin.amount, { maximumFractionDigits: 16 })} - {` ${fromCoin.symbol} `} - - - - - - {' '} - + {fNumber(toCoin.amount, { maximumFractionDigits: 16 })} - {` ${toCoin.symbol} `} - - - - - Price : - - 1 {fromCoin.symbol} ≈{' '} - {fNumber(BigNumber(toCoin.amount).div(fromCoin.amount).toString(), { - maximumFractionDigits: 8, - })} - {toCoin.symbol} - - - - Slippage : - {slippage * 100}% - - - - - + // + // + // + // + // + // + // + // + // + // {' '} + // - {fNumber(fromCoin.amount, { maximumFractionDigits: 16 })} + // {` ${fromCoin.symbol} `} + // + // + // + // + // + // {' '} + // + {fNumber(toCoin.amount, { maximumFractionDigits: 16 })} + // {` ${toCoin.symbol} `} + // + // + // + // + // Price : + // + // 1 {fromCoin.symbol} ≈{' '} + // {fNumber(BigNumber(toCoin.amount).div(fromCoin.amount).toString(), { + // maximumFractionDigits: 8, + // })} + // {toCoin.symbol} + // + // + // + // Slippage : + // {slippage * 100}% + // + // + // + // + // - - + // + // - - - Confirm - - - - - ); + // + // + // Confirm + // + // + // + // + // ); } diff --git a/infra/rooch-portal-v2/src/sections/trade/swap-v2/view.tsx b/infra/rooch-portal-v2/src/sections/trade/swap-v2/view.tsx index 4959d0f340..91d90535ae 100644 --- a/infra/rooch-portal-v2/src/sections/trade/swap-v2/view.tsx +++ b/infra/rooch-portal-v2/src/sections/trade/swap-v2/view.tsx @@ -1,298 +1,281 @@ 'use client'; -import type { CurveType, PoolVersion, InteractiveMode } from 'src/components/swap/types'; +// import type { CurveType, PoolVersion, InteractiveMode } from 'src/components/swap/types'; -import BigNumber from 'bignumber.js'; -import { useMemo, useState, useEffect, useCallback } from 'react'; -import { Args, type BalanceInfoView, type AnnotatedMoveStructView } from '@roochnetwork/rooch-sdk'; -import { - useRoochClient, - useCurrentAddress, - useRoochClientQuery, -} from '@roochnetwork/rooch-sdk-kit'; +// import BigNumber from 'bignumber.js'; +// import { useMemo, useState, useEffect, useCallback } from 'react'; +// import { Args, type BalanceInfoView, type AnnotatedMoveStructView } from '@roochnetwork/rooch-sdk'; +// import { +// useRoochClient, +// useCurrentAddress, +// useRoochClientQuery, +// } from '@roochnetwork/rooch-sdk-kit'; -import { useNetworkVariable } from 'src/hooks/use-networks'; +// import { useNetworkVariable } from 'src/hooks/use-networks'; -import { toDust, fromDust } from 'src/utils/number'; +// import { toDust, fromDust } from 'src/utils/number'; -import { DashboardContent } from 'src/layouts/dashboard'; +// import { DashboardContent } from 'src/layouts/dashboard'; -import Swap from 'src/components/swap/swap'; -import { toast } from 'src/components/snackbar'; +// import Swap from 'src/components/swap/swap'; +// import { toast } from 'src/components/snackbar'; -import SwapConfirmModal from './confirm-modal'; +// import SwapConfirmModal from './confirm-modal'; -type TokenType = { - id: string; - type: string; - name: string; -}; +// type TokenType = { +// id: string; +// type: string; +// name: string; +// }; -type TokenPairType = { - x2y: boolean; - x: TokenType; - y: TokenType; -}; +// type TokenPairType = { +// x2y: boolean; +// x: TokenType; +// y: TokenType; +// }; export default function SwapView() { - const dex = useNetworkVariable('dex'); - const client = useRoochClient(); - const currentAddress = useCurrentAddress(); - - const [loading, setLoading] = useState(false); - const [curve, setCurve] = useState('uncorrelated'); - const [version, setVersion] = useState(0); - const [slippage, setSlippage] = useState(0.005); - const [openSwapModal, setOpenSwapModal] = useState(false); - const [price, setPrice] = useState(''); - - const [interactiveMode, setInteractiveMode] = useState('from'); - - const [fromCoinType, setFromCoinType] = useState(); - const [toCoinType, setToCoinType] = useState(); - const [fromCoinAmount, setFromCoinAmount] = useState('0'); - const [toCoinAmount, setToCoinAmount] = useState(''); - - const { data: userBalances } = useRoochClientQuery( - 'getBalances', - { - owner: currentAddress?.toStr() || '', - }, - { - refetchInterval: 5000, - } - ); - - const assetsMap = useMemo(() => { - const assetsMap = new Map(); - userBalances?.data.forEach((i) => { - assetsMap.set(i.coin_type, { - ...i, - }); - }); - return assetsMap; - }, [userBalances]); - - useEffect(() => { - client - .queryObjectStates({ - filter: { - object_type: `${dex.address}::swap::TokenPair`, - }, - }) - .then((result) => { - const pair: TokenPairType[] = result.data.map((item) => { - const xView = item.decoded_value!.value.balance_x as AnnotatedMoveStructView; - let xType = xView.type.replace('0x2::object::Object<0x3::coin_store::CoinStore<', ''); - xType = xType.replace('>>', ''); - const xName = xType.split('::'); - const yView = item.decoded_value!.value.balance_y as AnnotatedMoveStructView; - let yType = yView.type.replace('0x2::object::Object<0x3::coin_store::CoinStore<', ''); - yType = yType.replace('>>', ''); - const yName = yType.split('::'); - return { - x2y: true, - x: { - id: xView.value.id as string, - type: xType, - name: xName[xName.length - 1].replace('>>', ''), - }, - y: { - id: yView.value.id as string, - type: yType, - name: yName[yName.length - 1].replace('>>', ''), - }, - }; - }); - - const pairMap = new Map(); - pair.forEach((p) => { - const key = p.x.name; - if (!pairMap.has(key)) { - pairMap.set(key, []); - } - pairMap.get(key)!.push(p); - - const key1 = p.y.name; - if (!pairMap.has(key1)) { - pairMap.set(key1, []); - } - pairMap.get(key1)!.push({ - x2y: false, - x: p.y, - y: p.x, - }); - }); - }); - }, [client, dex]); - - const fromCoinInfo = assetsMap.get(fromCoinType as string); - const toCoinInfo = assetsMap.get(toCoinType as string); - - const fromCoin = useMemo( - () => ({ - ...fromCoinInfo, - balance: BigInt(fromCoinInfo?.balance || 0), - amount: BigInt(toDust(fromCoinAmount.toString(), fromCoinInfo?.decimals || 0)), - coinType: fromCoinInfo?.coin_type || '', - decimals: fromCoinInfo?.decimals || 0, - icon: `data:image/svg+xml;utf8,${encodeURIComponent(fromCoinInfo?.icon_url || '')}` || '', - iconUrl: `data:image/svg+xml;utf8,${encodeURIComponent(fromCoinInfo?.icon_url || '')}` || '', - name: fromCoinInfo?.name || '', - symbol: fromCoinInfo?.symbol || '', - price: 0, - }), - [fromCoinAmount, fromCoinInfo] - ); - - const toCoin = useMemo( - () => ({ - ...toCoinInfo, - balance: BigInt(toCoinInfo?.balance || 0), - amount: BigInt(toDust(toCoinAmount.toString(), toCoinInfo?.decimals || 0)), - coinType: toCoinInfo?.coin_type || '', - decimals: toCoinInfo?.decimals || 0, - icon: `data:image/svg+xml;utf8,${encodeURIComponent(toCoinInfo?.icon_url || '')}` || '', - iconUrl: `data:image/svg+xml;utf8,${encodeURIComponent(toCoinInfo?.icon_url || '')}` || '', - name: toCoinInfo?.name || '', - symbol: toCoinInfo?.symbol || '', - price: 0, - }), - [toCoinAmount, toCoinInfo] - ); - - const fetchToCoin = useCallback(async () => { - if ( - fromCoinAmount === '0' || - fromCoinAmount === '' || - !fromCoin || - !toCoin || - !fromCoin.coinType || - !toCoin.coinType - ) { - return; - } - - try { - setLoading(true); - const fixedFromCoinAmount = toDust( - fromCoinAmount.toString().replaceAll(',', ''), - assetsMap?.get(fromCoin.coinType)?.decimals || 0 - ); - const result = await client.executeViewFunction({ - target: `${dex.address}::router::get_amount_out`, - args: [Args.u64(fixedFromCoinAmount)], - typeArgs: [fromCoin.coinType, toCoin.coinType], - }); - - if (result.vm_status !== 'Executed') { - toast.error('unknown error'); - } - - const toCoinAmount = result.return_values![0].decoded_value as string; - const fixedToCoinAmount = fromDust( - toCoinAmount, - assetsMap?.get(toCoin.coinType)?.decimals || 0 - ); - const ratio = BigNumber(fixedToCoinAmount).div(fromCoinAmount); - const fixedRatio = ratio.toFixed(8, 1); - const finalRatio = ratio.isInteger() ? ratio.toFixed(0) : fixedRatio; - setPrice(finalRatio); - setToCoinAmount(fixedToCoinAmount.toString()); - } catch (e) { - console.log(e); - } finally { - setLoading(false); - } - }, [fromCoinAmount, fromCoin, toCoin, assetsMap, client, dex.address]); - - useEffect(() => { - fetchToCoin(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fromCoinAmount, fromCoin, toCoin]); - - return ( - - ({ - ...i, - balance: BigInt(i.balance), - amount: BigInt(0), - coinType: i.coin_type, - decimals: i.decimals, - icon: `data:image/svg+xml;utf8,${encodeURIComponent(i.icon_url || '')}` || '', - iconUrl: `data:image/svg+xml;utf8,${encodeURIComponent(i.icon_url || '')}` || '', - price: 0, - }))} - fromCoin={fromCoin.coinType ? fromCoin : undefined} - toCoin={toCoin.coinType ? toCoin : undefined} - interactiveMode={interactiveMode} - canSelectCurve={false} - curve={curve} - convertRate={Number(price)} - platformFeePercent={0} - priceImpact={0} - priceImpactSeverity="normal" - version={version} - slippagePercent={slippage} - onSlippageChange={(slippage: number) => { - setSlippage(slippage); - }} - onCurveTypeChange={(curveType: CurveType) => setCurve(curveType)} - onVersionChange={(version: PoolVersion) => setVersion(version)} - onSwitch={() => { - setFromCoinType(toCoin.coinType); - setFromCoinAmount('0'); - setToCoinAmount('0'); - setToCoinType(fromCoin.coinType); - fetchToCoin(); - }} - onSwap={async (payload) => { - const { fromCoin, toCoin, interactiveMode } = payload; - setFromCoinType(fromCoin?.coinType); - setFromCoinAmount( - fromDust(fromCoin?.amount.toString() ?? '0', fromCoin?.decimals || 0).toString() - ); - setToCoinType(toCoin?.coinType); - setInteractiveMode(interactiveMode); - fetchToCoin(); - }} - onPreview={async () => { - setOpenSwapModal(true); - }} - onPropose={async () => {}} - /> - {fromCoin && toCoin && ( - setOpenSwapModal(false)} - fromCoin={{ - ...fromCoin, - type: fromCoin.coinType, - decimal: fromCoin.decimals, - balance: Number(fromCoin.balance), - amount: fromCoinAmount, - }} - toCoin={{ - ...toCoin, - type: toCoin.coinType, - decimal: toCoin.decimals, - balance: Number(toCoin.balance), - amount: toCoinAmount, - }} - /> - )} - - ); + return <>; + // const dex = useNetworkVariable('dex'); + // const client = useRoochClient(); + // const currentAddress = useCurrentAddress(); + // const [loading, setLoading] = useState(false); + // const [curve, setCurve] = useState('uncorrelated'); + // const [version, setVersion] = useState(0); + // const [slippage, setSlippage] = useState(0.005); + // const [openSwapModal, setOpenSwapModal] = useState(false); + // const [price, setPrice] = useState(''); + // const [interactiveMode, setInteractiveMode] = useState('from'); + // const [fromCoinType, setFromCoinType] = useState(); + // const [toCoinType, setToCoinType] = useState(); + // const [fromCoinAmount, setFromCoinAmount] = useState('0'); + // const [toCoinAmount, setToCoinAmount] = useState(''); + // const { data: userBalances } = useRoochClientQuery( + // 'getBalances', + // { + // owner: currentAddress?.toStr() || '', + // }, + // { + // refetchInterval: 5000, + // } + // ); + // const assetsMap = useMemo(() => { + // const assetsMap = new Map(); + // userBalances?.data.forEach((i) => { + // assetsMap.set(i.coin_type, { + // ...i, + // }); + // }); + // return assetsMap; + // }, [userBalances]); + // useEffect(() => { + // client + // .queryObjectStates({ + // filter: { + // object_type: `${dex.address}::swap::TokenPair`, + // }, + // }) + // .then((result) => { + // const pair: TokenPairType[] = result.data.map((item) => { + // const xView = item.decoded_value!.value.balance_x as AnnotatedMoveStructView; + // let xType = xView.type.replace('0x2::object::Object<0x3::coin_store::CoinStore<', ''); + // xType = xType.replace('>>', ''); + // const xName = xType.split('::'); + // const yView = item.decoded_value!.value.balance_y as AnnotatedMoveStructView; + // let yType = yView.type.replace('0x2::object::Object<0x3::coin_store::CoinStore<', ''); + // yType = yType.replace('>>', ''); + // const yName = yType.split('::'); + // return { + // x2y: true, + // x: { + // id: xView.value.id as string, + // type: xType, + // name: xName[xName.length - 1].replace('>>', ''), + // }, + // y: { + // id: yView.value.id as string, + // type: yType, + // name: yName[yName.length - 1].replace('>>', ''), + // }, + // }; + // }); + // const pairMap = new Map(); + // pair.forEach((p) => { + // const key = p.x.name; + // if (!pairMap.has(key)) { + // pairMap.set(key, []); + // } + // pairMap.get(key)!.push(p); + // const key1 = p.y.name; + // if (!pairMap.has(key1)) { + // pairMap.set(key1, []); + // } + // pairMap.get(key1)!.push({ + // x2y: false, + // x: p.y, + // y: p.x, + // }); + // }); + // }); + // }, [client, dex]); + // const fromCoinInfo = assetsMap.get(fromCoinType as string); + // const toCoinInfo = assetsMap.get(toCoinType as string); + // const fromCoin = useMemo( + // () => ({ + // ...fromCoinInfo, + // balance: BigInt(fromCoinInfo?.balance || 0), + // amount: BigInt(toDust(fromCoinAmount.toString(), fromCoinInfo?.decimals || 0)), + // coinType: fromCoinInfo?.coin_type || '', + // decimals: fromCoinInfo?.decimals || 0, + // icon: `data:image/svg+xml;utf8,${encodeURIComponent(fromCoinInfo?.icon_url || '')}` || '', + // iconUrl: `data:image/svg+xml;utf8,${encodeURIComponent(fromCoinInfo?.icon_url || '')}` || '', + // name: fromCoinInfo?.name || '', + // symbol: fromCoinInfo?.symbol || '', + // price: 0, + // }), + // [fromCoinAmount, fromCoinInfo] + // ); + // const toCoin = useMemo( + // () => ({ + // ...toCoinInfo, + // balance: BigInt(toCoinInfo?.balance || 0), + // amount: BigInt(toDust(toCoinAmount.toString(), toCoinInfo?.decimals || 0)), + // coinType: toCoinInfo?.coin_type || '', + // decimals: toCoinInfo?.decimals || 0, + // icon: `data:image/svg+xml;utf8,${encodeURIComponent(toCoinInfo?.icon_url || '')}` || '', + // iconUrl: `data:image/svg+xml;utf8,${encodeURIComponent(toCoinInfo?.icon_url || '')}` || '', + // name: toCoinInfo?.name || '', + // symbol: toCoinInfo?.symbol || '', + // price: 0, + // }), + // [toCoinAmount, toCoinInfo] + // ); + // const fetchToCoin = useCallback(async () => { + // if ( + // fromCoinAmount === '0' || + // fromCoinAmount === '' || + // !fromCoin || + // !toCoin || + // !fromCoin.coinType || + // !toCoin.coinType + // ) { + // return; + // } + // try { + // setLoading(true); + // const fixedFromCoinAmount = toDust( + // fromCoinAmount.toString().replaceAll(',', ''), + // assetsMap?.get(fromCoin.coinType)?.decimals || 0 + // ); + // const result = await client.executeViewFunction({ + // target: `${dex.address}::router::get_amount_out`, + // args: [Args.u64(fixedFromCoinAmount)], + // typeArgs: [fromCoin.coinType, toCoin.coinType], + // }); + // if (result.vm_status !== 'Executed') { + // toast.error('unknown error'); + // } + // const toCoinAmount = result.return_values![0].decoded_value as string; + // const fixedToCoinAmount = fromDust( + // toCoinAmount, + // assetsMap?.get(toCoin.coinType)?.decimals || 0 + // ); + // const ratio = BigNumber(fixedToCoinAmount).div(fromCoinAmount); + // const fixedRatio = ratio.toFixed(8, 1); + // const finalRatio = ratio.isInteger() ? ratio.toFixed(0) : fixedRatio; + // setPrice(finalRatio); + // setToCoinAmount(fixedToCoinAmount.toString()); + // } catch (e) { + // console.log(e); + // } finally { + // setLoading(false); + // } + // }, [fromCoinAmount, fromCoin, toCoin, assetsMap, client, dex.address]); + // useEffect(() => { + // fetchToCoin(); + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, [fromCoinAmount, fromCoin, toCoin]); + // return ( + // + // ({ + // ...i, + // balance: BigInt(i.balance), + // amount: BigInt(0), + // coinType: i.coin_type, + // decimals: i.decimals, + // icon: `data:image/svg+xml;utf8,${encodeURIComponent(i.icon_url || '')}` || '', + // iconUrl: `data:image/svg+xml;utf8,${encodeURIComponent(i.icon_url || '')}` || '', + // price: 0, + // }))} + // fromCoin={fromCoin.coinType ? fromCoin : undefined} + // toCoin={toCoin.coinType ? toCoin : undefined} + // interactiveMode={interactiveMode} + // canSelectCurve={false} + // curve={curve} + // convertRate={Number(price)} + // platformFeePercent={0} + // priceImpact={0} + // priceImpactSeverity="normal" + // version={version} + // slippagePercent={slippage} + // onSlippageChange={(slippage: number) => { + // setSlippage(slippage); + // }} + // onCurveTypeChange={(curveType: CurveType) => setCurve(curveType)} + // onVersionChange={(version: PoolVersion) => setVersion(version)} + // onSwitch={() => { + // setFromCoinType(toCoin.coinType); + // setFromCoinAmount('0'); + // setToCoinAmount('0'); + // setToCoinType(fromCoin.coinType); + // fetchToCoin(); + // }} + // onSwap={async (payload) => { + // const { fromCoin, toCoin, interactiveMode } = payload; + // setFromCoinType(fromCoin?.coinType); + // setFromCoinAmount( + // fromDust(fromCoin?.amount.toString() ?? '0', fromCoin?.decimals || 0).toString() + // ); + // setToCoinType(toCoin?.coinType); + // setInteractiveMode(interactiveMode); + // fetchToCoin(); + // }} + // onPreview={async () => { + // setOpenSwapModal(true); + // }} + // onPropose={async () => {}} + // /> + // {fromCoin && toCoin && ( + // setOpenSwapModal(false)} + // fromCoin={{ + // ...fromCoin, + // decimals: fromCoin.decimals, + // balance: fromCoin.balance.toString(), + // amount: fromCoinAmount, + // }} + // toCoin={{ + // ...toCoin, + // type: toCoin.coinType, + // decimal: toCoin.decimals, + // balance: Number(toCoin.balance), + // amount: toCoinAmount, + // }} + // /> + // )} + // + // ); } diff --git a/infra/rooch-portal-v2/src/sections/trade/swap/confirm-modal.tsx b/infra/rooch-portal-v2/src/sections/trade/swap/confirm-modal.tsx index ad1c32ac20..25423d2a00 100644 --- a/infra/rooch-portal-v2/src/sections/trade/swap/confirm-modal.tsx +++ b/infra/rooch-portal-v2/src/sections/trade/swap/confirm-modal.tsx @@ -47,8 +47,8 @@ export default function SwapConfirmModal({ return; } const tx = new Transaction(); - const fixdX = toDust(x.amount, x.decimal); - const fixdY = toDust(y.amount, y.decimal); + const fixdX = toDust(x.amount, x.decimals); + const fixdY = toDust(y.amount, y.decimals); const finalY = slippage !== 0 @@ -61,7 +61,7 @@ export default function SwapConfirmModal({ tx.callFunction({ target: `${dex.address}::router::swap_with_exact_input`, args: [Args.u64(fixdX), Args.u64(finalY)], - typeArgs: [x!.type, y!.type], + typeArgs: [x!.coin_type, y!.coin_type], }); mutateAsync({ transaction: tx }) @@ -101,7 +101,7 @@ export default function SwapConfirmModal({ component="span" className="mr-1" sx={{ width: 32, height: 32 }} - dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(x.icon || '') }} + dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(x.icon_url || '') }} /> {' '} @@ -119,7 +119,7 @@ export default function SwapConfirmModal({ component="span" className="mr-1" sx={{ width: 32, height: 32 }} - dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(y.icon || '') }} + dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(y.icon_url || '') }} /> {' '} diff --git a/infra/rooch-portal-v2/src/sections/trade/swap/view.tsx b/infra/rooch-portal-v2/src/sections/trade/swap/view.tsx index 972bba5efd..5e3407913e 100644 --- a/infra/rooch-portal-v2/src/sections/trade/swap/view.tsx +++ b/infra/rooch-portal-v2/src/sections/trade/swap/view.tsx @@ -2,9 +2,12 @@ import { useState } from 'react'; import BigNumber from 'bignumber.js'; +import { useSignAndExecuteTransaction } from '@roochnetwork/rooch-sdk-kit'; import { Box, Stack, Button, TextField, Typography, FormControl } from '@mui/material'; +import { useNetworkVariable } from 'src/hooks/use-networks'; + import { isNumber } from 'src/utils/reg'; import { formatByIntl } from 'src/utils/number'; @@ -32,7 +35,7 @@ export default function SwapView() { Trade tokens in an instant. {}} + onLoading={(loading) => {}} onCallback={(x, y) => { setX(x); setY(y); diff --git a/infra/rooch-portal-v2/src/utils/number.ts b/infra/rooch-portal-v2/src/utils/number.ts index 09e9931da3..30e4274069 100644 --- a/infra/rooch-portal-v2/src/utils/number.ts +++ b/infra/rooch-portal-v2/src/utils/number.ts @@ -3,13 +3,13 @@ import type { UserCoin } from 'src/components/swap/types'; import numeral from 'numeral'; import { BigNumber } from 'bignumber.js'; -export function formatByIntl(value?: number | string) { +export function formatByIntl(value?: number | string, zero: string = '-') { return value ? Intl.NumberFormat('en-us', { maximumFractionDigits: 8, minimumFractionDigits: 0, }).format(Number(value)) - : '-'; + : zero; } export function decimalsMultiplier(decimals?: BigNumber.Value) {