@xswap-link/sdk 0.1.2 → 0.1.4
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 +17 -0
- package/dist/index.css +95 -71
- package/dist/index.d.mts +60 -155
- package/dist/index.d.ts +60 -155
- package/dist/index.js +923 -1842
- package/dist/index.mjs +875 -1801
- package/package.json +1 -1
- package/src/components/Skeleton/index.tsx +8 -5
- package/src/components/TxConfigForm/Button.tsx +20 -0
- package/src/components/TxConfigForm/FeesDetails.tsx +5 -5
- package/src/components/TxConfigForm/Form.tsx +13 -7
- 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/global.css +0 -4
- 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
|
@@ -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
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -2,6 +2,8 @@ export * from "./contracts";
|
|
|
2
2
|
export * from "./numbers";
|
|
3
3
|
export * from "./strings";
|
|
4
4
|
|
|
5
|
+
import { format } from "date-fns";
|
|
6
|
+
|
|
5
7
|
// eslint-disable-next-line
|
|
6
8
|
export const replaceNull = (values: any[], newValue: any) => {
|
|
7
9
|
const modifiedValues = [...values];
|
|
@@ -48,3 +50,8 @@ export const chunkArray = (array: any[], chunkSize: number): any[][] => {
|
|
|
48
50
|
}
|
|
49
51
|
return result;
|
|
50
52
|
};
|
|
53
|
+
|
|
54
|
+
export const getDate = (blockTimestamp: number) => {
|
|
55
|
+
const date = new Date(blockTimestamp * 1000);
|
|
56
|
+
return format(date, "d MMM yyyy HH:mm:ss");
|
|
57
|
+
};
|
package/tailwind.config.js
CHANGED
|
@@ -12,10 +12,15 @@ module.exports = {
|
|
|
12
12
|
x_error_border: "rgba(255,111,0,1)",
|
|
13
13
|
x_blue_light: "rgba(54,129,198,1)",
|
|
14
14
|
x_blue_dark: "rgba(43,74,157,1)",
|
|
15
|
+
x_green_light: "rgba(43,74,157,1)",
|
|
16
|
+
x_green_dark: "rgba(46,125,50,1)",
|
|
15
17
|
},
|
|
16
18
|
width: {
|
|
17
19
|
x_desktop: "600px",
|
|
18
|
-
x_mobile: "
|
|
20
|
+
x_mobile: "320px",
|
|
21
|
+
},
|
|
22
|
+
animation: {
|
|
23
|
+
"spin-slow": "spin 3s linear infinite",
|
|
19
24
|
},
|
|
20
25
|
},
|
|
21
26
|
},
|
package/tsconfig.json
CHANGED
|
@@ -14,12 +14,8 @@
|
|
|
14
14
|
"noEmit": true,
|
|
15
15
|
"jsx": "react-jsx",
|
|
16
16
|
"paths": {
|
|
17
|
-
"@src/*": [
|
|
18
|
-
|
|
19
|
-
],
|
|
20
|
-
"@src/global.css": [
|
|
21
|
-
"./src/components/global.css"
|
|
22
|
-
]
|
|
17
|
+
"@src/*": ["./src/*"],
|
|
18
|
+
"@src/global.css": ["./src/components/global.css"]
|
|
23
19
|
}
|
|
24
20
|
}
|
|
25
|
-
}
|
|
21
|
+
}
|