@xswap-link/sdk 0.10.7 → 0.10.9

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.
Files changed (73) hide show
  1. package/.eslintrc.json +10 -1
  2. package/.github/workflows/publish.yml +10 -10
  3. package/CHANGELOG.md +12 -0
  4. package/dist/index.global.js +331 -331
  5. package/dist/index.js +9 -9
  6. package/dist/index.mjs +9 -9
  7. package/package.json +6 -3
  8. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +106 -9
  9. package/src/components/Swap/SwapView/SwapButton/index.tsx +11 -11
  10. package/src/components/TxDataCard/TxDataCardUI/index.tsx +12 -18
  11. package/src/components/TxDataCard/index.tsx +6 -2
  12. package/src/constants/index.ts +19 -2
  13. package/src/context/SwapProvider.tsx +7 -3
  14. package/src/services/api.ts +1 -0
  15. package/src/services/solana/jupiter/extract-swap-data.ts +6 -7
  16. package/src/services/svm/README.md +483 -0
  17. package/src/services/svm/bindings/accounts/AllowedOfframp.ts +73 -0
  18. package/src/services/svm/bindings/accounts/Config.ts +153 -0
  19. package/src/services/svm/bindings/accounts/DestChain.ts +113 -0
  20. package/src/services/svm/bindings/accounts/Nonce.ts +97 -0
  21. package/src/services/svm/bindings/accounts/index.ts +15 -0
  22. package/src/services/svm/bindings/accounts/tokenAdminRegistry.ts +128 -0
  23. package/src/services/svm/bindings/errors/anchor.ts +773 -0
  24. package/src/services/svm/bindings/errors/custom.ts +375 -0
  25. package/src/services/svm/bindings/errors/index.ts +62 -0
  26. package/src/services/svm/bindings/instructions/ccipSend.ts +112 -0
  27. package/src/services/svm/bindings/instructions/getFee.ts +73 -0
  28. package/src/services/svm/bindings/instructions/index.ts +4 -0
  29. package/src/services/svm/bindings/programId.ts +6 -0
  30. package/src/services/svm/bindings/types/BaseChain.ts +92 -0
  31. package/src/services/svm/bindings/types/BaseConfig.ts +184 -0
  32. package/src/services/svm/bindings/types/CodeVersion.ts +88 -0
  33. package/src/services/svm/bindings/types/CrossChainAmount.ts +53 -0
  34. package/src/services/svm/bindings/types/DestChainConfig.ts +76 -0
  35. package/src/services/svm/bindings/types/DestChainState.ts +76 -0
  36. package/src/services/svm/bindings/types/GetFeeResult.ts +72 -0
  37. package/src/services/svm/bindings/types/LockOrBurnInV1.ts +102 -0
  38. package/src/services/svm/bindings/types/LockOrBurnOutV1.ts +79 -0
  39. package/src/services/svm/bindings/types/RampMessageHeader.ts +94 -0
  40. package/src/services/svm/bindings/types/RateLimitConfig.ts +72 -0
  41. package/src/services/svm/bindings/types/RateLimitTokenBucket.ts +76 -0
  42. package/src/services/svm/bindings/types/ReleaseOrMintInV1.ts +156 -0
  43. package/src/services/svm/bindings/types/ReleaseOrMintOutV1.ts +53 -0
  44. package/src/services/svm/bindings/types/RemoteAddress.ts +61 -0
  45. package/src/services/svm/bindings/types/RemoteConfig.ts +86 -0
  46. package/src/services/svm/bindings/types/RestoreOnAction.ts +120 -0
  47. package/src/services/svm/bindings/types/SVM2AnyMessage.ts +128 -0
  48. package/src/services/svm/bindings/types/SVM2AnyRampMessage.ts +166 -0
  49. package/src/services/svm/bindings/types/SVM2AnyTokenTransfer.ts +118 -0
  50. package/src/services/svm/bindings/types/SVMTokenAmount.ts +64 -0
  51. package/src/services/svm/bindings/types/index.ts +78 -0
  52. package/src/services/svm/core/client/accounts.ts +97 -0
  53. package/src/services/svm/core/client/events.ts +95 -0
  54. package/src/services/svm/core/client/fee.ts +279 -0
  55. package/src/services/svm/core/client/index.ts +150 -0
  56. package/src/services/svm/core/client/send.ts +607 -0
  57. package/src/services/svm/core/client/utils.ts +131 -0
  58. package/src/services/svm/core/models.ts +236 -0
  59. package/src/services/svm/index.ts +32 -0
  60. package/src/services/svm/utils/conversion.ts +62 -0
  61. package/src/services/svm/utils/errors.ts +51 -0
  62. package/src/services/svm/utils/keypair.ts +19 -0
  63. package/src/services/svm/utils/logger.ts +171 -0
  64. package/src/services/svm/utils/pdas/common.ts +15 -0
  65. package/src/services/svm/utils/pdas/feeQuoter.ts +68 -0
  66. package/src/services/svm/utils/pdas/index.ts +12 -0
  67. package/src/services/svm/utils/pdas/receiver.ts +58 -0
  68. package/src/services/svm/utils/pdas/rmnRemote.ts +23 -0
  69. package/src/services/svm/utils/pdas/router.ts +328 -0
  70. package/src/services/svm/utils/pdas/tokenpool.ts +161 -0
  71. package/src/services/svm/utils/transaction.ts +132 -0
  72. package/src/utils/validation.ts +7 -3
  73. package/tsconfig.json +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xswap-link/sdk",
