@xswap-link/sdk 0.2.4 → 0.2.5
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 +8 -0
- package/dist/index.css +13 -7
- package/dist/index.d.mts +19 -12
- package/dist/index.d.ts +19 -12
- package/dist/index.js +408 -263
- package/dist/index.mjs +337 -192
- package/package.json +1 -1
- package/src/components/TxConfigForm/FeesDetails.tsx +17 -13
- package/src/components/TxConfigForm/Form.tsx +21 -5
- package/src/components/TxConfigForm/History.tsx +31 -4
- package/src/components/TxConfigForm/Summary.tsx +16 -4
- package/src/components/TxConfigForm/SwapPanel.tsx +1 -1
- package/src/components/TxConfigForm/index.tsx +5 -0
- package/src/components/TxStatusButton/index.tsx +21 -13
- package/src/components/UnknownTokenLogo/UnknownTokenLogo.tsx +14 -0
- package/src/components/global.css +1 -1
- package/src/config/init.tsx +2 -2
- package/src/index.ts +9 -1
- package/src/models/TokenData.ts +1 -1
- package/src/models/TransactionHistory.ts +12 -8
- package/src/models/payloads/GetRoutePayload.ts +1 -0
- package/src/models/payloads/GetSwapTxPayload.ts +1 -0
- package/src/services/api.ts +9 -0
- package/src/services/blockchain.ts +49 -0
- package/src/services/index.ts +1 -0
- package/src/services/integrations/monitoring.ts +34 -14
- package/src/services/integrations/transactions.ts +8 -3
- package/src/utils/strings.ts +4 -0
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
1
|
+
import { FC, useMemo } from "react";
|
|
2
2
|
import { CoinsIcon, TimerIcon, ChevronUpIcon, ChevronDownIcon } from "../icons";
|
|
3
3
|
import { safeBigNumberFrom, weiToHumanReadable } from "@src/utils";
|
|
4
4
|
import { Route, Token } from "@src/models";
|
|
@@ -27,6 +27,10 @@ export const FeesDetails: FC<Props> = ({
|
|
|
27
27
|
feesDetailsShown,
|
|
28
28
|
setFeesDetailsShown,
|
|
29
29
|
}) => {
|
|
30
|
+
const isExpressDeliveryPossible = useMemo(() => {
|
|
31
|
+
return expressChecked && !exceedsExpressDeliveryLimit;
|
|
32
|
+
}, [expressChecked, exceedsExpressDeliveryLimit]);
|
|
33
|
+
|
|
30
34
|
return (
|
|
31
35
|
<div className="flex flex-col gap-3 globalBorder rounded-lg bg-[rgba(15,15,15,1)] p-2 sm:p-4 mb-1">
|
|
32
36
|
<div className="flex w-full items-center justify-between text-xs sm:text-sm">
|
|
@@ -51,18 +55,18 @@ export const FeesDetails: FC<Props> = ({
|
|
|
51
55
|
)}
|
|
52
56
|
</div>
|
|
53
57
|
<div className="flex gap-1 items-center">
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
? "Fast ~ 30sec "
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
{route?.xSwapFees.expressDeliveryFee && !isGettingRoute && (
|
|
59
|
+
<div
|
|
60
|
+
className={`flex gap-1 items-center font-medium ${
|
|
61
|
+
isExpressDeliveryPossible
|
|
62
|
+
? "text-x_green"
|
|
63
|
+
: "text-white opacity-60"
|
|
64
|
+
}`}
|
|
65
|
+
>
|
|
66
|
+
<TimerIcon />
|
|
67
|
+
{isExpressDeliveryPossible ? "Fast ~ 30sec " : "Normal ~ 30min"}
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
66
70
|
<div
|
|
67
71
|
onClick={() => setFeesDetailsShown((x) => !x)}
|
|
68
72
|
className="font-medium text-white opacity-60 cursor-pointer flex items-center w-[15px] h-[9px]"
|
|
@@ -3,7 +3,7 @@ import React, { FormEvent, useEffect, useState } from "react";
|
|
|
3
3
|
import { ethers } from "ethers";
|
|
4
4
|
import { useAccount, useSwitchChain } from "wagmi";
|
|
5
5
|
import { Chain, Route, Token, TokenBalances, TokenPrices } from "@src/models";
|
|
6
|
-
import { getPrices, getRoute } from "@src/services";
|
|
6
|
+
import { getCustomTokenData, getPrices, getRoute } from "@src/services";
|
|
7
7
|
import { getBalances } from "@src/utils";
|
|
8
8
|
import { ROUTE_TIMEOUT_MS } from "@src/constants";
|
|
9
9
|
import { TxConfigFormProps } from "@src/components";
|
|
@@ -21,6 +21,7 @@ import { DEFAULT_SOURCE_CHAIN_ID } from "@src/constants";
|
|
|
21
21
|
import { Button } from "./Button";
|
|
22
22
|
|
|
23
23
|
export const Form = ({
|
|
24
|
+
integratorId,
|
|
24
25
|
dstChainId,
|
|
25
26
|
dstTokenAddr,
|
|
26
27
|
customContractCalls,
|
|
@@ -77,15 +78,29 @@ export const Form = ({
|
|
|
77
78
|
}, [supportedChains, dstChainId]);
|
|
78
79
|
|
|
79
80
|
useEffect(() => {
|
|
80
|
-
|
|
81
|
-
dstChain
|
|
81
|
+
(async () => {
|
|
82
|
+
if (!dstChain) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let dstTokenResult = dstChain?.tokens.find(
|
|
82
87
|
(token) => token.address.toLowerCase() === dstTokenAddr.toLowerCase(),
|
|
83
|
-
)
|
|
84
|
-
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (!dstTokenResult) {
|
|
91
|
+
dstTokenResult = await getCustomTokenData(
|
|
92
|
+
dstChain,
|
|
93
|
+
dstTokenAddr.toLowerCase(),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setDstToken(dstTokenResult);
|
|
98
|
+
})();
|
|
85
99
|
}, [dstChain]);
|
|
86
100
|
|
|
87
101
|
useEffect(() => {
|
|
88
102
|
if (
|
|
103
|
+
integratorId &&
|
|
89
104
|
srcChain &&
|
|
90
105
|
srcToken &&
|
|
91
106
|
dstChain &&
|
|
@@ -104,6 +119,7 @@ export const Form = ({
|
|
|
104
119
|
`Configuration error: selected token ($${srcToken.symbol} ${srcToken.name}) has unknown decimals param.`,
|
|
105
120
|
);
|
|
106
121
|
getRoute({
|
|
122
|
+
integratorId,
|
|
107
123
|
fromAmount: ethers.utils
|
|
108
124
|
.parseUnits(debouncedAmount, srcToken.decimals)
|
|
109
125
|
.toString(),
|
|
@@ -21,15 +21,42 @@ export const History: FC<Props> = ({ signer, supportedChains }) => {
|
|
|
21
21
|
const fetchedTransactions: Transaction[] = [];
|
|
22
22
|
if (downloadedHistory) {
|
|
23
23
|
for (const entry of downloadedHistory.history) {
|
|
24
|
+
let status: TransactionStatus = "IN_PROGRESS";
|
|
25
|
+
|
|
26
|
+
// single chain tx
|
|
24
27
|
if (!entry.source) {
|
|
25
28
|
continue;
|
|
26
29
|
}
|
|
27
|
-
|
|
28
|
-
if (entry.failed)
|
|
30
|
+
|
|
31
|
+
if (entry.failed) {
|
|
32
|
+
status = "REVERTED";
|
|
33
|
+
}
|
|
29
34
|
if (!!entry.target) {
|
|
30
35
|
status = "DONE";
|
|
31
|
-
}
|
|
32
|
-
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (entry.transferType === "SINGLE_CHAIN") {
|
|
39
|
+
if (!entry.target) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const blockTimestampMs = new Date(entry.target.blockTime).getTime();
|
|
44
|
+
const estimatedDeliveryTimestamp = blockTimestampMs / 1000;
|
|
45
|
+
|
|
46
|
+
fetchedTransactions.push({
|
|
47
|
+
hash: entry.target.transactionHash,
|
|
48
|
+
timestamp: blockTimestampMs / 1000,
|
|
49
|
+
sourceChainId: entry.target.blockchainId,
|
|
50
|
+
targetChainId: entry.target.blockchainId,
|
|
51
|
+
amountWei: entry.source.tokenAmount,
|
|
52
|
+
tokenAddress: entry.source.tokenAddress,
|
|
53
|
+
tokenOutAddress: entry.target?.tokenAmount,
|
|
54
|
+
tokenOutAmount: entry.target?.tokenAmount,
|
|
55
|
+
estimatedDeliveryTimestamp,
|
|
56
|
+
status,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
continue;
|
|
33
60
|
}
|
|
34
61
|
|
|
35
62
|
const blockTimestampMs = new Date(entry.source.blockTime).getTime();
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { weiToHumanReadable } from "@src/utils";
|
|
3
3
|
import { Chain, Route, Token, TokenPrices } from "@src/models";
|
|
4
4
|
import { ArrowDownIcon } from "../icons";
|
|
5
5
|
import { UsdPrice } from "@src/components/TxConfigForm/UsdPrice";
|
|
6
6
|
import { getPrices } from "@src/services";
|
|
7
7
|
import { Skeleton } from "@src/components";
|
|
8
|
+
import { UnknownTokenLogo } from "../UnknownTokenLogo/UnknownTokenLogo";
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
10
11
|
isGettingRoute: boolean;
|
|
@@ -58,10 +59,21 @@ export const Summary: FC<Props> = ({
|
|
|
58
59
|
</div>
|
|
59
60
|
<div className="flex flex-col items-end gap-1 text-sm">
|
|
60
61
|
<div className="flex justify-center items-center gap-1">
|
|
61
|
-
<div className="w-
|
|
62
|
-
|
|
62
|
+
<div className="w-5 h-5">
|
|
63
|
+
{dstToken?.image ? (
|
|
64
|
+
<img
|
|
65
|
+
className="w-5 h-5"
|
|
66
|
+
src={dstToken?.image}
|
|
67
|
+
alt={dstToken?.name}
|
|
68
|
+
/>
|
|
69
|
+
) : (
|
|
70
|
+
<UnknownTokenLogo
|
|
71
|
+
tokenName={"?"}
|
|
72
|
+
className="token-select__generated-logo"
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
63
75
|
</div>
|
|
64
|
-
<p className="text-base sm:text-xl">{dstToken?.
|
|
76
|
+
<p className="text-base sm:text-xl">{dstToken?.name}</p>
|
|
65
77
|
</div>
|
|
66
78
|
<div className="flex justify-center items-center gap-1">
|
|
67
79
|
<p className="text-[rgba(255,255,255,0.6)] text-right">on </p>
|
|
@@ -8,6 +8,7 @@ import { PoweredBy } from "@src/components/TxConfigForm/PoweredBy";
|
|
|
8
8
|
import { Form } from "./Form";
|
|
9
9
|
|
|
10
10
|
export type TxConfigFormProps = {
|
|
11
|
+
integratorId: string;
|
|
11
12
|
dstChainId: string;
|
|
12
13
|
dstTokenAddr: string;
|
|
13
14
|
customContractCalls: ContractCall[];
|
|
@@ -16,6 +17,7 @@ export type TxConfigFormProps = {
|
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
const TxConfigForm = ({
|
|
20
|
+
integratorId,
|
|
19
21
|
dstChainId,
|
|
20
22
|
dstTokenAddr,
|
|
21
23
|
customContractCalls,
|
|
@@ -50,6 +52,7 @@ const TxConfigForm = ({
|
|
|
50
52
|
>
|
|
51
53
|
<div className="relative bg-black rounded-3xl overflow-auto text-white border-2 border-solid border-[rgba(255,255,255,0.1)]">
|
|
52
54
|
<Form
|
|
55
|
+
integratorId={integratorId}
|
|
53
56
|
dstChainId={dstChainId}
|
|
54
57
|
dstTokenAddr={dstTokenAddr}
|
|
55
58
|
customContractCalls={customContractCalls}
|
|
@@ -67,6 +70,7 @@ const TxConfigForm = ({
|
|
|
67
70
|
};
|
|
68
71
|
|
|
69
72
|
export const openTxConfigForm = async ({
|
|
73
|
+
integratorId,
|
|
70
74
|
dstChainId,
|
|
71
75
|
dstTokenAddr,
|
|
72
76
|
customContractCalls,
|
|
@@ -78,6 +82,7 @@ export const openTxConfigForm = async ({
|
|
|
78
82
|
await waitForInitialization();
|
|
79
83
|
xswapRoot.render(
|
|
80
84
|
<TxConfigForm
|
|
85
|
+
integratorId={integratorId}
|
|
81
86
|
dstChainId={dstChainId}
|
|
82
87
|
dstTokenAddr={dstTokenAddr}
|
|
83
88
|
customContractCalls={customContractCalls}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "../icons";
|
|
10
10
|
import { MonitoredTransaction } from "@src/models";
|
|
11
11
|
import { txStatusRoot } from "@src/config";
|
|
12
|
+
import { UnknownTokenLogo } from "../UnknownTokenLogo/UnknownTokenLogo";
|
|
12
13
|
|
|
13
14
|
interface Props {
|
|
14
15
|
transaction: MonitoredTransaction;
|
|
@@ -16,15 +17,14 @@ interface Props {
|
|
|
16
17
|
|
|
17
18
|
export const TxStatusButton: FC<Props> = ({ transaction }) => {
|
|
18
19
|
const {
|
|
19
|
-
fromChain,
|
|
20
|
-
fromChainImage,
|
|
21
|
-
fromToken,
|
|
22
|
-
fromTokenImage,
|
|
23
|
-
fromAmount,
|
|
24
|
-
toChain,
|
|
25
|
-
toChainImage,
|
|
20
|
+
srcChain: fromChain,
|
|
21
|
+
srcChainImage: fromChainImage,
|
|
22
|
+
srcToken: fromToken,
|
|
23
|
+
srcTokenImage: fromTokenImage,
|
|
24
|
+
srcAmount: fromAmount,
|
|
25
|
+
dstChain: toChain,
|
|
26
|
+
dstChainImage: toChainImage,
|
|
26
27
|
isDone,
|
|
27
|
-
txHash,
|
|
28
28
|
explorer,
|
|
29
29
|
} = transaction;
|
|
30
30
|
const [isWide, setIsWide] = useState(false);
|
|
@@ -70,11 +70,19 @@ export const TxStatusButton: FC<Props> = ({ transaction }) => {
|
|
|
70
70
|
<div>Sent</div>
|
|
71
71
|
<div>{fromAmount}</div>
|
|
72
72
|
<div>{fromToken}</div>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
|
|
74
|
+
{fromTokenImage ? (
|
|
75
|
+
<img
|
|
76
|
+
className="w-5 h-5"
|
|
77
|
+
src={fromTokenImage}
|
|
78
|
+
alt="source token"
|
|
79
|
+
/>
|
|
80
|
+
) : (
|
|
81
|
+
<UnknownTokenLogo
|
|
82
|
+
tokenName={"?"}
|
|
83
|
+
className="token-select__generated-logo"
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
78
86
|
</div>
|
|
79
87
|
</div>
|
|
80
88
|
<a
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
tokenName: string;
|
|
3
|
+
className?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const UnknownTokenLogo = ({ tokenName, className }: Props) => {
|
|
7
|
+
return (
|
|
8
|
+
<div
|
|
9
|
+
className={`w-5 h-5 rounded-full bg-white shadow-sm flex items-center justify-center text-black ${className}`}
|
|
10
|
+
>
|
|
11
|
+
{tokenName.substring(0, 1)}
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
};
|
package/src/config/init.tsx
CHANGED
|
@@ -17,7 +17,7 @@ export const initDocument = () => {
|
|
|
17
17
|
|
|
18
18
|
Promise.all([
|
|
19
19
|
createStyleElement(),
|
|
20
|
-
|
|
20
|
+
createXSwapRoot(),
|
|
21
21
|
createTxStatusRoot(),
|
|
22
22
|
]).then(() => {
|
|
23
23
|
initCompleted = true;
|
|
@@ -46,7 +46,7 @@ const createStyleElement = async () => {
|
|
|
46
46
|
document.body.appendChild(style);
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
const
|
|
49
|
+
const createXSwapRoot = async () => {
|
|
50
50
|
const xswapElement = document.createElement("div");
|
|
51
51
|
xswapElement.setAttribute("id", "xswap-modal");
|
|
52
52
|
document.body.appendChild(xswapElement);
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { initDocument } from "@src/config/init";
|
|
2
|
+
import { openTransactionModal, renderTxStatus } from "@src/services";
|
|
2
3
|
|
|
3
4
|
initDocument();
|
|
4
5
|
|
|
5
6
|
export * from "@src/models";
|
|
6
|
-
export {
|
|
7
|
+
export { openTransactionModal, renderTxStatus } from "@src/services";
|
|
8
|
+
|
|
9
|
+
const XPay = {
|
|
10
|
+
openTransactionModal,
|
|
11
|
+
renderTxStatus,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default XPay;
|
package/src/models/TokenData.ts
CHANGED
|
@@ -34,7 +34,11 @@ export type HistoryTransaction = {
|
|
|
34
34
|
} | null;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
export type TransactionStatus =
|
|
37
|
+
export type TransactionStatus =
|
|
38
|
+
| "IN_PROGRESS"
|
|
39
|
+
| "DONE"
|
|
40
|
+
| "REVERTED"
|
|
41
|
+
| "NOT_FOUND";
|
|
38
42
|
|
|
39
43
|
export type Transaction = {
|
|
40
44
|
hash: string;
|
|
@@ -50,13 +54,13 @@ export type Transaction = {
|
|
|
50
54
|
};
|
|
51
55
|
|
|
52
56
|
export type MonitoredTransaction = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
srcChain: string | undefined;
|
|
58
|
+
srcChainImage: string | undefined;
|
|
59
|
+
srcToken: string | undefined;
|
|
60
|
+
srcTokenImage: string | undefined;
|
|
61
|
+
srcAmount: string | undefined;
|
|
62
|
+
dstChain: string | undefined;
|
|
63
|
+
dstChainImage: string | undefined;
|
|
60
64
|
isDone: boolean;
|
|
61
65
|
txHash: string;
|
|
62
66
|
explorer: string | undefined;
|
package/src/services/api.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
Token,
|
|
10
10
|
TokenPrices,
|
|
11
11
|
TransactionHistory,
|
|
12
|
+
TransactionStatus,
|
|
12
13
|
} from "@src/models";
|
|
13
14
|
|
|
14
15
|
async function _sendRequest<T>(
|
|
@@ -110,3 +111,11 @@ export async function getPrices(payload: GetPricesPayload) {
|
|
|
110
111
|
})}`,
|
|
111
112
|
);
|
|
112
113
|
}
|
|
114
|
+
|
|
115
|
+
export async function getTxStatus(payload: { transferId: string }) {
|
|
116
|
+
return await _sendRequest<{ status: TransactionStatus }>(
|
|
117
|
+
`/getTxStatus?${new URLSearchParams({
|
|
118
|
+
data: JSON.stringify(payload), // todo remove once gcp starts working
|
|
119
|
+
})}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ERC20Abi } from "@src/contracts";
|
|
2
|
+
import { ethers } from "ethers";
|
|
3
|
+
import { Chain, Token } from "@src/models";
|
|
4
|
+
|
|
5
|
+
export const getCustomTokenData = async (
|
|
6
|
+
chain: Chain,
|
|
7
|
+
tokenAddress: string,
|
|
8
|
+
): Promise<Token> => {
|
|
9
|
+
const rpcUrl = chain.publicRpcUrls[0];
|
|
10
|
+
|
|
11
|
+
const customTokenContract = new ethers.Contract(
|
|
12
|
+
tokenAddress.toLowerCase(),
|
|
13
|
+
ERC20Abi,
|
|
14
|
+
ethers.getDefaultProvider(rpcUrl),
|
|
15
|
+
);
|
|
16
|
+
try {
|
|
17
|
+
const query = async (
|
|
18
|
+
contract: ethers.Contract | null,
|
|
19
|
+
method: string,
|
|
20
|
+
args: unknown[] = [],
|
|
21
|
+
) => {
|
|
22
|
+
if (contract?.provider) {
|
|
23
|
+
const response = await contract[method](...args);
|
|
24
|
+
return response;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
28
|
+
const responses = await Promise.all([
|
|
29
|
+
query(customTokenContract, "decimals"),
|
|
30
|
+
query(customTokenContract, "name"),
|
|
31
|
+
query(customTokenContract, "symbol"),
|
|
32
|
+
]);
|
|
33
|
+
const [decimals, name, symbol] = responses;
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
address: tokenAddress,
|
|
37
|
+
symbol: symbol,
|
|
38
|
+
name: name,
|
|
39
|
+
decimals: decimals,
|
|
40
|
+
quickPick: false,
|
|
41
|
+
supported: true,
|
|
42
|
+
priority: 0,
|
|
43
|
+
};
|
|
44
|
+
} catch (_) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Provided token ${tokenAddress} does not exists on chain ${chain.displayName}`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
};
|
package/src/services/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Chain, MonitoredTransaction, Web3Environment } from "@src/models";
|
|
2
|
-
import { getChains } from "@src/services";
|
|
2
|
+
import { getChains, getTxStatus } from "@src/services";
|
|
3
3
|
import { ethers } from "ethers";
|
|
4
4
|
import { weiToHumanReadable } from "@src/utils";
|
|
5
5
|
import {
|
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
} from "@src/components";
|
|
19
19
|
import { ADDRESSES } from "@src/contracts";
|
|
20
20
|
import retry from "async-retry";
|
|
21
|
+
import { getCustomTokenData } from "../blockchain";
|
|
21
22
|
|
|
22
|
-
export const
|
|
23
|
+
export const renderTxStatus = async (
|
|
23
24
|
txChainId: string,
|
|
24
25
|
txHash: string,
|
|
25
26
|
): Promise<void> => {
|
|
@@ -52,11 +53,20 @@ export const monitorTransactionStatus = async (
|
|
|
52
53
|
const srcChain = supportedChains.find(
|
|
53
54
|
(chain) => chain.chainId === txChainId.toString(),
|
|
54
55
|
);
|
|
56
|
+
if (!srcChain) {
|
|
57
|
+
throw new Error(`Unknown src chain ${txChainId}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const tokenAddress = decodedMessageSentEvent.args?.token.toString();
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
let srcToken = srcChain.tokens.find(
|
|
57
63
|
(token) => token.address === decodedMessageSentEvent.args?.token.toString(),
|
|
58
64
|
);
|
|
59
65
|
|
|
66
|
+
if (!srcToken) {
|
|
67
|
+
srcToken = await getCustomTokenData(srcChain, tokenAddress);
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
const dstChain = supportedChains.find(
|
|
61
71
|
(chain) =>
|
|
62
72
|
chain.ccipChainId ===
|
|
@@ -69,19 +79,21 @@ export const monitorTransactionStatus = async (
|
|
|
69
79
|
throw new Error(`Unknown destination chain!`);
|
|
70
80
|
}
|
|
71
81
|
|
|
82
|
+
const tokenAmount = weiToHumanReadable({
|
|
83
|
+
amount: decodedMessageSentEvent.args?.tokenAmount.toString(),
|
|
84
|
+
decimals: srcToken?.decimals || 18,
|
|
85
|
+
precisionFractionalPlaces: 4,
|
|
86
|
+
});
|
|
87
|
+
|
|
72
88
|
const transaction: MonitoredTransaction = {
|
|
73
89
|
txHash: txHash,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
amount: decodedMessageSentEvent.args?.tokenAmount.toString(),
|
|
82
|
-
decimals: srcToken?.decimals || 18,
|
|
83
|
-
precisionFractionalPlaces: 4,
|
|
84
|
-
}),
|
|
90
|
+
srcChain: srcChain.displayName,
|
|
91
|
+
srcChainImage: srcChain.image,
|
|
92
|
+
dstChain: dstChain.displayName,
|
|
93
|
+
dstChainImage: dstChain.image,
|
|
94
|
+
srcToken: srcToken?.symbol,
|
|
95
|
+
srcTokenImage: srcToken?.image,
|
|
96
|
+
srcAmount: tokenAmount === "0" ? "<0.0001" : tokenAmount,
|
|
85
97
|
isDone: false,
|
|
86
98
|
explorer: `${CCIP_EXPLORER}/tx/${txHash}`,
|
|
87
99
|
};
|
|
@@ -120,6 +132,14 @@ export const monitorTransactionStatus = async (
|
|
|
120
132
|
removeTransactionFromRenderedTransactions(txHash);
|
|
121
133
|
renderTxStatusButtons();
|
|
122
134
|
};
|
|
135
|
+
|
|
136
|
+
// check tx status on backend
|
|
137
|
+
getTxStatus({ transferId: messageId }).then((response) => {
|
|
138
|
+
if (response.status === "DONE") {
|
|
139
|
+
onSuccess();
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
123
143
|
xSwapRouterOnDestination.once(msgReceivedEventFilter, () => onSuccess());
|
|
124
144
|
};
|
|
125
145
|
|
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
} from "@src/models";
|
|
7
7
|
import { getChains } from "@src/services";
|
|
8
8
|
import { openTxConfigForm } from "@src/components";
|
|
9
|
+
import { isETHAddressValid } from "@src/utils";
|
|
9
10
|
|
|
10
|
-
export const
|
|
11
|
+
export const openTransactionModal = async ({
|
|
12
|
+
integratorId,
|
|
11
13
|
dstChain,
|
|
12
14
|
dstToken,
|
|
13
15
|
customContractCalls = [],
|
|
@@ -21,6 +23,7 @@ export const getSwapTx = async ({
|
|
|
21
23
|
validateSwapTxData(supportedChains, dstChain, dstToken);
|
|
22
24
|
|
|
23
25
|
const route = await openTxConfigForm({
|
|
26
|
+
integratorId: integratorId,
|
|
24
27
|
dstChainId: dstChain,
|
|
25
28
|
dstTokenAddr: dstToken,
|
|
26
29
|
customContractCalls,
|
|
@@ -43,7 +46,9 @@ const validateSwapTxData = (
|
|
|
43
46
|
throw new Error(`Provided chain '${dstChain}' is not supported`);
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
if (!
|
|
47
|
-
throw new Error(
|
|
49
|
+
if (!isETHAddressValid(dstToken)) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Provided token address ${dstToken} on chain ${dstChain} is not correct`,
|
|
52
|
+
);
|
|
48
53
|
}
|
|
49
54
|
};
|