@xswap-link/sdk 0.6.10 → 0.8.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/CHANGELOG.md +16 -0
- package/dist/index.d.mts +124 -72
- package/dist/index.d.ts +124 -72
- package/dist/index.global.js +686 -281
- package/dist/index.js +10 -10
- package/dist/index.mjs +10 -10
- package/package.json +1 -1
- package/src/assets/icons/ArrowsExchange.tsx +18 -0
- package/src/assets/icons/index.ts +1 -0
- package/src/components/Modal/index.tsx +48 -41
- package/src/components/Swap/Header/index.tsx +4 -2
- package/src/components/Swap/HistoryView/index.tsx +2 -2
- package/src/components/Swap/ReorderButton/ReorderButton.tsx +37 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +1 -1
- package/src/components/Swap/SwapView/SwapButton/index.tsx +31 -22
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +55 -22
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +74 -10
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +83 -28
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +9 -5
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +12 -6
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +50 -29
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +8 -3
- package/src/components/Swap/SwapView/WalletPicker/index.tsx +7 -6
- package/src/components/Swap/SwapView/index.tsx +3 -3
- package/src/components/Swap/index.tsx +1 -1
- package/src/components/TxConfigForm/index.tsx +69 -19
- package/src/components/TxModal/index.tsx +59 -0
- package/src/components/TxWidgetWC/index.tsx +47 -2
- package/src/components/TxWidgetWCWrapped/index.tsx +33 -1
- package/src/components/index.ts +1 -0
- package/src/config/index.ts +1 -1
- package/src/context/SwapProvider.tsx +177 -27
- package/src/context/TxUIWrapper.tsx +5 -5
- package/src/hooks/index.ts +0 -1
- package/src/models/BridgeTokensDictionary.ts +7 -0
- package/src/models/TokenData.ts +3 -1
- package/src/models/index.ts +6 -5
- package/src/models/payloads/ModalIntegrationPayload.ts +17 -3
- package/src/models/payloads/WidgetIntegrationPayload.ts +15 -1
- package/src/services/api.ts +6 -1
- package/src/services/integrations/transactions.ts +40 -17
- package/src/types/global.d.ts +15 -0
- package/src/utils/validation.ts +367 -0
- package/tsconfig.json +3 -2
- package/src/context/ModalProvider.tsx +0 -63
- package/src/hooks/usePortal.ts +0 -79
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContractCall } from "@src/models";
|
|
1
|
+
import { ContractCall, Transaction } from "@src/models";
|
|
2
2
|
|
|
3
3
|
export type ModalIntegrationThemeStyles = {
|
|
4
4
|
mainAccentLight?: string;
|
|
@@ -38,8 +38,8 @@ export type ModalIntegrationStyles = Pick<
|
|
|
38
38
|
|
|
39
39
|
export type ModalIntegrationPayload = {
|
|
40
40
|
integratorId: string;
|
|
41
|
-
dstChain
|
|
42
|
-
dstToken
|
|
41
|
+
dstChain?: string;
|
|
42
|
+
dstToken?: string;
|
|
43
43
|
srcChain?: string;
|
|
44
44
|
srcToken?: string;
|
|
45
45
|
customContractCalls?: ContractCall[];
|
|
@@ -48,4 +48,18 @@ export type ModalIntegrationPayload = {
|
|
|
48
48
|
lightTheme?: boolean;
|
|
49
49
|
defaultWalletPicker?: boolean;
|
|
50
50
|
styles?: ModalIntegrationStyles;
|
|
51
|
+
onPendingTransactionsChange?: (transactions: Transaction[]) => void;
|
|
52
|
+
dstTokenLocked?: boolean;
|
|
53
|
+
dstChainLocked?: boolean;
|
|
54
|
+
srcTokenLocked?: boolean;
|
|
55
|
+
srcChainLocked?: boolean;
|
|
56
|
+
onDstTokenChange?: (
|
|
57
|
+
token: { address: string; symbol: string } | undefined,
|
|
58
|
+
) => void;
|
|
59
|
+
onDstChainChange?: (chain: string | undefined) => void;
|
|
60
|
+
onSrcTokenChange?: (
|
|
61
|
+
token: { address: string; symbol: string } | undefined,
|
|
62
|
+
) => void;
|
|
63
|
+
onSrcChainChange?: (chain: string | undefined) => void;
|
|
64
|
+
bridge?: boolean;
|
|
51
65
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContractCall, ModalIntegrationStyles } from "@src/models";
|
|
1
|
+
import { ContractCall, ModalIntegrationStyles, Transaction } from "@src/models";
|
|
2
2
|
|
|
3
3
|
export type WidgetIntegrationPayload = {
|
|
4
4
|
integratorId: string;
|
|
@@ -12,4 +12,18 @@ export type WidgetIntegrationPayload = {
|
|
|
12
12
|
lightTheme?: boolean;
|
|
13
13
|
defaultWalletPicker?: boolean;
|
|
14
14
|
styles?: ModalIntegrationStyles | string;
|
|
15
|
+
onPendingTransactionsChange?: (transactions: Transaction[]) => void;
|
|
16
|
+
dstTokenLocked?: boolean;
|
|
17
|
+
dstChainLocked?: boolean;
|
|
18
|
+
srcTokenLocked?: boolean;
|
|
19
|
+
srcChainLocked?: boolean;
|
|
20
|
+
onDstTokenChange?: (
|
|
21
|
+
token: { address: string; symbol: string } | undefined,
|
|
22
|
+
) => void;
|
|
23
|
+
onDstChainChange?: (chain: string | undefined) => void;
|
|
24
|
+
onSrcTokenChange?: (
|
|
25
|
+
token: { address: string; symbol: string } | undefined,
|
|
26
|
+
) => void;
|
|
27
|
+
onSrcChainChange?: (chain: string | undefined) => void;
|
|
28
|
+
bridge?: boolean;
|
|
15
29
|
};
|
package/src/services/api.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import xSwapConfig from "../../xswap.config";
|
|
2
1
|
import {
|
|
2
|
+
BridgeToken,
|
|
3
3
|
Chain,
|
|
4
4
|
Ecosystem,
|
|
5
5
|
GetFinishedLeaderboardQuestsPayload,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
TransactionHistory,
|
|
14
14
|
TransactionStatus,
|
|
15
15
|
} from "@src/models";
|
|
16
|
+
import xSwapConfig from "../../xswap.config";
|
|
16
17
|
|
|
17
18
|
async function _sendRequest<T>(
|
|
18
19
|
urlPath: string,
|
|
@@ -153,3 +154,7 @@ export async function getFinishedLeaderboardQuests(
|
|
|
153
154
|
})}`,
|
|
154
155
|
);
|
|
155
156
|
}
|
|
157
|
+
|
|
158
|
+
export async function getBridgeTokens(): Promise<BridgeToken[]> {
|
|
159
|
+
return _sendRequest<BridgeToken[]>(`/bridgeTokens`);
|
|
160
|
+
}
|
|
@@ -15,6 +15,16 @@ export const openTransactionModal = async ({
|
|
|
15
15
|
lightTheme,
|
|
16
16
|
defaultWalletPicker,
|
|
17
17
|
styles,
|
|
18
|
+
onPendingTransactionsChange,
|
|
19
|
+
dstTokenLocked,
|
|
20
|
+
dstChainLocked,
|
|
21
|
+
srcTokenLocked,
|
|
22
|
+
srcChainLocked,
|
|
23
|
+
onDstTokenChange,
|
|
24
|
+
onDstChainChange,
|
|
25
|
+
onSrcTokenChange,
|
|
26
|
+
onSrcChainChange,
|
|
27
|
+
bridge,
|
|
18
28
|
}: ModalIntegrationPayload) => {
|
|
19
29
|
const supportedChains: Chain[] = (await getChains()).filter(
|
|
20
30
|
({ web3Environment, swapSupported }) =>
|
|
@@ -43,14 +53,24 @@ export const openTransactionModal = async ({
|
|
|
43
53
|
lightTheme,
|
|
44
54
|
defaultWalletPicker,
|
|
45
55
|
styles,
|
|
56
|
+
onPendingTransactionsChange,
|
|
57
|
+
dstTokenLocked,
|
|
58
|
+
dstChainLocked,
|
|
59
|
+
srcTokenLocked,
|
|
60
|
+
srcChainLocked,
|
|
61
|
+
onDstTokenChange,
|
|
62
|
+
onDstChainChange,
|
|
63
|
+
onSrcTokenChange,
|
|
64
|
+
onSrcChainChange,
|
|
65
|
+
bridge,
|
|
46
66
|
});
|
|
47
67
|
};
|
|
48
68
|
|
|
49
69
|
const validateSwapTxData = (
|
|
50
70
|
integratorId: string,
|
|
51
71
|
supportedChains: Chain[],
|
|
52
|
-
dstChain
|
|
53
|
-
dstToken
|
|
72
|
+
dstChain?: string,
|
|
73
|
+
dstToken?: string,
|
|
54
74
|
srcChain?: string,
|
|
55
75
|
srcToken?: string,
|
|
56
76
|
) => {
|
|
@@ -60,21 +80,24 @@ const validateSwapTxData = (
|
|
|
60
80
|
);
|
|
61
81
|
}
|
|
62
82
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (!supportedDstChain) {
|
|
67
|
-
throw new Error(`Provided chain '${dstChain}' is not supported`);
|
|
68
|
-
}
|
|
69
|
-
if (
|
|
70
|
-
!isETHAddressValid(dstToken) ||
|
|
71
|
-
supportedDstChain.tokens.findIndex(
|
|
72
|
-
({ address }) => address.toLowerCase() === dstToken.toLowerCase(),
|
|
73
|
-
) === -1
|
|
74
|
-
) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
`Provided token address ${dstToken} on chain ${dstChain} is invalid`,
|
|
83
|
+
if (dstChain) {
|
|
84
|
+
const supportedDstChain = supportedChains.find(
|
|
85
|
+
({ chainId }) => chainId === dstChain,
|
|
77
86
|
);
|
|
87
|
+
if (!supportedDstChain) {
|
|
88
|
+
throw new Error(`Provided chain '${dstChain}' is not supported`);
|
|
89
|
+
}
|
|
90
|
+
if (
|
|
91
|
+
dstToken &&
|
|
92
|
+
(!isETHAddressValid(dstToken) ||
|
|
93
|
+
supportedDstChain.tokens.findIndex(
|
|
94
|
+
({ address }) => address.toLowerCase() === dstToken.toLowerCase(),
|
|
95
|
+
) === -1)
|
|
96
|
+
) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Provided token address ${dstToken} on chain ${dstChain} is invalid`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
78
101
|
}
|
|
79
102
|
|
|
80
103
|
if (srcChain) {
|
|
@@ -86,7 +109,7 @@ const validateSwapTxData = (
|
|
|
86
109
|
}
|
|
87
110
|
if (
|
|
88
111
|
srcToken &&
|
|
89
|
-
(!isETHAddressValid(
|
|
112
|
+
(!isETHAddressValid(srcToken) ||
|
|
90
113
|
supportedSrcChain.tokens.findIndex(
|
|
91
114
|
({ address }) => address.toLowerCase() === srcToken.toLowerCase(),
|
|
92
115
|
) === -1)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Transaction } from "@src/models";
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
xPayOnPendingTransactionsChange?: (transactions: Transaction[]) => void;
|
|
6
|
+
xPayOnDstTokenChange?: (
|
|
7
|
+
token: { address: string; symbol: string } | undefined,
|
|
8
|
+
) => void;
|
|
9
|
+
xPayOnDstChainChange?: (chain: string | undefined) => void;
|
|
10
|
+
xPayOnSrcTokenChange?: (
|
|
11
|
+
token: { address: string; symbol: string } | undefined,
|
|
12
|
+
) => void;
|
|
13
|
+
xPayOnSrcChainChange?: (chain: string | undefined) => void;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_DESTINATION_CHAIN_ID,
|
|
3
|
+
DEFAULT_SOURCE_CHAIN_ID,
|
|
4
|
+
} from "@src/constants";
|
|
5
|
+
import { BridgeTokensDictionary, Chain, Token } from "@src/models";
|
|
6
|
+
|
|
7
|
+
const getDefaultSourceChain = ({
|
|
8
|
+
supportedChains,
|
|
9
|
+
}: {
|
|
10
|
+
supportedChains: Chain[];
|
|
11
|
+
}): Chain => {
|
|
12
|
+
const defaultSourceChain =
|
|
13
|
+
supportedChains.find(
|
|
14
|
+
(chain) => chain.chainId === DEFAULT_SOURCE_CHAIN_ID,
|
|
15
|
+
) || supportedChains[0];
|
|
16
|
+
|
|
17
|
+
if (!defaultSourceChain) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`getDefaultSourceChain > couldn't find default source chain`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return defaultSourceChain;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const getDefaultDestinationChain = ({
|
|
27
|
+
supportedChains,
|
|
28
|
+
}: {
|
|
29
|
+
supportedChains: Chain[];
|
|
30
|
+
}): Chain => {
|
|
31
|
+
const defaultTargetChain =
|
|
32
|
+
supportedChains.find(
|
|
33
|
+
(chain) => chain.chainId === DEFAULT_DESTINATION_CHAIN_ID,
|
|
34
|
+
) || supportedChains[0];
|
|
35
|
+
|
|
36
|
+
if (!defaultTargetChain) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`getDefaultDestinationChain > couldn't find default destination chain`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return defaultTargetChain;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const getDefaultSwapTokenForChain = (chain: Chain) => {
|
|
46
|
+
const xswapToken = chain.tokens.find((token) => token.tokenId === "XSWAP");
|
|
47
|
+
|
|
48
|
+
if (xswapToken) {
|
|
49
|
+
return xswapToken;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const fallbackToken = chain.tokens.find((token) => token.supported);
|
|
53
|
+
|
|
54
|
+
if (fallbackToken) {
|
|
55
|
+
return fallbackToken;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return chain.tokens[0];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const getDefaultBridgeTokenForChain = ({
|
|
62
|
+
chain,
|
|
63
|
+
bridgeTokensDictionary,
|
|
64
|
+
}: {
|
|
65
|
+
chain: Chain;
|
|
66
|
+
bridgeTokensDictionary: BridgeTokensDictionary;
|
|
67
|
+
}) => {
|
|
68
|
+
const xswapToken = chain.tokens.find((token) => token.tokenId === "XSWAP");
|
|
69
|
+
|
|
70
|
+
if (xswapToken) {
|
|
71
|
+
return xswapToken;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const fallbackTokenAddress = Object.keys(
|
|
75
|
+
bridgeTokensDictionary[chain.chainId] || {},
|
|
76
|
+
)[0];
|
|
77
|
+
|
|
78
|
+
return chain.tokens.find(
|
|
79
|
+
(token) =>
|
|
80
|
+
token.address.toLowerCase() === fallbackTokenAddress?.toLowerCase(),
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const isSwapSourceValid = (sourceChain: Chain) => sourceChain.swapSupported;
|
|
85
|
+
|
|
86
|
+
const isSwapTargetChainValid = ({
|
|
87
|
+
sourceChain,
|
|
88
|
+
targetChain,
|
|
89
|
+
}: {
|
|
90
|
+
sourceChain: Chain | undefined;
|
|
91
|
+
targetChain: Chain;
|
|
92
|
+
}) => {
|
|
93
|
+
if (!sourceChain) {
|
|
94
|
+
throw new Error(`isSwapTargetChainValid > sourceChain should be defined.`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
targetChain.swapSupported &&
|
|
99
|
+
!sourceChain.disabledForDestination?.includes(targetChain.chainId)
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const isBridgeSourceValid = (sourceChain: Chain) => sourceChain.bridgeSupported;
|
|
104
|
+
|
|
105
|
+
const isBridgeTargetValid = ({
|
|
106
|
+
sourceChain,
|
|
107
|
+
targetChain,
|
|
108
|
+
sourceToken,
|
|
109
|
+
}: {
|
|
110
|
+
sourceChain: Chain | undefined;
|
|
111
|
+
targetChain: Chain;
|
|
112
|
+
sourceToken: Token | undefined;
|
|
113
|
+
}) => {
|
|
114
|
+
if (!sourceChain) {
|
|
115
|
+
throw new Error(`isBridgeTargetValid > sourceChain should be defined.`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (
|
|
119
|
+
sourceToken &&
|
|
120
|
+
!targetChain.tokens.find((token) => token.tokenId === sourceToken!.tokenId)
|
|
121
|
+
) {
|
|
122
|
+
// Bridge target chain is invalid when it doesn't have the same token available as selected in the source.
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
targetChain.bridgeSupported &&
|
|
128
|
+
// Source and target chains must be different for bridging.
|
|
129
|
+
sourceChain.chainId !== targetChain.chainId
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// It takes chain and token for source and target and returns them.
|
|
134
|
+
// If provided data is valid, it returns the same.
|
|
135
|
+
// If data is not valid, it returns other available chain/token.
|
|
136
|
+
export const mapToValidPath = ({
|
|
137
|
+
source,
|
|
138
|
+
target,
|
|
139
|
+
type,
|
|
140
|
+
supportedChains,
|
|
141
|
+
bridgeTokensDictionary,
|
|
142
|
+
}: {
|
|
143
|
+
source: { chain: Chain | undefined; token: Token | undefined };
|
|
144
|
+
target: { chain: Chain | undefined; token: Token | undefined };
|
|
145
|
+
type: "SWAP" | "BRIDGE";
|
|
146
|
+
supportedChains: Chain[];
|
|
147
|
+
bridgeTokensDictionary: BridgeTokensDictionary;
|
|
148
|
+
}): {
|
|
149
|
+
source: { chain: Chain | undefined; token: Token | undefined };
|
|
150
|
+
target: { chain: Chain | undefined; token: Token | undefined };
|
|
151
|
+
} => {
|
|
152
|
+
let newSourceChain: Chain | undefined =
|
|
153
|
+
source.chain || getDefaultSourceChain({ supportedChains });
|
|
154
|
+
let newTargetChain: Chain | undefined =
|
|
155
|
+
target.chain || getDefaultDestinationChain({ supportedChains });
|
|
156
|
+
let newSourceToken: Token | undefined =
|
|
157
|
+
source.token ||
|
|
158
|
+
(type === "SWAP"
|
|
159
|
+
? getDefaultSwapTokenForChain(newSourceChain)
|
|
160
|
+
: getDefaultBridgeTokenForChain({
|
|
161
|
+
chain: newSourceChain,
|
|
162
|
+
bridgeTokensDictionary,
|
|
163
|
+
}));
|
|
164
|
+
let newTargetToken: Token | undefined =
|
|
165
|
+
target.token ||
|
|
166
|
+
(type === "SWAP"
|
|
167
|
+
? getDefaultSwapTokenForChain(newTargetChain)
|
|
168
|
+
: getDefaultBridgeTokenForChain({
|
|
169
|
+
chain: newTargetChain,
|
|
170
|
+
bridgeTokensDictionary,
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
if (
|
|
174
|
+
!newSourceChain ||
|
|
175
|
+
!newTargetChain ||
|
|
176
|
+
!newSourceToken ||
|
|
177
|
+
!newTargetToken
|
|
178
|
+
) {
|
|
179
|
+
// This should never occur if our app is configured properly.
|
|
180
|
+
return {
|
|
181
|
+
source: { chain: undefined, token: undefined },
|
|
182
|
+
target: { chain: undefined, token: undefined },
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Setting chains
|
|
187
|
+
if (type === "SWAP") {
|
|
188
|
+
if (!isSwapSourceValid(newSourceChain)) {
|
|
189
|
+
newSourceChain = getDefaultSourceChain({ supportedChains });
|
|
190
|
+
// We can't have dangling token from a different chain.
|
|
191
|
+
newSourceToken = undefined;
|
|
192
|
+
|
|
193
|
+
if (!isSwapSourceValid(newSourceChain)) {
|
|
194
|
+
// This should never occur if our app is configured properly.
|
|
195
|
+
console.error("[WRONG CONFIG] default swap source chain is invalid.");
|
|
196
|
+
|
|
197
|
+
// Find any chain that is valid.
|
|
198
|
+
newSourceChain = supportedChains.find((chain) =>
|
|
199
|
+
isSwapSourceValid(chain),
|
|
200
|
+
);
|
|
201
|
+
if (!newSourceChain) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
"mapToValidSwap > None of the chains supports swap. Couldn't set source chain.",
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (
|
|
210
|
+
!isSwapTargetChainValid({
|
|
211
|
+
sourceChain: newSourceChain,
|
|
212
|
+
targetChain: newTargetChain,
|
|
213
|
+
})
|
|
214
|
+
) {
|
|
215
|
+
newTargetChain = getDefaultDestinationChain({ supportedChains });
|
|
216
|
+
// We can't have dangling token from a different chain.
|
|
217
|
+
newTargetToken = undefined;
|
|
218
|
+
|
|
219
|
+
if (
|
|
220
|
+
!isSwapTargetChainValid({
|
|
221
|
+
sourceChain: newSourceChain,
|
|
222
|
+
targetChain: newTargetChain,
|
|
223
|
+
})
|
|
224
|
+
) {
|
|
225
|
+
// This should never occur if our app is configured properly.
|
|
226
|
+
console.error("[WRONG CONFIG] default swap target chain is invalid.");
|
|
227
|
+
|
|
228
|
+
// Find any chain that is valid.
|
|
229
|
+
newTargetChain = supportedChains.find((chain) =>
|
|
230
|
+
isSwapTargetChainValid({
|
|
231
|
+
sourceChain: newSourceChain,
|
|
232
|
+
targetChain: chain,
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
if (!newTargetChain) {
|
|
236
|
+
throw new Error(
|
|
237
|
+
"mapToValidSwap > None of the chains supports swap. Couldn't set target chain.",
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} else {
|
|
243
|
+
if (!isBridgeSourceValid(newSourceChain)) {
|
|
244
|
+
newSourceChain = getDefaultSourceChain({ supportedChains });
|
|
245
|
+
// We can't have dangling token from a different chain.
|
|
246
|
+
newSourceToken = undefined;
|
|
247
|
+
|
|
248
|
+
if (!isBridgeSourceValid(newSourceChain)) {
|
|
249
|
+
// This should never occur if our app is configured properly.
|
|
250
|
+
console.error("[WRONG CONFIG] default bridge source chain is invalid.");
|
|
251
|
+
|
|
252
|
+
// Find any chain that is valid.
|
|
253
|
+
newSourceChain = supportedChains.find((chain) =>
|
|
254
|
+
isBridgeSourceValid(chain),
|
|
255
|
+
);
|
|
256
|
+
if (!newSourceChain) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
"mapToValidSwap > None of the chains supports bridge. Couldn't set source chain.",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (
|
|
265
|
+
!isBridgeTargetValid({
|
|
266
|
+
sourceChain: newSourceChain,
|
|
267
|
+
targetChain: newTargetChain,
|
|
268
|
+
sourceToken: newSourceToken,
|
|
269
|
+
})
|
|
270
|
+
) {
|
|
271
|
+
newTargetChain = getDefaultDestinationChain({ supportedChains });
|
|
272
|
+
// We can't have dangling token from a different chain.
|
|
273
|
+
newTargetToken = undefined;
|
|
274
|
+
|
|
275
|
+
if (
|
|
276
|
+
!isBridgeTargetValid({
|
|
277
|
+
sourceChain: newSourceChain,
|
|
278
|
+
targetChain: newTargetChain,
|
|
279
|
+
sourceToken: newSourceToken,
|
|
280
|
+
})
|
|
281
|
+
) {
|
|
282
|
+
// This should never occur if our app is configured properly.
|
|
283
|
+
console.error("[WRONG CONFIG] default bridge target chain is invalid.");
|
|
284
|
+
|
|
285
|
+
// Find any chain that is valid.
|
|
286
|
+
newTargetChain = supportedChains.find((chain) =>
|
|
287
|
+
isBridgeTargetValid({
|
|
288
|
+
sourceChain: newSourceChain,
|
|
289
|
+
targetChain: chain,
|
|
290
|
+
sourceToken: newSourceToken,
|
|
291
|
+
}),
|
|
292
|
+
);
|
|
293
|
+
if (!newTargetChain) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
"mapToValidSwap > None of the chains supports swap. Couldn't set target chain.",
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Setting tokens
|
|
303
|
+
if (type === "SWAP") {
|
|
304
|
+
if (!newSourceToken) {
|
|
305
|
+
newSourceToken = getDefaultSwapTokenForChain(newSourceChain);
|
|
306
|
+
}
|
|
307
|
+
if (!newTargetToken) {
|
|
308
|
+
newTargetToken = getDefaultSwapTokenForChain(newTargetChain);
|
|
309
|
+
}
|
|
310
|
+
} else {
|
|
311
|
+
if (!newSourceToken) {
|
|
312
|
+
const defaultToken = getDefaultBridgeTokenForChain({
|
|
313
|
+
chain: newSourceChain,
|
|
314
|
+
bridgeTokensDictionary,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
if (defaultToken) {
|
|
318
|
+
const isDefaultTokenBridgeable =
|
|
319
|
+
!!bridgeTokensDictionary[newSourceChain.chainId]?.[
|
|
320
|
+
defaultToken.address.toLowerCase()
|
|
321
|
+
]?.[newTargetChain.chainId];
|
|
322
|
+
|
|
323
|
+
if (isDefaultTokenBridgeable) {
|
|
324
|
+
newSourceToken = defaultToken;
|
|
325
|
+
} else {
|
|
326
|
+
// This should never occur if our app is configured properly.
|
|
327
|
+
console.error(
|
|
328
|
+
"[WRONG CONFIG] default bridge source token is invalid.",
|
|
329
|
+
);
|
|
330
|
+
// Default is invalid, so let's keep it unset.
|
|
331
|
+
newSourceToken = undefined;
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
// Default was not found, so let's keep it unset.
|
|
335
|
+
newSourceToken = undefined;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (newSourceToken?.tokenId !== newTargetToken?.tokenId) {
|
|
340
|
+
newTargetToken = undefined;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!newTargetToken) {
|
|
344
|
+
if (newSourceToken) {
|
|
345
|
+
const correspondingTokenAddress =
|
|
346
|
+
bridgeTokensDictionary[newSourceChain.chainId]?.[
|
|
347
|
+
newSourceToken.address.toLowerCase()
|
|
348
|
+
]?.[newTargetChain.chainId];
|
|
349
|
+
|
|
350
|
+
const correspondingToken = newTargetChain.tokens.find(
|
|
351
|
+
(token) =>
|
|
352
|
+
token.address.toLowerCase() ===
|
|
353
|
+
correspondingTokenAddress?.toLowerCase(),
|
|
354
|
+
);
|
|
355
|
+
newTargetToken = correspondingToken;
|
|
356
|
+
} else {
|
|
357
|
+
// If source token is not defined, destination token can't be defined as well.
|
|
358
|
+
newTargetToken = undefined;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
source: { chain: newSourceChain, token: newSourceToken },
|
|
365
|
+
target: { chain: newTargetChain, token: newTargetToken },
|
|
366
|
+
};
|
|
367
|
+
};
|
package/tsconfig.json
CHANGED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
|
2
|
-
import { useSwapContext } from "./SwapProvider";
|
|
3
|
-
|
|
4
|
-
interface ModalState {
|
|
5
|
-
openModal: (modalContent: ReactNode) => void;
|
|
6
|
-
closeModal: () => void;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const ModalContext = createContext<ModalState>({
|
|
10
|
-
openModal: () => {
|
|
11
|
-
throw new Error(`openModal is not implemented`);
|
|
12
|
-
},
|
|
13
|
-
closeModal: () => {
|
|
14
|
-
throw new Error(`closeModal is not implemented`);
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
export const ModalProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
|
19
|
-
const { overlay } = useSwapContext();
|
|
20
|
-
const [content, setContent] = useState<ReactNode | null>(null);
|
|
21
|
-
|
|
22
|
-
const openModal = (modalContent: ReactNode) => {
|
|
23
|
-
setContent(modalContent);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const closeModal = () => {
|
|
27
|
-
setContent(null);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<ModalContext.Provider value={{ openModal, closeModal }}>
|
|
32
|
-
<div
|
|
33
|
-
className={`${
|
|
34
|
-
overlay ? "" : "relative min-w-x_modal w-x_modal max-w-x_modal"
|
|
35
|
-
}`}
|
|
36
|
-
>
|
|
37
|
-
{children}
|
|
38
|
-
{content && (
|
|
39
|
-
<div
|
|
40
|
-
className={`${
|
|
41
|
-
overlay ? "fixed bg-[rgba(0,0,0,0.8)]" : "absolute"
|
|
42
|
-
} top-0 left-0 right-0 bottom-0 flex items-center justify-center z-10`}
|
|
43
|
-
>
|
|
44
|
-
<div
|
|
45
|
-
className="flex flex-col bg-t_bg_primary x-border rounded-3xl p-4 w-full min-w-[340px]"
|
|
46
|
-
style={{
|
|
47
|
-
height: overlay ? "600px" : "100%",
|
|
48
|
-
maxWidth: "480px",
|
|
49
|
-
maxHeight: "100%",
|
|
50
|
-
}}
|
|
51
|
-
>
|
|
52
|
-
{content}
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
)}
|
|
56
|
-
</div>
|
|
57
|
-
</ModalContext.Provider>
|
|
58
|
-
);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const useModal = () => {
|
|
62
|
-
return useContext(ModalContext);
|
|
63
|
-
};
|