@xswap-link/sdk 0.1.2 → 0.1.3
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 +11 -0
- package/dist/index.css +92 -33
- package/dist/index.d.mts +60 -155
- package/dist/index.d.ts +60 -155
- package/dist/index.js +915 -1841
- package/dist/index.mjs +867 -1800
- package/package.json +1 -1
- package/src/components/Skeleton/index.tsx +8 -5
- package/src/components/TxConfigForm/FeesDetails.tsx +5 -5
- package/src/components/TxConfigForm/Form.tsx +10 -3
- package/src/components/TxConfigForm/History.tsx +1 -1
- package/src/components/TxConfigForm/HistoryCard.tsx +19 -40
- package/src/components/TxConfigForm/Summary.tsx +57 -28
- package/src/components/TxConfigForm/SwapPanel.tsx +70 -77
- package/src/components/TxConfigForm/TokenPicker.tsx +2 -2
- package/src/components/TxConfigForm/TopBar.tsx +2 -2
- package/src/components/TxConfigForm/UsdPrice.tsx +41 -0
- package/src/components/TxConfigForm/index.tsx +1 -2
- package/src/components/TxHistoryButton/index.tsx +150 -0
- package/src/components/icons/ArrowLeftIcon.tsx +16 -0
- package/src/components/icons/ChevronUpIcon.tsx +1 -6
- package/src/components/icons/CircularProgressIcon.tsx +13 -15
- package/src/components/icons/XSwapLogo.tsx +98 -0
- package/src/components/icons/index.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/constants/index.ts +1 -0
- package/src/contracts/abi/index.ts +0 -2
- package/src/contracts/addresses.ts +6 -0
- package/src/models/Addresses.ts +1 -0
- package/src/models/TransactionHistory.ts +44 -29
- package/src/services/integrations/transactions.ts +166 -1
- package/src/utils/index.ts +7 -0
- package/tailwind.config.js +6 -1
- package/tsconfig.json +3 -7
- package/src/contracts/abi/XSwapRouter.json +0 -1242
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { FC, useState } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import {
|
|
4
|
+
ArrowLeftIcon,
|
|
5
|
+
ArrowRightIcon,
|
|
6
|
+
CheckIcon,
|
|
7
|
+
CircularProgressIcon,
|
|
8
|
+
} from "../icons";
|
|
9
|
+
import { ArrowUpRightIcon, XSwapLogo } from "../icons";
|
|
10
|
+
import { MonitoredTransaction } from "@src/models";
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
transaction: MonitoredTransaction;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const TxHistoryButton: FC<Props> = ({ transaction }) => {
|
|
17
|
+
const {
|
|
18
|
+
fromChain,
|
|
19
|
+
fromChainImage,
|
|
20
|
+
fromToken,
|
|
21
|
+
fromTokenImage,
|
|
22
|
+
fromAmount,
|
|
23
|
+
toChain,
|
|
24
|
+
toChainImage,
|
|
25
|
+
isDone,
|
|
26
|
+
txHash,
|
|
27
|
+
explorer,
|
|
28
|
+
} = transaction;
|
|
29
|
+
const [isWide, setIsWide] = useState(false);
|
|
30
|
+
return (
|
|
31
|
+
<div className="flex gap-2" onClick={() => setIsWide((x: boolean) => !x)}>
|
|
32
|
+
{isWide && (
|
|
33
|
+
<div
|
|
34
|
+
className={`flex items-center min-w-60 sm:w-[520px] text-white h-14 px-4 text-sm gap-3 rounded-xl bg-gradient-to-r ${
|
|
35
|
+
isDone
|
|
36
|
+
? "from-[rgba(76,175,80,0.1)] to-[rgba(46,125,50,0.1)] border border-solid border-x_green_dark"
|
|
37
|
+
: "from-[rgba(54,129,198,0.1)] to-[rgba(43,74,157,0.1)] border border-solid border-x_blue_dark"
|
|
38
|
+
}`}
|
|
39
|
+
>
|
|
40
|
+
<div className="flex justify-between flex-col gap-2 sm:gap-5 sm:flex-row w-full">
|
|
41
|
+
<div className="flex items-center gap-2">
|
|
42
|
+
<img
|
|
43
|
+
className="w-5 h-5"
|
|
44
|
+
src={fromChainImage}
|
|
45
|
+
alt="source chain"
|
|
46
|
+
/>
|
|
47
|
+
<div>{fromChain}</div>
|
|
48
|
+
<div className="w-3.5 h-3.5">
|
|
49
|
+
<ArrowRightIcon />
|
|
50
|
+
</div>
|
|
51
|
+
<img className="w-5 h-5" src={toChainImage} alt="to chain" />
|
|
52
|
+
<div>{toChain}</div>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div className="flex items-center gap-2">
|
|
56
|
+
<div>Sent</div>
|
|
57
|
+
<div>{fromAmount}</div>
|
|
58
|
+
<div>{fromToken}</div>
|
|
59
|
+
<img
|
|
60
|
+
className="w-5 h-5"
|
|
61
|
+
src={fromTokenImage}
|
|
62
|
+
alt="source token"
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
<a
|
|
67
|
+
href={explorer}
|
|
68
|
+
target="_blank"
|
|
69
|
+
rel="noreferrer"
|
|
70
|
+
className="no-underline cursor-pointer"
|
|
71
|
+
aria-label="Show the transaction in the chain explorer"
|
|
72
|
+
>
|
|
73
|
+
<div className="w-3.5 h-3.5">
|
|
74
|
+
<ArrowUpRightIcon />
|
|
75
|
+
</div>
|
|
76
|
+
</a>
|
|
77
|
+
</div>
|
|
78
|
+
)}
|
|
79
|
+
<div
|
|
80
|
+
className={`text-white rounded-xl cursor-pointer bg-gradient-to-r
|
|
81
|
+
${
|
|
82
|
+
isDone
|
|
83
|
+
? "from-[rgba(76,175,80,0.1)] to-[rgba(46,125,50,0.1)] border border-solid border-x_green_dark"
|
|
84
|
+
: "from-[rgba(54,129,198,0.1)] to-[rgba(43,74,157,0.1)] border border-solid border-x_blue_dark"
|
|
85
|
+
}`}
|
|
86
|
+
>
|
|
87
|
+
<div className="flex gap-2 items-center h-14 w-20 justify-center">
|
|
88
|
+
<ArrowLeftIcon />
|
|
89
|
+
<div className="relative flex items-center justify-center w-9 h-9">
|
|
90
|
+
{isDone ? (
|
|
91
|
+
<div className="text-x_green w-5 h-5">
|
|
92
|
+
<CheckIcon />
|
|
93
|
+
</div>
|
|
94
|
+
) : (
|
|
95
|
+
<>
|
|
96
|
+
<div className="w-5 h-5">
|
|
97
|
+
<XSwapLogo />
|
|
98
|
+
</div>
|
|
99
|
+
<div className="absolute flex items-center justify-center top-0 left-0 right-0 bottom-0 text-white">
|
|
100
|
+
<CircularProgressIcon />
|
|
101
|
+
</div>
|
|
102
|
+
</>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
let renderedTransactions: MonitoredTransaction[] = [];
|
|
112
|
+
|
|
113
|
+
export const addTransactionToRenderedTransactions = (
|
|
114
|
+
transaction: MonitoredTransaction,
|
|
115
|
+
) => {
|
|
116
|
+
if (!renderedTransactions.some(({ txHash }) => txHash === transaction.txHash))
|
|
117
|
+
renderedTransactions.push(transaction);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export const removeTransactionFromRenderedTransactions = (txHash: string) => {
|
|
121
|
+
const filteredRenderedTransactions = renderedTransactions.filter(
|
|
122
|
+
(item) => item.txHash !== txHash,
|
|
123
|
+
);
|
|
124
|
+
renderedTransactions = [...filteredRenderedTransactions];
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const updateTransactionDoneInRenderedTransactions = (txHash: string) => {
|
|
128
|
+
const transaction = renderedTransactions.find(
|
|
129
|
+
(item) => item.txHash === txHash,
|
|
130
|
+
);
|
|
131
|
+
if (transaction) {
|
|
132
|
+
transaction.isDone = true;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const historyElement = document.createElement("div");
|
|
137
|
+
historyElement.setAttribute("id", "xswap-history");
|
|
138
|
+
historyElement.setAttribute(
|
|
139
|
+
"class",
|
|
140
|
+
"absolute bottom-5 right-2 flex flex-col gap-3 pl-9 items-end w-full z-50",
|
|
141
|
+
);
|
|
142
|
+
document.body.appendChild(historyElement);
|
|
143
|
+
const txHistoryButtonRoot = createRoot(historyElement);
|
|
144
|
+
|
|
145
|
+
export const renderTxHistoryButtons = () => {
|
|
146
|
+
const buttons = renderedTransactions.map((item) => (
|
|
147
|
+
<TxHistoryButton key={item.txHash} transaction={item} />
|
|
148
|
+
));
|
|
149
|
+
txHistoryButtonRoot.render(buttons);
|
|
150
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const ArrowLeftIcon = () => {
|
|
2
|
+
return (
|
|
3
|
+
<svg
|
|
4
|
+
width="10"
|
|
5
|
+
height="16"
|
|
6
|
+
viewBox="0 0 10 16"
|
|
7
|
+
fill="none"
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
d="M0.5 8L8.13251 15.5L9.5 14.1562L3.20318 8L9.4682 1.84375L8.10071 0.5L0.5 8Z"
|
|
12
|
+
fill="white"
|
|
13
|
+
/>
|
|
14
|
+
</svg>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
export const ChevronUpIcon = () => {
|
|
2
2
|
return (
|
|
3
|
-
<svg
|
|
4
|
-
height="12"
|
|
5
|
-
width="12"
|
|
6
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
-
viewBox="0 0 512 512"
|
|
8
|
-
>
|
|
3
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
9
4
|
<path
|
|
10
5
|
fill="currentColor"
|
|
11
6
|
d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
export const CircularProgressIcon = () => {
|
|
2
2
|
return (
|
|
3
3
|
<svg
|
|
4
|
-
className="animate-spin
|
|
5
|
-
|
|
4
|
+
className="animate-spin-slow text-white"
|
|
5
|
+
width="33"
|
|
6
|
+
height="33"
|
|
7
|
+
viewBox="0 0 33 33"
|
|
6
8
|
fill="none"
|
|
7
|
-
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8
10
|
>
|
|
9
11
|
<circle
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
strokeWidth="
|
|
16
|
-
|
|
17
|
-
<path
|
|
18
|
-
className="opacity-75"
|
|
19
|
-
fill="currentColor"
|
|
20
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
21
|
-
></path>
|
|
12
|
+
cx="16.5"
|
|
13
|
+
cy="16.5"
|
|
14
|
+
r="15.5"
|
|
15
|
+
stroke="white"
|
|
16
|
+
strokeOpacity="0.2"
|
|
17
|
+
strokeWidth="2"
|
|
18
|
+
/>
|
|
19
|
+
<path d="M1 16C1 7.71573 7.71573 1 16 1" stroke="white" strokeWidth="2" />
|
|
22
20
|
</svg>
|
|
23
21
|
);
|
|
24
22
|
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export const XSwapLogo = () => {
|
|
2
|
+
return (
|
|
3
|
+
<svg
|
|
4
|
+
version="1.1"
|
|
5
|
+
id="Layer_1"
|
|
6
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
+
x="0px"
|
|
8
|
+
y="0px"
|
|
9
|
+
viewBox="0 0 50 50"
|
|
10
|
+
enableBackground="new 0 0 50 50"
|
|
11
|
+
>
|
|
12
|
+
<image
|
|
13
|
+
id="image0"
|
|
14
|
+
x="0"
|
|
15
|
+
y="0"
|
|
16
|
+
href="data:image/png;base64,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"
|
|
95
|
+
/>
|
|
96
|
+
</svg>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./ArrowRightIcon";
|
|
2
2
|
export * from "./ArrowDownIcon";
|
|
3
|
+
export * from "./ArrowLeftIcon";
|
|
3
4
|
export * from "./ArrowUpRightIcon";
|
|
4
5
|
export * from "./CheckIcon";
|
|
5
6
|
export * from "./ChevronDownIcon";
|
|
@@ -18,3 +19,4 @@ export * from "./InfoIcon";
|
|
|
18
19
|
export * from "./SettingsIcon";
|
|
19
20
|
export * from "./XSwapBadgeIcon";
|
|
20
21
|
export * from "./ChainlinkCCIPIcon";
|
|
22
|
+
export * from "./XSwapLogo";
|
package/src/components/index.ts
CHANGED
package/src/constants/index.ts
CHANGED
|
@@ -4,31 +4,37 @@ export const ADDRESSES: Addresses = {
|
|
|
4
4
|
// arbitrum
|
|
5
5
|
"42161": {
|
|
6
6
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
7
|
+
[ContractName.XSwapRouter]: "0xe1c14b9f065dead2e89ee35382f8bd42bdb87a04",
|
|
7
8
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
8
9
|
},
|
|
9
10
|
// avalanche
|
|
10
11
|
"43114": {
|
|
11
12
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
13
|
+
[ContractName.XSwapRouter]: "0xe1c14b9f065dead2e89ee35382f8bd42bdb87a04",
|
|
12
14
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
13
15
|
},
|
|
14
16
|
// base
|
|
15
17
|
"8453": {
|
|
16
18
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
19
|
+
[ContractName.XSwapRouter]: "0xe1c14b9f065dead2e89ee35382f8bd42bdb87a04",
|
|
17
20
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
18
21
|
},
|
|
19
22
|
// ethereum
|
|
20
23
|
"1": {
|
|
21
24
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
25
|
+
[ContractName.XSwapRouter]: "0xe1c14b9f065dead2e89ee35382f8bd42bdb87a04",
|
|
22
26
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
23
27
|
},
|
|
24
28
|
// optimism
|
|
25
29
|
"10": {
|
|
26
30
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
31
|
+
[ContractName.XSwapRouter]: "0xe1c14b9f065dead2e89ee35382f8bd42bdb87a04",
|
|
27
32
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
28
33
|
},
|
|
29
34
|
// polygon
|
|
30
35
|
"137": {
|
|
31
36
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
37
|
+
[ContractName.XSwapRouter]: "0xe1c14b9f065dead2e89ee35382f8bd42bdb87a04",
|
|
32
38
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
33
39
|
},
|
|
34
40
|
};
|
package/src/models/Addresses.ts
CHANGED
|
@@ -1,35 +1,37 @@
|
|
|
1
1
|
type TransferType = "CROSS_CHAIN" | "SINGLE_CHAIN";
|
|
2
2
|
|
|
3
3
|
export type TransactionHistory = {
|
|
4
|
-
history:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
4
|
+
history: HistoryTransaction[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type HistoryTransaction = {
|
|
8
|
+
transferId: string;
|
|
9
|
+
transferType: TransferType;
|
|
10
|
+
walletAddress: string;
|
|
11
|
+
// ExecutorRunFailed
|
|
12
|
+
failed: boolean;
|
|
13
|
+
// MessageSent
|
|
14
|
+
source: {
|
|
15
|
+
blockchainId: string;
|
|
16
|
+
transactionHash: string;
|
|
17
|
+
blockTime: Date;
|
|
18
|
+
tokenAmount: string;
|
|
19
|
+
tokenAddress: string;
|
|
20
|
+
transferredTokenAddress: string;
|
|
21
|
+
transferredTokenAmount: string;
|
|
22
|
+
valueForInstantCcipRecieve: string;
|
|
23
|
+
tokenOutAddress: string;
|
|
24
|
+
estimatedAmountOut: string;
|
|
25
|
+
targetBlockchainId: string;
|
|
26
|
+
} | null;
|
|
27
|
+
// MessageReceived
|
|
28
|
+
target: {
|
|
29
|
+
blockchainId: string;
|
|
30
|
+
transactionHash: string;
|
|
31
|
+
blockTime: Date;
|
|
32
|
+
tokenAmount: string;
|
|
33
|
+
tokenAddress: string;
|
|
34
|
+
} | null;
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
export type TransactionStatus = "IN_PROGRESS" | "DONE" | "REVERTED";
|
|
@@ -46,3 +48,16 @@ export type Transaction = {
|
|
|
46
48
|
estimatedDeliveryTimestamp: number;
|
|
47
49
|
status: TransactionStatus;
|
|
48
50
|
};
|
|
51
|
+
|
|
52
|
+
export type MonitoredTransaction = {
|
|
53
|
+
fromChain: string | undefined;
|
|
54
|
+
fromChainImage: string | undefined;
|
|
55
|
+
fromToken: string | undefined;
|
|
56
|
+
fromTokenImage: string | undefined;
|
|
57
|
+
fromAmount: string | undefined;
|
|
58
|
+
toChain: string | undefined;
|
|
59
|
+
toChainImage: string | undefined;
|
|
60
|
+
isDone: boolean;
|
|
61
|
+
txHash: string;
|
|
62
|
+
explorer: string | undefined;
|
|
63
|
+
};
|
|
@@ -3,9 +3,20 @@ import {
|
|
|
3
3
|
GetSwapTxPayload,
|
|
4
4
|
Transactions,
|
|
5
5
|
Web3Environment,
|
|
6
|
+
MonitoredTransaction,
|
|
6
7
|
} from "@src/models";
|
|
7
8
|
import { getChains } from "@src/services";
|
|
8
|
-
import {
|
|
9
|
+
import { ethers } from "ethers";
|
|
10
|
+
import { ADDRESSES } from "@src/contracts";
|
|
11
|
+
import {
|
|
12
|
+
openTxConfigForm,
|
|
13
|
+
addTransactionToRenderedTransactions,
|
|
14
|
+
removeTransactionFromRenderedTransactions,
|
|
15
|
+
renderTxHistoryButtons,
|
|
16
|
+
updateTransactionDoneInRenderedTransactions,
|
|
17
|
+
} from "@src/components";
|
|
18
|
+
import { weiToHumanReadable } from "@src/utils";
|
|
19
|
+
import { CCIP_EXPLORER } from "@src/constants";
|
|
9
20
|
|
|
10
21
|
export const getSwapTx = async ({
|
|
11
22
|
dstChain,
|
|
@@ -18,6 +29,8 @@ export const getSwapTx = async ({
|
|
|
18
29
|
web3Environment === Web3Environment.MAINNET && swapSupported,
|
|
19
30
|
);
|
|
20
31
|
|
|
32
|
+
validateSwapTxData(supportedChains, dstChain, dstToken);
|
|
33
|
+
|
|
21
34
|
const route = await openTxConfigForm({
|
|
22
35
|
dstChainId: dstChain,
|
|
23
36
|
dstTokenAddr: dstToken,
|
|
@@ -28,3 +41,155 @@ export const getSwapTx = async ({
|
|
|
28
41
|
|
|
29
42
|
return route.transactions;
|
|
30
43
|
};
|
|
44
|
+
|
|
45
|
+
const validateSwapTxData = (
|
|
46
|
+
supportedChains: Chain[],
|
|
47
|
+
dstChain: string,
|
|
48
|
+
dstToken: string,
|
|
49
|
+
) => {
|
|
50
|
+
const supportedDstChain = supportedChains.find(
|
|
51
|
+
({ chainId }) => chainId === dstChain,
|
|
52
|
+
);
|
|
53
|
+
if (!supportedDstChain) {
|
|
54
|
+
throw new Error(`Provided chain '${dstChain}' is not supported`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!supportedDstChain.tokens.some(({ address }) => address === dstToken)) {
|
|
58
|
+
throw new Error(`Provided token '${dstToken}' is not supported`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const monitorTransactionStatus = async (
|
|
63
|
+
srcChainId: number,
|
|
64
|
+
txHash: string,
|
|
65
|
+
) => {
|
|
66
|
+
const txReceipt = await getTxReceipt(srcChainId, txHash);
|
|
67
|
+
|
|
68
|
+
if (!txReceipt) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`No transaction found for chain ${srcChainId} tx ${txHash}`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const supportedChains: Chain[] = (await getChains()).filter(
|
|
75
|
+
({ web3Environment, swapSupported }) =>
|
|
76
|
+
web3Environment === Web3Environment.MAINNET && swapSupported,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const messageSentEventSignature =
|
|
80
|
+
"MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
|
|
81
|
+
|
|
82
|
+
const messageSentEventAbi = [
|
|
83
|
+
"event MessageSent(bytes32 indexed messageId, uint64 indexed destinationChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount, uint256 valueForInstantCcipRecieve, address transferedToken, uint256 transferedTokenAmount)",
|
|
84
|
+
];
|
|
85
|
+
const messageReceivedEventSignature =
|
|
86
|
+
"MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
|
|
87
|
+
|
|
88
|
+
const messageReceivedEventAbi = [
|
|
89
|
+
"event MessageReceived(bytes32 indexed messageId, uint64 indexed sourceChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount)",
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const messageSentEvent = txReceipt.logs?.find((log) => {
|
|
93
|
+
return log.topics[0] === ethers.utils.id(messageSentEventSignature);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (!messageSentEvent) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`No transaction event found for chain ${srcChainId} tx ${txHash}`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const messageId = messageSentEvent?.topics[1] as string;
|
|
103
|
+
const iface = new ethers.utils.Interface(messageSentEventAbi);
|
|
104
|
+
const decodedMessageSentEvent = iface.parseLog(messageSentEvent);
|
|
105
|
+
|
|
106
|
+
if (!decodedMessageSentEvent) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`No transaction event arguments found for chain ${srcChainId} tx ${txHash}`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const srcChain = supportedChains.find(
|
|
112
|
+
(chain) => chain.chainId === srcChainId.toString(),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const srcToken = srcChain?.tokens.find(
|
|
116
|
+
(token) => token.address === decodedMessageSentEvent.args?.token.toString(),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const targetChain = supportedChains.find(
|
|
120
|
+
(chain) =>
|
|
121
|
+
chain.ccipChainId ===
|
|
122
|
+
decodedMessageSentEvent.args?.destinationChainSelector?.toString(),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const toChainId = targetChain?.chainId;
|
|
126
|
+
|
|
127
|
+
if (!toChainId) {
|
|
128
|
+
throw new Error(`Unknown destination chain!`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const transaction: MonitoredTransaction = {
|
|
132
|
+
txHash: txHash,
|
|
133
|
+
fromChain: srcChain?.displayName,
|
|
134
|
+
fromChainImage: srcChain?.image,
|
|
135
|
+
toChain: targetChain.displayName,
|
|
136
|
+
toChainImage: targetChain.image,
|
|
137
|
+
fromToken: srcToken?.symbol,
|
|
138
|
+
fromTokenImage: srcToken?.image,
|
|
139
|
+
fromAmount: weiToHumanReadable({
|
|
140
|
+
amount: decodedMessageSentEvent.args?.tokenAmount.toString(),
|
|
141
|
+
decimals: srcToken?.decimals || 18,
|
|
142
|
+
precisionFractionalPlaces: 4,
|
|
143
|
+
}),
|
|
144
|
+
isDone: false,
|
|
145
|
+
explorer: `${CCIP_EXPLORER}/tx/${txHash}`,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
addTransactionToRenderedTransactions(transaction);
|
|
149
|
+
renderTxHistoryButtons();
|
|
150
|
+
|
|
151
|
+
// start listening
|
|
152
|
+
// 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.
|
|
153
|
+
|
|
154
|
+
const xSwapRouterOnDestinationAddress = ADDRESSES[toChainId]?.XSwapRouter;
|
|
155
|
+
if (!xSwapRouterOnDestinationAddress) {
|
|
156
|
+
throw new Error(`Unknown destination XSwapRouter!`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const xSwapRouterOnDestination = new ethers.Contract(
|
|
160
|
+
xSwapRouterOnDestinationAddress,
|
|
161
|
+
messageReceivedEventAbi,
|
|
162
|
+
ethers.getDefaultProvider(
|
|
163
|
+
supportedChains.find((chain) => chain.chainId === toChainId)
|
|
164
|
+
?.publicRpcUrls[0],
|
|
165
|
+
),
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const eventFilter = {
|
|
169
|
+
address: xSwapRouterOnDestinationAddress,
|
|
170
|
+
topics: [ethers.utils.id(messageReceivedEventSignature), messageId],
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const onSuccess = async () => {
|
|
174
|
+
updateTransactionDoneInRenderedTransactions(txHash);
|
|
175
|
+
renderTxHistoryButtons();
|
|
176
|
+
await new Promise((resolve) => setTimeout(() => resolve(true), 5000));
|
|
177
|
+
removeTransactionFromRenderedTransactions(txHash);
|
|
178
|
+
renderTxHistoryButtons();
|
|
179
|
+
};
|
|
180
|
+
xSwapRouterOnDestination.once(eventFilter, () => onSuccess());
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const getTxReceipt = async (txChainId: number, txHash: string) => {
|
|
184
|
+
const chains = await getChains();
|
|
185
|
+
const chain = chains.find((chain) => chain.chainId === txChainId.toString());
|
|
186
|
+
const provider = new ethers.providers.JsonRpcProvider(
|
|
187
|
+
chain?.publicRpcUrls[0],
|
|
188
|
+
);
|
|
189
|
+
try {
|
|
190
|
+
return await provider.getTransactionReceipt(txHash);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error("Error fetching transaction receipt:", error);
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
};
|