3
- "version": "0.10.7",
3
+ "version": "0.10.9",
4
4
  "description": "JavaScript SDK for XSwap platform",
5
5
  "homepage": "https://github.com/xswap-link/xswap-sdk",
6
6
  "repository": {
@@ -30,6 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@coral-xyz/anchor": "^0.29.0",
33
+ "@coral-xyz/borsh": "^0.31.1",
33
34
  "@ethersproject/providers": "^5.7.2",
34
35
  "@fortawesome/fontawesome-svg-core": "^6.4.2",
35
36
  "@fortawesome/free-regular-svg-icons": "^6.4.2",
@@ -45,19 +46,21 @@
45
46
  "@wagmi/core": "^2.16.3",
46
47
  "async-retry": "^1.3.3",
47
48
  "bignumber.js": "4.0.4",
49
+ "bn.js": "^5.2.2",
48
50
  "crypto": "npm:crypto-browserify@latest",
49
51
  "date-fns": "^3.6.0",
50
52
  "ethers": "5.7.2",
51
53
  "http": "npm:http-browserify@latest",
52
54
  "https": "npm:https-browserify@latest",
55
+ "loglevel": "^1.9.2",
53
56
  "notistack": "^3.0.1",
54
57
  "react-error-boundary": "^4.1.0",
55
58
  "react-virtuoso": "^4.7.12",
56
59
  "stream": "npm:stream-browserify@latest",
57
60
  "url": "npm:url-browserify@latest",
58
- "zlib": "npm:zlib-browserify@latest",
59
61
  "viem": "~2.29.1",
60
- "wagmi": "^2.14.9"
62
+ "wagmi": "^2.14.9",
63
+ "zlib": "npm:zlib-browserify@latest"
61
64
  },
