@rango-dev/widget-embedded 0.1.10-next.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +29 -0
- package/public/index.html +11 -0
- package/readme.md +2 -0
- package/src/App.tsx +78 -0
- package/src/app.css +28 -0
- package/src/components/AppRouter.tsx +15 -0
- package/src/components/AppRoutes.tsx +32 -0
- package/src/components/BottomLogo.tsx +44 -0
- package/src/components/Footer.tsx +8 -0
- package/src/components/Header.tsx +25 -0
- package/src/components/HeaderButtons.tsx +34 -0
- package/src/components/Layout.tsx +55 -0
- package/src/components/SwitchFromAndTo.tsx +30 -0
- package/src/components/TokenInfo.tsx +218 -0
- package/src/components/UpdateUrl.tsx +85 -0
- package/src/constants/errors.ts +3 -0
- package/src/constants/navigationRoutes.ts +14 -0
- package/src/constants/numbers.ts +3 -0
- package/src/constants/searchParams.ts +7 -0
- package/src/globalStyles.ts +16 -0
- package/src/hooks/useBestRoute.ts +70 -0
- package/src/hooks/useConfirmSwap.ts +234 -0
- package/src/hooks/useTheme.ts +37 -0
- package/src/index.tsx +12 -0
- package/src/mockData/pendingSwap.ts +607 -0
- package/src/pages/ConfirmSwapPage.tsx +24 -0
- package/src/pages/ConfirmWalletsPage.tsx +51 -0
- package/src/pages/HistoryPage.tsx +793 -0
- package/src/pages/Home.tsx +176 -0
- package/src/pages/LiquiditySourcesPage.tsx +49 -0
- package/src/pages/SelectChainPage.tsx +62 -0
- package/src/pages/SelectTokenPage.tsx +84 -0
- package/src/pages/SettingsPage.tsx +60 -0
- package/src/pages/SwapDetailsPage.tsx +9 -0
- package/src/pages/WalletsPage.tsx +61 -0
- package/src/services/httpService.ts +3 -0
- package/src/store/bestRoute.ts +82 -0
- package/src/store/meta.ts +35 -0
- package/src/store/selectors.ts +19 -0
- package/src/store/settings.ts +72 -0
- package/src/store/wallets.ts +144 -0
- package/src/utils/common.ts +3 -0
- package/src/utils/numbers.ts +94 -0
- package/src/utils/routing.ts +108 -0
- package/src/utils/swap.ts +155 -0
- package/src/utils/wallets.ts +345 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Token } from 'rango-sdk';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { useLocation, useSearchParams } from 'react-router-dom';
|
|
4
|
+
import { useBestRouteStore } from '../store/bestRoute';
|
|
5
|
+
import { useMetaStore } from '../store/meta';
|
|
6
|
+
import { SearchParams } from '../constants/searchParams';
|
|
7
|
+
|
|
8
|
+
function searchParamsToToken(tokens: Token[], searchParams: string | null): Token | null {
|
|
9
|
+
return (
|
|
10
|
+
tokens.find((token) => {
|
|
11
|
+
const symbolAndAddress = searchParams?.split('--');
|
|
12
|
+
if (symbolAndAddress?.length === 1)
|
|
13
|
+
return token.symbol === symbolAndAddress[0] && token.address === null;
|
|
14
|
+
return token.symbol === symbolAndAddress?.[0] && token.address === symbolAndAddress?.[1];
|
|
15
|
+
}) || null
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function UpdateUrl() {
|
|
20
|
+
const firstRender = useRef(true);
|
|
21
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
22
|
+
const location = useLocation();
|
|
23
|
+
|
|
24
|
+
const fromChain = useBestRouteStore.use.fromChain();
|
|
25
|
+
const toChain = useBestRouteStore.use.toChain();
|
|
26
|
+
const fromToken = useBestRouteStore.use.fromToken();
|
|
27
|
+
const toToken = useBestRouteStore.use.toToken();
|
|
28
|
+
const setFromChain = useBestRouteStore.use.setFromChain();
|
|
29
|
+
const setFromToken = useBestRouteStore.use.setFromToken();
|
|
30
|
+
const setToChain = useBestRouteStore.use.setToChain();
|
|
31
|
+
const setToToken = useBestRouteStore.use.setToToken();
|
|
32
|
+
const inputAmount = useBestRouteStore.use.inputAmount();
|
|
33
|
+
const setInputAmount = useBestRouteStore.use.setInputAmount();
|
|
34
|
+
const loadingStatus = useMetaStore.use.loadingStatus();
|
|
35
|
+
const { blockchains, tokens } = useMetaStore.use.meta();
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!firstRender.current) {
|
|
39
|
+
const fromChainString = fromChain?.name || '';
|
|
40
|
+
const fromTokenString =
|
|
41
|
+
(fromToken?.symbol || '') + (fromToken?.address ? `--${fromToken?.address}` : '');
|
|
42
|
+
const toChainString = toChain?.name || '';
|
|
43
|
+
const toTokenString =
|
|
44
|
+
(toToken?.symbol || '') + (toToken?.address ? `--${toToken?.address}` : '');
|
|
45
|
+
const fromAmount = inputAmount;
|
|
46
|
+
|
|
47
|
+
setSearchParams(
|
|
48
|
+
{
|
|
49
|
+
...(fromChainString && { [SearchParams.FROM_CHAIN]: fromChainString }),
|
|
50
|
+
...(fromTokenString && { [SearchParams.FROM_TOKEN]: fromTokenString }),
|
|
51
|
+
...(toChainString && { [SearchParams.TO_CHAIN]: toChainString }),
|
|
52
|
+
...(toTokenString && { [SearchParams.TO_TOKEN]: toTokenString }),
|
|
53
|
+
...(fromAmount && { [SearchParams.FROM_AMOUNT]: fromAmount.toString() }),
|
|
54
|
+
},
|
|
55
|
+
{ replace: true },
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
firstRender.current = false;
|
|
59
|
+
}, [location.pathname, inputAmount]);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (loadingStatus === 'success') {
|
|
63
|
+
const fronChainString = searchParams.get(SearchParams.FROM_CHAIN);
|
|
64
|
+
const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
|
|
65
|
+
const toChainString = searchParams.get(SearchParams.TO_CHAIN);
|
|
66
|
+
const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
|
|
67
|
+
const fromAmount = searchParams.get(SearchParams.FROM_AMOUNT);
|
|
68
|
+
const fromChain = blockchains.find((blockchain) => blockchain.name === fronChainString);
|
|
69
|
+
const fromToken = searchParamsToToken(tokens, fromTokenString);
|
|
70
|
+
const toChain = blockchains.find((blockchain) => blockchain.name === toChainString);
|
|
71
|
+
const toToken = searchParamsToToken(tokens, toTokenString);
|
|
72
|
+
if (!!fromChain) {
|
|
73
|
+
setFromChain(fromChain);
|
|
74
|
+
if (!!fromToken) setFromToken(fromToken);
|
|
75
|
+
}
|
|
76
|
+
if (!!toChain) {
|
|
77
|
+
setToChain(toChain);
|
|
78
|
+
if (!!toToken) setToToken(toToken);
|
|
79
|
+
}
|
|
80
|
+
if (fromAmount) setInputAmount(fromAmount);
|
|
81
|
+
}
|
|
82
|
+
}, [loadingStatus]);
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const navigationRoutes = {
|
|
2
|
+
home: '/',
|
|
3
|
+
fromChain: '/from-chain',
|
|
4
|
+
fromToken: '/from-token',
|
|
5
|
+
toChain: '/to-chain',
|
|
6
|
+
toToken: '/to-token',
|
|
7
|
+
settings: '/settings',
|
|
8
|
+
liquiditySources: '/liquidity-sources',
|
|
9
|
+
history: '/history',
|
|
10
|
+
wallets: '/wallets',
|
|
11
|
+
confirmSwap: '/confirm-swap',
|
|
12
|
+
confirmWallets: '/confirm-wallets',
|
|
13
|
+
swapDetails: '/swap-details',
|
|
14
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { globalCss } from '@rango-dev/ui';
|
|
2
|
+
|
|
3
|
+
export const globalStyles = globalCss({
|
|
4
|
+
'*': {
|
|
5
|
+
'&::-webkit-scrollbar': { width: '$8' },
|
|
6
|
+
'&::-webkit-scrollbar-thumb': {
|
|
7
|
+
backgroundColor: '$neutrals400',
|
|
8
|
+
},
|
|
9
|
+
'&::-webkit-scrollbar-thumb:hover': {
|
|
10
|
+
backgroundColor: '$neutrals500',
|
|
11
|
+
},
|
|
12
|
+
'&::-webkit-scrollbar-track': {
|
|
13
|
+
backgroundColor: '$neutrals300',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { BestRouteRequest, BestRouteResponse } from 'rango-sdk';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { httpService } from '../services/httpService';
|
|
4
|
+
import { useBestRouteStore } from '../store/bestRoute';
|
|
5
|
+
import { useSettingsStore } from '../store/settings';
|
|
6
|
+
|
|
7
|
+
export function useBestRoute() {
|
|
8
|
+
const fromToken = useBestRouteStore.use.fromToken();
|
|
9
|
+
const toToken = useBestRouteStore.use.toToken();
|
|
10
|
+
const inputAmount = useBestRouteStore.use.inputAmount();
|
|
11
|
+
|
|
12
|
+
const slippage = useSettingsStore.use.slippage();
|
|
13
|
+
const customSlippage = useSettingsStore.use.customSlippage();
|
|
14
|
+
const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
|
|
15
|
+
const [count, setCount] = useState(0);
|
|
16
|
+
const [loading, setLoading] = useState(false);
|
|
17
|
+
const [error, setError] = useState('');
|
|
18
|
+
const [data, setData] = useState<BestRouteResponse | null>(null);
|
|
19
|
+
const abortControllerRef = useRef<AbortController | null>(null);
|
|
20
|
+
|
|
21
|
+
const retry = () => {
|
|
22
|
+
setCount((prev) => prev + 1);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (abortControllerRef.current) abortControllerRef.current.abort();
|
|
27
|
+
const abortController = new AbortController();
|
|
28
|
+
abortControllerRef.current = abortController;
|
|
29
|
+
if (!!fromToken && !!toToken && !!inputAmount) {
|
|
30
|
+
if (!!data) setData(null);
|
|
31
|
+
const requestBody: BestRouteRequest = {
|
|
32
|
+
amount: inputAmount?.toString(),
|
|
33
|
+
connectedWallets: [],
|
|
34
|
+
selectedWallets: {},
|
|
35
|
+
checkPrerequisites: false,
|
|
36
|
+
swapperGroups: disabledLiquiditySources,
|
|
37
|
+
swappersGroupsExclude: true,
|
|
38
|
+
from: {
|
|
39
|
+
address: fromToken.address,
|
|
40
|
+
blockchain: fromToken.blockchain,
|
|
41
|
+
symbol: fromToken.symbol,
|
|
42
|
+
},
|
|
43
|
+
to: { address: toToken.address, blockchain: toToken.blockchain, symbol: toToken.symbol },
|
|
44
|
+
};
|
|
45
|
+
setLoading(true);
|
|
46
|
+
httpService
|
|
47
|
+
.getBestRoute(requestBody, { signal: abortControllerRef.current.signal })
|
|
48
|
+
.then((res) => {
|
|
49
|
+
setData(res);
|
|
50
|
+
setLoading(false);
|
|
51
|
+
abortControllerRef.current = null;
|
|
52
|
+
})
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
if (error.code === 'ERR_CANCELED') return;
|
|
55
|
+
setError(error.message);
|
|
56
|
+
setLoading(false);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}, [
|
|
60
|
+
fromToken,
|
|
61
|
+
toToken,
|
|
62
|
+
inputAmount,
|
|
63
|
+
count,
|
|
64
|
+
slippage,
|
|
65
|
+
customSlippage,
|
|
66
|
+
disabledLiquiditySources.length,
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
return { loading, error, data, retry };
|
|
70
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { PendingSwap } from '@rango-dev/ui/dist/containers/History/types';
|
|
2
|
+
import {
|
|
3
|
+
BestRouteType,
|
|
4
|
+
SimulationValidationStatus,
|
|
5
|
+
SwapSavedSettings,
|
|
6
|
+
} from '@rango-dev/ui/dist/types/swaps';
|
|
7
|
+
import { WalletType } from '@rango-dev/wallets-shared';
|
|
8
|
+
import BigNumber from 'bignumber.js';
|
|
9
|
+
import { BestRouteRequest, BestRouteResponse } from 'rango-sdk';
|
|
10
|
+
import { useState } from 'react';
|
|
11
|
+
import { httpService } from '../services/httpService';
|
|
12
|
+
import { useBestRouteStore } from '../store/bestRoute';
|
|
13
|
+
import { useSettingsStore } from '../store/settings';
|
|
14
|
+
import { useWalletsStore } from '../store/wallets';
|
|
15
|
+
import { compareRoutes, getRequiredBalanceOfWallet } from '../utils/routing';
|
|
16
|
+
import { calculatePendingSwap } from '../utils/swap';
|
|
17
|
+
import { SelectedWallet } from '../utils/wallets';
|
|
18
|
+
|
|
19
|
+
type CheckFeeAndBalanceResult =
|
|
20
|
+
| {
|
|
21
|
+
hasEnoughBalanceOrSlippage: { balance: boolean; slippage: boolean; routeChanged: boolean };
|
|
22
|
+
bestRoute: BestRouteType;
|
|
23
|
+
}
|
|
24
|
+
| { bestRoute: null }
|
|
25
|
+
| null;
|
|
26
|
+
|
|
27
|
+
export function useConfirmSwap() {
|
|
28
|
+
const fromToken = useBestRouteStore.use.fromToken();
|
|
29
|
+
const toToken = useBestRouteStore.use.toToken();
|
|
30
|
+
const inputAmount = useBestRouteStore.use.inputAmount();
|
|
31
|
+
const bestRoute = useBestRouteStore.use.bestRoute();
|
|
32
|
+
const setBestRoute = useBestRouteStore.use.setBestRoute();
|
|
33
|
+
const accounts = useWalletsStore.use.accounts();
|
|
34
|
+
const selectedWallets = useWalletsStore.use.selectedWallets();
|
|
35
|
+
|
|
36
|
+
const slippage = useSettingsStore.use.slippage();
|
|
37
|
+
const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
|
|
38
|
+
const [loading, setLoading] = useState(false);
|
|
39
|
+
const [error, setError] = useState('');
|
|
40
|
+
const [warning, setWarning] = useState('');
|
|
41
|
+
const [data, setData] = useState<BestRouteResponse | null>(null);
|
|
42
|
+
const [feeStatus, setFeeStatus] = useState<SimulationValidationStatus[] | null>(null);
|
|
43
|
+
const [bestRouteChanged, setBestRouteChanged] = useState(false);
|
|
44
|
+
const [enoughBalance, setEnoughBalance] = useState<boolean | null>(null);
|
|
45
|
+
|
|
46
|
+
const hasEnoughBalanceOrProperSlippage = (
|
|
47
|
+
route: BestRouteType,
|
|
48
|
+
selectedWallets: SelectedWallet[],
|
|
49
|
+
userSlippage: string,
|
|
50
|
+
routeChanged: boolean,
|
|
51
|
+
): { balance: boolean; slippage: boolean; routeChanged: boolean } => {
|
|
52
|
+
const fee = route.validationStatus;
|
|
53
|
+
|
|
54
|
+
if (fee === null || fee.length === 0) return { balance: true, slippage: true, routeChanged };
|
|
55
|
+
|
|
56
|
+
for (const wallet of selectedWallets) {
|
|
57
|
+
const requiredAssets = getRequiredBalanceOfWallet(wallet, fee);
|
|
58
|
+
if (!requiredAssets) continue;
|
|
59
|
+
|
|
60
|
+
const hasEnoughBalance = requiredAssets?.map((it) => it.ok).reduce((a, b) => a && b);
|
|
61
|
+
if (!hasEnoughBalance) return { balance: false, slippage: true, routeChanged };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const slippages = route.result?.swaps?.map((s) => s.recommendedSlippage);
|
|
65
|
+
const slippageError = (slippages?.filter((s) => !!s?.error)?.length || 0) > 0;
|
|
66
|
+
const minSlippage =
|
|
67
|
+
slippages
|
|
68
|
+
?.map((s) => parseFloat(s?.slippage.toString() || '0') || 0)
|
|
69
|
+
.filter((s) => s > 0)
|
|
70
|
+
.sort((a, b) => b - a)
|
|
71
|
+
.find(() => true) || null;
|
|
72
|
+
if (slippageError) {
|
|
73
|
+
setError('Server cannot calculated required slippage for your swap');
|
|
74
|
+
return { balance: true, slippage: false, routeChanged };
|
|
75
|
+
} else if (minSlippage !== null && minSlippage > parseFloat(userSlippage)) {
|
|
76
|
+
setError(`Your slippage should be ${minSlippage} at least`);
|
|
77
|
+
return { balance: true, slippage: false, routeChanged };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { balance: true, slippage: true, routeChanged };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const checkFeeAndBalance = async (
|
|
84
|
+
selectedWallets: SelectedWallet[],
|
|
85
|
+
): Promise<CheckFeeAndBalanceResult> => {
|
|
86
|
+
setLoading(true);
|
|
87
|
+
setFeeStatus(null);
|
|
88
|
+
|
|
89
|
+
const selectedWalletsMap = selectedWallets.reduce(
|
|
90
|
+
(selectedWalletsMap: BestRouteRequest['selectedWallets'], selectedWallet) => (
|
|
91
|
+
(selectedWalletsMap[selectedWallet.chain] = selectedWallet.address), selectedWalletsMap
|
|
92
|
+
),
|
|
93
|
+
{},
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const connectedWallets: BestRouteRequest['connectedWallets'] = [];
|
|
97
|
+
|
|
98
|
+
accounts.forEach((account) => {
|
|
99
|
+
const chainAndAccounts = connectedWallets.find((wallet) => wallet.blockchain);
|
|
100
|
+
if (!!chainAndAccounts) chainAndAccounts.addresses.push(account.address);
|
|
101
|
+
else connectedWallets.push({ blockchain: account.chain, addresses: [account.address] });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const r = await httpService
|
|
105
|
+
.getBestRoute({
|
|
106
|
+
amount: inputAmount!.toString(),
|
|
107
|
+
checkPrerequisites: true,
|
|
108
|
+
from: {
|
|
109
|
+
address: fromToken!.address,
|
|
110
|
+
blockchain: fromToken!.blockchain,
|
|
111
|
+
symbol: fromToken!.symbol,
|
|
112
|
+
},
|
|
113
|
+
to: {
|
|
114
|
+
address: toToken!.address,
|
|
115
|
+
blockchain: toToken!.blockchain,
|
|
116
|
+
symbol: toToken!.symbol,
|
|
117
|
+
},
|
|
118
|
+
connectedWallets,
|
|
119
|
+
selectedWallets: selectedWalletsMap,
|
|
120
|
+
//@ts-ignore
|
|
121
|
+
swapperGroups: disabledLiquiditySources,
|
|
122
|
+
swappersGroupsExclude: true,
|
|
123
|
+
})
|
|
124
|
+
.catch((error) => {
|
|
125
|
+
setError(error.message);
|
|
126
|
+
setLoading(false);
|
|
127
|
+
});
|
|
128
|
+
setLoading(false);
|
|
129
|
+
if (!r || !r.result || !bestRoute) return { bestRoute: null };
|
|
130
|
+
if (!new BigNumber(r.requestAmount).isEqualTo(new BigNumber(inputAmount || '-1'))) return null;
|
|
131
|
+
setFeeStatus(r.validationStatus);
|
|
132
|
+
const routeChangeStatus = compareRoutes(
|
|
133
|
+
bestRoute,
|
|
134
|
+
r,
|
|
135
|
+
inputAmount!.toString(),
|
|
136
|
+
fromToken!.usdPrice,
|
|
137
|
+
toToken!.usdPrice,
|
|
138
|
+
);
|
|
139
|
+
setBestRoute(r);
|
|
140
|
+
const isChanged = routeChangeStatus.isChanged;
|
|
141
|
+
const changeWarningMessage = routeChangeStatus.warningMessage;
|
|
142
|
+
setBestRouteChanged(isChanged);
|
|
143
|
+
setWarning('Best route changed');
|
|
144
|
+
setData(r);
|
|
145
|
+
return {
|
|
146
|
+
hasEnoughBalanceOrSlippage: hasEnoughBalanceOrProperSlippage(
|
|
147
|
+
r,
|
|
148
|
+
selectedWallets,
|
|
149
|
+
slippage.toString(),
|
|
150
|
+
isChanged,
|
|
151
|
+
),
|
|
152
|
+
bestRoute: r,
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const swap = () => {
|
|
157
|
+
if (!bestRoute) return;
|
|
158
|
+
if (inputAmount!.toString() === '') return;
|
|
159
|
+
const wallets = selectedWallets.reduce(
|
|
160
|
+
(
|
|
161
|
+
selectedWalletsMap: { [p: string]: { address: string; walletType: WalletType } },
|
|
162
|
+
selectedWallet,
|
|
163
|
+
) => (
|
|
164
|
+
(selectedWalletsMap[selectedWallet.chain] = {
|
|
165
|
+
address: selectedWallet.address,
|
|
166
|
+
walletType: selectedWallet.walletType,
|
|
167
|
+
}),
|
|
168
|
+
selectedWalletsMap
|
|
169
|
+
),
|
|
170
|
+
{},
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const proceedAnyway = enoughBalance !== null;
|
|
174
|
+
|
|
175
|
+
const settings: SwapSavedSettings = {
|
|
176
|
+
slippage: slippage.toString(),
|
|
177
|
+
disabledSwappersGroups: ['Osmosis'],
|
|
178
|
+
disabledSwappersIds: [],
|
|
179
|
+
};
|
|
180
|
+
if (proceedAnyway) {
|
|
181
|
+
const newSwap: PendingSwap = calculatePendingSwap(
|
|
182
|
+
inputAmount!.toString(),
|
|
183
|
+
bestRoute,
|
|
184
|
+
wallets,
|
|
185
|
+
settings,
|
|
186
|
+
false,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
!proceedAnyway &&
|
|
191
|
+
checkFeeAndBalance(selectedWallets)
|
|
192
|
+
.then((data) => {
|
|
193
|
+
if (!data) {
|
|
194
|
+
setError('confirm swap error');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!data.bestRoute) {
|
|
199
|
+
setError('confirm swap error');
|
|
200
|
+
return;
|
|
201
|
+
} else {
|
|
202
|
+
const { hasEnoughBalanceOrSlippage, bestRoute: newBestRoute } = data;
|
|
203
|
+
if (!hasEnoughBalanceOrSlippage) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
setEnoughBalance(
|
|
208
|
+
hasEnoughBalanceOrSlippage.balance && hasEnoughBalanceOrSlippage.slippage,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
if (
|
|
212
|
+
hasEnoughBalanceOrSlippage.balance &&
|
|
213
|
+
hasEnoughBalanceOrSlippage.slippage &&
|
|
214
|
+
!hasEnoughBalanceOrSlippage.routeChanged
|
|
215
|
+
) {
|
|
216
|
+
const newSwap: PendingSwap = calculatePendingSwap(
|
|
217
|
+
inputAmount!.toString(),
|
|
218
|
+
newBestRoute,
|
|
219
|
+
wallets,
|
|
220
|
+
settings,
|
|
221
|
+
true,
|
|
222
|
+
);
|
|
223
|
+
} else if (!hasEnoughBalanceOrSlippage.balance) {
|
|
224
|
+
setError('not enough balance');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
.catch((error) => {
|
|
229
|
+
console.log('unexpected error', error);
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return { loading, error, data, warning, feeStatus, bestRouteChanged, enoughBalance, swap };
|
|
234
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { lightTheme, darkTheme } from '@rango-dev/ui';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { useMetaStore } from '../store/meta';
|
|
4
|
+
import { useSettingsStore } from '../store/settings';
|
|
5
|
+
|
|
6
|
+
export function useTheme() {
|
|
7
|
+
const theme = useSettingsStore.use.theme();
|
|
8
|
+
const fetchMeta = useMetaStore.use.fetchMeta();
|
|
9
|
+
|
|
10
|
+
const [OSTheme, setOSTheme] = useState(lightTheme);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
(async () => {
|
|
13
|
+
await fetchMeta();
|
|
14
|
+
})();
|
|
15
|
+
|
|
16
|
+
const switchTheme = (event: MediaQueryListEvent) => {
|
|
17
|
+
if (event.matches) setOSTheme(darkTheme);
|
|
18
|
+
else setOSTheme(lightTheme);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
22
|
+
setOSTheme(darkTheme);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', switchTheme);
|
|
26
|
+
return () => {
|
|
27
|
+
window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', switchTheme);
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
const getActiveTheme = () => {
|
|
32
|
+
if (theme === 'auto') return OSTheme;
|
|
33
|
+
else return theme === 'dark' ? darkTheme : lightTheme;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return { activeTheme: getActiveTheme() };
|
|
37
|
+
}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
4
|
+
import { App } from './App';
|
|
5
|
+
|
|
6
|
+
const container = document.getElementById('app')!;
|
|
7
|
+
const root = createRoot(container);
|
|
8
|
+
root.render(
|
|
9
|
+
<BrowserRouter>
|
|
10
|
+
<App />,
|
|
11
|
+
</BrowserRouter>,
|
|
12
|
+
);
|