@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 +6 -0
- package/dist/index.css +11 -8
- package/dist/index.d.mts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +103 -77
- package/dist/index.mjs +99 -78
- package/package.json +5 -3
- package/src/components/TxConfigForm/index.tsx +1 -1
- package/src/components/TxHistoryButton/index.tsx +20 -12
- package/src/constants/index.ts +14 -0
- package/src/services/integrations/index.ts +1 -0
- package/src/services/integrations/monitoring.ts +148 -0
- package/src/services/integrations/transactions.ts +1 -147
package/CHANGELOG.md
CHANGED
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\.
|
|
804
|
-
--tw-gradient-from: rgba(54,129,198,0.
|
|
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\.
|
|
814
|
-
--tw-gradient-from: rgba(76,175,80,0.
|
|
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\.
|
|
827
|
-
--tw-gradient-to: rgba(43,74,157,0.
|
|
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\.
|
|
833
|
-
--tw-gradient-to: rgba(46,125,50,0.
|
|
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/
|
|
872
|
+
// src/services/integrations/monitoring.ts
|
|
859
873
|
var import_ethers4 = require("ethers");
|
|
860
|
-
var
|
|
861
|
-
|
|
862
|
-
|
|
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(
|
|
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 ${
|
|
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(
|
|
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 ${
|
|
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 ===
|
|
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
|
|
902
|
+
const dstChain = supportedChains.find(
|
|
931
903
|
(chain) => chain.ccipChainId === decodedMessageSentEvent.args?.destinationChainSelector?.toString()
|
|
932
904
|
);
|
|
933
|
-
const
|
|
934
|
-
if (!
|
|
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:
|
|
942
|
-
toChainImage:
|
|
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[
|
|
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
|
-
|
|
933
|
+
MSG_RECEIVED_EVENT_ABI,
|
|
962
934
|
import_ethers4.ethers.getDefaultProvider(
|
|
963
|
-
supportedChains.find((chain) => chain.chainId ===
|
|
935
|
+
supportedChains.find((chain) => chain.chainId === dstChainId)?.publicRpcUrls[0]
|
|
964
936
|
)
|
|
965
937
|
);
|
|
966
|
-
const
|
|
938
|
+
const msgReceivedEventFilter = {
|
|
967
939
|
address: xSwapRouterOnDestinationAddress,
|
|
968
|
-
topics: [import_ethers4.ethers.utils.id(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
789
|
+
// src/services/integrations/monitoring.ts
|
|
781
790
|
import { ethers as ethers3 } from "ethers";
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
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(
|
|
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 ${
|
|
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(
|
|
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 ${
|
|
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 ===
|
|
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
|
|
819
|
+
const dstChain = supportedChains.find(
|
|
853
820
|
(chain) => chain.ccipChainId === decodedMessageSentEvent.args?.destinationChainSelector?.toString()
|
|
854
821
|
);
|
|
855
|
-
const
|
|
856
|
-
if (!
|
|
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:
|
|
864
|
-
toChainImage:
|
|
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[
|
|
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
|
-
|
|
850
|
+
MSG_RECEIVED_EVENT_ABI,
|
|
884
851
|
ethers3.getDefaultProvider(
|
|
885
|
-
supportedChains.find((chain) => chain.chainId ===
|
|
852
|
+
supportedChains.find((chain) => chain.chainId === dstChainId)?.publicRpcUrls[0]
|
|
886
853
|
)
|
|
887
854
|
);
|
|
888
|
-
const
|
|
855
|
+
const msgReceivedEventFilter = {
|
|
889
856
|
address: xSwapRouterOnDestinationAddress,
|
|
890
|
-
topics: [ethers3.utils.id(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 />
|
package/src/constants/index.ts
CHANGED
|
@@ -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
|
+
];
|
|
@@ -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 {
|
|
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
|
-
};
|