@rango-dev/widget-embedded 0.1.10 → 0.1.11-next.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rango-dev/widget-embedded",
3
- "version": "0.1.10",
3
+ "version": "0.1.11-next.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -0,0 +1,33 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import React from 'react';
3
+ import { getPercentageChange } from '../utils/swap';
4
+ import { Typography } from '@rango-dev/ui';
5
+ import { numberToString } from '../utils/numbers';
6
+
7
+ interface PropTypes {
8
+ inputUsdValue: BigNumber | null;
9
+ outputUsdValue: BigNumber | null;
10
+ }
11
+
12
+ export function PercentageChange(props: PropTypes) {
13
+ const { inputUsdValue, outputUsdValue } = props;
14
+
15
+ if (!inputUsdValue || !outputUsdValue || !outputUsdValue.gt(0)) return null;
16
+
17
+ const percentageChange = getPercentageChange(
18
+ inputUsdValue.toNumber(),
19
+ outputUsdValue.toNumber()
20
+ );
21
+
22
+ const showPercentageChange = percentageChange?.lt(0);
23
+
24
+ return (
25
+ <>
26
+ {showPercentageChange && (
27
+ <Typography variant="caption" color="$error500">
28
+ {`(${numberToString(percentageChange, 0, 2)}%)`}
29
+ </Typography>
30
+ )}
31
+ </>
32
+ );
33
+ }
@@ -17,6 +17,7 @@ import { getBalanceFromWallet } from '../utils/wallets';
17
17
  import { useWalletsStore } from '../store/wallets';
18
18
  import { useTranslation } from 'react-i18next';
19
19
  import { Spacer } from '@rango-dev/ui';
20
+ import { PercentageChange } from './PercentageChange';
20
21
 
21
22
  type PropTypes = (
22
23
  | {
@@ -80,6 +81,13 @@ const Container = styled('div', {
80
81
  width: '30%',
81
82
  },
82
83
  },
84
+ '.output-usd': {
85
+ display: 'flex',
86
+ div: {
87
+ display: 'flex',
88
+ paddingLeft: '$8',
89
+ },
90
+ },
83
91
  });
84
92
 
