@xswap-link/sdk 0.8.7 → 0.9.1
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/.github/workflows/main.yml +2 -1
- package/CHANGELOG.md +12 -0
- package/babel.config.cjs +8 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.global.js +132 -135
- package/dist/index.js +9 -9
- package/dist/index.mjs +10 -10
- package/jest.config.ts +37 -0
- package/package.json +17 -5
- package/src/components/Modal/index.tsx +1 -1
- package/src/components/Swap/Header/index.tsx +1 -1
- package/src/components/Swap/ReorderButton/ReorderButton.tsx +12 -10
- package/src/components/Swap/SwapView/FeesPanel/index.tsx +1 -1
- package/src/components/Swap/SwapView/SwapButton/index.tsx +23 -21
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +4 -2
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +51 -59
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +47 -13
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +138 -35
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +6 -2
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +1 -1
- package/src/components/Swap/SwapView/index.tsx +2 -2
- package/src/components/Tooltip/index.tsx +1 -1
- package/src/context/HistoryProvider.tsx +2 -2
- package/src/context/SwapProvider.tsx +174 -100
- package/src/context/TransactionProvider.tsx +1 -1
- package/src/models/TokenData.ts +3 -1
- package/src/models/payloads/GetPricesPayload.ts +1 -1
- package/src/utils/validation.ts +50 -16
- package/tailwind.config.js +1 -0
- package/test/context/SwapProvider.test.tsx +851 -0
- package/test/fileMock.ts +1 -0
- package/test/fixtures/bridgeTokens.mock.ts +1318 -0
- package/test/fixtures/bridgeTokensDictionary.mock.ts +1272 -0
- package/test/fixtures/integrationConfig.mock.ts +10 -0
- package/test/fixtures/supportedChains.mock.ts +32950 -0
- package/test/{api.test.ts → services/getChains.test.ts} +6 -5
- package/test/setup.ts +13 -0
- package/test/styleMock.ts +1 -0
- package/jest.config.json +0 -8
- package/test/api.mock.ts +0 -106
- package/test/setupTests.ts +0 -3
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { TxConfigFormPayload } from "@src/components";
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_DESTINATION_CHAIN_ID,
|
|
4
|
-
DEFAULT_DESTINATION_TOKEN_ADDR,
|
|
5
4
|
DEFAULT_REQUEST_ABORT_MSG,
|
|
6
5
|
DEFAULT_SOURCE_CHAIN_ID,
|
|
7
|
-
DEFAULT_SOURCE_TOKEN_ADDR,
|
|
8
6
|
} from "@src/constants";
|
|
9
7
|
import { ADDRESSES } from "@src/contracts";
|
|
10
8
|
import {
|
|
@@ -32,9 +30,8 @@ import {
|
|
|
32
30
|
safeBigNumberFrom,
|
|
33
31
|
weiToHumanReadable,
|
|
34
32
|
} from "@src/utils";
|
|
35
|
-
import { mapToValidPath } from "@src/utils/validation";
|
|
36
33
|
import BigNumberJS from "bignumber.js";
|
|
37
|
-
import { BigNumber, constants } from "ethers";
|
|
34
|
+
import { BigNumber, constants, ethers } from "ethers";
|
|
38
35
|
import {
|
|
39
36
|
createContext,
|
|
40
37
|
Dispatch,
|
|
@@ -49,6 +46,7 @@ import {
|
|
|
49
46
|
} from "react";
|
|
50
47
|
import { Config, useAccount } from "wagmi";
|
|
51
48
|
import { useHistory } from "./HistoryProvider";
|
|
49
|
+
import { mapToValidPath } from "@src/utils/validation";
|
|
52
50
|
|
|
53
51
|
type Tab = "Swap" | "History" | "Settings";
|
|
54
52
|
type SwapContext = {
|
|
@@ -66,8 +64,7 @@ type SwapContext = {
|
|
|
66
64
|
setSrcChain: Dispatch<SetStateAction<Chain | undefined>>;
|
|
67
65
|
srcChainTokensOptions: TokenOption[];
|
|
68
66
|
srcChainOtherTokensOptions: TokenOption[];
|
|
69
|
-
|
|
70
|
-
dstChainTokensPrices: TokenPrices;
|
|
67
|
+
tokenPrices: TokenPrices;
|
|
71
68
|
srcToken: Token | undefined;
|
|
72
69
|
setSrcToken: Dispatch<SetStateAction<Token | undefined>>;
|
|
73
70
|
dstChain: Chain | undefined;
|
|
@@ -130,8 +127,7 @@ const init: SwapContext = {
|
|
|
130
127
|
srcChain: undefined,
|
|
131
128
|
srcChainTokensOptions: [],
|
|
132
129
|
srcChainOtherTokensOptions: [],
|
|
133
|
-
|
|
134
|
-
dstChainTokensPrices: {},
|
|
130
|
+
tokenPrices: {},
|
|
135
131
|
dstChain: undefined,
|
|
136
132
|
dstChainTokensOptions: [],
|
|
137
133
|
dstChainOtherTokensOptions: [],
|
|
@@ -150,7 +146,7 @@ const init: SwapContext = {
|
|
|
150
146
|
dstValueMin: "",
|
|
151
147
|
lastTx: undefined,
|
|
152
148
|
expressDelivery: true,
|
|
153
|
-
infiniteApproval:
|
|
149
|
+
infiniteApproval: true,
|
|
154
150
|
slippage: "1.5",
|
|
155
151
|
route: undefined,
|
|
156
152
|
isAsyncDataLoaded: false,
|
|
@@ -248,12 +244,7 @@ export const SwapProvider = ({
|
|
|
248
244
|
const [dstChainTokensOptions, setDstChainTokensOptions] = useState(
|
|
249
245
|
init.dstChainTokensOptions,
|
|
250
246
|
);
|
|
251
|
-
const [
|
|
252
|
-
init.srcChainTokensPrices,
|
|
253
|
-
);
|
|
254
|
-
const [dstChainTokensPrices, setDstChainTokensPrices] = useState(
|
|
255
|
-
init.dstChainTokensPrices,
|
|
256
|
-
);
|
|
247
|
+
const [tokenPrices, setTokenPrices] = useState(init.tokenPrices);
|
|
257
248
|
const [srcChainOtherTokensOptions, setSrcChainOtherTokensOptions] = useState(
|
|
258
249
|
init.srcChainOtherTokensOptions,
|
|
259
250
|
);
|
|
@@ -267,6 +258,15 @@ export const SwapProvider = ({
|
|
|
267
258
|
|
|
268
259
|
const { history } = useHistory();
|
|
269
260
|
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
if (supportedChains.length > 0) {
|
|
263
|
+
const chainIds = supportedChains.map((chain) => chain.chainId);
|
|
264
|
+
getPrices({ chainId: chainIds }).then((prices) => {
|
|
265
|
+
setTokenPrices(prices);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}, [supportedChains]);
|
|
269
|
+
|
|
270
270
|
const supportedTokens: Record<string, Record<string, Token>> = useMemo(() => {
|
|
271
271
|
const customTokens = !isServer
|
|
272
272
|
? JSON.parse(localStorage.getItem("custom-tokens") || "{}")
|
|
@@ -344,8 +344,8 @@ export const SwapProvider = ({
|
|
|
344
344
|
}, [bridgeTokens]);
|
|
345
345
|
|
|
346
346
|
const getTokenOptions = useCallback(
|
|
347
|
-
(chainId: string | undefined
|
|
348
|
-
if (!chainId
|
|
347
|
+
(chainId: string | undefined) => {
|
|
348
|
+
if (!chainId) {
|
|
349
349
|
return [];
|
|
350
350
|
}
|
|
351
351
|
|
|
@@ -408,36 +408,21 @@ export const SwapProvider = ({
|
|
|
408
408
|
[srcToken?.decimals, srcValue],
|
|
409
409
|
);
|
|
410
410
|
|
|
411
|
-
// fetch srcTokenPrices
|
|
412
|
-
useEffect(() => {
|
|
413
|
-
if (srcChain) {
|
|
414
|
-
getPrices({ chainId: srcChain.chainId, currency: "USD" }).then((prices) =>
|
|
415
|
-
setSrcChainTokensPrices(prices),
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
}, [srcChain]);
|
|
419
|
-
|
|
420
|
-
// fetch dstTokenPrices
|
|
421
|
-
useEffect(() => {
|
|
422
|
-
if (dstChain) {
|
|
423
|
-
getPrices({ chainId: dstChain.chainId, currency: "USD" }).then((prices) =>
|
|
424
|
-
setDstChainTokensPrices(prices),
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
}, [dstChain]);
|
|
428
|
-
|
|
429
411
|
const srcValueUsd = useMemo(() => {
|
|
430
412
|
if (
|
|
431
413
|
srcToken &&
|
|
432
|
-
|
|
433
|
-
|
|
414
|
+
srcChain &&
|
|
415
|
+
tokenPrices &&
|
|
416
|
+
tokenPrices[srcChain.chainId] &&
|
|
417
|
+
tokenPrices[srcChain.chainId]?.[srcToken.address]
|
|
434
418
|
) {
|
|
435
419
|
return (
|
|
436
|
-
Number(srcValue) *
|
|
420
|
+
Number(srcValue) *
|
|
421
|
+
Number(tokenPrices[srcChain.chainId]?.[srcToken.address])
|
|
437
422
|
).toFixed(2);
|
|
438
423
|
}
|
|
439
424
|
return null;
|
|
440
|
-
}, [
|
|
425
|
+
}, [tokenPrices, srcToken, srcValue, srcChain]);
|
|
441
426
|
const dstValue = useMemo(
|
|
442
427
|
() =>
|
|
443
428
|
weiToHumanReadable({
|
|
@@ -459,15 +444,18 @@ export const SwapProvider = ({
|
|
|
459
444
|
const dstValueUsd = useMemo(() => {
|
|
460
445
|
if (
|
|
461
446
|
dstToken &&
|
|
462
|
-
|
|
463
|
-
|
|
447
|
+
dstChain &&
|
|
448
|
+
tokenPrices &&
|
|
449
|
+
tokenPrices[dstChain?.chainId] &&
|
|
450
|
+
tokenPrices[dstChain?.chainId]?.[dstToken.address]
|
|
464
451
|
) {
|
|
465
452
|
return (
|
|
466
|
-
Number(dstValue) *
|
|
453
|
+
Number(dstValue) *
|
|
454
|
+
Number(tokenPrices[dstChain?.chainId]?.[dstToken.address])
|
|
467
455
|
).toFixed(2);
|
|
468
456
|
}
|
|
469
457
|
return null;
|
|
470
|
-
}, [
|
|
458
|
+
}, [tokenPrices, dstToken, dstValue, dstChain]);
|
|
471
459
|
const dstValueMin = useMemo(
|
|
472
460
|
() =>
|
|
473
461
|
weiToHumanReadable({
|
|
@@ -564,7 +552,6 @@ export const SwapProvider = ({
|
|
|
564
552
|
// source chain
|
|
565
553
|
const srcTokenOptions: TokenOption[] = getTokenOptions(
|
|
566
554
|
srcChain?.chainId,
|
|
567
|
-
dstChain?.chainId,
|
|
568
555
|
).filter(({ symbol }) =>
|
|
569
556
|
dstChain?.chainId === srcChain?.chainId
|
|
570
557
|
? symbol !== dstToken?.symbol
|
|
@@ -575,7 +562,6 @@ export const SwapProvider = ({
|
|
|
575
562
|
// destination chain
|
|
576
563
|
const dstTokenOptions: TokenOption[] = getTokenOptions(
|
|
577
564
|
dstChain?.chainId,
|
|
578
|
-
dstChain?.chainId,
|
|
579
565
|
).filter(({ symbol }) =>
|
|
580
566
|
dstChain?.chainId === srcChain?.chainId
|
|
581
567
|
? symbol !== srcToken?.symbol
|
|
@@ -603,7 +589,7 @@ export const SwapProvider = ({
|
|
|
603
589
|
);
|
|
604
590
|
for (const { chainId } of srcOtherChains) {
|
|
605
591
|
srcOtherTokenOptions.push(
|
|
606
|
-
...getTokenOptions(chainId
|
|
592
|
+
...getTokenOptions(chainId).filter(({ symbol }) =>
|
|
607
593
|
chainId === dstChain?.chainId ? symbol !== dstToken?.symbol : true,
|
|
608
594
|
),
|
|
609
595
|
);
|
|
@@ -620,7 +606,7 @@ export const SwapProvider = ({
|
|
|
620
606
|
);
|
|
621
607
|
for (const { chainId } of dstOtherChains) {
|
|
622
608
|
dstOtherTokenOptions.push(
|
|
623
|
-
...getTokenOptions(chainId
|
|
609
|
+
...getTokenOptions(chainId).filter(({ symbol }) =>
|
|
624
610
|
chainId === srcChain?.chainId ? symbol !== srcToken?.symbol : true,
|
|
625
611
|
),
|
|
626
612
|
);
|
|
@@ -714,64 +700,149 @@ export const SwapProvider = ({
|
|
|
714
700
|
);
|
|
715
701
|
}, [srcChain]);
|
|
716
702
|
|
|
703
|
+
// Add new state to track initial setup
|
|
704
|
+
const [isInitialStateSet, setIsInitialStateSet] = useState(false);
|
|
705
|
+
|
|
717
706
|
useEffect(() => {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
(walletChainId ? `${walletChainId}` : undefined) ||
|
|
726
|
-
// default chain
|
|
727
|
-
(bridgeUI ? undefined : DEFAULT_SOURCE_CHAIN_ID);
|
|
728
|
-
|
|
729
|
-
const initSrcChain = supportedChains.find(
|
|
730
|
-
({ chainId }) => chainId === searchedChainId,
|
|
731
|
-
);
|
|
707
|
+
// apply wallet chain only after initial state is set
|
|
708
|
+
if (!walletChainId || !isInitialStateSet || integrationConfig?.srcChainId) {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const initSrcChain = supportedChains.find(
|
|
712
|
+
({ chainId }) => chainId === `${walletChainId}`,
|
|
713
|
+
);
|
|
732
714
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
715
|
+
if (initSrcChain) {
|
|
716
|
+
setSrcChain(initSrcChain);
|
|
717
|
+
}
|
|
718
|
+
}, [
|
|
719
|
+
walletChainId,
|
|
720
|
+
isInitialStateSet,
|
|
721
|
+
supportedChains,
|
|
722
|
+
integrationConfig?.srcChainId,
|
|
723
|
+
]);
|
|
740
724
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
725
|
+
useEffect(() => {
|
|
726
|
+
if (isInitialStateSet) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
setSrcToken(undefined);
|
|
730
|
+
setDstToken(undefined);
|
|
731
|
+
setSrcChain(undefined);
|
|
732
|
+
setDstChain(undefined);
|
|
733
|
+
|
|
734
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
735
|
+
}, [bridgeUI]);
|
|
736
|
+
|
|
737
|
+
useEffect(() => {
|
|
738
|
+
// Skip if initial state was already set or wait if supported chains are not loaded yet
|
|
750
739
|
|
|
751
|
-
|
|
740
|
+
if (
|
|
741
|
+
isInitialStateSet ||
|
|
742
|
+
!supportedChains ||
|
|
743
|
+
supportedChains.length === 0 ||
|
|
744
|
+
!bridgeTokensDictionary
|
|
745
|
+
) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
let srcTokenAddress = integrationConfig.srcTokenAddr;
|
|
750
|
+
let dstTokenAddress = integrationConfig.dstTokenAddr;
|
|
751
|
+
// is it a valid eth address? if not try to find it by symbol / tokenId
|
|
752
|
+
if (srcTokenAddress && !ethers.utils.isAddress(srcTokenAddress)) {
|
|
753
|
+
srcTokenAddress = supportedChains
|
|
754
|
+
.find((chain) => chain.chainId === integrationConfig?.srcChainId)
|
|
755
|
+
?.tokens.find(
|
|
756
|
+
(token) => token.tokenId === integrationConfig?.srcTokenAddr,
|
|
757
|
+
)
|
|
758
|
+
?.address?.toLowerCase();
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (dstTokenAddress && !ethers.utils.isAddress(dstTokenAddress)) {
|
|
762
|
+
dstTokenAddress = supportedChains
|
|
763
|
+
.find((chain) => chain.chainId === integrationConfig?.dstChainId)
|
|
764
|
+
?.tokens.find(
|
|
765
|
+
(token) => token.tokenId === integrationConfig?.dstTokenAddr,
|
|
766
|
+
)
|
|
767
|
+
?.address?.toLowerCase();
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
const searchedChainId =
|
|
771
|
+
// currently set chain
|
|
772
|
+
srcChain ||
|
|
773
|
+
// chain set by the integrator
|
|
774
|
+
integrationConfig?.srcChainId ||
|
|
775
|
+
// wallet chain
|
|
776
|
+
(walletChainId ? `${walletChainId}` : undefined) ||
|
|
777
|
+
// default chain
|
|
778
|
+
(bridgeUI ? undefined : DEFAULT_SOURCE_CHAIN_ID);
|
|
779
|
+
|
|
780
|
+
const initSrcChain = supportedChains.find(
|
|
781
|
+
({ chainId }) => chainId === searchedChainId,
|
|
782
|
+
);
|
|
783
|
+
|
|
784
|
+
let initSrcToken: Token | undefined;
|
|
785
|
+
if (initSrcChain) {
|
|
786
|
+
initSrcToken = initSrcChain.tokens.find(
|
|
787
|
+
({ address }) =>
|
|
788
|
+
address.toLowerCase() === srcTokenAddress?.toLowerCase(),
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
let initDstChain: Chain | undefined = bridgeUI
|
|
752
793
|
? undefined
|
|
753
794
|
: supportedChains.find(
|
|
754
|
-
({ chainId }) =>
|
|
755
|
-
chainId ===
|
|
756
|
-
(integrationConfig.dstChainId || DEFAULT_DESTINATION_CHAIN_ID),
|
|
795
|
+
({ chainId }) => chainId === DEFAULT_DESTINATION_CHAIN_ID,
|
|
757
796
|
);
|
|
758
|
-
setDstChain(initDstChain);
|
|
759
797
|
|
|
798
|
+
// if integrator set it, use it
|
|
799
|
+
if (integrationConfig.dstChainId) {
|
|
800
|
+
initDstChain = supportedChains.find(
|
|
801
|
+
({ chainId }) => chainId === integrationConfig.dstChainId,
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
let initDstToken: Token | undefined;
|
|
760
806
|
if (initDstChain) {
|
|
761
|
-
|
|
762
|
-
({ address }) =>
|
|
763
|
-
address.toLowerCase() ===
|
|
764
|
-
(integrationConfig.dstTokenAddr?.toLowerCase() ||
|
|
765
|
-
DEFAULT_DESTINATION_TOKEN_ADDR.toLowerCase()),
|
|
807
|
+
initDstToken = initDstChain.tokens.find(
|
|
808
|
+
({ address }) => address.toLowerCase() === dstTokenAddress,
|
|
766
809
|
);
|
|
767
|
-
setDstToken(initDstToken);
|
|
768
|
-
} else {
|
|
769
|
-
setDstToken(undefined);
|
|
770
810
|
}
|
|
771
|
-
|
|
811
|
+
|
|
812
|
+
// the values here should not be from state but from the code above
|
|
813
|
+
const { source, target } = mapToValidPath({
|
|
814
|
+
source: { chain: initSrcChain, token: initSrcToken },
|
|
815
|
+
target: { chain: initDstChain, token: initDstToken },
|
|
816
|
+
type: bridgeUI ? "BRIDGE" : "SWAP",
|
|
817
|
+
supportedChains,
|
|
818
|
+
bridgeTokensDictionary,
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
setSrcChain(source.chain);
|
|
822
|
+
setDstChain(target.chain);
|
|
823
|
+
setSrcToken(source.token);
|
|
824
|
+
setDstToken(target.token);
|
|
825
|
+
// Mark initial state as set
|
|
826
|
+
setIsInitialStateSet(true);
|
|
827
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
828
|
+
}, [
|
|
829
|
+
integrationConfig?.srcChainId,
|
|
830
|
+
integrationConfig?.srcTokenAddr,
|
|
831
|
+
integrationConfig?.dstChainId,
|
|
832
|
+
integrationConfig?.dstTokenAddr,
|
|
833
|
+
supportedChains,
|
|
834
|
+
bridgeUI,
|
|
835
|
+
walletChainId,
|
|
836
|
+
isInitialStateSet,
|
|
837
|
+
bridgeTokensDictionary,
|
|
838
|
+
]);
|
|
772
839
|
|
|
773
840
|
useEffect(() => {
|
|
774
|
-
if (
|
|
841
|
+
if (
|
|
842
|
+
!bridgeTokensDictionary ||
|
|
843
|
+
supportedChains.length === 0 ||
|
|
844
|
+
!isInitialStateSet
|
|
845
|
+
) {
|
|
775
846
|
return;
|
|
776
847
|
}
|
|
777
848
|
|
|
@@ -814,11 +885,12 @@ export const SwapProvider = ({
|
|
|
814
885
|
} else if (window.xPayOnDstChainChange) {
|
|
815
886
|
window.xPayOnDstChainChange(dstChain?.chainId);
|
|
816
887
|
}
|
|
817
|
-
|
|
888
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
889
|
+
}, [integrationConfig.onDstChainChange, dstChain]);
|
|
818
890
|
|
|
819
891
|
useEffect(() => {
|
|
820
892
|
const token = dstToken
|
|
821
|
-
? { address: dstToken.address.toLowerCase(), symbol: dstToken.
|
|
893
|
+
? { address: dstToken.address.toLowerCase(), symbol: dstToken.tokenId }
|
|
822
894
|
: undefined;
|
|
823
895
|
|
|
824
896
|
if (integrationConfig.onDstTokenChange) {
|
|
@@ -826,7 +898,8 @@ export const SwapProvider = ({
|
|
|
826
898
|
} else if (window.xPayOnDstTokenChange) {
|
|
827
899
|
window.xPayOnDstTokenChange(token);
|
|
828
900
|
}
|
|
829
|
-
|
|
901
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
902
|
+
}, [integrationConfig.onDstTokenChange, dstToken]);
|
|
830
903
|
|
|
831
904
|
useEffect(() => {
|
|
832
905
|
if (integrationConfig.onSrcChainChange) {
|
|
@@ -834,11 +907,12 @@ export const SwapProvider = ({
|
|
|
834
907
|
} else if (window.xPayOnSrcChainChange) {
|
|
835
908
|
window.xPayOnSrcChainChange(srcChain?.chainId);
|
|
836
909
|
}
|
|
837
|
-
|
|
910
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
911
|
+
}, [integrationConfig.onSrcChainChange, srcChain]);
|
|
838
912
|
|
|
839
913
|
useEffect(() => {
|
|
840
914
|
const token = srcToken
|
|
841
|
-
? { address: srcToken.address.toLowerCase(), symbol: srcToken.
|
|
915
|
+
? { address: srcToken.address.toLowerCase(), symbol: srcToken.tokenId }
|
|
842
916
|
: undefined;
|
|
843
917
|
|
|
844
918
|
if (integrationConfig.onSrcTokenChange) {
|
|
@@ -846,7 +920,8 @@ export const SwapProvider = ({
|
|
|
846
920
|
} else if (window.xPayOnSrcTokenChange) {
|
|
847
921
|
window.xPayOnSrcTokenChange(token);
|
|
848
922
|
}
|
|
849
|
-
|
|
923
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
924
|
+
}, [integrationConfig.onSrcTokenChange, srcToken]);
|
|
850
925
|
|
|
851
926
|
return (
|
|
852
927
|
<swapContext.Provider
|
|
@@ -865,8 +940,7 @@ export const SwapProvider = ({
|
|
|
865
940
|
setSrcChain,
|
|
866
941
|
srcChainTokensOptions,
|
|
867
942
|
srcChainOtherTokensOptions,
|
|
868
|
-
|
|
869
|
-
srcChainTokensPrices,
|
|
943
|
+
tokenPrices,
|
|
870
944
|
dstChain,
|
|
871
945
|
setDstChain,
|
|
872
946
|
dstChainTokensOptions,
|
package/src/models/TokenData.ts
CHANGED
package/src/utils/validation.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_DESTINATION_CHAIN_ID,
|
|
3
|
+
DEFAULT_DESTINATION_TOKEN_ADDR,
|
|
3
4
|
DEFAULT_SOURCE_CHAIN_ID,
|
|
5
|
+
DEFAULT_SOURCE_TOKEN_ADDR,
|
|
4
6
|
} from "@src/constants";
|
|
5
7
|
import { BridgeTokensDictionary, Chain, Token } from "@src/models";
|
|
6
8
|
|
|
7
|
-
const
|
|
9
|
+
export const getDefaultSwapSourceChain = ({
|
|
8
10
|
supportedChains,
|
|
9
11
|
}: {
|
|
10
12
|
supportedChains: Chain[];
|
|
@@ -23,7 +25,7 @@ const getDefaultSourceChain = ({
|
|
|
23
25
|
return defaultSourceChain;
|
|
24
26
|
};
|
|
25
27
|
|
|
26
|
-
const getDefaultDestinationChain = ({
|
|
28
|
+
export const getDefaultDestinationChain = ({
|
|
27
29
|
supportedChains,
|
|
28
30
|
}: {
|
|
29
31
|
supportedChains: Chain[];
|
|
@@ -42,15 +44,26 @@ const getDefaultDestinationChain = ({
|
|
|
42
44
|
return defaultTargetChain;
|
|
43
45
|
};
|
|
44
46
|
|
|
45
|
-
const getDefaultSwapTokenForChain = (
|
|
47
|
+
export const getDefaultSwapTokenForChain = (
|
|
46
48
|
chain: Chain,
|
|
49
|
+
defaultTokenAddress: string,
|
|
47
50
|
sameChain?: boolean,
|
|
48
51
|
sourceTokenId?: string,
|
|
49
52
|
) => {
|
|
50
|
-
|
|
53
|
+
// First check if there are any supported tokens at all
|
|
54
|
+
const hasAnySupportedTokens = chain.tokens.some((token) => token.supported);
|
|
55
|
+
if (!hasAnySupportedTokens) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
const defaultToken = chain.tokens.find(
|
|
60
|
+
(token) =>
|
|
61
|
+
token.address.toLowerCase() === defaultTokenAddress.toLowerCase() &&
|
|
62
|
+
token.supported,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (defaultToken) {
|
|
66
|
+
return defaultToken;
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
const fallbackToken = chain.tokens.find((token) =>
|
|
@@ -63,10 +76,10 @@ const getDefaultSwapTokenForChain = (
|
|
|
63
76
|
return fallbackToken;
|
|
64
77
|
}
|
|
65
78
|
|
|
66
|
-
return
|
|
79
|
+
return undefined;
|
|
67
80
|
};
|
|
68
81
|
|
|
69
|
-
const getDefaultBridgeTokenForChain = ({
|
|
82
|
+
export const getDefaultBridgeTokenForChain = ({
|
|
70
83
|
chain,
|
|
71
84
|
bridgeTokensDictionary,
|
|
72
85
|
}: {
|
|
@@ -158,15 +171,17 @@ const mapToValidPathSwap = ({
|
|
|
158
171
|
supportedChains,
|
|
159
172
|
}: Omit<MapToValidPathParams, "type">) => {
|
|
160
173
|
let newSourceChain: Chain | undefined =
|
|
161
|
-
source.chain ||
|
|
174
|
+
source.chain || getDefaultSwapSourceChain({ supportedChains });
|
|
162
175
|
let newTargetChain: Chain | undefined =
|
|
163
176
|
target.chain || getDefaultDestinationChain({ supportedChains });
|
|
164
177
|
let newSourceToken: Token | undefined =
|
|
165
|
-
source.token ||
|
|
178
|
+
source.token ||
|
|
179
|
+
getDefaultSwapTokenForChain(newSourceChain, DEFAULT_SOURCE_TOKEN_ADDR);
|
|
166
180
|
let newTargetToken: Token | undefined =
|
|
167
181
|
target.token ||
|
|
168
182
|
getDefaultSwapTokenForChain(
|
|
169
183
|
newTargetChain,
|
|
184
|
+
DEFAULT_DESTINATION_TOKEN_ADDR,
|
|
170
185
|
newSourceChain.chainId === newTargetChain.chainId,
|
|
171
186
|
newSourceToken?.tokenId,
|
|
172
187
|
);
|
|
@@ -185,7 +200,7 @@ const mapToValidPathSwap = ({
|
|
|
185
200
|
}
|
|
186
201
|
|
|
187
202
|
if (!isSwapSourceValid(newSourceChain)) {
|
|
188
|
-
newSourceChain =
|
|
203
|
+
newSourceChain = getDefaultSwapSourceChain({ supportedChains });
|
|
189
204
|
// We can't have dangling token from a different chain.
|
|
190
205
|
newSourceToken = undefined;
|
|
191
206
|
|
|
@@ -242,11 +257,15 @@ const mapToValidPathSwap = ({
|
|
|
242
257
|
// Setting tokens
|
|
243
258
|
|
|
244
259
|
if (!newSourceToken) {
|
|
245
|
-
newSourceToken = getDefaultSwapTokenForChain(
|
|
260
|
+
newSourceToken = getDefaultSwapTokenForChain(
|
|
261
|
+
newSourceChain,
|
|
262
|
+
DEFAULT_SOURCE_TOKEN_ADDR,
|
|
263
|
+
);
|
|
246
264
|
}
|
|
247
|
-
if (!newTargetToken) {
|
|
265
|
+
if (!newTargetToken || newSourceToken === newTargetToken) {
|
|
248
266
|
newTargetToken = getDefaultSwapTokenForChain(
|
|
249
267
|
newTargetChain,
|
|
268
|
+
DEFAULT_DESTINATION_TOKEN_ADDR,
|
|
250
269
|
newSourceChain.chainId === newTargetChain.chainId,
|
|
251
270
|
newSourceToken?.tokenId,
|
|
252
271
|
);
|
|
@@ -270,8 +289,7 @@ const mapToValidPathBridge = ({
|
|
|
270
289
|
let newTargetToken = target.token;
|
|
271
290
|
|
|
272
291
|
if (!isBridgeSourceValid(newSourceChain)) {
|
|
273
|
-
newSourceChain =
|
|
274
|
-
// We can't have dangling token from a different chain.
|
|
292
|
+
newSourceChain = undefined;
|
|
275
293
|
newSourceToken = undefined;
|
|
276
294
|
|
|
277
295
|
if (!isBridgeSourceValid(newSourceChain)) {
|
|
@@ -297,7 +315,7 @@ const mapToValidPathBridge = ({
|
|
|
297
315
|
sourceToken: newSourceToken,
|
|
298
316
|
})
|
|
299
317
|
) {
|
|
300
|
-
newTargetChain =
|
|
318
|
+
newTargetChain = undefined;
|
|
301
319
|
// We can't have dangling token from a different chain.
|
|
302
320
|
newTargetToken = undefined;
|
|
303
321
|
|
|
@@ -329,6 +347,18 @@ const mapToValidPathBridge = ({
|
|
|
329
347
|
|
|
330
348
|
// Setting tokens
|
|
331
349
|
|
|
350
|
+
// check if the source token is bridgeable
|
|
351
|
+
if (newSourceToken && newSourceChain && newTargetChain) {
|
|
352
|
+
const isBridgeable =
|
|
353
|
+
!!bridgeTokensDictionary[newSourceChain.chainId]?.[
|
|
354
|
+
newSourceToken.address.toLowerCase()
|
|
355
|
+
]?.[newTargetChain.chainId];
|
|
356
|
+
|
|
357
|
+
if (!isBridgeable) {
|
|
358
|
+
newSourceToken = undefined;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
332
362
|
if (!newSourceToken) {
|
|
333
363
|
const defaultToken = getDefaultBridgeTokenForChain({
|
|
334
364
|
chain: newSourceChain,
|
|
@@ -378,6 +408,10 @@ const mapToValidPathBridge = ({
|
|
|
378
408
|
}
|
|
379
409
|
}
|
|
380
410
|
|
|
411
|
+
if (!newTargetToken) {
|
|
412
|
+
newTargetChain = undefined;
|
|
413
|
+
}
|
|
414
|
+
|
|
381
415
|
return {
|
|
382
416
|
source: { chain: newSourceChain, token: newSourceToken },
|
|
383
417
|
target: { chain: newTargetChain, token: newTargetToken },
|
package/tailwind.config.js
CHANGED
|
@@ -6,6 +6,7 @@ export default {
|
|
|
6
6
|
fontFamily: {
|
|
7
7
|
body: ["'Satoshi-Medium'", "Tahoma", "Verdana", "ui-sans-serif"],
|
|
8
8
|
sans: ["Satoshi-Medium", "Tahoma", "Verdana", "ui-sans-serif"],
|
|
9
|
+
"sans-bold": ["Satoshi-Bold", "Tahoma", "Verdana", "ui-sans-serif"],
|
|
9
10
|
},
|
|
10
11
|
extend: {
|
|
11
12
|
colors: {
|