62
65
  "devDependencies": {
63
66
  "@babel/core": "^7.26.0",
@@ -1,6 +1,13 @@
1
1
  import { Button } from "@src/components";
2
2
  import {
3
+ CCIP_ROUTER_PROGRAM_ID,
3
4
  FALLBACK_CROSSCHAIN_ESTIMATION_TIME,
5
+ FEE_QUOTER_PROGRAM_ID,
6
+ LINK_TOKEN_MINT,
7
+ PROGRAM_ID,
8
+ RMN_REMOTE_PROGRAM_ID,
9
+ SOLANA_MAINNET_RPC_URL,
10
+ SYSTEM_PROGRAM_ID,
4
11
  crosschainEstimationTimes,
5
12
  } from "@src/constants";
6
13
  import { useHistory, useSwapContext, useTxUIWrapper } from "@src/context";
@@ -21,7 +28,20 @@ import { Header } from "./Header";
21
28
  import { Steps } from "./Steps";
22
29
  import { SwapPanel } from "./SwapPanel";
23
30
  import { useWallet } from "@solana/wallet-adapter-react";
24
- import { VersionedTransaction } from "@solana/web3.js";
31
+ import {
32
+ Connection,
33
+ Keypair,
34
+ PublicKey,
35
+ VersionedTransaction,
36
+ } from "@solana/web3.js";
37
+ import {
38
+ CCIPClient,
39
+ CCIPContext,
40
+ CCIPCoreConfig,
41
+ CCIPProvider,
42
+ CCIPSendRequest,
43
+ } from "@src/services/svm";
44
+ import BigNumber from "bignumber.js";
25
45
 
26
46
  type Props = {
27
47
  onCloseClick: () => void;
@@ -38,6 +58,7 @@ export const TxOverview = ({ onCloseClick }: Props) => {
38
58
  dstValueWei,
39
59
  route,
40
60
  refreshBalance,
61
+ bridgeUI,
41
62
  } = useSwapContext();
42
63
 
43
64
  const {
@@ -53,7 +74,7 @@ export const TxOverview = ({ onCloseClick }: Props) => {
53
74
 
54
75
  const {
55
76
  networks: {
56
- evm: { signer },
77
+ evm: { signer, address: evmAddress },
57
78
  },
58
79
  } = useNetworks();
59
80
  const wallet = useWallet();
@@ -186,8 +207,8 @@ export const TxOverview = ({ onCloseClick }: Props) => {
186
207
  );
187
208
 
188
209
  const enqueueSwapTx = useCallback(async () => {
189
- if (srcToken && route) {
190
- if (route.ecosystem === Ecosystem.EVM) {
210
+ if (srcToken) {
211
+ if (route && route.ecosystem === Ecosystem.EVM) {
191
212
  const enqueueSwap = () => {
192
213
  enqueueTransaction({
193
214
  executeTransaction: () => {
@@ -247,10 +268,81 @@ export const TxOverview = ({ onCloseClick }: Props) => {
247
268
  setTxNeedsApproval(false);
248
269
  enqueueSwap();
249
270
  }
250
- } else if (route.ecosystem === Ecosystem.SOLANA) {
271
+ } else if (srcChain?.ecosystem === Ecosystem.SOLANA) {
251
272
  enqueueTransaction({
252
- executeTransaction: () => {
253
- if (!route.swapTransaction || !wallet) {
273
+ executeTransaction: async () => {
274
+ if (bridgeUI) {
275
+ // this section should be removed when we will implement cross-chain swap on solana
276
+ const connection = new Connection(
277
+ SOLANA_MAINNET_RPC_URL,
278
+ "confirmed",
279
+ );
280
+
281
+ const provider: CCIPProvider = {
282
+ connection,
283
+ wallet: Keypair.generate(),
284
+ getAddress() {
285
+ return wallet.publicKey || PublicKey.default;
286
+ },
287
+ async signTransaction(tx: VersionedTransaction) {
288
+ const signedTransaction = await wallet.signTransaction?.(tx);
289
+ if (!signedTransaction) {
290
+ throw new Error("Failed to sign the transaction.");
291
+ }
292
+ return signedTransaction;
293
+ },
294
+ };
295
+
296
+ const config: CCIPCoreConfig = {
297
+ ccipRouterProgramId: CCIP_ROUTER_PROGRAM_ID,
298
+ feeQuoterProgramId: FEE_QUOTER_PROGRAM_ID,
299
+ tokenMint: new PublicKey(srcToken.address),
300
+ rmnRemoteProgramId: RMN_REMOTE_PROGRAM_ID,
301
+ linkTokenMint: LINK_TOKEN_MINT,
302
+ nativeSol: PublicKey.default,
303
+ systemProgramId: SYSTEM_PROGRAM_ID,
304
+ programId: PROGRAM_ID,
305
+ };
306
+
307
+ const context: CCIPContext = {
308
+ provider,
309
+ config,
310
+ };
311
+
312
+ const client = new CCIPClient(context);
313
+
314
+ const extraArgs = client.createExtraArgs({
315
+ gasLimit: 0,
316
+ allowOutOfOrderExecution: true,
317
+ });
318
+
319
+ if (!dstToken) return undefined;
320
+
321
+ const sendRequest: CCIPSendRequest = {
322
+ destChainSelector: new BigNumber(dstChain?.ccipChainId ?? ""),
323
+ receiver: Buffer.from(
324
+ evmAddress && evmAddress.startsWith("0x")
325
+ ? evmAddress.slice(2)
326
+ : evmAddress || "",
327
+ "hex",
328
+ ),
329
+ data: Buffer.alloc(0),
330
+ tokenAmounts: [
331
+ {
332
+ token: new PublicKey(srcToken.address),
333
+ amount: new BigNumber(srcValueWei.toString()), // TODO: Check if this is correct, probably not
334
+ },
335
+ ],
336
+ feeToken: PublicKey.default,
337
+ extraArgs: extraArgs,
338
+ };
339
+
340
+ const result = await client.sendWithMessageId(sendRequest);
341
+ console.log(`Message sent! Transaction: ${result.txSignature}`);
342
+ console.log(`Message ID: ${result.messageId}`);
343
+ }
344
+
345
+ if (!route || !route.swapTransaction || !wallet) {
254
346
  return;
255
347
  }
256
348
 
@@ -274,18 +366,23 @@ export const TxOverview = ({ onCloseClick }: Props) => {
274
366
  }, [
275
367
  srcToken,
276
368
  route,
369
+ srcChain?.ecosystem,
370
+ srcChain?.chainId,
277
371
  enqueueTransaction,
278
372
  signer,
279
373
  evmContractApi,
280
374
  setTxStatus,
281
375
  refreshBalance,
282
376
  trackTransaction,
283
- srcChain?.chainId,
284
377
  dstChain?.chainId,
285
- dstToken?.address,
378
+ dstChain?.ccipChainId,
379
+ dstToken,
286
380
  dstValueWei,
287
381
  setTxNeedsApproval,
382
+ bridgeUI,
288
383
  wallet,
384
+ evmAddress,
385
+ srcValueWei,
289
386
  ]);
290
387
 
291
388
  return (
@@ -175,17 +175,17 @@ export const SwapButton = () => {
175
175
  };
176
176
  }
177
177
 
178
- if (
179
- srcValueWei &&
180
- srcTokenBalanceWei &&
181
- safeBigNumberFrom(srcValueWei).gt(safeBigNumberFrom(srcTokenBalanceWei))
182
- ) {
183
- return {
184
- text: "Insufficient Balance",
185
- fn: () => {},
186
- disabled: true,
187
- };
188
- }
178
+ // if (
179
+ // srcValueWei &&
180
+ // srcTokenBalanceWei &&
181
+ // safeBigNumberFrom(srcValueWei).gt(safeBigNumberFrom(srcTokenBalanceWei))
182
+ // ) {
183
+ // return {
184
+ // text: "Insufficient Balance",
185
+ // fn: () => {},
186
+ // disabled: true,
187
+ // };
188
+ // }
189
189
 
190
190
  if (safeBigNumberFrom(srcValueWei || "0").lte(safeBigNumberFrom("0"))) {
191
191
  return {
@@ -32,22 +32,16 @@ export const TxDataCardUI = ({
32
32
 
33
33
  const date = getDate(transaction.timestamp);
34
34
 
35
- const transferredAmount =
36
- transaction.sourceChainId === "mainnet-beta"
37
- ? transaction.amountWei
38
- : weiToHumanReadable({
39
- amount: transaction.amountWei,
40
- decimals: srcToken?.decimals || 18,
41
- precisionFractionalPlaces: 4,
42
- });
43
- const receivedAmount =
44
- transaction.sourceChainId === "mainnet-beta"
45
- ? (transaction.tokenOutAmount as string)
46
- : weiToHumanReadable({
47
- amount: transaction?.tokenOutAmount || "0",
48
- decimals: dstToken?.decimals || 18,
49
- precisionFractionalPlaces: 4,
50
- });
35
+ const transferredAmount = weiToHumanReadable({
36
+ amount: transaction.amountWei,
37
+ decimals: srcToken?.decimals || 18,
38
+ precisionFractionalPlaces: 4,
39
+ });
40
+ const receivedAmount = weiToHumanReadable({
41
+ amount: transaction?.tokenOutAmount || "0",
42
+ decimals: dstToken?.decimals || 18,
43
+ precisionFractionalPlaces: 4,
44
+ });
51
45
 
52
46
  const srcChain = supportedChains.find(
53
47
  (chain) => chain.chainId === transaction.sourceChainId,
@@ -84,11 +78,11 @@ export const TxDataCardUI = ({
84
78
  </div>
85
79
  ) : transaction.status === "DONE" ? (
86
80
  <div className="flex items-center grow justify-end text-xs">
87
- <div className=" mr-1 text-t_text_green">Done</div>
81
+ <div className="mr-1 text-t_text_green">Done</div>
88
82
  </div>
89
83
  ) : transaction.status === "REVERTED" ? (
90
84
  <div className="flex items-center grow justify-end text-xs">
91
- <div className="w-4 h-4 mr-1 text-t_text_red">Reverted</div>
85
+ <div className="mr-1 text-t_text_red">Reverted</div>
92
86
  </div>
93
87
  ) : null}
94
88
 
@@ -10,12 +10,16 @@ export const TxDataCard = ({ transaction }: Props) => {
10
10
  const { supportedChains, findTokenDataByAddressAndChain } = useSwapContext();
11
11
 
12
12
  const srcToken = findTokenDataByAddressAndChain(
13
- transaction.tokenAddress.toLowerCase(),
13
+ transaction.sourceChainId === "mainnet-beta"
14
+ ? transaction.tokenAddress
15
+ : transaction.tokenAddress.toLowerCase(),
14
16
  transaction.sourceChainId,
15
17
  );
16
18
  const dstToken = transaction.tokenOutAddress
17
19
  ? findTokenDataByAddressAndChain(
18
- transaction.tokenOutAddress?.toLowerCase(),
20
+ transaction.sourceChainId === "mainnet-beta"
21
+ ? transaction.tokenOutAddress
22
+ : transaction.tokenOutAddress?.toLowerCase(),
19
23
  transaction.targetChainId,
20
24
  )
21
25
  : undefined;
@@ -8,10 +8,27 @@ 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 CCIP_ROUTER_PROGRAM_ID = new PublicKey(
12
+ "Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C",
13
+ );
14
+ export const FEE_QUOTER_PROGRAM_ID = new PublicKey(
15
+ "FeeQhewH1cd6ZyHqhfMiKAQntgzPT6bWwK26cJ5qSFo6",
16
+ );
17
+ export const LINK_TOKEN_MINT = new PublicKey(
18
+ "LinkhB3afbBKb2EQQu7s7umdZceV3wcvAUJhQAfQ23L",
19
+ );
20
+ export const SYSTEM_PROGRAM_ID = new PublicKey(
21
+ "11111111111111111111111111111111",
22
+ );
23
+ export const PROGRAM_ID = new PublicKey(
24
+ "52XvWQKuZHRjnR7qHsEGE532jqgQ3MBiBMgVkBowP1LD",
25
+ );
26
+ export const RMN_REMOTE_PROGRAM_ID = new PublicKey(
27
+ "RmnXLft1mSEwDgMKu2okYuHkiazxntFFcZFrrcXxYg7",
28
+ );
11
29
  export const METADATA_PROGRAM_ID =
12
30
  "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
13
- export const SOLANA_MAINNET_RPC_URL =
14
- "https://orbital-thrilling-water.solana-mainnet.quiknode.pro/6b4a6d73d2cbe0590ce45bad3b375b183acef83f/";
31
+ export const SOLANA_MAINNET_RPC_URL = "https://api.mainnet-beta.solana.com";
15
32
  export const JUPITER_V6_PROGRAM_ID = new PublicKey(
16
33
  "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
17
34
  );
@@ -543,7 +543,8 @@ export const SwapProvider = ({
543
543
  !dstToken ||
544
544
  !srcValueWei ||
545
545
  safeBigNumberFrom(srcValueWei).eq(0) ||
546
- (bridgeUI && !bridgeTokensDictionary)
546
+ (bridgeUI && !bridgeTokensDictionary) ||
547
+ (bridgeUI && srcChain.ecosystem !== Ecosystem.EVM)
547
548
  ) {
548
549
  setRoute(undefined);
549
550
  return;
@@ -601,7 +602,11 @@ export const SwapProvider = ({
601
602
  fromAddress:
602
603
  evmAddress || ADDRESSES[srcChain.chainId]?.FeeCollector || "",
603
604
  toAddress:
604
- evmAddress || ADDRESSES[dstChain.chainId]?.FeeCollector || "",
605
+ dstChain.ecosystem === Ecosystem.SOLANA
606
+ ? solanaAddress ||
607
+ ADDRESSES[dstChain.chainId]?.FeeCollector ||
608
+ ""
609
+ : evmAddress || ADDRESSES[dstChain.chainId]?.FeeCollector || "",
605
610
  fromToken: srcToken.address,
606
611
  toToken: dstToken.address,
607
612
  fromAmount: srcValueWei,
@@ -694,7 +699,6 @@ export const SwapProvider = ({
694
699
  (account) =>
695
700
  account.account.data.parsed.info.mint === srcToken.address,
696
701
  );
697
-
698
702
  if (!tokenAccount) {
699
703
  balance = "0";
700
704
  } else {
@@ -16,6 +16,7 @@ import {
16
16
  } from "@src/models";
17
17
 
18
18
  let XSWAP_API_URL = "https://xswap.link/api";
19
+ // let XSWAP_API_URL = "https://develop-72sp7lmyaa-ew.a.run.app/api/beta/";
19
20
 
20
21
  export const setApiUrl = (url: string) => {
21
22
  XSWAP_API_URL = url;
@@ -89,8 +89,8 @@ export async function extractSolanaSwapData(
89
89
  initialPositions?.includes(index) && swap.inMint === inMint,
90
90
  );
91
91
 
92
- const inAmountInDecimal = inSwapData.reduce((acc, curr) => {
93
- return acc.plus(curr.inAmountInDecimal || 0);
92
+ const inAmount = inSwapData.reduce((acc, curr) => {
93
+ return acc.plus(new BigNumber(curr.inAmount || "0"));
94
94
  }, new BigNumber(0));
95
95
 
96
96
  const outMint = swapData[finalPosition]?.outMint;
@@ -98,9 +98,8 @@ export async function extractSolanaSwapData(
98
98
  (swap, index) =>
99
99
  finalPositions?.includes(index) && swap.outMint === outMint,
100
100
  );
101
-
102
- const outAmountInDecimal = outSwapData.reduce((acc, curr) => {
103
- return acc.plus(curr.outAmountInDecimal || 0);
101
+ const outAmount = outSwapData.reduce((acc, curr) => {
102
+ return acc.plus(new BigNumber(curr.outAmount || "0"));
104
103
  }, new BigNumber(0));
105
104
 
106
105
  const isSuccessful = tx.meta?.status?.Ok === null;
@@ -110,10 +109,10 @@ export async function extractSolanaSwapData(
110
109
  swap.hash = signature;
111
110
  swap.timestamp = tx.blockTime ?? 0;
112
111
 
113
- swap.amountWei = inAmountInDecimal.toString();
112
+ swap.amountWei = inAmount.toString();
114
113
  swap.tokenAddress = inMint;
115
114
 
116
- swap.tokenOutAmount = outAmountInDecimal.toString();
115
+ swap.tokenOutAmount = outAmount.toString();
117
116
  swap.tokenOutAddress = outMint;
118
117
 
119
118
  swap.sourceChainId = "mainnet-beta";