85
93
  const StyledImage = styled('img', {
@@ -201,10 +209,18 @@ export function TokenInfo(props: PropTypes) {
201
209
  </div>
202
210
  </Options>
203
211
  ) : (
204
- <Typography
205
- variant="caption"
206
- color="neutrals600"
207
- >{`$${numberToString(props.outputUsdValue)}`}</Typography>
212
+ <div className="output-usd">
213
+ <PercentageChange
214
+ inputUsdValue={inputUsdValue}
215
+ outputUsdValue={props.outputUsdValue}
216
+ />
217
+ <div>
218
+ <Typography
219
+ variant="caption"
220
+ color="neutrals600"
221
+ >{`$${numberToString(props.outputUsdValue)}`}</Typography>
222
+ </div>
223
+ </div>
208
224
  )}
209
225
  </div>
210
226
  <div className="form">
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { ReactNode } from 'react';
2
2
  import { Button, InfoCircleIcon, styled, Typography } from '@rango-dev/ui';
3
3
  import { LoadingStatus } from '../store/meta';
4
4
  import { useTranslation } from 'react-i18next';
@@ -37,6 +37,9 @@ const Container = styled('div', {
37
37
  justifyContent: 'space-between',
38
38
  alignItems: 'center',
39
39
  minHeight: '32px',
40
+ '.usd-value': {
41
+ paddingLeft: '$8',
42
+ },
40
43
  },
41
44
  '.form': {
42
45
  display: 'flex',
@@ -95,10 +98,11 @@ interface PropTypes {
95
98
  symbol: string;
96
99
  image: string;
97
100
  };
101
+ percentageChange?: ReactNode;
98
102
  }
99
103
 
100
104
  export function TokenPreview(props: PropTypes) {
101
- const { chain, token, loadingStatus } = props;
105
+ const { chain, token, loadingStatus, percentageChange } = props;
102
106
  const { t } = useTranslation();
103
107
 
104
108
  const ItemSuffix = (
@@ -120,12 +124,16 @@ export function TokenPreview(props: PropTypes) {
120
124
  <Typography variant="body2" color="neutrals800">
121
125
  {props.label}
122
126
  </Typography>
123
- {props.usdValue && (
124
- <Typography
125
- variant="caption"
126
- color="neutrals600"
127
- >{`$${numberToString(props.usdValue)}`}</Typography>
128
- )}
127
+ <div>
128
+ {percentageChange}
129
+ {props.usdValue && (
130
+ <Typography
131
+ variant="caption"
132
+ color="neutrals600"
133
+ className="usd-value"
134
+ >{`$${numberToString(props.usdValue)}`}</Typography>
135
+ )}
136
+ </div>
129
137
  </div>
130
138
  <div className="form">
131
139
  <Button
@@ -10,11 +10,7 @@ import {
10
10
  getSelectableWallets,
11
11
  isExperimentalChain,
12
12
  } from '../utils/wallets';
13
- import {
14
- calcOutputUsdValue,
15
- getTotalFeeInUsd,
16
- requiredWallets,
17
- } from '../utils/swap';
13
+ import { getTotalFeeInUsd, requiredWallets } from '../utils/swap';
18
14
  import { decimalNumber, numberToString } from '../utils/numbers';
19
15
  import { useMetaStore } from '../store/meta';
20
16
  import { Network, WalletType } from '@rango-dev/wallets-shared';
@@ -33,6 +29,7 @@ import { ConfirmSwapErrors } from '../components/ConfirmSwapErrors';
33
29
  import { ConfirmSwapWarnings } from '../components/ConfirmSwapWarnings';
34
30
  import { ConfirmSwapExtraMessages } from '../components/warnings/ConfirmSwapExtraMessages';
35
31
  import { getBestRouteStatus } from '../utils/routing';
32
+ import { PercentageChange } from '../components/PercentageChange';
36
33
 
37
34
  export function ConfirmSwapPage() {
38
35
  const navigate = useNavigate();
@@ -48,6 +45,8 @@ export function ConfirmSwapPage() {
48
45
  const setSelectedWallet = useWalletsStore.use.setSelectedWallet();
49
46
  const slippage = useSettingsStore.use.slippage();
50
47
  const customSlippage = useSettingsStore.use.customSlippage();
48
+ const inputUsdValue = useBestRouteStore.use.inputUsdValue();
49
+ const outputUsdValue = useBestRouteStore.use.outputUsdValue();
51
50
 
52
51
  const bestRouteloadingStatus = getBestRouteStatus(
53
52
  fetchingBestRoute,
@@ -134,7 +133,7 @@ export function ConfirmSwapPage() {
134
133
  symbol: firstStep?.from.symbol || '',
135
134
  image: firstStep?.from.logo || '',
136
135
  }}
137
- usdValue={calcOutputUsdValue(fromAmount, firstStep?.from.usdPrice)}
136
+ usdValue={inputUsdValue}
138
137
  amount={fromAmount}
139
138
  label={t('From')}
140
139
  loadingStatus={bestRouteloadingStatus}
@@ -149,10 +148,16 @@ export function ConfirmSwapPage() {
149
148
  symbol: lastStep?.to.symbol || '',
150
149
  image: lastStep?.to.logo || '',
151
150
  }}
152
- usdValue={calcOutputUsdValue(toAmount, lastStep?.to.usdPrice)}
151
+ usdValue={outputUsdValue}
153
152
  amount={toAmount}
154
153
  label={t('To')}
155
154
  loadingStatus={bestRouteloadingStatus}
155
+ percentageChange={
156
+ <PercentageChange
157
+ inputUsdValue={inputUsdValue}
158
+ outputUsdValue={outputUsdValue}
159
+ />
160
+ }
156
161
  />
157
162
  </>
158
163
  }
@@ -78,10 +78,6 @@ export function Home(props: PropTypes) {
78
78
  const fromToken = useBestRouteStore.use.fromToken();
79
79
  const toChain = useBestRouteStore.use.toChain();
80
80
  const toToken = useBestRouteStore.use.toToken();
81
- const setFromChain = useBestRouteStore.use.setFromChain();
82
- const setFromToken = useBestRouteStore.use.setFromToken();
83
- const setToChain = useBestRouteStore.use.setToChain();
84
- const setToToken = useBestRouteStore.use.setToToken();
85
81
  const setInputAmount = useBestRouteStore.use.setInputAmount();
86
82
  const inputUsdValue = useBestRouteStore.use.inputUsdValue();
87
83
  const inputAmount = useBestRouteStore.use.inputAmount();
@@ -94,15 +90,7 @@ export function Home(props: PropTypes) {
94
90
  const loadingMetaStatus = useMetaStore.use.loadingStatus();
95
91
  const accounts = useWalletsStore.use.accounts();
96
92
  const setCurrentPage = useUiStore.use.setCurrentPage();
97
-
98
- const swithFromAndTo = () => {
99
- setFromChain(toChain);
100
- setFromToken(toToken);
101
- setToChain(fromChain);
102
- setToToken(fromToken);
103
- setInputAmount(outputAmount?.toString() || '');
104
- setCount((prev) => prev + 1);
105
- };
93
+ const switchFromAndTo = useBestRouteStore.use.switchFromAndTo();
106
94
 
107
95
  const errorMessage =
108
96
  loadingMetaStatus === 'failed'
@@ -170,7 +158,13 @@ export function Home(props: PropTypes) {
170
158
  inputAmount={inputAmount}
171
159
  />
172
160
  <SwitchButtonContainer>
173
- <Button variant="ghost" onClick={swithFromAndTo}>
161
+ <Button
162
+ variant="ghost"
163
+ onClick={() => {
164
+ switchFromAndTo();
165
+ setCount((prev) => prev + 1);
166
+ }}
167
+ >
174
168
  <VerticalSwapIcon size={32} />
175
169
  {isRouterInContext && <SwithFromAndTo count={count} />}
176
170
  </Button>
@@ -49,6 +49,7 @@ export interface RouteState {
49
49
  bestRoute: BestRouteResponse | null;
50
50
  setBestRoute: (bestRoute: BestRouteResponse | null) => void;
51
51
  retry: (pendingSwap: PendingSwap) => void;
52
+ switchFromAndTo: () => void;
52
53
  }
53
54
 
54
55
  export const useBestRouteStore = createSelectors(
@@ -146,7 +147,6 @@ export const useBestRouteStore = createSelectors(
146
147
  toToken: token,
147
148
  })),
148
149
  setInputAmount: (amount) => {
149
- console.log(amount, typeof amount);
150
150
  set((state) => ({
151
151
  inputAmount: amount,
152
152
  ...(!amount && {
@@ -224,6 +224,20 @@ export const useBestRouteStore = createSelectors(
224
224
  destinationTokens: sortedDestinationTokens,
225
225
  });
226
226
  },
227
+ switchFromAndTo: () =>
228
+ set((state) => ({
229
+ fromChain: state.toChain,
230
+ fromToken: state.toToken,
231
+ toChain: state.fromChain,
232
+ toToken: state.fromToken,
233
+ sourceTokens: state.destinationTokens,
234
+ destinationTokens: state.sourceTokens,
235
+ inputAmount: state.outputAmount?.toString() || '',
236
+ inputUsdValue: getUsdValue(
237
+ state.toToken,
238
+ state.outputAmount?.toString() || ''
239
+ ),
240
+ })),
227
241
  }))
228
242
  )
229
243
  );
@@ -282,7 +296,7 @@ const bestRoute = (
282
296
  const bestRouteParamsListener = () => {
283
297
  const { fromToken, toToken, inputAmount, inputUsdValue } =
284
298
  useBestRouteStore.getState();
285
- if (!inputAmount || inputAmount === '0') return;
299
+ if (!inputAmount || inputAmount === '0' || inputUsdValue.eq(0)) return;
286
300
 
287
301
  if (tokensAreEqual(fromToken, toToken))
288
302
  return bestRouteStore.setState({
@@ -312,8 +326,15 @@ const bestRoute = (
312
326
  }),
313
327
  bestRouteParamsListener,
314
328
  {
315
- equalityFn: (prevState, state) => {
316
- if (isRouteParametersChanged(prevState, state)) return false;
329
+ equalityFn: (prevState, currentState) => {
330
+ if (
331
+ isRouteParametersChanged({
332
+ store: 'bestRoute',
333
+ prevState,
334
+ currentState,
335
+ })
336
+ )
337
+ return false;
317
338
  else return true;
318
339
  },
319
340
  }
@@ -324,11 +345,19 @@ const bestRoute = (
324
345
  slippage: state.slippage,
325
346
  customSlippage: state.customSlippage,
326
347
  disabledLiquiditySources: state.disabledLiquiditySources,
348
+ infiniteApprove: state.infiniteApprove,
327
349
  }),
328
350
  bestRouteParamsListener,
329
351
  {
330
- equalityFn: (prevState, state) => {
331
- if (isRouteParametersChanged(prevState, state)) return false;
352
+ equalityFn: (prevState, currentState) => {
353
+ if (
354
+ isRouteParametersChanged({
355
+ store: 'settings',
356
+ prevState,
357
+ currentState,
358
+ })
359
+ )
360
+ return false;
332
361
  else return true;
333
362
  },
334
363
  }
@@ -1,17 +1,33 @@
1
1
  import { RouteState } from '../store/bestRoute';
2
2
  import { SettingsState } from '../store/settings';
3
3
 
4
- export interface BestRouteParams {
4
+ interface BestRouteStoreParams {
5
5
  fromChain?: RouteState['fromChain'];
6
6
  toChain?: RouteState['toChain'];
7
7
  fromToken?: RouteState['fromToken'];
8
8
  toToken?: RouteState['toToken'];
9
9
  inputAmount?: RouteState['inputAmount'];
10
+ }
11
+
12
+ interface SettingsStoreParams {
10
13
  slippage?: SettingsState['slippage'];
11
14
  customSlippage?: SettingsState['customSlippage'];
12
15
  disabledLiquiditySources?: SettingsState['disabledLiquiditySources'];
16
+ infiniteApprove?: SettingsState['infiniteApprove'];
13
17
  }
14
18
 
19
+ export type BestRouteEqualityParams =
20
+ | {
21
+ store: 'bestRoute';
22
+ prevState: BestRouteStoreParams;
23
+ currentState: BestRouteStoreParams;
24
+ }
25
+ | {
26
+ store: 'settings';
27
+ prevState: SettingsStoreParams;
28
+ currentState: SettingsStoreParams;
29
+ };
30
+
15
31
  export enum ConfirmSwapErrorTypes {
16
32
  NO_ROUTE,
17
33
  ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS,
@@ -6,7 +6,7 @@ import BigNumber from 'bignumber.js';
6
6
  import { BestRouteResponse, BlockchainMeta, Token } from 'rango-sdk';
7
7
  import { areEqual } from './common';
8
8
  import { SelectedWallet } from './wallets';
9
- import { BestRouteParams } from '../types';
9
+ import { BestRouteEqualityParams } from '../types';
10
10
  import { TokenMeta } from '@rango-dev/ui/dist/types/meta';
11
11
  import { numberToString } from './numbers';
12
12
  import { getUsdFeeOfStep } from './swap';
@@ -112,28 +112,34 @@ export function getRequiredBalanceOfWallet(
112
112
  return relatedFeeStatus.requiredAssets;
113
113
  }
114
114
 
115
- export function isRouteParametersChanged(
116
- prevParams: BestRouteParams,
117
- currentParams: BestRouteParams
118
- ) {
119
- return (
120
- !!currentParams.fromToken &&
121
- !!currentParams.toToken &&
122
- (prevParams.fromChain?.name !== currentParams.fromChain?.name ||
123
- prevParams.toChain?.name !== currentParams.toChain?.name ||
124
- prevParams.fromToken?.symbol !== currentParams.fromToken?.symbol ||
125
- prevParams.toToken?.symbol !== currentParams.toToken?.symbol ||
126
- prevParams.fromToken?.blockchain !==
127
- currentParams.fromToken?.blockchain ||
128
- prevParams.toToken?.blockchain !== currentParams.toToken?.blockchain ||
129
- prevParams.fromToken?.address !== currentParams.fromToken?.address ||
130
- prevParams.toToken?.address !== currentParams.toToken?.address ||
131
- prevParams.inputAmount !== currentParams.inputAmount ||
132
- prevParams.slippage !== currentParams.slippage ||
133
- prevParams.customSlippage !== currentParams.customSlippage ||
134
- prevParams.disabledLiquiditySources?.length !==
135
- currentParams.disabledLiquiditySources?.length)
136
- );
115
+ export function isRouteParametersChanged(params: BestRouteEqualityParams) {
116
+ if (params.store === 'bestRoute') {
117
+ const { prevState, currentState } = params;
118
+ return (
119
+ !!currentState.fromToken &&
120
+ !!currentState.toToken &&
121
+ (prevState.fromChain?.name !== currentState.fromChain?.name ||
122
+ prevState.toChain?.name !== currentState.toChain?.name ||
123
+ prevState.fromToken?.symbol !== currentState.fromToken?.symbol ||
124
+ prevState.toToken?.symbol !== currentState.toToken?.symbol ||
125
+ prevState.fromToken?.blockchain !== prevState.fromToken?.blockchain ||
126
+ prevState.toToken?.blockchain !== currentState.toToken?.blockchain ||
127
+ prevState.fromToken?.address !== currentState.fromToken?.address ||
128
+ prevState.toToken?.address !== currentState.toToken?.address ||
129
+ prevState.inputAmount !== currentState.inputAmount)
130
+ );
131
+ } else if (params.store === 'settings') {
132
+ const { prevState, currentState } = params;
133
+ return (
134
+ prevState.slippage !== currentState.slippage ||
135
+ prevState.customSlippage !== currentState.customSlippage ||
136
+ prevState.disabledLiquiditySources?.length !==
137
+ currentState.disabledLiquiditySources?.length ||
138
+ prevState.infiniteApprove ||
139
+ currentState.infiniteApprove
140
+ );
141
+ }
142
+ return false;
137
143
  }
138
144
 
139
145
  export function getBestRouteWithCalculatedFees(
package/src/utils/swap.ts CHANGED
@@ -140,7 +140,8 @@ export function getSwapButtonState(
140
140
  if (accounts.length == 0) return { title: 'Connect Wallet', disabled: false };
141
141
  if (loading) return { title: 'Finding Best Route...', disabled: true };
142
142
  else if (inputIsZero) return { title: 'Enter an amount', disabled: true };
143
- else if (!bestRoute) return { title: 'Swap', disabled: true };
143
+ else if (!bestRoute || !bestRoute.result)
144
+ return { title: 'Swap', disabled: true };
144
145
  else if (hasLimitError) return { title: 'Limit Error', disabled: true };
145
146
  else if (highValueLoss)
146
147
  return { title: 'Price impact is too high!', disabled: true };