@rango-dev/widget-embedded 0.20.1-next.17 → 0.20.1-next.19
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/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts +460 -1112
- package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts.map +1 -1
- package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.d.ts.map +1 -1
- package/dist/components/CustomCollapsible/CustomCollapsible.d.ts +5 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.d.ts.map +1 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.styles.d.ts +654 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.styles.d.ts.map +1 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.types.d.ts +10 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.types.d.ts.map +1 -0
- package/dist/components/Quote/Quote.d.ts.map +1 -1
- package/dist/components/Quote/Quote.types.d.ts +4 -0
- package/dist/components/Quote/Quote.types.d.ts.map +1 -1
- package/dist/components/Quote/QuoteCostDetails.d.ts +4 -0
- package/dist/components/Quote/QuoteCostDetails.d.ts.map +1 -0
- package/dist/components/Quote/QuoteCostDetails.styles.d.ts +806 -0
- package/dist/components/Quote/QuoteCostDetails.styles.d.ts.map +1 -0
- package/dist/constants/quote.d.ts +12 -0
- package/dist/constants/quote.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +4 -4
- package/dist/utils/swap.d.ts +5 -1
- package/dist/utils/swap.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/ConfirmWalletsModal/ConfirmWallets.styles.ts +27 -96
- package/src/components/ConfirmWalletsModal/ConfirmWalletsModal.tsx +24 -39
- package/src/components/CustomCollapsible/CustomCollapsible.styles.ts +75 -0
- package/src/components/CustomCollapsible/CustomCollapsible.tsx +55 -0
- package/src/components/CustomCollapsible/CustomCollapsible.types.ts +10 -0
- package/src/components/Quote/Quote.styles.ts +1 -1
- package/src/components/Quote/Quote.tsx +3 -19
- package/src/components/Quote/Quote.types.ts +5 -0
- package/src/components/Quote/QuoteCostDetails.styles.ts +50 -0
- package/src/components/Quote/QuoteCostDetails.tsx +218 -0
- package/src/constants/quote.ts +23 -0
- package/src/utils/swap.ts +35 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { QuoteCostDetailsProps } from './Quote.types';
|
|
2
|
+
import type { NameOfFees } from '../../constants/quote';
|
|
3
|
+
|
|
4
|
+
import { i18n } from '@lingui/core';
|
|
5
|
+
import {
|
|
6
|
+
ChevronDownIcon,
|
|
7
|
+
CloseIcon,
|
|
8
|
+
Divider,
|
|
9
|
+
IconButton,
|
|
10
|
+
Modal,
|
|
11
|
+
QuoteCost,
|
|
12
|
+
Tooltip,
|
|
13
|
+
Typography,
|
|
14
|
+
} from '@rango-dev/ui';
|
|
15
|
+
import BigNumber from 'bignumber.js';
|
|
16
|
+
import React, { useState } from 'react';
|
|
17
|
+
|
|
18
|
+
import { NAME_OF_FEES } from '../../constants/quote';
|
|
19
|
+
import {
|
|
20
|
+
GAS_FEE_MAX_DECIMALS,
|
|
21
|
+
GAS_FEE_MIN_DECIMALS,
|
|
22
|
+
USD_VALUE_MAX_DECIMALS,
|
|
23
|
+
USD_VALUE_MIN_DECIMALS,
|
|
24
|
+
} from '../../constants/routing';
|
|
25
|
+
import { useAppStore } from '../../store/AppStore';
|
|
26
|
+
import { getContainer } from '../../utils/common';
|
|
27
|
+
import {
|
|
28
|
+
formatTooltipNumbers,
|
|
29
|
+
numberToString,
|
|
30
|
+
secondsToString,
|
|
31
|
+
totalArrivalTime,
|
|
32
|
+
} from '../../utils/numbers';
|
|
33
|
+
import {
|
|
34
|
+
getFeesGroup,
|
|
35
|
+
getTotalFeeInUsd,
|
|
36
|
+
getTotalFeesInUsd,
|
|
37
|
+
getUsdFee,
|
|
38
|
+
} from '../../utils/swap';
|
|
39
|
+
import { CustomCollapsible } from '../CustomCollapsible/CustomCollapsible';
|
|
40
|
+
import { ExpandedIcon } from '../CustomCollapsible/CustomCollapsible.styles';
|
|
41
|
+
|
|
42
|
+
import {
|
|
43
|
+
FeeSection,
|
|
44
|
+
Line,
|
|
45
|
+
ModalContainer,
|
|
46
|
+
ModalHeader,
|
|
47
|
+
trigger,
|
|
48
|
+
} from './QuoteCostDetails.styles';
|
|
49
|
+
|
|
50
|
+
const GAS_FEE_MAX = 30;
|
|
51
|
+
|
|
52
|
+
const NonPayableFee = (props: { fee: BigNumber; label: string }) => {
|
|
53
|
+
return !props.fee.isZero() ? (
|
|
54
|
+
<FeeSection>
|
|
55
|
+
<Typography variant="label" size="medium" color="neutral600">
|
|
56
|
+
{props.label}
|
|
57
|
+
</Typography>
|
|
58
|
+
<Typography variant="label" size="medium">
|
|
59
|
+
$
|
|
60
|
+
{numberToString(
|
|
61
|
+
props.fee,
|
|
62
|
+
USD_VALUE_MIN_DECIMALS,
|
|
63
|
+
USD_VALUE_MAX_DECIMALS
|
|
64
|
+
)}
|
|
65
|
+
</Typography>
|
|
66
|
+
</FeeSection>
|
|
67
|
+
) : null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export function QuoteCostDetails(props: QuoteCostDetailsProps) {
|
|
71
|
+
const [open, setOpen] = useState<boolean>(false);
|
|
72
|
+
const [openCollapse, setOpenCollapse] = useState<boolean>(false);
|
|
73
|
+
const { steps, quote } = props;
|
|
74
|
+
const tokens = useAppStore().tokens();
|
|
75
|
+
const totalTime = secondsToString(totalArrivalTime(quote.result?.swaps));
|
|
76
|
+
const swaps = quote.result?.swaps ?? [];
|
|
77
|
+
const container = getContainer();
|
|
78
|
+
|
|
79
|
+
const totalFee = getTotalFeeInUsd(swaps, tokens);
|
|
80
|
+
|
|
81
|
+
const feesGroup = getFeesGroup(swaps);
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<>
|
|
85
|
+
<QuoteCost
|
|
86
|
+
onClickFee={() => setOpen(!open)}
|
|
87
|
+
fee={numberToString(
|
|
88
|
+
totalFee,
|
|
89
|
+
GAS_FEE_MIN_DECIMALS,
|
|
90
|
+
GAS_FEE_MAX_DECIMALS
|
|
91
|
+
)}
|
|
92
|
+
feeWarning={totalFee.gte(new BigNumber(GAS_FEE_MAX))}
|
|
93
|
+
time={totalTime}
|
|
94
|
+
steps={steps}
|
|
95
|
+
tooltipGas={i18n.t('View more info')}
|
|
96
|
+
tooltipContainer={container}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
<Modal
|
|
100
|
+
container={container}
|
|
101
|
+
open={open}
|
|
102
|
+
header={
|
|
103
|
+
<ModalHeader>
|
|
104
|
+
<Typography variant="title" size="medium">
|
|
105
|
+
{i18n.t('Gas & Fee Explanation')}
|
|
106
|
+
</Typography>
|
|
107
|
+
|
|
108
|
+
<IconButton onClick={() => setOpen(false)} variant="ghost">
|
|
109
|
+
<CloseIcon color="gray" size={14} />
|
|
110
|
+
</IconButton>
|
|
111
|
+
</ModalHeader>
|
|
112
|
+
}
|
|
113
|
+
onClose={() => setOpen(false)}>
|
|
114
|
+
<ModalContainer>
|
|
115
|
+
<Typography variant="title" size="small">
|
|
116
|
+
{i18n.t('Details')}
|
|
117
|
+
</Typography>
|
|
118
|
+
<Divider size={10} />
|
|
119
|
+
{Object.entries(feesGroup.payable).flatMap(
|
|
120
|
+
([payableFeesKey, feeArray]) =>
|
|
121
|
+
feeArray.map((fee, index) => {
|
|
122
|
+
const key = `payable-fee-${index}`;
|
|
123
|
+
const usdValue = getUsdFee(fee);
|
|
124
|
+
return (
|
|
125
|
+
<FeeSection key={key}>
|
|
126
|
+
<Typography
|
|
127
|
+
variant="label"
|
|
128
|
+
size="medium"
|
|
129
|
+
color="neutral600">
|
|
130
|
+
{NAME_OF_FEES[payableFeesKey as NameOfFees]}
|
|
131
|
+
</Typography>
|
|
132
|
+
<Tooltip
|
|
133
|
+
content={formatTooltipNumbers(fee.amount)}
|
|
134
|
+
container={container}>
|
|
135
|
+
<Typography variant="label" size="medium">
|
|
136
|
+
{numberToString(
|
|
137
|
+
fee.amount,
|
|
138
|
+
GAS_FEE_MIN_DECIMALS,
|
|
139
|
+
GAS_FEE_MAX_DECIMALS
|
|
140
|
+
)}{' '}
|
|
141
|
+
{fee.asset.symbol} ($
|
|
142
|
+
{numberToString(
|
|
143
|
+
usdValue,
|
|
144
|
+
USD_VALUE_MIN_DECIMALS,
|
|
145
|
+
USD_VALUE_MAX_DECIMALS
|
|
146
|
+
)}
|
|
147
|
+
)
|
|
148
|
+
</Typography>
|
|
149
|
+
</Tooltip>
|
|
150
|
+
</FeeSection>
|
|
151
|
+
);
|
|
152
|
+
})
|
|
153
|
+
)}
|
|
154
|
+
|
|
155
|
+
<FeeSection className="total_payable_fee">
|
|
156
|
+
<Typography variant="label" size="medium">
|
|
157
|
+
{i18n.t('Total Payable Fee')}
|
|
158
|
+
</Typography>
|
|
159
|
+
<Typography variant="label" size="medium">
|
|
160
|
+
$
|
|
161
|
+
{numberToString(
|
|
162
|
+
totalFee,
|
|
163
|
+
USD_VALUE_MIN_DECIMALS,
|
|
164
|
+
USD_VALUE_MAX_DECIMALS
|
|
165
|
+
)}
|
|
166
|
+
</Typography>
|
|
167
|
+
</FeeSection>
|
|
168
|
+
<Line />
|
|
169
|
+
{Object.keys(feesGroup.nonePayable).length && (
|
|
170
|
+
<CustomCollapsible
|
|
171
|
+
triggerAnchor="bottom"
|
|
172
|
+
onClickTrigger={() => setOpenCollapse((prev) => !prev)}
|
|
173
|
+
trigger={
|
|
174
|
+
<div className={trigger()}>
|
|
175
|
+
<Typography size="small" variant="body" color="neutral700">
|
|
176
|
+
{openCollapse
|
|
177
|
+
? i18n.t('Hide non-payable fees')
|
|
178
|
+
: i18n.t('Show non-payable fees')}
|
|
179
|
+
</Typography>
|
|
180
|
+
<Divider size={4} direction="horizontal" />
|
|
181
|
+
<ExpandedIcon orientation={openCollapse ? 'up' : 'down'}>
|
|
182
|
+
<ChevronDownIcon size={12} color="gray" />
|
|
183
|
+
</ExpandedIcon>
|
|
184
|
+
</div>
|
|
185
|
+
}
|
|
186
|
+
open={openCollapse}>
|
|
187
|
+
<Typography size="small" variant="title">
|
|
188
|
+
{i18n.t('Description')}
|
|
189
|
+
</Typography>
|
|
190
|
+
<Divider size={4} />
|
|
191
|
+
<Typography size="small" variant="body" color="neutral700">
|
|
192
|
+
{i18n.t(`The following fees are considered in the transaction output and
|
|
193
|
+
you won’t need to pay extra gas for them.`)}
|
|
194
|
+
</Typography>
|
|
195
|
+
<Divider size={10} />
|
|
196
|
+
{Object.entries(feesGroup.nonePayable).map(
|
|
197
|
+
([nonPayableFeesKey, fees], index) => {
|
|
198
|
+
const totalFeeInUsd = getTotalFeesInUsd(fees);
|
|
199
|
+
const label = NAME_OF_FEES[nonPayableFeesKey as NameOfFees];
|
|
200
|
+
const key = `non-payable-fee-${index}`;
|
|
201
|
+
return (
|
|
202
|
+
<NonPayableFee
|
|
203
|
+
key={key}
|
|
204
|
+
fee={totalFeeInUsd}
|
|
205
|
+
label={label}
|
|
206
|
+
/>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
)}
|
|
210
|
+
|
|
211
|
+
<Line />
|
|
212
|
+
</CustomCollapsible>
|
|
213
|
+
)}
|
|
214
|
+
</ModalContainer>
|
|
215
|
+
</Modal>
|
|
216
|
+
</>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SwapFee } from 'rango-sdk';
|
|
2
|
+
|
|
3
|
+
import { i18n } from '@lingui/core';
|
|
4
|
+
|
|
5
|
+
export type NameOfFees =
|
|
6
|
+
| 'Swapper Fee'
|
|
7
|
+
| 'Affiliate Fee'
|
|
8
|
+
| 'Outbound network fee'
|
|
9
|
+
| 'Rango Fee'
|
|
10
|
+
| 'Network Fee';
|
|
11
|
+
|
|
12
|
+
export const NAME_OF_FEES: Record<NameOfFees, string> = {
|
|
13
|
+
'Network Fee': i18n.t('Network Fee'),
|
|
14
|
+
'Swapper Fee': i18n.t('Protocol Fee'),
|
|
15
|
+
'Affiliate Fee': i18n.t('Affiliate Fee'),
|
|
16
|
+
'Outbound network fee': i18n.t('Outbound Fee'),
|
|
17
|
+
'Rango Fee': i18n.t('Rango Fee'),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type FeesGroup = {
|
|
21
|
+
payable: { [key in NameOfFees]?: SwapFee[] };
|
|
22
|
+
nonePayable: { [key in NameOfFees]?: SwapFee[] };
|
|
23
|
+
};
|
package/src/utils/swap.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-magic-numbers */
|
|
2
|
+
import type { FeesGroup, NameOfFees } from '../constants/quote';
|
|
2
3
|
import type { FetchStatus } from '../store/slices/data';
|
|
3
4
|
import type {
|
|
4
5
|
ConvertedToken,
|
|
@@ -14,6 +15,7 @@ import type {
|
|
|
14
15
|
BestRouteResponse,
|
|
15
16
|
BlockchainMeta,
|
|
16
17
|
RecommendedSlippage,
|
|
18
|
+
SwapFee,
|
|
17
19
|
SwapResult,
|
|
18
20
|
Token,
|
|
19
21
|
} from 'rango-sdk';
|
|
@@ -328,6 +330,39 @@ export function getTotalFeeInUsd(
|
|
|
328
330
|
);
|
|
329
331
|
}
|
|
330
332
|
|
|
333
|
+
export function getUsdFee(fee: SwapFee): BigNumber {
|
|
334
|
+
let totalFeeInUsd = ZERO;
|
|
335
|
+
totalFeeInUsd = totalFeeInUsd.plus(
|
|
336
|
+
new BigNumber(fee.amount).multipliedBy(fee.price || 0)
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
return totalFeeInUsd;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export function getTotalFeesInUsd(fees: SwapFee[]): BigNumber {
|
|
343
|
+
return fees.reduce(
|
|
344
|
+
(totalFee: BigNumber, fee) => totalFee.plus(getUsdFee(fee)),
|
|
345
|
+
ZERO
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
export function getFeesGroup(swaps: SwapResult[]): FeesGroup {
|
|
349
|
+
return swaps.reduce(
|
|
350
|
+
(result, swap) => {
|
|
351
|
+
for (const fee of swap.fee) {
|
|
352
|
+
const name = fee.name as NameOfFees;
|
|
353
|
+
const feeGroup =
|
|
354
|
+
fee.expenseType !== 'DECREASE_FROM_OUTPUT'
|
|
355
|
+
? result.payable
|
|
356
|
+
: result.nonePayable;
|
|
357
|
+
|
|
358
|
+
feeGroup[name] = [...(feeGroup[name] || []), fee];
|
|
359
|
+
}
|
|
360
|
+
return result;
|
|
361
|
+
},
|
|
362
|
+
{ payable: {}, nonePayable: {} } as FeesGroup
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
331
366
|
export function hasHighFee(totalFeeInUsd: BigNumber | null) {
|
|
332
367
|
if (!totalFeeInUsd) {
|
|
333
368
|
return false;
|