@xswap-link/sdk 0.10.15 → 0.11.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 +6 -0
- package/dist/index.global.js +394 -394
- package/dist/index.js +29742 -87
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +29799 -87
- package/dist/index.mjs.map +1 -0
- package/package.json +2 -2
- package/src/assets/icons/DotRedIcon.tsx +12 -0
- package/src/assets/icons/index.ts +1 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/SwapPanel/index.tsx +15 -8
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +196 -29
- package/src/components/Swap/SwapView/ConfirmationView/TxResult/index.tsx +11 -1
- package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +12 -7
- package/src/components/Swap/SwapView/FeesPanel/index.tsx +158 -9
- package/src/components/Swap/SwapView/SwapButton/index.tsx +40 -11
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +27 -1
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +60 -18
- package/src/components/Swap/SwapView/WalletPicker/index.tsx +98 -27
- package/src/constants/index.ts +5 -2
- package/src/context/SwapProvider.tsx +10 -2
- package/src/services/svm/core/client/index.ts +8 -2
- package/src/services/svm/core/client/send.ts +3 -44
- package/src/services/svm/core/models.ts +1 -1
- package/tsup.config.ts +2 -2
|
@@ -31,6 +31,7 @@ export const SwapButton = () => {
|
|
|
31
31
|
srcToken,
|
|
32
32
|
dstToken,
|
|
33
33
|
srcValueWei,
|
|
34
|
+
srcTokenBalanceWei,
|
|
34
35
|
isFetchingRoute,
|
|
35
36
|
isAsyncDataLoaded,
|
|
36
37
|
hasOnConnectWalletCallback,
|
|
@@ -163,6 +164,32 @@ export const SwapButton = () => {
|
|
|
163
164
|
disabled: false,
|
|
164
165
|
};
|
|
165
166
|
}
|
|
167
|
+
if (
|
|
168
|
+
srcChain?.ecosystem === Ecosystem.SOLANA &&
|
|
169
|
+
dstChain?.ecosystem === Ecosystem.EVM &&
|
|
170
|
+
!address
|
|
171
|
+
) {
|
|
172
|
+
return {
|
|
173
|
+
text: "Connect EVM Wallet",
|
|
174
|
+
fn: () => {
|
|
175
|
+
setOpenEVMWalletModal(true);
|
|
176
|
+
},
|
|
177
|
+
disabled: false,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
if (
|
|
181
|
+
srcChain?.ecosystem === Ecosystem.EVM &&
|
|
182
|
+
dstChain?.ecosystem === Ecosystem.SOLANA &&
|
|
183
|
+
!solana.address
|
|
184
|
+
) {
|
|
185
|
+
return {
|
|
186
|
+
text: "Connect Solana Wallet",
|
|
187
|
+
fn: () => {
|
|
188
|
+
setOpenSolanaWalletModal(true);
|
|
189
|
+
},
|
|
190
|
+
disabled: false,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
166
193
|
if (
|
|
167
194
|
srcChain?.ecosystem !== Ecosystem.SOLANA &&
|
|
168
195
|
chainId?.toString() !== srcChainId
|
|
@@ -174,17 +201,17 @@ export const SwapButton = () => {
|
|
|
174
201
|
};
|
|
175
202
|
}
|
|
176
203
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
204
|
+
if (
|
|
205
|
+
srcValueWei &&
|
|
206
|
+
srcTokenBalanceWei &&
|
|
207
|
+
safeBigNumberFrom(srcValueWei).gt(safeBigNumberFrom(srcTokenBalanceWei))
|
|
208
|
+
) {
|
|
209
|
+
return {
|
|
210
|
+
text: "Insufficient Balance",
|
|
211
|
+
fn: () => {},
|
|
212
|
+
disabled: true,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
188
215
|
|
|
189
216
|
if (safeBigNumberFrom(srcValueWei || "0").lte(safeBigNumberFrom("0"))) {
|
|
190
217
|
return {
|
|
@@ -237,6 +264,7 @@ export const SwapButton = () => {
|
|
|
237
264
|
isAsyncDataLoaded,
|
|
238
265
|
error,
|
|
239
266
|
srcChain?.ecosystem,
|
|
267
|
+
dstChain?.ecosystem,
|
|
240
268
|
address,
|
|
241
269
|
srcChainId,
|
|
242
270
|
dstChainId,
|
|
@@ -256,6 +284,7 @@ export const SwapButton = () => {
|
|
|
256
284
|
switchChainAsync,
|
|
257
285
|
enqueueTransaction,
|
|
258
286
|
approve,
|
|
287
|
+
srcTokenBalanceWei,
|
|
259
288
|
routerAddress,
|
|
260
289
|
getAllowance,
|
|
261
290
|
setTxStatus,
|
|
@@ -4,6 +4,7 @@ import { useSwapContext } from "@src/context";
|
|
|
4
4
|
import { useMemo } from "react";
|
|
5
5
|
import { SwapPanelType } from "../../../SwapView";
|
|
6
6
|
import { Balance } from "./Balance";
|
|
7
|
+
import { Ecosystem } from "@src/models";
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
9
10
|
type: SwapPanelType;
|
|
@@ -11,14 +12,39 @@ type Props = {
|
|
|
11
12
|
|
|
12
13
|
export const AmountPanel = ({ type }: Props) => {
|
|
13
14
|
const {
|
|
15
|
+
srcChain,
|
|
14
16
|
srcValue,
|
|
15
17
|
srcValueUsd,
|
|
18
|
+
dstToken,
|
|
19
|
+
dstChain,
|
|
16
20
|
dstValue,
|
|
17
21
|
dstValueUsd,
|
|
18
22
|
setSrcValue,
|
|
19
23
|
isFetchingRoute,
|
|
24
|
+
bridgeUI,
|
|
20
25
|
} = useSwapContext();
|
|
21
26
|
|
|
27
|
+
const value = useMemo(() => {
|
|
28
|
+
if (
|
|
29
|
+
type === "destination" &&
|
|
30
|
+
dstToken &&
|
|
31
|
+
dstChain &&
|
|
32
|
+
bridgeUI &&
|
|
33
|
+
srcChain?.ecosystem === Ecosystem.SOLANA
|
|
34
|
+
) {
|
|
35
|
+
return srcValue;
|
|
36
|
+
}
|
|
37
|
+
return type === "source" ? srcValue : dstValue;
|
|
38
|
+
}, [
|
|
39
|
+
type,
|
|
40
|
+
bridgeUI,
|
|
41
|
+
srcChain?.ecosystem,
|
|
42
|
+
srcValue,
|
|
43
|
+
dstValue,
|
|
44
|
+
dstToken,
|
|
45
|
+
dstChain,
|
|
46
|
+
]);
|
|
47
|
+
|
|
22
48
|
const valueUsd = useMemo(
|
|
23
49
|
() => (type === "source" ? srcValueUsd : dstValueUsd),
|
|
24
50
|
[dstValueUsd, srcValueUsd, type],
|
|
@@ -50,7 +76,7 @@ export const AmountPanel = ({ type }: Props) => {
|
|
|
50
76
|
<div
|
|
51
77
|
className={`text-xl text-t_text_secondary font-sans-bold font-bold`}
|
|
52
78
|
>
|
|
53
|
-
{
|
|
79
|
+
{value || 0}
|
|
54
80
|
</div>
|
|
55
81
|
{valueUsd && (
|
|
56
82
|
<div className={`text-sx opacity-60`}>{`$${valueUsd}`}</div>
|
|
@@ -27,6 +27,7 @@ import { TokenItem } from "./TokenItem";
|
|
|
27
27
|
import { useAccount } from "wagmi";
|
|
28
28
|
import { Connection, PublicKey } from "@solana/web3.js";
|
|
29
29
|
import { METADATA_PROGRAM_ID } from "@src/constants";
|
|
30
|
+
import { useWallet } from "@src/context/WalletProvider";
|
|
30
31
|
|
|
31
32
|
type Props = {
|
|
32
33
|
type: SwapPanelType;
|
|
@@ -66,6 +67,9 @@ export const TokenPicker = ({
|
|
|
66
67
|
addTokenToChainIfNotExists,
|
|
67
68
|
} = useSwapContext();
|
|
68
69
|
const { address } = useAccount();
|
|
70
|
+
const {
|
|
71
|
+
solana: { address: solanaAddress },
|
|
72
|
+
} = useWallet();
|
|
69
73
|
const evmContractApi = useEvmContractApi();
|
|
70
74
|
|
|
71
75
|
useEffect(() => {
|
|
@@ -258,7 +262,12 @@ export const TokenPicker = ({
|
|
|
258
262
|
if (
|
|
259
263
|
!bridgeUI &&
|
|
260
264
|
chain &&
|
|
261
|
-
!findTokenDataByAddressAndChain(
|
|
265
|
+
!findTokenDataByAddressAndChain(
|
|
266
|
+
chain.ecosystem === Ecosystem.EVM
|
|
267
|
+
? searchValue.toLowerCase()
|
|
268
|
+
: searchValue,
|
|
269
|
+
chain.chainId,
|
|
270
|
+
)
|
|
262
271
|
) {
|
|
263
272
|
if (chain.ecosystem === Ecosystem.EVM && isETHAddressValid(searchValue)) {
|
|
264
273
|
getCustomTokenData();
|
|
@@ -321,17 +330,20 @@ export const TokenPicker = ({
|
|
|
321
330
|
}
|
|
322
331
|
}, [isOpen]);
|
|
323
332
|
|
|
324
|
-
const
|
|
325
|
-
|
|
333
|
+
const calculateTokenValue = useCallback(
|
|
334
|
+
(token: TokenOption) => {
|
|
326
335
|
if (!token.balance || !token.decimals) return 0;
|
|
327
336
|
const balance = Number(
|
|
328
337
|
ethers.utils.formatUnits(token.balance, token.decimals),
|
|
329
338
|
);
|
|
330
339
|
const price = tokenPrices[token.chainId]?.[token.address];
|
|
331
340
|
return price ? balance * Number(price) : 0;
|
|
332
|
-
}
|
|
341
|
+
},
|
|
342
|
+
[tokenPrices],
|
|
343
|
+
);
|
|
333
344
|
|
|
334
|
-
|
|
345
|
+
const ownedFilteredTokens = useMemo(() => {
|
|
346
|
+
return [
|
|
335
347
|
...filteredTokens.filter((token) =>
|
|
336
348
|
BigNumber.from(token?.balance || "0").gt(0),
|
|
337
349
|
),
|
|
@@ -348,13 +360,14 @@ export const TokenPicker = ({
|
|
|
348
360
|
// If USD values are equal (or both 0), sort by priority
|
|
349
361
|
return tokenB.priority - tokenA.priority;
|
|
350
362
|
});
|
|
363
|
+
}, [filteredTokens, otherFilteredTokens, calculateTokenValue]);
|
|
351
364
|
|
|
365
|
+
const allTokens = useMemo(() => {
|
|
352
366
|
const currentChainTokens = filteredTokens
|
|
353
367
|
.filter((token) => BigNumber.from(token?.balance || "0").eq(0))
|
|
354
368
|
.sort(
|
|
355
369
|
(tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
|
|
356
370
|
);
|
|
357
|
-
|
|
358
371
|
const otherChainTokens = otherFilteredTokens
|
|
359
372
|
.filter((token) => BigNumber.from(token?.balance || "0").eq(0))
|
|
360
373
|
.sort(
|
|
@@ -364,21 +377,28 @@ export const TokenPicker = ({
|
|
|
364
377
|
// Create groups based on chain and wallet connection status
|
|
365
378
|
const groups = chain
|
|
366
379
|
? [
|
|
367
|
-
...(!!address && ownedFilteredTokens.length
|
|
380
|
+
...(!!(address || solanaAddress) && ownedFilteredTokens.length
|
|
368
381
|
? [ownedFilteredTokens]
|
|
369
382
|
: []),
|
|
370
383
|
currentChainTokens,
|
|
371
384
|
otherChainTokens,
|
|
372
385
|
]
|
|
373
386
|
: [
|
|
374
|
-
...(!!address && ownedFilteredTokens.length
|
|
387
|
+
...(!!(address || solanaAddress) && ownedFilteredTokens.length
|
|
375
388
|
? [ownedFilteredTokens]
|
|
376
389
|
: []),
|
|
377
390
|
[...currentChainTokens, ...otherChainTokens],
|
|
378
391
|
];
|
|
379
392
|
|
|
380
393
|
return groups.flat();
|
|
381
|
-
}, [
|
|
394
|
+
}, [
|
|
395
|
+
filteredTokens,
|
|
396
|
+
otherFilteredTokens,
|
|
397
|
+
ownedFilteredTokens,
|
|
398
|
+
chain,
|
|
399
|
+
address,
|
|
400
|
+
solanaAddress,
|
|
401
|
+
]);
|
|
382
402
|
|
|
383
403
|
const ownedTokens = useMemo(
|
|
384
404
|
() => allTokens.filter((token) => token.balance?.gt(0)),
|
|
@@ -386,17 +406,39 @@ export const TokenPicker = ({
|
|
|
386
406
|
);
|
|
387
407
|
|
|
388
408
|
const tokenGroups = useMemo(() => {
|
|
409
|
+
const currentChainTokens = filteredTokens
|
|
410
|
+
.filter((token) => BigNumber.from(token?.balance || "0").eq(0))
|
|
411
|
+
.sort(
|
|
412
|
+
(tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
|
|
413
|
+
);
|
|
414
|
+
const otherChainTokens = otherFilteredTokens
|
|
415
|
+
.filter((token) => BigNumber.from(token?.balance || "0").eq(0))
|
|
416
|
+
.sort(
|
|
417
|
+
(tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
|
|
418
|
+
);
|
|
419
|
+
|
|
389
420
|
return chain
|
|
390
421
|
? [
|
|
391
|
-
...(!!address &&
|
|
392
|
-
|
|
393
|
-
|
|
422
|
+
...(!!(address || solanaAddress) && ownedFilteredTokens.length
|
|
423
|
+
? [ownedFilteredTokens]
|
|
424
|
+
: []),
|
|
425
|
+
currentChainTokens,
|
|
426
|
+
otherChainTokens,
|
|
394
427
|
]
|
|
395
428
|
: [
|
|
396
|
-
...(!!address &&
|
|
397
|
-
|
|
429
|
+
...(!!(address || solanaAddress) && ownedFilteredTokens.length
|
|
430
|
+
? [ownedFilteredTokens]
|
|
431
|
+
: []),
|
|
432
|
+
[...currentChainTokens, ...otherChainTokens],
|
|
398
433
|
];
|
|
399
|
-
}, [
|
|
434
|
+
}, [
|
|
435
|
+
chain,
|
|
436
|
+
address,
|
|
437
|
+
solanaAddress,
|
|
438
|
+
filteredTokens,
|
|
439
|
+
otherFilteredTokens,
|
|
440
|
+
ownedFilteredTokens,
|
|
441
|
+
]);
|
|
400
442
|
|
|
401
443
|
return showImportWarning ? (
|
|
402
444
|
<>
|
|
@@ -568,7 +610,7 @@ export const TokenPicker = ({
|
|
|
568
610
|
) : (
|
|
569
611
|
<div className="flex flex-col h-full gap-8 w-[calc(100%+32px)] mx-[-16px]">
|
|
570
612
|
<GroupedVirtuoso
|
|
571
|
-
style={{ maxHeight: "
|
|
613
|
+
style={{ maxHeight: "700px", height: "100%" }}
|
|
572
614
|
groupCounts={tokenGroups.map((group) => group?.length)}
|
|
573
615
|
scrollerRef={(ref) => {
|
|
574
616
|
if (ref) {
|
|
@@ -586,7 +628,7 @@ export const TokenPicker = ({
|
|
|
586
628
|
// chain is selected
|
|
587
629
|
switch (index) {
|
|
588
630
|
case 0: {
|
|
589
|
-
if (!address) {
|
|
631
|
+
if (!address && !solanaAddress) {
|
|
590
632
|
return `${chain.displayName} network`;
|
|
591
633
|
}
|
|
592
634
|
return ownedTokens.length
|
|
@@ -594,7 +636,7 @@ export const TokenPicker = ({
|
|
|
594
636
|
: `${chain.displayName} network`;
|
|
595
637
|
}
|
|
596
638
|
case 1: {
|
|
597
|
-
if (!address) {
|
|
639
|
+
if (!address && !solanaAddress) {
|
|
598
640
|
return "Other networks";
|
|
599
641
|
}
|
|
600
642
|
return `${chain.displayName} network`;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CloseIcon,
|
|
3
|
+
DotGreenIcon,
|
|
4
|
+
DotRedIcon,
|
|
5
|
+
WalletConnectIcon,
|
|
6
|
+
} from "@src/assets/icons";
|
|
2
7
|
import { FC, useCallback } from "react";
|
|
3
|
-
import { Connector, useConnect } from "wagmi";
|
|
8
|
+
import { Connector, useAccount, useConnect, useDisconnect } from "wagmi";
|
|
4
9
|
import { useWallet as useSolanaWallet } from "@solana/wallet-adapter-react";
|
|
5
10
|
import { Ecosystem } from "@src/models";
|
|
6
11
|
|
|
@@ -34,7 +39,16 @@ export const WalletPicker: FC<{
|
|
|
34
39
|
onClose: () => void;
|
|
35
40
|
}> = ({ ecosystem, className, onClose }) => {
|
|
36
41
|
const { connectors, connectAsync } = useConnect();
|
|
37
|
-
const {
|
|
42
|
+
const { connector: activeConnector } = useAccount();
|
|
43
|
+
const { disconnect } = useDisconnect();
|
|
44
|
+
const {
|
|
45
|
+
wallet: activeWallet,
|
|
46
|
+
wallets,
|
|
47
|
+
select,
|
|
48
|
+
connect,
|
|
49
|
+
publicKey,
|
|
50
|
+
disconnect: disconnectSolana,
|
|
51
|
+
} = useSolanaWallet();
|
|
38
52
|
|
|
39
53
|
const handleEvmWalletClick = useCallback(
|
|
40
54
|
async (connector: Connector) => {
|
|
@@ -78,34 +92,91 @@ export const WalletPicker: FC<{
|
|
|
78
92
|
<div className="h-full pt-4">
|
|
79
93
|
{ecosystem === Ecosystem.EVM && (
|
|
80
94
|
<>
|
|
81
|
-
{connectors.map((connector) =>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
{connectors.map((connector) => {
|
|
96
|
+
const isConnected = activeConnector?.id === connector.id;
|
|
97
|
+
return (
|
|
98
|
+
<button
|
|
99
|
+
key={connector.id}
|
|
100
|
+
onClick={async () => {
|
|
101
|
+
isConnected
|
|
102
|
+
? disconnect()
|
|
103
|
+
: await handleEvmWalletClick(connector);
|
|
104
|
+
onClose();
|
|
105
|
+
}}
|
|
106
|
+
className="group flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
|
|
107
|
+
>
|
|
108
|
+
<ConnectorIcon connector={connector} />
|
|
109
|
+
<div className="text-t_text_primary">{connector.name}</div>
|
|
110
|
+
{isConnected && (
|
|
111
|
+
<>
|
|
112
|
+
<div className="flex w-full justify-end items-baseline gap-1">
|
|
113
|
+
<div className="group-hover:hidden">
|
|
114
|
+
<DotGreenIcon />
|
|
115
|
+
</div>
|
|
116
|
+
<div className="hidden group-hover:block">
|
|
117
|
+
<DotRedIcon />
|
|
118
|
+
</div>
|
|
119
|
+
<div className="text-t_text_green group-hover:hidden">
|
|
120
|
+
connected
|
|
121
|
+
</div>
|
|
122
|
+
<div className="text-t_text_red hidden group-hover:block">
|
|
123
|
+
disconnect
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</>
|
|
127
|
+
)}
|
|
128
|
+
</button>
|
|
129
|
+
);
|
|
130
|
+
})}
|
|
91
131
|
</>
|
|
92
132
|
)}
|
|
93
133
|
{ecosystem === Ecosystem.SOLANA && (
|
|
94
134
|
<>
|
|
95
|
-
{wallets.map((wallet) =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
{wallets.map((wallet) => {
|
|
136
|
+
const isConnected =
|
|
137
|
+
publicKey && activeWallet?.adapter.name === wallet.adapter.name;
|
|
138
|
+
return (
|
|
139
|
+
<button
|
|
140
|
+
key={wallet.adapter.name}
|
|
141
|
+
onClick={async () => {
|
|
142
|
+
isConnected
|
|
143
|
+
? await disconnectSolana()
|
|
144
|
+
: await handleConnectSolana(wallet.adapter.name);
|
|
145
|
+
onClose();
|
|
146
|
+
}}
|
|
147
|
+
className="group flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
|
|
148
|
+
>
|
|
149
|
+
<img
|
|
150
|
+
src={wallet.adapter.icon}
|
|
151
|
+
alt={wallet.adapter.name}
|
|
152
|
+
className={`w-[34px] h-[34px] rounded-md ${
|
|
153
|
+
className || ""
|
|
154
|
+
}`}
|
|
155
|
+
/>
|
|
156
|
+
<div className="text-t_text_primary">
|
|
157
|
+
{wallet.adapter.name}
|
|
158
|
+
</div>
|
|
159
|
+
{isConnected && (
|
|
160
|
+
<>
|
|
161
|
+
<div className="flex w-full justify-end items-baseline gap-1">
|
|
162
|
+
<div className="group-hover:hidden">
|
|
163
|
+
<DotGreenIcon />
|
|
164
|
+
</div>
|
|
165
|
+
<div className="hidden group-hover:block">
|
|
166
|
+
<DotRedIcon />
|
|
167
|
+
</div>
|
|
168
|
+
<div className="text-t_text_green group-hover:hidden">
|
|
169
|
+
connected
|
|
170
|
+
</div>
|
|
171
|
+
<div className="text-t_text_red hidden group-hover:block">
|
|
172
|
+
disconnect
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</>
|
|
176
|
+
)}
|
|
177
|
+
</button>
|
|
178
|
+
);
|
|
179
|
+
})}
|
|
109
180
|
</>
|
|
110
181
|
)}
|
|
111
182
|
</div>
|
package/src/constants/index.ts
CHANGED
|
@@ -8,11 +8,14 @@ export const SOLANA_NATIVE_TOKEN_ADDRESS = new PublicKey(
|
|
|
8
8
|
export const SOLANA_TOKEN_PROGRAM_ID = new PublicKey(
|
|
9
9
|
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
|
|
10
10
|
);
|
|
11
|
+
export const SOLANA_TOKEN_2022_PROGRAM_ID = new PublicKey(
|
|
12
|
+
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
|
|
13
|
+
);
|
|
11
14
|
export const CCIP_ROUTER_PROGRAM_ID = new PublicKey(
|
|
12
|
-
"
|
|
15
|
+
"Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C",
|
|
13
16
|
);
|
|
14
17
|
export const FEE_QUOTER_PROGRAM_ID = new PublicKey(
|
|
15
|
-
"
|
|
18
|
+
"FeeQPGkKDeRV1MgoYfMH6L8o3KeuYjwUZrgn4LRKfjHi",
|
|
16
19
|
);
|
|
17
20
|
export const LINK_TOKEN_MINT = new PublicKey(
|
|
18
21
|
"LinkhB3afbBKb2EQQu7s7umdZceV3wcvAUJhQAfQ23L",
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
DEFAULT_REQUEST_ABORT_MSG,
|
|
5
5
|
DEFAULT_SOURCE_CHAIN_ID,
|
|
6
6
|
SOLANA_NATIVE_TOKEN_ADDRESS,
|
|
7
|
+
SOLANA_TOKEN_2022_PROGRAM_ID,
|
|
7
8
|
SOLANA_TOKEN_PROGRAM_ID,
|
|
8
9
|
} from "@src/constants";
|
|
9
10
|
import { ADDRESSES } from "@src/contracts";
|
|
@@ -479,7 +480,6 @@ export const SwapProvider = ({
|
|
|
479
480
|
if (!srcToken || !srcTokenBalanceWei || (!evmAddress && !solanaAddress)) {
|
|
480
481
|
return "";
|
|
481
482
|
}
|
|
482
|
-
|
|
483
483
|
if (safeBigNumberFrom(srcTokenBalanceWei).eq(0)) {
|
|
484
484
|
return "0";
|
|
485
485
|
}
|
|
@@ -695,7 +695,15 @@ export const SwapProvider = ({
|
|
|
695
695
|
programId: SOLANA_TOKEN_PROGRAM_ID,
|
|
696
696
|
},
|
|
697
697
|
);
|
|
698
|
-
const
|
|
698
|
+
const token2022Accounts =
|
|
699
|
+
await connection.getParsedTokenAccountsByOwner(solanaPublicKey, {
|
|
700
|
+
programId: SOLANA_TOKEN_2022_PROGRAM_ID,
|
|
701
|
+
});
|
|
702
|
+
const allTokenAccount = [
|
|
703
|
+
...tokenAccounts.value,
|
|
704
|
+
...token2022Accounts.value,
|
|
705
|
+
];
|
|
706
|
+
const tokenAccount = allTokenAccount.find(
|
|
699
707
|
(account) =>
|
|
700
708
|
account.account.data.parsed.info.mint === srcToken.address,
|
|
701
709
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
2
|
// @ts-nocheck
|
|
3
|
-
import { TransactionInstruction } from "@solana/web3.js";
|
|
3
|
+
import { TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
|
|
4
4
|
import { createLogger, Logger, LogLevel } from "../../utils/logger";
|
|
5
5
|
import {
|
|
6
6
|
CCIPContext,
|
|
@@ -120,7 +120,10 @@ export class CCIPClient {
|
|
|
120
120
|
request: CCIPSendRequest,
|
|
121
121
|
computeBudgetInstruction?: TransactionInstruction,
|
|
122
122
|
sendOptions?: CCIPSendOptions,
|
|
123
|
-
): Promise<
|
|
123
|
+
): Promise<{
|
|
124
|
+
txSignature: VersionedTransaction;
|
|
125
|
+
messageId: string;
|
|
126
|
+
}> {
|
|
124
127
|
const txSignature = await this.send(
|
|
125
128
|
request,
|
|
126
129
|
computeBudgetInstruction,
|
|
@@ -136,6 +139,9 @@ export class CCIPClient {
|
|
|
136
139
|
return {
|
|
137
140
|
txSignature,
|
|
138
141
|
messageId: eventData.messageId,
|
|
142
|
+
} as {
|
|
143
|
+
txSignature: VersionedTransaction;
|
|
144
|
+
messageId: string;
|
|
139
145
|
};
|
|
140
146
|
}
|
|
141
147
|
|
|
@@ -62,7 +62,7 @@ export async function sendCCIPMessage(
|
|
|
62
62
|
accountReader: CCIPAccountReader,
|
|
63
63
|
computeBudgetInstruction?: TransactionInstruction,
|
|
64
64
|
sendOptions?: CCIPSendOptions,
|
|
65
|
-
): Promise<
|
|
65
|
+
): Promise<VersionedTransaction> {
|
|
66
66
|
if (!context.logger) {
|
|
67
67
|
throw new Error("Logger is required for sendCCIPMessage");
|
|
68
68
|
}
|
|
@@ -72,22 +72,12 @@ export async function sendCCIPMessage(
|
|
|
72
72
|
const connection = context.provider.connection;
|
|
73
73
|
const enhanceError = createErrorEnhancer(logger);
|
|
74
74
|
|
|
75
|
-
logger.info(
|
|
76
|
-
`Sending CCIP message to destination chain ${request.destChainSelector.toString()}`,
|
|
77
|
-
);
|
|
78
|
-
|
|
79
75
|
// Determine if we're using native SOL
|
|
80
76
|
const isNativeSol = request.feeToken.equals(PublicKey.default);
|
|
81
77
|
|
|
82
78
|
// For native SOL, we use NATIVE_MINT as the token mint
|
|
83
79
|
const feeTokenMint = isNativeSol ? NATIVE_MINT : request.feeToken;
|
|
84
80
|
|
|
85
|
-
logger.debug(
|
|
86
|
-
`Using fee token: ${feeTokenMint.toString()} (${
|
|
87
|
-
isNativeSol ? "Native SOL" : "SPL Token"
|
|
88
|
-
})`,
|
|
89
|
-
);
|
|
90
|
-
|
|
91
81
|
// Determine the correct fee token program ID
|
|
92
82
|
let feeTokenProgramId = TOKEN_PROGRAM_ID;
|
|
93
83
|
if (!isNativeSol) {
|
|
@@ -151,18 +141,6 @@ export async function sendCCIPMessage(
|
|
|
151
141
|
instruction.keys.push(...remainingAccounts);
|
|
152
142
|
}
|
|
153
143
|
|
|
154
|
-
// Log complete instruction accounts in TRACE mode
|
|
155
|
-
logger.trace(
|
|
156
|
-
"Complete instruction accounts:",
|
|
157
|
-
instruction.keys.map((key, index) => ({
|
|
158
|
-
index,
|
|
159
|
-
pubkey: key.pubkey.toString(),
|
|
160
|
-
isSigner: key.isSigner,
|
|
161
|
-
isWritable: key.isWritable,
|
|
162
|
-
})),
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
// Get recent blockhash with longer validity
|
|
166
144
|
const { blockhash, lastValidBlockHeight } =
|
|
167
145
|
await connection.getLatestBlockhash({
|
|
168
146
|
commitment: "finalized", // Using finalized for longer validity
|
|
@@ -187,28 +165,9 @@ export async function sendCCIPMessage(
|
|
|
187
165
|
}).compileToV0Message(lookupTableList);
|
|
188
166
|
|
|
189
167
|
const tx = new VersionedTransaction(messageV0);
|
|
190
|
-
await context.provider.signTransaction(tx);
|
|
191
|
-
|
|
192
|
-
// Send the transaction with improved options
|
|
193
|
-
const signature = await connection.sendTransaction(tx, {
|
|
194
|
-
skipPreflight: sendOptions?.skipPreflight ?? false,
|
|
195
|
-
preflightCommitment: "processed", // Faster preflight check
|
|
196
|
-
maxRetries: 5, // Increased retries
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Wait for transaction confirmation with improved options
|
|
200
|
-
await connection.confirmTransaction(
|
|
201
|
-
{
|
|
202
|
-
signature,
|
|
203
|
-
blockhash,
|
|
204
|
-
lastValidBlockHeight,
|
|
205
|
-
},
|
|
206
|
-
"finalized",
|
|
207
|
-
); // Using finalized
|
|
208
|
-
|
|
209
|
-
logger.info(`CCIP message sent successfully: ${signature}`);
|
|
168
|
+
const signedTx = await context.provider.signTransaction(tx);
|
|
210
169
|
|
|
211
|
-
return
|
|
170
|
+
return signedTx;
|
|
212
171
|
}
|
|
213
172
|
|
|
214
173
|
/**
|
package/tsup.config.ts
CHANGED
|
@@ -8,9 +8,9 @@ export default defineConfig(() => {
|
|
|
8
8
|
format: ["cjs", "esm"],
|
|
9
9
|
dts: true,
|
|
10
10
|
clean: true,
|
|
11
|
-
minify:
|
|
11
|
+
minify: false,
|
|
12
12
|
splitting: false,
|
|
13
|
-
sourcemap:
|
|
13
|
+
sourcemap: true,
|
|
14
14
|
noExternal: ["ethers"],
|
|
15
15
|
outDir: "dist",
|
|
16
16
|
esbuildOptions(options) {
|