@xswap-link/sdk 0.2.5 → 0.3.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/.github/workflows/main.yml +2 -2
- package/.github/workflows/publish.yml +2 -2
- package/CHANGELOG.md +12 -0
- package/dist/index.css +325 -257
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1296 -516
- package/dist/index.mjs +1323 -537
- package/package.json +1 -1
- package/src/components/Alert/index.tsx +1 -1
- package/src/components/Skeleton/index.tsx +3 -1
- package/src/components/Spinner/index.tsx +28 -0
- package/src/components/TxConfigForm/BalanceComponent.tsx +1 -1
- package/src/components/TxConfigForm/Button.tsx +1 -1
- package/src/components/TxConfigForm/ChainListElement.tsx +2 -2
- package/src/components/TxConfigForm/ConfirmationAmount.tsx +91 -0
- package/src/components/TxConfigForm/Description.tsx +5 -3
- package/src/components/TxConfigForm/ErrorField.tsx +4 -2
- package/src/components/TxConfigForm/FeesDetails.tsx +25 -31
- package/src/components/TxConfigForm/Form.tsx +763 -118
- package/src/components/TxConfigForm/History.tsx +5 -5
- package/src/components/TxConfigForm/HistoryCard.tsx +33 -40
- package/src/components/TxConfigForm/PoweredBy.tsx +2 -2
- package/src/components/TxConfigForm/Settings.tsx +33 -27
- package/src/components/TxConfigForm/Summary.tsx +33 -31
- package/src/components/TxConfigForm/SwapPanel.tsx +12 -15
- package/src/components/TxConfigForm/TokenPicker.tsx +36 -34
- package/src/components/TxConfigForm/TopBar.tsx +8 -8
- package/src/components/TxConfigForm/UsdPrice.tsx +4 -14
- package/src/components/TxConfigForm/index.tsx +37 -10
- package/src/components/TxStatusButton/index.tsx +42 -28
- package/src/components/UnknownTokenLogo/UnknownTokenLogo.tsx +1 -1
- package/src/components/global.css +7 -5
- package/src/components/icons/CircularProgressIcon.tsx +1 -1
- package/src/components/icons/ErrorIcon.tsx +32 -0
- package/src/components/icons/SignIcon.tsx +17 -0
- package/src/components/icons/SuccessIcon.tsx +29 -0
- package/src/components/icons/index.ts +3 -0
- package/src/config/init.tsx +42 -24
- package/src/constants/index.ts +2 -2
- package/src/models/payloads/GetSwapTxPayload.ts +2 -0
- package/src/services/integrations/monitoring.ts +10 -3
- package/src/services/integrations/transactions.ts +9 -3
- package/src/utils/contracts.ts +18 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/parseWeb3Error.ts +93 -0
- package/tailwind.config.js +40 -0
package/src/config/init.tsx
CHANGED
|
@@ -3,31 +3,33 @@ import xswapConfig from "../../xswap.config";
|
|
|
3
3
|
import { version } from "../../package.json";
|
|
4
4
|
import { WaitingForInit } from "@src/components/WaitingForInit";
|
|
5
5
|
|
|
6
|
-
export let
|
|
7
|
-
export let
|
|
8
|
-
export let
|
|
6
|
+
export let xpayRoot: Root | null = null;
|
|
7
|
+
export let xpayInitIndicatorRoot: Root | null = null;
|
|
8
|
+
export let xpayTxStatusRoot: Root | null = null;
|
|
9
9
|
|
|
10
|
-
let
|
|
10
|
+
let xPayInitCompleted = false;
|
|
11
|
+
|
|
12
|
+
const isServer = typeof window === "undefined";
|
|
11
13
|
|
|
12
14
|
export const initDocument = () => {
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
+
if (isServer) {
|
|
16
|
+
return;
|
|
15
17
|
}
|
|
16
|
-
|
|
18
|
+
createXPayInitIndicatorRoot();
|
|
17
19
|
|
|
18
20
|
Promise.all([
|
|
19
21
|
createStyleElement(),
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
createXPayRoot(),
|
|
23
|
+
createXPayTxStatusRoot(),
|
|
22
24
|
]).then(() => {
|
|
23
|
-
|
|
25
|
+
xPayInitCompleted = true;
|
|
24
26
|
});
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
export const waitForInitialization = async () => {
|
|
28
|
-
if (!
|
|
30
|
+
if (!xPayInitCompleted) {
|
|
29
31
|
displayInitIndicator(true);
|
|
30
|
-
while (!
|
|
32
|
+
while (!xPayInitCompleted) {
|
|
31
33
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
32
34
|
}
|
|
33
35
|
displayInitIndicator(false);
|
|
@@ -35,6 +37,9 @@ export const waitForInitialization = async () => {
|
|
|
35
37
|
};
|
|
36
38
|
|
|
37
39
|
const createStyleElement = async () => {
|
|
40
|
+
if (isServer) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
38
43
|
const css = await fetch(
|
|
39
44
|
`${xswapConfig.apiUrl}/sdk/css?${new URLSearchParams({
|
|
40
45
|
data: JSON.stringify({ version }),
|
|
@@ -46,30 +51,43 @@ const createStyleElement = async () => {
|
|
|
46
51
|
document.body.appendChild(style);
|
|
47
52
|
};
|
|
48
53
|
|
|
49
|
-
const
|
|
54
|
+
const createXPayRoot = async () => {
|
|
55
|
+
if (isServer) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
50
58
|
const xswapElement = document.createElement("div");
|
|
51
|
-
xswapElement.setAttribute("id", "
|
|
59
|
+
xswapElement.setAttribute("id", "xpay-root");
|
|
60
|
+
xswapElement.setAttribute("class", "xpay");
|
|
52
61
|
document.body.appendChild(xswapElement);
|
|
53
|
-
|
|
62
|
+
xpayRoot = createRoot(xswapElement);
|
|
54
63
|
};
|
|
55
64
|
|
|
56
|
-
const
|
|
65
|
+
const createXPayTxStatusRoot = async () => {
|
|
66
|
+
if (isServer) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
57
69
|
const txStatusElement = document.createElement("div");
|
|
58
|
-
txStatusElement.setAttribute("id", "
|
|
59
|
-
txStatusElement.setAttribute("class", "
|
|
70
|
+
txStatusElement.setAttribute("id", "xpay-tx-status");
|
|
71
|
+
txStatusElement.setAttribute("class", "xpay-tx-status");
|
|
60
72
|
document.body.appendChild(txStatusElement);
|
|
61
|
-
|
|
73
|
+
xpayTxStatusRoot = createRoot(txStatusElement);
|
|
62
74
|
};
|
|
63
75
|
|
|
64
|
-
const
|
|
76
|
+
const createXPayInitIndicatorRoot = () => {
|
|
77
|
+
if (isServer) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
65
80
|
const initIndicatorElement = document.createElement("div");
|
|
66
|
-
initIndicatorElement.setAttribute("id", "
|
|
81
|
+
initIndicatorElement.setAttribute("id", "xpay-init-indicator");
|
|
67
82
|
document.body.appendChild(initIndicatorElement);
|
|
68
|
-
|
|
83
|
+
xpayInitIndicatorRoot = createRoot(initIndicatorElement);
|
|
69
84
|
};
|
|
70
85
|
|
|
71
86
|
const displayInitIndicator = (display: boolean) => {
|
|
87
|
+
if (isServer || !xpayInitIndicatorRoot) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
72
90
|
display
|
|
73
|
-
?
|
|
74
|
-
:
|
|
91
|
+
? xpayInitIndicatorRoot.render(<WaitingForInit />)
|
|
92
|
+
: xpayInitIndicatorRoot.render(null);
|
|
75
93
|
};
|
package/src/constants/index.ts
CHANGED
|
@@ -7,11 +7,11 @@ export const DELIVERY_TIME = 30 * 1000 * 60;
|
|
|
7
7
|
export const EXPRESS_DELIVERY_TIME = 30 * 1000;
|
|
8
8
|
export const EXPRESS_DELIVERY_LIMIT = 1000; // USD
|
|
9
9
|
export const BALANCES_CHUNK_SIZE = 500;
|
|
10
|
-
export const ROUTE_TIMEOUT_MS =
|
|
10
|
+
export const ROUTE_TIMEOUT_MS = 10000;
|
|
11
11
|
export const MINIMUM_DISPLAYED_TOKEN_AMOUNT = 0.0001;
|
|
12
12
|
export const DEFAULT_SOURCE_CHAIN_ID = "1";
|
|
13
13
|
export const CCIP_EXPLORER = "https://ccip.chain.link/";
|
|
14
|
-
export const TX_RECEIPT_STATUS_LIFETIME =
|
|
14
|
+
export const TX_RECEIPT_STATUS_LIFETIME = 60000;
|
|
15
15
|
|
|
16
16
|
export const MSG_SENT_EVENT_SIG =
|
|
17
17
|
"MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
|
|
@@ -101,9 +101,6 @@ export const renderTxStatus = async (
|
|
|
101
101
|
addTransactionToRenderedTransactions(transaction);
|
|
102
102
|
renderTxStatusButtons();
|
|
103
103
|
|
|
104
|
-
// start listening
|
|
105
|
-
// TODO if someone will provide tx which already is done then we will never get the event. Will need to add status endpoint on backend for transactions to check if they are done or not.
|
|
106
|
-
|
|
107
104
|
const xSwapRouterOnDestinationAddress = ADDRESSES[dstChainId]?.XSwapRouter;
|
|
108
105
|
if (!xSwapRouterOnDestinationAddress) {
|
|
109
106
|
throw new Error(`Unknown destination XSwapRouter!`);
|
|
@@ -140,6 +137,16 @@ export const renderTxStatus = async (
|
|
|
140
137
|
}
|
|
141
138
|
});
|
|
142
139
|
|
|
140
|
+
setTimeout(
|
|
141
|
+
() =>
|
|
142
|
+
getTxStatus({ transferId: messageId }).then((response) => {
|
|
143
|
+
if (response.status === "DONE") {
|
|
144
|
+
onSuccess();
|
|
145
|
+
}
|
|
146
|
+
}),
|
|
147
|
+
30 * 60 * 1000,
|
|
148
|
+
); // additional check after 30 min
|
|
149
|
+
|
|
143
150
|
xSwapRouterOnDestination.once(msgReceivedEventFilter, () => onSuccess());
|
|
144
151
|
};
|
|
145
152
|
|
|
@@ -14,7 +14,9 @@ export const openTransactionModal = async ({
|
|
|
14
14
|
dstToken,
|
|
15
15
|
customContractCalls = [],
|
|
16
16
|
desc,
|
|
17
|
-
|
|
17
|
+
retrunTransactions,
|
|
18
|
+
dstDisplayToken,
|
|
19
|
+
}: GetSwapTxPayload): Promise<Transactions | undefined> => {
|
|
18
20
|
const supportedChains: Chain[] = (await getChains()).filter(
|
|
19
21
|
({ web3Environment, swapSupported }) =>
|
|
20
22
|
web3Environment === Web3Environment.MAINNET && swapSupported,
|
|
@@ -29,9 +31,13 @@ export const openTransactionModal = async ({
|
|
|
29
31
|
customContractCalls,
|
|
30
32
|
desc,
|
|
31
33
|
supportedChains,
|
|
34
|
+
retrunTransactions,
|
|
35
|
+
dstDisplayTokenAddr: dstDisplayToken,
|
|
32
36
|
});
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
if (retrunTransactions) {
|
|
39
|
+
return route.transactions;
|
|
40
|
+
}
|
|
35
41
|
};
|
|
36
42
|
|
|
37
43
|
const validateSwapTxData = (
|
|
@@ -48,7 +54,7 @@ const validateSwapTxData = (
|
|
|
48
54
|
|
|
49
55
|
if (!isETHAddressValid(dstToken)) {
|
|
50
56
|
throw new Error(
|
|
51
|
-
`Provided token address ${dstToken} on chain ${dstChain} is
|
|
57
|
+
`Provided token address ${dstToken} on chain ${dstChain} is invalid`,
|
|
52
58
|
);
|
|
53
59
|
}
|
|
54
60
|
};
|
package/src/utils/contracts.ts
CHANGED
|
@@ -23,6 +23,24 @@ export const getBalanceOf = async (
|
|
|
23
23
|
await contract.decimals(),
|
|
24
24
|
);
|
|
25
25
|
};
|
|
26
|
+
export const getAllowanceOf = async (
|
|
27
|
+
token: string,
|
|
28
|
+
wallet: string,
|
|
29
|
+
spender: string,
|
|
30
|
+
rpcUrl: string,
|
|
31
|
+
): Promise<string> => {
|
|
32
|
+
const provider = ethers.getDefaultProvider(rpcUrl);
|
|
33
|
+
|
|
34
|
+
if (token === ethers.constants.AddressZero) {
|
|
35
|
+
return ethers.constants.MaxUint256.toString();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const contract = new ethers.Contract(token, ERC20Abi, provider);
|
|
39
|
+
return ethers.utils.formatUnits(
|
|
40
|
+
await contract.allowance(wallet, spender),
|
|
41
|
+
await contract.decimals(),
|
|
42
|
+
);
|
|
43
|
+
};
|
|
26
44
|
|
|
27
45
|
export const getBalances = async (
|
|
28
46
|
chain: Chain,
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parses a Web3 error and returns a user-friendly error message.
|
|
5
|
+
* @param error - The error object or message to parse.
|
|
6
|
+
* @returns A user-friendly error message.
|
|
7
|
+
*/
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
export function parseWeb3Error(error: any): string {
|
|
10
|
+
const errorMessage =
|
|
11
|
+
typeof error === "string"
|
|
12
|
+
? error
|
|
13
|
+
: error?.message || "An unknown error occurred";
|
|
14
|
+
|
|
15
|
+
// User rejected the transaction
|
|
16
|
+
if (
|
|
17
|
+
errorMessage.includes("User denied transaction signature") ||
|
|
18
|
+
errorMessage.includes("User rejected the request")
|
|
19
|
+
) {
|
|
20
|
+
return "Transaction was cancelled.";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Insufficient funds
|
|
24
|
+
if (errorMessage.includes("insufficient funds")) {
|
|
25
|
+
return "Insufficient funds to complete the transaction.";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Gas price too low
|
|
29
|
+
if (errorMessage.includes("gas price too low")) {
|
|
30
|
+
return "Gas price is too low. Please increase the gas price and try again.";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Nonce too low
|
|
34
|
+
if (errorMessage.includes("nonce too low")) {
|
|
35
|
+
return "Transaction nonce is too low. Please reset your account in MetaMask and try again.";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Contract execution error
|
|
39
|
+
if (errorMessage.includes("execution reverted")) {
|
|
40
|
+
const revertReason = errorMessage.match(/reason: (.+?)(?:, method|$)/)?.[1];
|
|
41
|
+
return revertReason
|
|
42
|
+
? `Transaction failed: ${revertReason}`
|
|
43
|
+
: "Transaction failed during contract execution.";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Gas limit exceeded
|
|
47
|
+
if (errorMessage.includes("exceeds block gas limit")) {
|
|
48
|
+
return "Transaction exceeded gas limit. Please try again with a higher gas limit.";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Network error
|
|
52
|
+
if (
|
|
53
|
+
errorMessage.includes("network error") ||
|
|
54
|
+
errorMessage.includes("connection error")
|
|
55
|
+
) {
|
|
56
|
+
return "Network error. Please check your internet connection and try again.";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Metamask specific errors
|
|
60
|
+
if (errorMessage.includes("MetaMask Tx Signature:")) {
|
|
61
|
+
return (
|
|
62
|
+
"MetaMask error: " +
|
|
63
|
+
errorMessage.split("MetaMask Tx Signature:")[1].trim()
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Ethers.js specific errors
|
|
68
|
+
if (error.code) {
|
|
69
|
+
switch (error.code) {
|
|
70
|
+
case ethers.errors.INVALID_ARGUMENT:
|
|
71
|
+
return "Invalid argument provided to the transaction.";
|
|
72
|
+
case ethers.errors.MISSING_ARGUMENT:
|
|
73
|
+
return "Missing required argument for the transaction.";
|
|
74
|
+
case ethers.errors.UNEXPECTED_ARGUMENT:
|
|
75
|
+
return "Unexpected argument provided to the transaction.";
|
|
76
|
+
case ethers.errors.CALL_EXCEPTION:
|
|
77
|
+
return "Contract call failed. The transaction might have been reverted.";
|
|
78
|
+
case ethers.errors.INSUFFICIENT_FUNDS:
|
|
79
|
+
return "Insufficient funds to complete the transaction.";
|
|
80
|
+
case ethers.errors.NONCE_EXPIRED:
|
|
81
|
+
return "Transaction nonce has expired. Please try again.";
|
|
82
|
+
case ethers.errors.REPLACEMENT_UNDERPRICED:
|
|
83
|
+
return "Replacement transaction underpriced. Please increase the gas price.";
|
|
84
|
+
case ethers.errors.UNPREDICTABLE_GAS_LIMIT:
|
|
85
|
+
return "Unable to estimate gas limit. The transaction might fail.";
|
|
86
|
+
default:
|
|
87
|
+
return "An error occurred: " + error.message;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// If no specific error is caught, return a generic message
|
|
92
|
+
return "An error occurred while processing the transaction. Please try again.";
|
|
93
|
+
}
|
package/tailwind.config.js
CHANGED
|
@@ -15,6 +15,45 @@ export default {
|
|
|
15
15
|
x_blue_dark: "rgba(43,74,157,1)",
|
|
16
16
|
x_green_light: "rgba(43,74,157,1)",
|
|
17
17
|
x_green_dark: "rgba(46,125,50,1)",
|
|
18
|
+
|
|
19
|
+
x_gray_100: "#D1D3D4",
|
|
20
|
+
x_gray_200: "#90A4AE",
|
|
21
|
+
x_gray_300: "#3C3C3B",
|
|
22
|
+
x_gray_400: "#272727",
|
|
23
|
+
x_gray_500: "#0F0F0F",
|
|
24
|
+
x_gray_600: "#020202",
|
|
25
|
+
x_green_100: "#11EFAA",
|
|
26
|
+
x_green_200: "#07C166",
|
|
27
|
+
x_green_300: "#4CAF50",
|
|
28
|
+
x_green_400: "#2E7D32",
|
|
29
|
+
x_green_500: "#08493C",
|
|
30
|
+
x_green_600: "#032921",
|
|
31
|
+
x_red_100: "#FFB7B2",
|
|
32
|
+
x_red_200: "#FE796F",
|
|
33
|
+
x_red_300: "#F44336",
|
|
34
|
+
x_red_400: "#C62828",
|
|
35
|
+
x_red_500: "#890000",
|
|
36
|
+
x_red_600: "#540000",
|
|
37
|
+
x_blue_100: "#A0F2FE",
|
|
38
|
+
x_blue_200: "#12AAFF",
|
|
39
|
+
x_blue_300: "#3681C6",
|
|
40
|
+
x_blue_300_20: "#3681C633",
|
|
41
|
+
x_blue_400: "#2B4A9D",
|
|
42
|
+
x_blue_400_20: "#2B4A9D33",
|
|
43
|
+
x_blue_500: "#1C227B",
|
|
44
|
+
x_blue_600: "#0B173A",
|
|
45
|
+
x_purple_100: "#EFA9FF",
|
|
46
|
+
x_purple_200: "#D427FC",
|
|
47
|
+
x_purple_300: "#AC8FFF",
|
|
48
|
+
x_purple_400: "#8247E5",
|
|
49
|
+
x_purple_500: "#46139D",
|
|
50
|
+
x_purple_600: "#2E075F",
|
|
51
|
+
x_orange_100: "#FEECA8",
|
|
52
|
+
x_orange_200: "#FDD835",
|
|
53
|
+
x_orange_300: "#FFCA28",
|
|
54
|
+
x_orange_400: "#F7A80D",
|
|
55
|
+
x_orange_500: "#FF6F00",
|
|
56
|
+
x_orange_600: "#795548",
|
|
18
57
|
},
|
|
19
58
|
width: {
|
|
20
59
|
x_desktop: "600px",
|
|
@@ -26,4 +65,5 @@ export default {
|
|
|
26
65
|
},
|
|
27
66
|
},
|
|
28
67
|
plugins: [],
|
|
68
|
+
prefix: "xpay-",
|
|
29
69
|
};
|