@xswap-link/sdk 0.2.0 → 0.2.1

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @xswap-link/xswap-sdk
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 0f722ce: tx monitoring integration update
8
+
3
9
  ## 0.2.0
4
10
 
5
11
  ### Minor Changes
package/dist/index.css CHANGED
@@ -756,6 +756,9 @@ video {
756
756
  .bg-\[rgba\(15\,15\,15\,1\)\] {
757
757
  background-color: rgba(15, 15, 15, 1);
758
758
  }
759
+ .bg-\[rgba\(2\,2\,2\,1\)\] {
760
+ background-color: rgba(2, 2, 2, 1);
761
+ }
759
762
  .bg-\[rgba\(255\,255\,255\,0\.1\)\] {
760
763
  background-color: rgba(255, 255, 255, 0.1);
761
764
  }
@@ -800,8 +803,8 @@ video {
800
803
  --tw-gradient-to: rgb(54 129 198 / 0) var(--tw-gradient-to-position);
801
804
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
802
805
  }
803
- .from-\[rgba\(54\,129\,198\,0\.1\)\] {
804
- --tw-gradient-from: rgba(54,129,198,0.1) var(--tw-gradient-from-position);
806
+ .from-\[rgba\(54\,129\,198\,0\.2\)\] {
807
+ --tw-gradient-from: rgba(54,129,198,0.2) var(--tw-gradient-from-position);
805
808
  --tw-gradient-to: rgba(54, 129, 198, 0) var(--tw-gradient-to-position);
806
809
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
807
810
  }
@@ -810,8 +813,8 @@ video {
810
813
  --tw-gradient-to: rgba(54, 129, 198, 0) var(--tw-gradient-to-position);
811
814
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
812
815
  }
813
- .from-\[rgba\(76\,175\,80\,0\.1\)\] {
814
- --tw-gradient-from: rgba(76,175,80,0.1) var(--tw-gradient-from-position);
816
+ .from-\[rgba\(76\,175\,80\,0\.2\)\] {
817
+ --tw-gradient-from: rgba(76,175,80,0.2) var(--tw-gradient-from-position);
815
818
  --tw-gradient-to: rgba(76, 175, 80, 0) var(--tw-gradient-to-position);
816
819
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
817
820
  }
@@ -823,14 +826,14 @@ video {
823
826
  .to-\[\#2b4a9d\] {
824
827
  --tw-gradient-to: #2b4a9d var(--tw-gradient-to-position);
825
828
  }
826
- .to-\[rgba\(43\,74\,157\,0\.1\)\] {
827
- --tw-gradient-to: rgba(43,74,157,0.1) var(--tw-gradient-to-position);
829
+ .to-\[rgba\(43\,74\,157\,0\.2\)\] {
830
+ --tw-gradient-to: rgba(43,74,157,0.2) var(--tw-gradient-to-position);
828
831
  }
829
832
  .to-\[rgba\(43\,74\,157\,1\)\] {
830
833
  --tw-gradient-to: rgba(43,74,157,1) var(--tw-gradient-to-position);
831
834
  }
832
- .to-\[rgba\(46\,125\,50\,0\.1\)\] {
833
- --tw-gradient-to: rgba(46,125,50,0.1) var(--tw-gradient-to-position);
835
+ .to-\[rgba\(46\,125\,50\,0\.2\)\] {
836
+ --tw-gradient-to: rgba(46,125,50,0.2) var(--tw-gradient-to-position);
834
837
  }
835
838
  .to-x_blue_dark {
836
839
  --tw-gradient-to: rgba(43,74,157,1) var(--tw-gradient-to-position);
package/dist/index.d.mts CHANGED
@@ -291,6 +291,11 @@ declare const ROUTE_TIMEOUT_MS = 5000;
291
291
  declare const MINIMUM_DISPLAYED_TOKEN_AMOUNT = 0.0001;
292
292
  declare const DEFAULT_SOURCE_CHAIN_ID = "1";
293
293
  declare const CCIP_EXPLORER = "https://ccip.chain.link/";
294
+ declare const TX_RECEIPT_STATUS_LIFETIME = 10000;
295
+ declare const MSG_SENT_EVENT_SIG = "MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
296
+ declare const MSG_SENT_EVENT_ABI: string[];
297
+ declare const MSG_RECEIVED_EVENT_SIG = "MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
298
+ declare const MSG_RECEIVED_EVENT_ABI: string[];
294
299
 
295
300
  declare const BatchQueryAbi: ({
296
301
  inputs: {
@@ -389,8 +394,9 @@ declare function getPrices(payload: GetPricesPayload): Promise<TokenPrices>;
389
394
 
390
395
  declare const generateStakingCalls: ({ token, staking, stakingAbi, stakingFunName, stakingFunParams, }: GenerateStakingCallsParams) => ContractCall[];
391
396
 
397
+ declare const monitorTransactionStatus: (txChainId: string, txHash: string) => Promise<void>;
398
+
392
399
  declare const getSwapTx: ({ dstChain, dstToken, customContractCalls, desc, }: GetSwapTxPayload) => Promise<Transactions>;
393
- declare const monitorTransactionStatus: (srcChainId: number, txHash: string) => Promise<void>;
394
400
 
395
401
  declare const IERC20: ethers.utils.Interface;
396
402
  declare const getBalanceOf: (wallet: string, token: string, rpcUrl: string) => Promise<string>;
@@ -424,4 +430,4 @@ declare const deepMergeObjects: (obj1: Record<string, any>, obj2: Record<string,
424
430
  declare const chunkArray: (array: any[], chunkSize: number) => any[][];
425
431
  declare const getDate: (blockTimestamp: number) => string;
426
432
 
427
- export { ADDRESSES, type AddReferralPayload, type Addresses, Alert, BALANCES_CHUNK_SIZE, BatchQueryAbi, type BridgeToken, CCIP_EXPLORER, type Chain, type CoinTypeAddress, type CollectFees, type ContractCall, ContractName, type Contracts, DEFAULT_ECOSYSTEM, DEFAULT_SOURCE_CHAIN_ID, DELIVERY_TIME, ERC20Abi, EXPRESS_DELIVERY_TIME, Ecosystem, Environment, type GenerateStakingCallsParams, type GetPricesPayload, type GetRoutePayload, type GetSwapTxPayload, type HistoryTransaction, IERC20, MINIMUM_DISPLAYED_TOKEN_AMOUNT, type MonitoredTransaction, NUMBER_INPUT_REGEX, type Prices, type Protocol, ROUTE_TIMEOUT_MS, type Referral, type ReferralInfo, type Route, SLIPPAGE_PRESETS, Skeleton, type Token, type TokenBalances, type TokenPrices, type Transaction, type TransactionHistory, type TransactionStatus, type Transactions, type TxConfigFormData, type TxConfigFormProps, TxHistoryButton, Web3Environment, XSwapCallType, type XSwapConfig, type XSwapFee, type XSwapFees, addTransactionToRenderedTransactions, chunkArray, deepMergeObjects, findPlaceholderIndex, generateApproveTxData, generateRandomBigNumber, generateStakingCalls, generateUniqueRandomBigNumber, getBalanceOf, getBalances, getBridgeTokens, getChainData, getChains, getDate, getHistory, getPrices, getRoute, getSwapTx, getTokens, monitorTransactionStatus, openTxConfigForm, removeTransactionFromRenderedTransactions, renderTxHistoryButtons, replaceNull, safeBigNumberFrom, shortAddress, updateTransactionDoneInRenderedTransactions, weiToHumanReadable };
433
+ export { ADDRESSES, type AddReferralPayload, type Addresses, Alert, BALANCES_CHUNK_SIZE, BatchQueryAbi, type BridgeToken, CCIP_EXPLORER, type Chain, type CoinTypeAddress, type CollectFees, type ContractCall, ContractName, type Contracts, DEFAULT_ECOSYSTEM, DEFAULT_SOURCE_CHAIN_ID, DELIVERY_TIME, ERC20Abi, EXPRESS_DELIVERY_TIME, Ecosystem, Environment, type GenerateStakingCallsParams, type GetPricesPayload, type GetRoutePayload, type GetSwapTxPayload, type HistoryTransaction, IERC20, MINIMUM_DISPLAYED_TOKEN_AMOUNT, MSG_RECEIVED_EVENT_ABI, MSG_RECEIVED_EVENT_SIG, MSG_SENT_EVENT_ABI, MSG_SENT_EVENT_SIG, type MonitoredTransaction, NUMBER_INPUT_REGEX, type Prices, type Protocol, ROUTE_TIMEOUT_MS, type Referral, type ReferralInfo, type Route, SLIPPAGE_PRESETS, Skeleton, TX_RECEIPT_STATUS_LIFETIME, type Token, type TokenBalances, type TokenPrices, type Transaction, type TransactionHistory, type TransactionStatus, type Transactions, type TxConfigFormData, type TxConfigFormProps, TxHistoryButton, Web3Environment, XSwapCallType, type XSwapConfig, type XSwapFee, type XSwapFees, addTransactionToRenderedTransactions, chunkArray, deepMergeObjects, findPlaceholderIndex, generateApproveTxData, generateRandomBigNumber, generateStakingCalls, generateUniqueRandomBigNumber, getBalanceOf, getBalances, getBridgeTokens, getChainData, getChains, getDate, getHistory, getPrices, getRoute, getSwapTx, getTokens, monitorTransactionStatus, openTxConfigForm, removeTransactionFromRenderedTransactions, renderTxHistoryButtons, replaceNull, safeBigNumberFrom, shortAddress, updateTransactionDoneInRenderedTransactions, weiToHumanReadable };
package/dist/index.d.ts CHANGED
@@ -291,6 +291,11 @@ declare const ROUTE_TIMEOUT_MS = 5000;
291
291
  declare const MINIMUM_DISPLAYED_TOKEN_AMOUNT = 0.0001;
292
292
  declare const DEFAULT_SOURCE_CHAIN_ID = "1";
293
293
  declare const CCIP_EXPLORER = "https://ccip.chain.link/";
294
+ declare const TX_RECEIPT_STATUS_LIFETIME = 10000;
295
+ declare const MSG_SENT_EVENT_SIG = "MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
296
+ declare const MSG_SENT_EVENT_ABI: string[];
297
+ declare const MSG_RECEIVED_EVENT_SIG = "MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
298
+ declare const MSG_RECEIVED_EVENT_ABI: string[];
294
299
 
295
300
  declare const BatchQueryAbi: ({
296
301
  inputs: {
@@ -389,8 +394,9 @@ declare function getPrices(payload: GetPricesPayload): Promise<TokenPrices>;
389
394
 
390
395
  declare const generateStakingCalls: ({ token, staking, stakingAbi, stakingFunName, stakingFunParams, }: GenerateStakingCallsParams) => ContractCall[];
391
396
 
397
+ declare const monitorTransactionStatus: (txChainId: string, txHash: string) => Promise<void>;
398
+
392
399
  declare const getSwapTx: ({ dstChain, dstToken, customContractCalls, desc, }: GetSwapTxPayload) => Promise<Transactions>;
393
- declare const monitorTransactionStatus: (srcChainId: number, txHash: string) => Promise<void>;
394
400
 
395
401
  declare const IERC20: ethers.utils.Interface;
396
402
  declare const getBalanceOf: (wallet: string, token: string, rpcUrl: string) => Promise<string>;
@@ -424,4 +430,4 @@ declare const deepMergeObjects: (obj1: Record<string, any>, obj2: Record<string,
424
430
  declare const chunkArray: (array: any[], chunkSize: number) => any[][];
425
431
  declare const getDate: (blockTimestamp: number) => string;
426
432
 
427
- export { ADDRESSES, type AddReferralPayload, type Addresses, Alert, BALANCES_CHUNK_SIZE, BatchQueryAbi, type BridgeToken, CCIP_EXPLORER, type Chain, type CoinTypeAddress, type CollectFees, type ContractCall, ContractName, type Contracts, DEFAULT_ECOSYSTEM, DEFAULT_SOURCE_CHAIN_ID, DELIVERY_TIME, ERC20Abi, EXPRESS_DELIVERY_TIME, Ecosystem, Environment, type GenerateStakingCallsParams, type GetPricesPayload, type GetRoutePayload, type GetSwapTxPayload, type HistoryTransaction, IERC20, MINIMUM_DISPLAYED_TOKEN_AMOUNT, type MonitoredTransaction, NUMBER_INPUT_REGEX, type Prices, type Protocol, ROUTE_TIMEOUT_MS, type Referral, type ReferralInfo, type Route, SLIPPAGE_PRESETS, Skeleton, type Token, type TokenBalances, type TokenPrices, type Transaction, type TransactionHistory, type TransactionStatus, type Transactions, type TxConfigFormData, type TxConfigFormProps, TxHistoryButton, Web3Environment, XSwapCallType, type XSwapConfig, type XSwapFee, type XSwapFees, addTransactionToRenderedTransactions, chunkArray, deepMergeObjects, findPlaceholderIndex, generateApproveTxData, generateRandomBigNumber, generateStakingCalls, generateUniqueRandomBigNumber, getBalanceOf, getBalances, getBridgeTokens, getChainData, getChains, getDate, getHistory, getPrices, getRoute, getSwapTx, getTokens, monitorTransactionStatus, openTxConfigForm, removeTransactionFromRenderedTransactions, renderTxHistoryButtons, replaceNull, safeBigNumberFrom, shortAddress, updateTransactionDoneInRenderedTransactions, weiToHumanReadable };
433
+ export { ADDRESSES, type AddReferralPayload, type Addresses, Alert, BALANCES_CHUNK_SIZE, BatchQueryAbi, type BridgeToken, CCIP_EXPLORER, type Chain, type CoinTypeAddress, type CollectFees, type ContractCall, ContractName, type Contracts, DEFAULT_ECOSYSTEM, DEFAULT_SOURCE_CHAIN_ID, DELIVERY_TIME, ERC20Abi, EXPRESS_DELIVERY_TIME, Ecosystem, Environment, type GenerateStakingCallsParams, type GetPricesPayload, type GetRoutePayload, type GetSwapTxPayload, type HistoryTransaction, IERC20, MINIMUM_DISPLAYED_TOKEN_AMOUNT, MSG_RECEIVED_EVENT_ABI, MSG_RECEIVED_EVENT_SIG, MSG_SENT_EVENT_ABI, MSG_SENT_EVENT_SIG, type MonitoredTransaction, NUMBER_INPUT_REGEX, type Prices, type Protocol, ROUTE_TIMEOUT_MS, type Referral, type ReferralInfo, type Route, SLIPPAGE_PRESETS, Skeleton, TX_RECEIPT_STATUS_LIFETIME, type Token, type TokenBalances, type TokenPrices, type Transaction, type TransactionHistory, type TransactionStatus, type Transactions, type TxConfigFormData, type TxConfigFormProps, TxHistoryButton, Web3Environment, XSwapCallType, type XSwapConfig, type XSwapFee, type XSwapFees, addTransactionToRenderedTransactions, chunkArray, deepMergeObjects, findPlaceholderIndex, generateApproveTxData, generateRandomBigNumber, generateStakingCalls, generateUniqueRandomBigNumber, getBalanceOf, getBalances, getBridgeTokens, getChainData, getChains, getDate, getHistory, getPrices, getRoute, getSwapTx, getTokens, monitorTransactionStatus, openTxConfigForm, removeTransactionFromRenderedTransactions, renderTxHistoryButtons, replaceNull, safeBigNumberFrom, shortAddress, updateTransactionDoneInRenderedTransactions, weiToHumanReadable };
package/dist/index.js CHANGED
@@ -45,10 +45,15 @@ __export(src_exports, {
45
45
  Environment: () => Environment,
46
46
  IERC20: () => IERC20,
47
47
  MINIMUM_DISPLAYED_TOKEN_AMOUNT: () => MINIMUM_DISPLAYED_TOKEN_AMOUNT,
48
+ MSG_RECEIVED_EVENT_ABI: () => MSG_RECEIVED_EVENT_ABI,
49
+ MSG_RECEIVED_EVENT_SIG: () => MSG_RECEIVED_EVENT_SIG,
50
+ MSG_SENT_EVENT_ABI: () => MSG_SENT_EVENT_ABI,
51
+ MSG_SENT_EVENT_SIG: () => MSG_SENT_EVENT_SIG,
48
52
  NUMBER_INPUT_REGEX: () => NUMBER_INPUT_REGEX,
49
53
  ROUTE_TIMEOUT_MS: () => ROUTE_TIMEOUT_MS,
50
54
  SLIPPAGE_PRESETS: () => SLIPPAGE_PRESETS,
51
55
  Skeleton: () => Skeleton,
56
+ TX_RECEIPT_STATUS_LIFETIME: () => TX_RECEIPT_STATUS_LIFETIME,
52
57
  TxHistoryButton: () => TxHistoryButton,
53
58
  Web3Environment: () => Web3Environment,
54
59
  XSwapCallType: () => XSwapCallType,
@@ -649,6 +654,15 @@ var ROUTE_TIMEOUT_MS = 5e3;
649
654
  var MINIMUM_DISPLAYED_TOKEN_AMOUNT = 1e-4;
650
655
  var DEFAULT_SOURCE_CHAIN_ID = "1";
651
656
  var CCIP_EXPLORER = "https://ccip.chain.link/";
657
+ var TX_RECEIPT_STATUS_LIFETIME = 1e4;
658
+ var MSG_SENT_EVENT_SIG = "MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
659
+ var MSG_SENT_EVENT_ABI = [
660
+ "event MessageSent(bytes32 indexed messageId, uint64 indexed destinationChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount, uint256 valueForInstantCcipRecieve, address transferedToken, uint256 transferedTokenAmount)"
661
+ ];
662
+ var MSG_RECEIVED_EVENT_SIG = "MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
663
+ var MSG_RECEIVED_EVENT_ABI = [
664
+ "event MessageReceived(bytes32 indexed messageId, uint64 indexed sourceChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount)"
665
+ ];
652
666
 
653
667
  // src/utils/contracts.ts
654
668
  var IERC20 = new import_ethers2.ethers.utils.Interface(ERC20Abi);
@@ -855,91 +869,49 @@ var generateStakingCalls = ({
855
869
  return [stakingApproveCall, stakingCall];
856
870
  };
857
871
 
858
- // src/services/integrations/transactions.ts
872
+ // src/services/integrations/monitoring.ts
859
873
  var import_ethers4 = require("ethers");
860
- var getSwapTx = async ({
861
- dstChain,
862
- dstToken,
863
- customContractCalls = [],
864
- desc
865
- }) => {
874
+ var import_async_retry = __toESM(require("async-retry"));
875
+ var monitorTransactionStatus = async (txChainId, txHash) => {
876
+ const txReceipt = await getTxReceipt(txChainId, txHash);
866
877
  const supportedChains = (await getChains()).filter(
867
878
  ({ web3Environment, swapSupported }) => web3Environment === "mainnet" /* MAINNET */ && swapSupported
868
879
  );
869
- validateSwapTxData(supportedChains, dstChain, dstToken);
870
- const route = await openTxConfigForm({
871
- dstChainId: dstChain,
872
- dstTokenAddr: dstToken,
873
- customContractCalls,
874
- desc,
875
- supportedChains
876
- });
877
- return route.transactions;
878
- };
879
- var validateSwapTxData = (supportedChains, dstChain, dstToken) => {
880
- const supportedDstChain = supportedChains.find(
881
- ({ chainId }) => chainId === dstChain
882
- );
883
- if (!supportedDstChain) {
884
- throw new Error(`Provided chain '${dstChain}' is not supported`);
885
- }
886
- if (!supportedDstChain.tokens.some(({ address }) => address === dstToken)) {
887
- throw new Error(`Provided token '${dstToken}' is not supported`);
888
- }
889
- };
890
- var monitorTransactionStatus = async (srcChainId, txHash) => {
891
- const txReceipt = await getTxReceipt(srcChainId, txHash);
892
- if (!txReceipt) {
893
- throw new Error(
894
- `No transaction found for chain ${srcChainId} tx ${txHash}`
895
- );
896
- }
897
- const supportedChains = (await getChains()).filter(
898
- ({ web3Environment, swapSupported }) => web3Environment === "mainnet" /* MAINNET */ && swapSupported
899
- );
900
- const messageSentEventSignature = "MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
901
- const messageSentEventAbi = [
902
- "event MessageSent(bytes32 indexed messageId, uint64 indexed destinationChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount, uint256 valueForInstantCcipRecieve, address transferedToken, uint256 transferedTokenAmount)"
903
- ];
904
- const messageReceivedEventSignature = "MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
905
- const messageReceivedEventAbi = [
906
- "event MessageReceived(bytes32 indexed messageId, uint64 indexed sourceChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount)"
907
- ];
908
880
  const messageSentEvent = txReceipt.logs?.find((log) => {
909
- return log.topics[0] === import_ethers4.ethers.utils.id(messageSentEventSignature);
881
+ return log.topics[0] === import_ethers4.ethers.utils.id(MSG_SENT_EVENT_SIG);
910
882
  });
911
883
  if (!messageSentEvent) {
912
884
  throw new Error(
913
- `No transaction event found for chain ${srcChainId} tx ${txHash}`
885
+ `No transaction event found for chain ${txChainId} tx ${txHash}`
914
886
  );
915
887
  }
916
888
  const messageId = messageSentEvent?.topics[1];
917
- const iface = new import_ethers4.ethers.utils.Interface(messageSentEventAbi);
889
+ const iface = new import_ethers4.ethers.utils.Interface(MSG_SENT_EVENT_ABI);
918
890
  const decodedMessageSentEvent = iface.parseLog(messageSentEvent);
919
891
  if (!decodedMessageSentEvent) {
920
892
  throw new Error(
921
- `No transaction event arguments found for chain ${srcChainId} tx ${txHash}`
893
+ `No transaction event arguments found for chain ${txChainId} tx ${txHash}`
922
894
  );
923
895
  }
924
896
  const srcChain = supportedChains.find(
925
- (chain) => chain.chainId === srcChainId.toString()
897
+ (chain) => chain.chainId === txChainId.toString()
926
898
  );
927
899
  const srcToken = srcChain?.tokens.find(
928
900
  (token) => token.address === decodedMessageSentEvent.args?.token.toString()
929
901
  );
930
- const targetChain = supportedChains.find(
902
+ const dstChain = supportedChains.find(
931
903
  (chain) => chain.ccipChainId === decodedMessageSentEvent.args?.destinationChainSelector?.toString()
932
904
  );
933
- const toChainId = targetChain?.chainId;
934
- if (!toChainId) {
905
+ const dstChainId = dstChain?.chainId;
906
+ if (!dstChainId) {
935
907
  throw new Error(`Unknown destination chain!`);
936
908
  }
937
909
  const transaction = {
938
910
  txHash,
939
911
  fromChain: srcChain?.displayName,
940
912
  fromChainImage: srcChain?.image,
941
- toChain: targetChain.displayName,
942
- toChainImage: targetChain.image,
913
+ toChain: dstChain.displayName,
914
+ toChainImage: dstChain.image,
943
915
  fromToken: srcToken?.symbol,
944
916
  fromTokenImage: srcToken?.image,
945
917
  fromAmount: weiToHumanReadable({
@@ -952,41 +924,83 @@ var monitorTransactionStatus = async (srcChainId, txHash) => {
952
924
  };
953
925
  addTransactionToRenderedTransactions(transaction);
954
926
  renderTxHistoryButtons();
955
- const xSwapRouterOnDestinationAddress = ADDRESSES[toChainId]?.XSwapRouter;
927
+ const xSwapRouterOnDestinationAddress = ADDRESSES[dstChainId]?.XSwapRouter;
956
928
  if (!xSwapRouterOnDestinationAddress) {
957
929
  throw new Error(`Unknown destination XSwapRouter!`);
958
930
  }
959
931
  const xSwapRouterOnDestination = new import_ethers4.ethers.Contract(
960
932
  xSwapRouterOnDestinationAddress,
961
- messageReceivedEventAbi,
933
+ MSG_RECEIVED_EVENT_ABI,
962
934
  import_ethers4.ethers.getDefaultProvider(
963
- supportedChains.find((chain) => chain.chainId === toChainId)?.publicRpcUrls[0]
935
+ supportedChains.find((chain) => chain.chainId === dstChainId)?.publicRpcUrls[0]
964
936
  )
965
937
  );
966
- const eventFilter = {
938
+ const msgReceivedEventFilter = {
967
939
  address: xSwapRouterOnDestinationAddress,
968
- topics: [import_ethers4.ethers.utils.id(messageReceivedEventSignature), messageId]
940
+ topics: [import_ethers4.ethers.utils.id(MSG_RECEIVED_EVENT_SIG), messageId]
969
941
  };
970
942
  const onSuccess = async () => {
971
943
  updateTransactionDoneInRenderedTransactions(txHash);
972
944
  renderTxHistoryButtons();
973
- await new Promise((resolve) => setTimeout(() => resolve(true), 5e3));
945
+ await new Promise(
946
+ (resolve) => setTimeout(() => resolve(true), TX_RECEIPT_STATUS_LIFETIME)
947
+ );
974
948
  removeTransactionFromRenderedTransactions(txHash);
975
949
  renderTxHistoryButtons();
976
950
  };
977
- xSwapRouterOnDestination.once(eventFilter, () => onSuccess());
951
+ xSwapRouterOnDestination.once(msgReceivedEventFilter, () => onSuccess());
978
952
  };
979
953
  var getTxReceipt = async (txChainId, txHash) => {
980
- const chains = await getChains();
981
- const chain = chains.find((chain2) => chain2.chainId === txChainId.toString());
982
- const provider = new import_ethers4.ethers.providers.JsonRpcProvider(
983
- chain?.publicRpcUrls[0]
984
- );
985
954
  try {
986
- return await provider.getTransactionReceipt(txHash);
987
- } catch (error) {
988
- console.error("Error fetching transaction receipt:", error);
989
- return null;
955
+ const chain = (await getChains()).find(
956
+ (chain2) => chain2.chainId === txChainId
957
+ );
958
+ const provider = new import_ethers4.ethers.providers.JsonRpcProvider(
959
+ chain?.publicRpcUrls[0]
960
+ );
961
+ return await (0, import_async_retry.default)(async () => {
962
+ const txReceipt = await provider.getTransactionReceipt(txHash);
963
+ if (!txReceipt) {
964
+ throw new Error(`Couldn't fetch tx receipt`);
965
+ }
966
+ return txReceipt;
967
+ });
968
+ } catch (e) {
969
+ throw new Error(
970
+ `Couldn't fetch tx ${txHash} receipt on chain ${txChainId}`
971
+ );
972
+ }
973
+ };
974
+
975
+ // src/services/integrations/transactions.ts
976
+ var getSwapTx = async ({
977
+ dstChain,
978
+ dstToken,
979
+ customContractCalls = [],
980
+ desc
981
+ }) => {
982
+ const supportedChains = (await getChains()).filter(
983
+ ({ web3Environment, swapSupported }) => web3Environment === "mainnet" /* MAINNET */ && swapSupported
984
+ );
985
+ validateSwapTxData(supportedChains, dstChain, dstToken);
986
+ const route = await openTxConfigForm({
987
+ dstChainId: dstChain,
988
+ dstTokenAddr: dstToken,
989
+ customContractCalls,
990
+ desc,
991
+ supportedChains
992
+ });
993
+ return route.transactions;
994
+ };
995
+ var validateSwapTxData = (supportedChains, dstChain, dstToken) => {
996
+ const supportedDstChain = supportedChains.find(
997
+ ({ chainId }) => chainId === dstChain
998
+ );
999
+ if (!supportedDstChain) {
1000
+ throw new Error(`Provided chain '${dstChain}' is not supported`);
1001
+ }
1002
+ if (!supportedDstChain.tokens.some(({ address }) => address === dstToken)) {
1003
+ throw new Error(`Provided token '${dstToken}' is not supported`);
990
1004
  }
991
1005
  };
992
1006
 
@@ -2524,7 +2538,7 @@ var Form = ({
2524
2538
  };
2525
2539
 
2526
2540
  // package.json
2527
- var version = "0.2.0";
2541
+ var version = "0.2.1";
2528
2542
 
2529
2543
  // src/components/TxConfigForm/index.tsx
2530
2544
  var import_jsx_runtime39 = require("react/jsx-runtime");
@@ -2622,7 +2636,7 @@ if (typeof document !== "undefined") {
2622
2636
  const xswapStyleElement = document.createElement("link");
2623
2637
  xswapStyleElement.rel = "stylesheet";
2624
2638
  xswapStyleElement.type = "text/css";
2625
- xswapStyleElement.href = `${xswap_config_default.apiUrl}/sdk/css/${version}`;
2639
+ xswapStyleElement.href = `${xswap_config_default.apiUrl}/sdk/css?data={"version": "${version}"}`;
2626
2640
  document.head.appendChild(xswapStyleElement);
2627
2641
  const xswapModalElement = document.createElement("div");
2628
2642
  xswapModalElement.setAttribute("id", "xswap-modal");
@@ -2648,11 +2662,19 @@ var TxHistoryButton = ({ transaction }) => {
2648
2662
  explorer
2649
2663
  } = transaction;
2650
2664
  const [isWide, setIsWide] = (0, import_react12.useState)(false);
2665
+ const background = (0, import_react12.useMemo)(
2666
+ () => isDone ? "bg-[rgba(2,2,2,1)] bg-gradient-to-r from-[rgba(76,175,80,0.2)] to-[rgba(46,125,50,0.2)]" : "bg-[rgba(2,2,2,1)] bg-gradient-to-r from-[rgba(54,129,198,0.2)] to-[rgba(43,74,157,0.2)]",
2667
+ [isDone]
2668
+ );
2669
+ const border = (0, import_react12.useMemo)(
2670
+ () => isDone ? "border border-solid border-x_green_dark" : "border border-solid border-x_blue_dark",
2671
+ [isDone]
2672
+ );
2651
2673
  return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex gap-2", onClick: () => setIsWide((x) => !x), children: [
2652
2674
  isWide && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2653
2675
  "div",
2654
2676
  {
2655
- 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 ${isDone ? "from-[rgba(76,175,80,0.1)] to-[rgba(46,125,50,0.1)] border border-solid border-x_green_dark" : "from-[rgba(54,129,198,0.1)] to-[rgba(43,74,157,0.1)] border border-solid border-x_blue_dark"}`,
2677
+ className: `flex items-center min-w-60 sm:w-[520px] text-white h-14 px-4 text-sm gap-3 rounded-xl ${background} ${border}`,
2656
2678
  children: [
2657
2679
  /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex justify-between flex-col gap-2 sm:gap-5 sm:flex-row w-full", children: [
2658
2680
  /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2", children: [
@@ -2700,8 +2722,7 @@ var TxHistoryButton = ({ transaction }) => {
2700
2722
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2701
2723
  "div",
2702
2724
  {
2703
- className: `text-white rounded-xl cursor-pointer bg-gradient-to-r
2704
- ${isDone ? "from-[rgba(76,175,80,0.1)] to-[rgba(46,125,50,0.1)] border border-solid border-x_green_dark" : "from-[rgba(54,129,198,0.1)] to-[rgba(43,74,157,0.1)] border border-solid border-x_blue_dark"}`,
2725
+ className: `text-white rounded-xl cursor-pointer ${background} ${border}`,
2705
2726
  children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex gap-2 items-center h-14 w-20 justify-center", children: [
2706
2727
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ArrowLeftIcon, {}),
2707
2728
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "relative flex items-center justify-center w-9 h-9", children: isDone ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "text-x_green w-5 h-5", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CheckIcon, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
@@ -2767,10 +2788,15 @@ var Skeleton = ({ width, height }) => {
2767
2788
  Environment,
2768
2789
  IERC20,
2769
2790
  MINIMUM_DISPLAYED_TOKEN_AMOUNT,
2791
+ MSG_RECEIVED_EVENT_ABI,
2792
+ MSG_RECEIVED_EVENT_SIG,
2793
+ MSG_SENT_EVENT_ABI,
2794
+ MSG_SENT_EVENT_SIG,
2770
2795
  NUMBER_INPUT_REGEX,
2771
2796
  ROUTE_TIMEOUT_MS,
2772
2797
  SLIPPAGE_PRESETS,
2773
2798
  Skeleton,
2799
+ TX_RECEIPT_STATUS_LIFETIME,
2774
2800
  TxHistoryButton,
2775
2801
  Web3Environment,
2776
2802
  XSwapCallType,
package/dist/index.mjs CHANGED
@@ -571,6 +571,15 @@ var ROUTE_TIMEOUT_MS = 5e3;
571
571
  var MINIMUM_DISPLAYED_TOKEN_AMOUNT = 1e-4;
572
572
  var DEFAULT_SOURCE_CHAIN_ID = "1";
573
573
  var CCIP_EXPLORER = "https://ccip.chain.link/";
574
+ var TX_RECEIPT_STATUS_LIFETIME = 1e4;
575
+ var MSG_SENT_EVENT_SIG = "MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
576
+ var MSG_SENT_EVENT_ABI = [
577
+ "event MessageSent(bytes32 indexed messageId, uint64 indexed destinationChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount, uint256 valueForInstantCcipRecieve, address transferedToken, uint256 transferedTokenAmount)"
578
+ ];
579
+ var MSG_RECEIVED_EVENT_SIG = "MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
580
+ var MSG_RECEIVED_EVENT_ABI = [
581
+ "event MessageReceived(bytes32 indexed messageId, uint64 indexed sourceChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount)"
582
+ ];
574
583
 
575
584
  // src/utils/contracts.ts
576
585
  var IERC20 = new ethers.utils.Interface(ERC20Abi);
@@ -777,91 +786,49 @@ var generateStakingCalls = ({
777
786
  return [stakingApproveCall, stakingCall];
778
787
  };
779
788
 
780
- // src/services/integrations/transactions.ts
789
+ // src/services/integrations/monitoring.ts
781
790
  import { ethers as ethers3 } from "ethers";
782
- var getSwapTx = async ({
783
- dstChain,
784
- dstToken,
785
- customContractCalls = [],
786
- desc
787
- }) => {
791
+ import retry from "async-retry";
792
+ var monitorTransactionStatus = async (txChainId, txHash) => {
793
+ const txReceipt = await getTxReceipt(txChainId, txHash);
788
794
  const supportedChains = (await getChains()).filter(
789
795
  ({ web3Environment, swapSupported }) => web3Environment === "mainnet" /* MAINNET */ && swapSupported
790
796
  );
791
- validateSwapTxData(supportedChains, dstChain, dstToken);
792
- const route = await openTxConfigForm({
793
- dstChainId: dstChain,
794
- dstTokenAddr: dstToken,
795
- customContractCalls,
796
- desc,
797
- supportedChains
798
- });
799
- return route.transactions;
800
- };
801
- var validateSwapTxData = (supportedChains, dstChain, dstToken) => {
802
- const supportedDstChain = supportedChains.find(
803
- ({ chainId }) => chainId === dstChain
804
- );
805
- if (!supportedDstChain) {
806
- throw new Error(`Provided chain '${dstChain}' is not supported`);
807
- }
808
- if (!supportedDstChain.tokens.some(({ address }) => address === dstToken)) {
809
- throw new Error(`Provided token '${dstToken}' is not supported`);
810
- }
811
- };
812
- var monitorTransactionStatus = async (srcChainId, txHash) => {
813
- const txReceipt = await getTxReceipt(srcChainId, txHash);
814
- if (!txReceipt) {
815
- throw new Error(
816
- `No transaction found for chain ${srcChainId} tx ${txHash}`
817
- );
818
- }
819
- const supportedChains = (await getChains()).filter(
820
- ({ web3Environment, swapSupported }) => web3Environment === "mainnet" /* MAINNET */ && swapSupported
821
- );
822
- const messageSentEventSignature = "MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
823
- const messageSentEventAbi = [
824
- "event MessageSent(bytes32 indexed messageId, uint64 indexed destinationChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount, uint256 valueForInstantCcipRecieve, address transferedToken, uint256 transferedTokenAmount)"
825
- ];
826
- const messageReceivedEventSignature = "MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
827
- const messageReceivedEventAbi = [
828
- "event MessageReceived(bytes32 indexed messageId, uint64 indexed sourceChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount)"
829
- ];
830
797
  const messageSentEvent = txReceipt.logs?.find((log) => {
831
- return log.topics[0] === ethers3.utils.id(messageSentEventSignature);
798
+ return log.topics[0] === ethers3.utils.id(MSG_SENT_EVENT_SIG);
832
799
  });
833
800
  if (!messageSentEvent) {
834
801
  throw new Error(
835
- `No transaction event found for chain ${srcChainId} tx ${txHash}`
802
+ `No transaction event found for chain ${txChainId} tx ${txHash}`
836
803
  );
837
804
  }
838
805
  const messageId = messageSentEvent?.topics[1];
839
- const iface = new ethers3.utils.Interface(messageSentEventAbi);
806
+ const iface = new ethers3.utils.Interface(MSG_SENT_EVENT_ABI);
840
807
  const decodedMessageSentEvent = iface.parseLog(messageSentEvent);
841
808
  if (!decodedMessageSentEvent) {
842
809
  throw new Error(
843
- `No transaction event arguments found for chain ${srcChainId} tx ${txHash}`
810
+ `No transaction event arguments found for chain ${txChainId} tx ${txHash}`
844
811
  );
845
812
  }
846
813
  const srcChain = supportedChains.find(
847
- (chain) => chain.chainId === srcChainId.toString()
814
+ (chain) => chain.chainId === txChainId.toString()
848
815
  );
849
816
  const srcToken = srcChain?.tokens.find(
850
817
  (token) => token.address === decodedMessageSentEvent.args?.token.toString()
851
818
  );
852
- const targetChain = supportedChains.find(
819
+ const dstChain = supportedChains.find(
853
820
  (chain) => chain.ccipChainId === decodedMessageSentEvent.args?.destinationChainSelector?.toString()
854
821
  );
855
- const toChainId = targetChain?.chainId;
856
- if (!toChainId) {
822
+ const dstChainId = dstChain?.chainId;
823
+ if (!dstChainId) {
857
824
  throw new Error(`Unknown destination chain!`);
858
825
  }
859
826
  const transaction = {
860
827
  txHash,
861
828
  fromChain: srcChain?.displayName,
862
829
  fromChainImage: srcChain?.image,
863
- toChain: targetChain.displayName,
864
- toChainImage: targetChain.image,
830
+ toChain: dstChain.displayName,
831
+ toChainImage: dstChain.image,
865
832
  fromToken: srcToken?.symbol,
866
833
  fromTokenImage: srcToken?.image,
867
834
  fromAmount: weiToHumanReadable({
@@ -874,41 +841,83 @@ var monitorTransactionStatus = async (srcChainId, txHash) => {
874
841
  };
875
842
  addTransactionToRenderedTransactions(transaction);
876
843
  renderTxHistoryButtons();
877
- const xSwapRouterOnDestinationAddress = ADDRESSES[toChainId]?.XSwapRouter;
844
+ const xSwapRouterOnDestinationAddress = ADDRESSES[dstChainId]?.XSwapRouter;
878
845
  if (!xSwapRouterOnDestinationAddress) {
879
846
  throw new Error(`Unknown destination XSwapRouter!`);
880
847
  }
881
848
  const xSwapRouterOnDestination = new ethers3.Contract(
882
849
  xSwapRouterOnDestinationAddress,
883
- messageReceivedEventAbi,
850
+ MSG_RECEIVED_EVENT_ABI,
884
851
  ethers3.getDefaultProvider(
885
- supportedChains.find((chain) => chain.chainId === toChainId)?.publicRpcUrls[0]
852
+ supportedChains.find((chain) => chain.chainId === dstChainId)?.publicRpcUrls[0]
886
853
  )
887
854
  );
888
- const eventFilter = {
855
+ const msgReceivedEventFilter = {
889
856
  address: xSwapRouterOnDestinationAddress,
890
- topics: [ethers3.utils.id(messageReceivedEventSignature), messageId]
857
+ topics: [ethers3.utils.id(MSG_RECEIVED_EVENT_SIG), messageId]
891
858
  };
892
859
  const onSuccess = async () => {
893
860
  updateTransactionDoneInRenderedTransactions(txHash);
894
861
  renderTxHistoryButtons();
895
- await new Promise((resolve) => setTimeout(() => resolve(true), 5e3));
862
+ await new Promise(
863
+ (resolve) => setTimeout(() => resolve(true), TX_RECEIPT_STATUS_LIFETIME)
864
+ );
896
865
  removeTransactionFromRenderedTransactions(txHash);
897
866
  renderTxHistoryButtons();
898
867
  };
899
- xSwapRouterOnDestination.once(eventFilter, () => onSuccess());
868
+ xSwapRouterOnDestination.once(msgReceivedEventFilter, () => onSuccess());
900
869
  };
901
870
  var getTxReceipt = async (txChainId, txHash) => {
902
- const chains = await getChains();
903
- const chain = chains.find((chain2) => chain2.chainId === txChainId.toString());
904
- const provider = new ethers3.providers.JsonRpcProvider(
905
- chain?.publicRpcUrls[0]
906
- );
907
871
  try {
908
- return await provider.getTransactionReceipt(txHash);
909
- } catch (error) {
910
- console.error("Error fetching transaction receipt:", error);
911
- return null;
872
+ const chain = (await getChains()).find(
873
+ (chain2) => chain2.chainId === txChainId
874
+ );
875
+ const provider = new ethers3.providers.JsonRpcProvider(
876
+ chain?.publicRpcUrls[0]
877
+ );
878
+ return await retry(async () => {
879
+ const txReceipt = await provider.getTransactionReceipt(txHash);
880
+ if (!txReceipt) {
881
+ throw new Error(`Couldn't fetch tx receipt`);
882
+ }
883
+ return txReceipt;
884
+ });
885
+ } catch (e) {
886
+ throw new Error(
887
+ `Couldn't fetch tx ${txHash} receipt on chain ${txChainId}`
888
+ );
889
+ }
890
+ };
891
+
892
+ // src/services/integrations/transactions.ts
893
+ var getSwapTx = async ({
894
+ dstChain,
895
+ dstToken,
896
+ customContractCalls = [],
897
+ desc
898
+ }) => {
899
+ const supportedChains = (await getChains()).filter(
900
+ ({ web3Environment, swapSupported }) => web3Environment === "mainnet" /* MAINNET */ && swapSupported
901
+ );
902
+ validateSwapTxData(supportedChains, dstChain, dstToken);
903
+ const route = await openTxConfigForm({
904
+ dstChainId: dstChain,
905
+ dstTokenAddr: dstToken,
906
+ customContractCalls,
907
+ desc,
908
+ supportedChains
909
+ });
910
+ return route.transactions;
911
+ };
912
+ var validateSwapTxData = (supportedChains, dstChain, dstToken) => {
913
+ const supportedDstChain = supportedChains.find(
914
+ ({ chainId }) => chainId === dstChain
915
+ );
916
+ if (!supportedDstChain) {
917
+ throw new Error(`Provided chain '${dstChain}' is not supported`);
918
+ }
919
+ if (!supportedDstChain.tokens.some(({ address }) => address === dstToken)) {
920
+ throw new Error(`Provided token '${dstToken}' is not supported`);
912
921
  }
913
922
  };
914
923
 
@@ -2446,7 +2455,7 @@ var Form = ({
2446
2455
  };
2447
2456
 
2448
2457
  // package.json
2449
- var version = "0.2.0";
2458
+ var version = "0.2.1";
2450
2459
 
2451
2460
  // src/components/TxConfigForm/index.tsx
2452
2461
  import { jsx as jsx38, jsxs as jsxs17 } from "react/jsx-runtime";
@@ -2544,7 +2553,7 @@ if (typeof document !== "undefined") {
2544
2553
  const xswapStyleElement = document.createElement("link");
2545
2554
  xswapStyleElement.rel = "stylesheet";
2546
2555
  xswapStyleElement.type = "text/css";
2547
- xswapStyleElement.href = `${xswap_config_default.apiUrl}/sdk/css/${version}`;
2556
+ xswapStyleElement.href = `${xswap_config_default.apiUrl}/sdk/css?data={"version": "${version}"}`;
2548
2557
  document.head.appendChild(xswapStyleElement);
2549
2558
  const xswapModalElement = document.createElement("div");
2550
2559
  xswapModalElement.setAttribute("id", "xswap-modal");
@@ -2553,7 +2562,7 @@ if (typeof document !== "undefined") {
2553
2562
  }
2554
2563
 
2555
2564
  // src/components/TxHistoryButton/index.tsx
2556
- import { useState as useState9 } from "react";
2565
+ import { useMemo as useMemo8, useState as useState9 } from "react";
2557
2566
  import { createRoot as createRoot2 } from "react-dom/client";
2558
2567
  import { Fragment as Fragment6, jsx as jsx39, jsxs as jsxs18 } from "react/jsx-runtime";
2559
2568
  var TxHistoryButton = ({ transaction }) => {
@@ -2570,11 +2579,19 @@ var TxHistoryButton = ({ transaction }) => {
2570
2579
  explorer
2571
2580
  } = transaction;
2572
2581
  const [isWide, setIsWide] = useState9(false);
2582
+ const background = useMemo8(
2583
+ () => isDone ? "bg-[rgba(2,2,2,1)] bg-gradient-to-r from-[rgba(76,175,80,0.2)] to-[rgba(46,125,50,0.2)]" : "bg-[rgba(2,2,2,1)] bg-gradient-to-r from-[rgba(54,129,198,0.2)] to-[rgba(43,74,157,0.2)]",
2584
+ [isDone]
2585
+ );
2586
+ const border = useMemo8(
2587
+ () => isDone ? "border border-solid border-x_green_dark" : "border border-solid border-x_blue_dark",
2588
+ [isDone]
2589
+ );
2573
2590
  return /* @__PURE__ */ jsxs18("div", { className: "flex gap-2", onClick: () => setIsWide((x) => !x), children: [
2574
2591
  isWide && /* @__PURE__ */ jsxs18(
2575
2592
  "div",
2576
2593
  {
2577
- 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 ${isDone ? "from-[rgba(76,175,80,0.1)] to-[rgba(46,125,50,0.1)] border border-solid border-x_green_dark" : "from-[rgba(54,129,198,0.1)] to-[rgba(43,74,157,0.1)] border border-solid border-x_blue_dark"}`,
2594
+ className: `flex items-center min-w-60 sm:w-[520px] text-white h-14 px-4 text-sm gap-3 rounded-xl ${background} ${border}`,
2578
2595
  children: [
2579
2596
  /* @__PURE__ */ jsxs18("div", { className: "flex justify-between flex-col gap-2 sm:gap-5 sm:flex-row w-full", children: [
2580
2597
  /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-2", children: [
@@ -2622,8 +2639,7 @@ var TxHistoryButton = ({ transaction }) => {
2622
2639
  /* @__PURE__ */ jsx39(
2623
2640
  "div",
2624
2641
  {
2625
- className: `text-white rounded-xl cursor-pointer bg-gradient-to-r
2626
- ${isDone ? "from-[rgba(76,175,80,0.1)] to-[rgba(46,125,50,0.1)] border border-solid border-x_green_dark" : "from-[rgba(54,129,198,0.1)] to-[rgba(43,74,157,0.1)] border border-solid border-x_blue_dark"}`,
2642
+ className: `text-white rounded-xl cursor-pointer ${background} ${border}`,
2627
2643
  children: /* @__PURE__ */ jsxs18("div", { className: "flex gap-2 items-center h-14 w-20 justify-center", children: [
2628
2644
  /* @__PURE__ */ jsx39(ArrowLeftIcon, {}),
2629
2645
  /* @__PURE__ */ jsx39("div", { className: "relative flex items-center justify-center w-9 h-9", children: isDone ? /* @__PURE__ */ jsx39("div", { className: "text-x_green w-5 h-5", children: /* @__PURE__ */ jsx39(CheckIcon, {}) }) : /* @__PURE__ */ jsxs18(Fragment6, { children: [
@@ -2688,10 +2704,15 @@ export {
2688
2704
  Environment,
2689
2705
  IERC20,
2690
2706
  MINIMUM_DISPLAYED_TOKEN_AMOUNT,
2707
+ MSG_RECEIVED_EVENT_ABI,
2708
+ MSG_RECEIVED_EVENT_SIG,
2709
+ MSG_SENT_EVENT_ABI,
2710
+ MSG_SENT_EVENT_SIG,
2691
2711
  NUMBER_INPUT_REGEX,
2692
2712
  ROUTE_TIMEOUT_MS,
2693
2713
  SLIPPAGE_PRESETS,
2694
2714
  Skeleton,
2715
+ TX_RECEIPT_STATUS_LIFETIME,
2695
2716
  TxHistoryButton,
2696
2717
  Web3Environment,
2697
2718
  XSwapCallType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xswap-link/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "JavaScript SDK for XSwap platform",
5
5
  "homepage": "https://github.com/xswap-link/xswap-sdk",
6
6
  "repository": {
@@ -23,6 +23,7 @@
23
23
  "@tanstack/react-query": "^5.35.5",
24
24
  "@types/react": "18.2.0",
25
25
  "@types/react-dom": "18.2.0",
26
+ "async-retry": "^1.3.3",
26
27
  "bignumber.js": "4.0.4",
27
28
  "date-fns": "^3.6.0",
28
29
  "ethers": "^5.7.2",
@@ -33,6 +34,7 @@
33
34
  },
34
35
  "devDependencies": {
35
36
  "@changesets/cli": "^2.27.1",
37
+ "@types/async-retry": "^1.4.8",
36
38
  "@types/jest": "^29.5.12",
37
39
  "@types/node": "^20.11.17",
38
40
  "@typescript-eslint/eslint-plugin": "^7.1.0",
@@ -56,8 +58,8 @@
56
58
  },
57
59
  "scripts": {
58
60
  "build": "tsup src/index.ts --format cjs,esm --dts",
59
- "watch": "nodemon",
60
- "release": "pnpm run build && changeset publish",
61
+ "watch": "pnpm build && nodemon",
62
+ "release": "pnpm build && changeset publish",
61
63
  "lint": "tsc && eslint . --ext .ts",
62
64
  "test": "jest"
63
65
  }
@@ -118,7 +118,7 @@ if (typeof document !== "undefined") {
118
118
  const xswapStyleElement = document.createElement("link");
119
119
  xswapStyleElement.rel = "stylesheet";
120
120
  xswapStyleElement.type = "text/css";
121
- xswapStyleElement.href = `${xswapConfig.apiUrl}/sdk/css/${version}`;
121
+ xswapStyleElement.href = `${xswapConfig.apiUrl}/sdk/css?data={"version": "${version}"}`;
122
122
  document.head.appendChild(xswapStyleElement);
123
123
 
124
124
  const xswapModalElement = document.createElement("div");
@@ -1,4 +1,4 @@
1
- import { FC, useState } from "react";
1
+ import { FC, useMemo, useState } from "react";
2
2
  import { createRoot } from "react-dom/client";
3
3
  import {
4
4
  ArrowLeftIcon,
@@ -27,15 +27,28 @@ export const TxHistoryButton: FC<Props> = ({ transaction }) => {
27
27
  explorer,
28
28
  } = transaction;
29
29
  const [isWide, setIsWide] = useState(false);
30
+
31
+ const background = useMemo(
32
+ () =>
33
+ isDone
34
+ ? "bg-[rgba(2,2,2,1)] bg-gradient-to-r from-[rgba(76,175,80,0.2)] to-[rgba(46,125,50,0.2)]"
35
+ : "bg-[rgba(2,2,2,1)] bg-gradient-to-r from-[rgba(54,129,198,0.2)] to-[rgba(43,74,157,0.2)]",
36
+ [isDone],
37
+ );
38
+
39
+ const border = useMemo(
40
+ () =>
41
+ isDone
42
+ ? "border border-solid border-x_green_dark"
43
+ : "border border-solid border-x_blue_dark",
44
+ [isDone],
45
+ );
46
+
30
47
  return (
31
48
  <div className="flex gap-2" onClick={() => setIsWide((x: boolean) => !x)}>
32
49
  {isWide && (
33
50
  <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
- }`}
51
+ className={`flex items-center min-w-60 sm:w-[520px] text-white h-14 px-4 text-sm gap-3 rounded-xl ${background} ${border}`}
39
52
  >
40
53
  <div className="flex justify-between flex-col gap-2 sm:gap-5 sm:flex-row w-full">
41
54
  <div className="flex items-center gap-2">
@@ -77,12 +90,7 @@ export const TxHistoryButton: FC<Props> = ({ transaction }) => {
77
90
  </div>
78
91
  )}
79
92
  <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
- }`}
93
+ className={`text-white rounded-xl cursor-pointer ${background} ${border}`}
86
94
  >
87
95
  <div className="flex gap-2 items-center h-14 w-20 justify-center">
88
96
  <ArrowLeftIcon />
@@ -10,3 +10,17 @@ export const ROUTE_TIMEOUT_MS = 5000;
10
10
  export const MINIMUM_DISPLAYED_TOKEN_AMOUNT = 0.0001;
11
11
  export const DEFAULT_SOURCE_CHAIN_ID = "1";
12
12
  export const CCIP_EXPLORER = "https://ccip.chain.link/";
13
+ export const TX_RECEIPT_STATUS_LIFETIME = 10000;
14
+
15
+ export const MSG_SENT_EVENT_SIG =
16
+ "MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)";
17
+
18
+ export const MSG_SENT_EVENT_ABI = [
19
+ "event MessageSent(bytes32 indexed messageId, uint64 indexed destinationChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount, uint256 valueForInstantCcipRecieve, address transferedToken, uint256 transferedTokenAmount)",
20
+ ];
21
+ export const MSG_RECEIVED_EVENT_SIG =
22
+ "MessageReceived(bytes32,uint64,address,bytes,address,uint256)";
23
+
24
+ export const MSG_RECEIVED_EVENT_ABI = [
25
+ "event MessageReceived(bytes32 indexed messageId, uint64 indexed sourceChainSelector, address indexed sender, bytes data, address token, uint256 tokenAmount)",
26
+ ];
@@ -1,2 +1,3 @@
1
1
  export * from "./customCalls";
2
+ export * from "./monitoring";
2
3
  export * from "./transactions";
@@ -0,0 +1,148 @@
1
+ import { Chain, MonitoredTransaction, Web3Environment } from "@src/models";
2
+ import { getChains } from "@src/services";
3
+ import { ethers } from "ethers";
4
+ import { weiToHumanReadable } from "@src/utils";
5
+ import {
6
+ CCIP_EXPLORER,
7
+ MSG_RECEIVED_EVENT_ABI,
8
+ MSG_RECEIVED_EVENT_SIG,
9
+ MSG_SENT_EVENT_ABI,
10
+ MSG_SENT_EVENT_SIG,
11
+ TX_RECEIPT_STATUS_LIFETIME,
12
+ } from "@src/constants";
13
+ import {
14
+ addTransactionToRenderedTransactions,
15
+ removeTransactionFromRenderedTransactions,
16
+ renderTxHistoryButtons,
17
+ updateTransactionDoneInRenderedTransactions,
18
+ } from "@src/components";
19
+ import { ADDRESSES } from "@src/contracts";
20
+ import retry from "async-retry";
21
+
22
+ export const monitorTransactionStatus = async (
23
+ txChainId: string,
24
+ txHash: string,
25
+ ): Promise<void> => {
26
+ const txReceipt = await getTxReceipt(txChainId, txHash);
27
+
28
+ const supportedChains: Chain[] = (await getChains()).filter(
29
+ ({ web3Environment, swapSupported }) =>
30
+ web3Environment === Web3Environment.MAINNET && swapSupported,
31
+ );
32
+
33
+ const messageSentEvent = txReceipt.logs?.find((log: { topics: string[] }) => {
34
+ return log.topics[0] === ethers.utils.id(MSG_SENT_EVENT_SIG);
35
+ });
36
+
37
+ if (!messageSentEvent) {
38
+ throw new Error(
39
+ `No transaction event found for chain ${txChainId} tx ${txHash}`,
40
+ );
41
+ }
42
+
43
+ const messageId = messageSentEvent?.topics[1] as string;
44
+ const iface = new ethers.utils.Interface(MSG_SENT_EVENT_ABI);
45
+ const decodedMessageSentEvent = iface.parseLog(messageSentEvent);
46
+
47
+ if (!decodedMessageSentEvent) {
48
+ throw new Error(
49
+ `No transaction event arguments found for chain ${txChainId} tx ${txHash}`,
50
+ );
51
+ }
52
+ const srcChain = supportedChains.find(
53
+ (chain) => chain.chainId === txChainId.toString(),
54
+ );
55
+
56
+ const srcToken = srcChain?.tokens.find(
57
+ (token) => token.address === decodedMessageSentEvent.args?.token.toString(),
58
+ );
59
+
60
+ const dstChain = supportedChains.find(
61
+ (chain) =>
62
+ chain.ccipChainId ===
63
+ decodedMessageSentEvent.args?.destinationChainSelector?.toString(),
64
+ );
65
+
66
+ const dstChainId = dstChain?.chainId;
67
+
68
+ if (!dstChainId) {
69
+ throw new Error(`Unknown destination chain!`);
70
+ }
71
+
72
+ const transaction: MonitoredTransaction = {
73
+ txHash: txHash,
74
+ fromChain: srcChain?.displayName,
75
+ fromChainImage: srcChain?.image,
76
+ toChain: dstChain.displayName,
77
+ toChainImage: dstChain.image,
78
+ fromToken: srcToken?.symbol,
79
+ fromTokenImage: srcToken?.image,
80
+ fromAmount: weiToHumanReadable({
81
+ amount: decodedMessageSentEvent.args?.tokenAmount.toString(),
82
+ decimals: srcToken?.decimals || 18,
83
+ precisionFractionalPlaces: 4,
84
+ }),
85
+ isDone: false,
86
+ explorer: `${CCIP_EXPLORER}/tx/${txHash}`,
87
+ };
88
+
89
+ addTransactionToRenderedTransactions(transaction);
90
+ renderTxHistoryButtons();
91
+
92
+ // start listening
93
+ // 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.
94
+
95
+ const xSwapRouterOnDestinationAddress = ADDRESSES[dstChainId]?.XSwapRouter;
96
+ if (!xSwapRouterOnDestinationAddress) {
97
+ throw new Error(`Unknown destination XSwapRouter!`);
98
+ }
99
+
100
+ const xSwapRouterOnDestination = new ethers.Contract(
101
+ xSwapRouterOnDestinationAddress,
102
+ MSG_RECEIVED_EVENT_ABI,
103
+ ethers.getDefaultProvider(
104
+ supportedChains.find((chain) => chain.chainId === dstChainId)
105
+ ?.publicRpcUrls[0],
106
+ ),
107
+ );
108
+
109
+ const msgReceivedEventFilter = {
110
+ address: xSwapRouterOnDestinationAddress,
111
+ topics: [ethers.utils.id(MSG_RECEIVED_EVENT_SIG), messageId],
112
+ };
113
+
114
+ const onSuccess = async () => {
115
+ updateTransactionDoneInRenderedTransactions(txHash);
116
+ renderTxHistoryButtons();
117
+ await new Promise((resolve) =>
118
+ setTimeout(() => resolve(true), TX_RECEIPT_STATUS_LIFETIME),
119
+ );
120
+ removeTransactionFromRenderedTransactions(txHash);
121
+ renderTxHistoryButtons();
122
+ };
123
+ xSwapRouterOnDestination.once(msgReceivedEventFilter, () => onSuccess());
124
+ };
125
+
126
+ const getTxReceipt = async (txChainId: string, txHash: string) => {
127
+ try {
128
+ const chain = (await getChains()).find(
129
+ (chain) => chain.chainId === txChainId,
130
+ );
131
+
132
+ const provider = new ethers.providers.JsonRpcProvider(
133
+ chain?.publicRpcUrls[0],
134
+ );
135
+
136
+ return await retry(async () => {
137
+ const txReceipt = await provider.getTransactionReceipt(txHash);
138
+ if (!txReceipt) {
139
+ throw new Error(`Couldn't fetch tx receipt`);
140
+ }
141
+ return txReceipt;
142
+ });
143
+ } catch (e) {
144
+ throw new Error(
145
+ `Couldn't fetch tx ${txHash} receipt on chain ${txChainId}`,
146
+ );
147
+ }
148
+ };
@@ -3,20 +3,9 @@ import {
3
3
  GetSwapTxPayload,
4
4
  Transactions,
5
5
  Web3Environment,
6
- MonitoredTransaction,
7
6
  } from "@src/models";
8
7
  import { getChains } from "@src/services";
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";
8
+ import { openTxConfigForm } from "@src/components";
20
9
 
21
10
  export const getSwapTx = async ({
22
11
  dstChain,
@@ -58,138 +47,3 @@ const validateSwapTxData = (
58
47
  throw new Error(`Provided token '${dstToken}' is not supported`);
59
48
  }
60
49
  };
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
- };