@xswap-link/sdk 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/main.yml +4 -4
- package/.github/workflows/publish.yml +4 -4
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.global.js +311 -5458
- package/dist/index.js +278 -1222
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +276 -1220
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +4 -23
- package/src/components/TxConfigForm/index.tsx +8 -2
- package/src/components/TxWidgetWCWrapped/index.tsx +6 -0
- package/src/config/wagmiConfig.ts +2 -1
- package/src/context/SwapProvider.tsx +26 -17
- package/src/contracts/abi/index.ts +0 -2
- package/src/contracts/addresses.ts +0 -4
- package/src/contracts/bridgeDisplayTokens.ts +46 -0
- package/src/contracts/index.ts +1 -0
- package/src/models/Addresses.ts +0 -1
- package/src/models/payloads/ModalIntegrationPayload.ts +2 -0
- package/src/models/payloads/WidgetIntegrationPayload.ts +2 -0
- package/src/services/integrations/transactions.ts +2 -0
- package/src/types/global.d.ts +2 -0
- package/src/contracts/abi/CustomXSwapRouter.json +0 -953
package/package.json
CHANGED
|
@@ -11,11 +11,7 @@ import {
|
|
|
11
11
|
crosschainEstimationTimes,
|
|
12
12
|
} from "@src/constants";
|
|
13
13
|
import { useHistory, useSwapContext, useTxUIWrapper } from "@src/context";
|
|
14
|
-
import {
|
|
15
|
-
ADDRESSES,
|
|
16
|
-
CustomXSwapRouterAbi,
|
|
17
|
-
XSwapRouterAbi,
|
|
18
|
-
} from "@src/contracts";
|
|
14
|
+
import { ADDRESSES, XSwapRouterAbi } from "@src/contracts";
|
|
19
15
|
import { useEvmContractApi } from "@src/hooks";
|
|
20
16
|
import useNetworks from "@src/hooks/networkManagement/useNetworks";
|
|
21
17
|
import {
|
|
@@ -131,11 +127,6 @@ export const TxOverview = ({ onCloseClick }: Props) => {
|
|
|
131
127
|
"MessageSent(bytes32,uint64,address,bytes,address,uint256,uint256,address,uint256)"; // TODO think of getting this signature in a different way becase its easy to forgot about it when we will change event on smartcontract
|
|
132
128
|
const messageReceivedEventSignature =
|
|
133
129
|
"MessageReceived(bytes32,uint64,address,bytes,address,uint256)"; // TODO think of getting this signature in a different way because its easy to forgot about it when we will change event on smartcontract
|
|
134
|
-
// cross-chain bridge via custom xswap router
|
|
135
|
-
const messageSentXSwapCustomRouterEventSignature =
|
|
136
|
-
"MessageSent(bytes32,uint64,address,address,address,address,uint256)"; // TODO think of getting this signature in a different way becase its easy to forgot about it when we will change event on smartcontract
|
|
137
|
-
const messageReceivedXSwapCustomRouterEventSignature =
|
|
138
|
-
"MessageReceived(bytes32,uint64,address,bytes)"; // TODO think of getting this signature in a different way because its easy to forgot about it when we will change event on smartcontract
|
|
139
130
|
|
|
140
131
|
const destinationChainProvider = ethers.getDefaultProvider(
|
|
141
132
|
supportedChains.find(
|
|
@@ -146,7 +137,6 @@ export const TxOverview = ({ onCloseClick }: Props) => {
|
|
|
146
137
|
);
|
|
147
138
|
|
|
148
139
|
const handleMessageEvent = async (
|
|
149
|
-
contractKey: "XSwapRouter" | "CustomXSwapRouter",
|
|
150
140
|
messageSentEventSignature: string,
|
|
151
141
|
messageReceivedEventSignature: string,
|
|
152
142
|
) => {
|
|
@@ -159,15 +149,13 @@ export const TxOverview = ({ onCloseClick }: Props) => {
|
|
|
159
149
|
transactionData.messageId = messageId;
|
|
160
150
|
|
|
161
151
|
const xSwapRouterOnDestination = new ethers.Contract(
|
|
162
|
-
ADDRESSES[dstChain!.chainId]
|
|
163
|
-
|
|
164
|
-
? XSwapRouterAbi
|
|
165
|
-
: CustomXSwapRouterAbi,
|
|
152
|
+
ADDRESSES[dstChain!.chainId]!.XSwapRouter!,
|
|
153
|
+
XSwapRouterAbi,
|
|
166
154
|
destinationChainProvider,
|
|
167
155
|
);
|
|
168
156
|
|
|
169
157
|
const eventFilter = {
|
|
170
|
-
address: ADDRESSES[dstChain.chainId]?.
|
|
158
|
+
address: ADDRESSES[dstChain.chainId]?.XSwapRouter,
|
|
171
159
|
topics: [
|
|
172
160
|
ethers.utils.id(messageReceivedEventSignature),
|
|
173
161
|
messageId,
|
|
@@ -194,16 +182,9 @@ export const TxOverview = ({ onCloseClick }: Props) => {
|
|
|
194
182
|
};
|
|
195
183
|
|
|
196
184
|
await handleMessageEvent(
|
|
197
|
-
"XSwapRouter",
|
|
198
185
|
messageSentEventSignature,
|
|
199
186
|
messageReceivedEventSignature,
|
|
200
187
|
);
|
|
201
|
-
|
|
202
|
-
await handleMessageEvent(
|
|
203
|
-
"CustomXSwapRouter",
|
|
204
|
-
messageSentXSwapCustomRouterEventSignature,
|
|
205
|
-
messageReceivedXSwapCustomRouterEventSignature,
|
|
206
|
-
);
|
|
207
188
|
}
|
|
208
189
|
|
|
209
190
|
addTransactionToLocalHistory(transactionData, txReceipt.from);
|
|
@@ -110,6 +110,7 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
|
|
|
110
110
|
integratorFee,
|
|
111
111
|
integratorFeeReceiverAddress,
|
|
112
112
|
highlightedDstTokens,
|
|
113
|
+
wagmiConfig: providedWagmiConfig,
|
|
113
114
|
} = normalizedProps;
|
|
114
115
|
|
|
115
116
|
const onBackdropClick = (e: MouseEvent) => {
|
|
@@ -122,8 +123,11 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
|
|
|
122
123
|
};
|
|
123
124
|
|
|
124
125
|
const wagmiConfig = useMemo(
|
|
125
|
-
() =>
|
|
126
|
-
|
|
126
|
+
() =>
|
|
127
|
+
providedWagmiConfig ??
|
|
128
|
+
window.xPayWagmiConfig ??
|
|
129
|
+
getWagmiConfig(supportedChains),
|
|
130
|
+
[providedWagmiConfig, supportedChains],
|
|
127
131
|
);
|
|
128
132
|
|
|
129
133
|
useEffect(() => {
|
|
@@ -223,6 +227,7 @@ export const openTxConfigForm = async ({
|
|
|
223
227
|
srcTokenLocked,
|
|
224
228
|
srcChainLocked,
|
|
225
229
|
override,
|
|
230
|
+
wagmiConfig,
|
|
226
231
|
}: TxConfigFormPayload): Promise<UnifiedRoute> => {
|
|
227
232
|
try {
|
|
228
233
|
if (xpayRoot === null) {
|
|
@@ -267,6 +272,7 @@ export const openTxConfigForm = async ({
|
|
|
267
272
|
srcTokenLocked={srcTokenLocked}
|
|
268
273
|
srcChainLocked={srcChainLocked}
|
|
269
274
|
override={override}
|
|
275
|
+
wagmiConfig={wagmiConfig}
|
|
270
276
|
/>,
|
|
271
277
|
);
|
|
272
278
|
});
|
|
@@ -51,7 +51,13 @@ export const TxWidgetWCWrapped = ({
|
|
|
51
51
|
integratorFee,
|
|
52
52
|
integratorFeeReceiverAddress,
|
|
53
53
|
highlightedDstTokens,
|
|
54
|
+
wagmiConfig,
|
|
54
55
|
}: WidgetIntegrationPayload) => {
|
|
56
|
+
// Must be synchronous: the WC mounts its inner React tree before useEffect fires.
|
|
57
|
+
if (typeof window !== "undefined") {
|
|
58
|
+
window.xPayWagmiConfig = wagmiConfig;
|
|
59
|
+
}
|
|
60
|
+
|
|
55
61
|
useEffect(() => {
|
|
56
62
|
// We couldn't find a way to pass a function to the web component created by @r2wc/core.
|
|
57
63
|
// It is assigned to window to be accessed later from within the web component.
|
|
@@ -4,7 +4,7 @@ import { defineChain, Transport } from "viem";
|
|
|
4
4
|
import * as WagmiChains from "viem/chains";
|
|
5
5
|
import { mainnet } from "viem/chains";
|
|
6
6
|
import { Config, createConfig, createStorage, http } from "@wagmi/core";
|
|
7
|
-
import { walletConnect } from "@wagmi/connectors";
|
|
7
|
+
import { injected, walletConnect } from "@wagmi/connectors";
|
|
8
8
|
|
|
9
9
|
const storage = createStorage({
|
|
10
10
|
key: "xpay.wagmi.store",
|
|
@@ -18,6 +18,7 @@ export const getWagmiConfig = (supportedChains: Chain[]): Config => {
|
|
|
18
18
|
chains,
|
|
19
19
|
transports,
|
|
20
20
|
connectors: [
|
|
21
|
+
injected(),
|
|
21
22
|
walletConnect({
|
|
22
23
|
projectId: "c392898b45ac587a280b5eb33e92aeb0",
|
|
23
24
|
showQrModal: true,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
SOLANA_TOKEN_2022_PROGRAM_ID,
|
|
9
9
|
SOLANA_TOKEN_PROGRAM_ID,
|
|
10
10
|
} from "@src/constants";
|
|
11
|
-
import { ADDRESSES } from "@src/contracts";
|
|
11
|
+
import { ADDRESSES, resolveBridgeDisplayToken } from "@src/contracts";
|
|
12
12
|
import {
|
|
13
13
|
BridgeToken,
|
|
14
14
|
BridgeTokensDictionary,
|
|
@@ -383,8 +383,15 @@ export const SwapProvider = ({
|
|
|
383
383
|
// Skip invalid token pairs.
|
|
384
384
|
continue;
|
|
385
385
|
}
|
|
386
|
-
const [chainId0,
|
|
387
|
-
const [chainId1,
|
|
386
|
+
const [chainId0, rawAddress0] = entries[0]!;
|
|
387
|
+
const [chainId1, rawAddress1] = entries[1]!;
|
|
388
|
+
|
|
389
|
+
// Some pairs use an internal, CCIP-connected token (e.g. a wrapped
|
|
390
|
+
// variant) that the backend relies on for routing. In the bridge UI we
|
|
391
|
+
// display/select the user-facing token instead; the backend wraps it into
|
|
392
|
+
// the CCIP token when building the route.
|
|
393
|
+
const address0 = resolveBridgeDisplayToken(chainId0, rawAddress0);
|
|
394
|
+
const address1 = resolveBridgeDisplayToken(chainId1, rawAddress1);
|
|
388
395
|
|
|
389
396
|
addMapping(chainId0, address0, chainId1, address1);
|
|
390
397
|
addMapping(chainId1, address1, chainId0, address0);
|
|
@@ -673,19 +680,24 @@ export const SwapProvider = ({
|
|
|
673
680
|
|
|
674
681
|
const nonce = crypto.randomUUID();
|
|
675
682
|
refreshSelectedTokenBalanceNonce.current = nonce;
|
|
676
|
-
|
|
677
683
|
setIsFetchingBalance(true);
|
|
678
684
|
let balance = "0";
|
|
679
685
|
if (srcChain?.ecosystem === Ecosystem.EVM && evmAddress) {
|
|
680
|
-
const
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
686
|
+
const balanceFromBackend =
|
|
687
|
+
tokenBalances[srcChain?.chainId]?.[srcToken.address];
|
|
688
|
+
if (balanceFromBackend === undefined) {
|
|
689
|
+
const balanceUI = await getBalanceOf(
|
|
690
|
+
evmAddress,
|
|
691
|
+
srcToken.address,
|
|
692
|
+
srcChain?.publicRpcUrls[0],
|
|
693
|
+
);
|
|
694
|
+
balance = humanReadableToWei({
|
|
695
|
+
amount: balanceUI,
|
|
696
|
+
decimals: srcToken.decimals,
|
|
697
|
+
});
|
|
698
|
+
} else {
|
|
699
|
+
balance = balanceFromBackend;
|
|
700
|
+
}
|
|
689
701
|
} else if (srcChain?.ecosystem === Ecosystem.SOLANA && solanaAddress) {
|
|
690
702
|
const solanaPublicKey = new PublicKey(solanaAddress);
|
|
691
703
|
const connection = new Connection(srcChain.publicRpcUrls[0]!);
|
|
@@ -719,7 +731,6 @@ export const SwapProvider = ({
|
|
|
719
731
|
}
|
|
720
732
|
}
|
|
721
733
|
}
|
|
722
|
-
|
|
723
734
|
if (nonce !== refreshSelectedTokenBalanceNonce.current) {
|
|
724
735
|
return;
|
|
725
736
|
}
|
|
@@ -727,7 +738,7 @@ export const SwapProvider = ({
|
|
|
727
738
|
setSrcTokenBalanceWei(balance);
|
|
728
739
|
|
|
729
740
|
setIsFetchingBalance(false);
|
|
730
|
-
}, [evmAddress, solanaAddress, srcChain, srcToken]);
|
|
741
|
+
}, [evmAddress, solanaAddress, srcChain, srcToken, tokenBalances]);
|
|
731
742
|
// retrieves token details for a given token address and chain from supported tokens mapping. (including imported tokens)
|
|
732
743
|
const findTokenDataByAddressAndChain = useCallback(
|
|
733
744
|
(tokenAddress: string, chainId: string): Token | undefined => {
|
|
@@ -796,10 +807,8 @@ export const SwapProvider = ({
|
|
|
796
807
|
// fetches user all token balances when a wallet address is available and supported chains are loaded.
|
|
797
808
|
useEffect(() => {
|
|
798
809
|
let isCancelled = false;
|
|
799
|
-
|
|
800
810
|
if ((evmAddress || solanaAddress) && supportedChains.length > 0) {
|
|
801
811
|
setIsFetchingBalances(true);
|
|
802
|
-
|
|
803
812
|
getBalances({
|
|
804
813
|
walletAddress: evmAddress,
|
|
805
814
|
solanaWalletAddress: solanaAddress,
|
|
@@ -2,12 +2,10 @@ import BatchQuery from "./BatchQuery.json";
|
|
|
2
2
|
import ERC20 from "./ERC20.json";
|
|
3
3
|
import XSwapRouter from "./XSwapRouter.json";
|
|
4
4
|
import XSwapTokenFeeDistributor from "./XSwapTokenFeeDistributor.json";
|
|
5
|
-
import CustomXSwapRouter from "./CustomXSwapRouter.json";
|
|
6
5
|
import StakingStableAPR from "./StakingStableAPR.json";
|
|
7
6
|
|
|
8
7
|
export const BatchQueryAbi = BatchQuery;
|
|
9
8
|
export const ERC20Abi = ERC20;
|
|
10
9
|
export const XSwapRouterAbi = XSwapRouter;
|
|
11
10
|
export const XSwapTokenFeeDistributorAbi = XSwapTokenFeeDistributor;
|
|
12
|
-
export const CustomXSwapRouterAbi = CustomXSwapRouter;
|
|
13
11
|
export const StakingStableAPRAbi = StakingStableAPR;
|
|
@@ -23,8 +23,6 @@ export const ADDRESSES: Addresses = {
|
|
|
23
23
|
"8453": {
|
|
24
24
|
[ContractName.USDC]: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
25
25
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
26
|
-
[ContractName.CustomXSwapRouter]:
|
|
27
|
-
"0x9B64aC0aD647768838a3957Bc12c40E1C539cb93",
|
|
28
26
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
29
27
|
[ContractName.StakingCosmicCadets]:
|
|
30
28
|
"0x67798736bFb7d9A1F143215E258fe15Da68c85F0",
|
|
@@ -41,8 +39,6 @@ export const ADDRESSES: Addresses = {
|
|
|
41
39
|
"1": {
|
|
42
40
|
[ContractName.USDC]: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
|
43
41
|
[ContractName.BatchQuery]: "0xb5f9934ea0810ef5faa677e8c68c6983b88664b1",
|
|
44
|
-
[ContractName.CustomXSwapRouter]:
|
|
45
|
-
"0x9B64aC0aD647768838a3957Bc12c40E1C539cb93",
|
|
46
42
|
[ContractName.FeeCollector]: "0xb37275558f02f05104c2ba35199d16adeb43432f",
|
|
47
43
|
[ContractName.XSwapRouter]: "0xe1c14b9f065dead2e89ee35382f8bd42bdb87a04",
|
|
48
44
|
[ContractName.XSwapToken]: "0x8fe815417913a93ea99049fc0718ee1647a2a07c",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge UI display overrides.
|
|
3
|
+
*
|
|
4
|
+
* Some tokens returned by the `/bridgeTokens` endpoint are internal,
|
|
5
|
+
* directly-CCIP-connected tokens (e.g. a wrapped variant) that the backend
|
|
6
|
+
* relies on for routing, but that we do NOT want users to see or pick in the
|
|
7
|
+
* bridge UI. This map replaces such a CCIP token with the user-facing token we
|
|
8
|
+
* display and let users select / hold instead.
|
|
9
|
+
*
|
|
10
|
+
* The backend accepts the user-facing token in `/route` and wraps it into the
|
|
11
|
+
* CCIP token under the hood (e.g. real USDC -> XSwapUSDC via the wrapper), so
|
|
12
|
+
* the selected token is what flows through balances, approval and the route
|
|
13
|
+
* request, while the actual cross-chain hop still uses the CCIP token.
|
|
14
|
+
*
|
|
15
|
+
* Shape: { [chainId]: { [ccipTokenAddressLowercased]: displayTokenAddressLowercased } }
|
|
16
|
+
*
|
|
17
|
+
* IMPORTANT: addresses must be lowercased on both sides — the bridge dictionary
|
|
18
|
+
* and its consumers compare EVM addresses lowercased.
|
|
19
|
+
*/
|
|
20
|
+
export const bridgeDisplayTokenOverrides: Record<
|
|
21
|
+
string,
|
|
22
|
+
Record<string, string>
|
|
23
|
+
> = {
|
|
24
|
+
// base: XSwapUSDC -> real USDC
|
|
25
|
+
"8453": {
|
|
26
|
+
"0x5426188a207fd0365dca5cff345059ff531d1aa7":
|
|
27
|
+
"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the user-facing token address to display in the bridge UI for a given
|
|
33
|
+
* `/bridgeTokens` entry, or the original address when there is no override.
|
|
34
|
+
*
|
|
35
|
+
* EVM addresses are matched case-insensitively; non-EVM addresses (e.g. Solana)
|
|
36
|
+
* are returned untouched.
|
|
37
|
+
*/
|
|
38
|
+
export const resolveBridgeDisplayToken = (
|
|
39
|
+
chainId: string,
|
|
40
|
+
tokenAddress: string,
|
|
41
|
+
): string => {
|
|
42
|
+
return (
|
|
43
|
+
bridgeDisplayTokenOverrides[chainId]?.[tokenAddress.toLowerCase()] ??
|
|
44
|
+
tokenAddress
|
|
45
|
+
);
|
|
46
|
+
};
|
package/src/contracts/index.ts
CHANGED
package/src/models/Addresses.ts
CHANGED
|
@@ -9,7 +9,6 @@ export type Contracts = Partial<{
|
|
|
9
9
|
export enum ContractName {
|
|
10
10
|
USDC = "USDC",
|
|
11
11
|
BatchQuery = "BatchQuery",
|
|
12
|
-
CustomXSwapRouter = "CustomXSwapRouter",
|
|
13
12
|
FeeCollector = "FeeCollector",
|
|
14
13
|
StakingCosmicCadets = "StakingCosmicCadets",
|
|
15
14
|
StakingSolarDivision = "StakingSolarDivision",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ContractCall, Transaction } from "@src/models";
|
|
2
|
+
import { Config } from "@wagmi/core";
|
|
2
3
|
|
|
3
4
|
export type ModalIntegrationThemeStyles = {
|
|
4
5
|
mainAccentLight?: string;
|
|
@@ -71,4 +72,5 @@ export type ModalIntegrationPayload = {
|
|
|
71
72
|
integratorFee?: number;
|
|
72
73
|
integratorFeeReceiverAddress?: string;
|
|
73
74
|
highlightedDstTokens?: string[];
|
|
75
|
+
wagmiConfig?: Config;
|
|
74
76
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ContractCall, ModalIntegrationStyles, Transaction } from "@src/models";
|
|
2
|
+
import { Config } from "@wagmi/core";
|
|
2
3
|
|
|
3
4
|
export type WidgetIntegrationPayload = {
|
|
4
5
|
integratorId: string;
|
|
@@ -33,4 +34,5 @@ export type WidgetIntegrationPayload = {
|
|
|
33
34
|
integratorFee?: number;
|
|
34
35
|
integratorFeeReceiverAddress?: string;
|
|
35
36
|
highlightedDstTokens?: string[];
|
|
37
|
+
wagmiConfig?: Config;
|
|
36
38
|
};
|
|
@@ -26,6 +26,7 @@ export const openTransactionModal = async ({
|
|
|
26
26
|
onSrcChainChange,
|
|
27
27
|
bridge,
|
|
28
28
|
highlightedDstTokens,
|
|
29
|
+
wagmiConfig,
|
|
29
30
|
}: ModalIntegrationPayload) => {
|
|
30
31
|
const supportedChains: Chain[] = (await getChains()).filter(
|
|
31
32
|
({ web3Environment, swapSupported, bridgeSupported }) =>
|
|
@@ -66,6 +67,7 @@ export const openTransactionModal = async ({
|
|
|
66
67
|
onSrcChainChange,
|
|
67
68
|
bridge,
|
|
68
69
|
highlightedDstTokens,
|
|
70
|
+
wagmiConfig,
|
|
69
71
|
});
|
|
70
72
|
};
|
|
71
73
|
|
package/src/types/global.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Transaction } from "@src/models";
|
|
2
|
+
import { Config } from "@wagmi/core";
|
|
2
3
|
|
|
3
4
|
declare global {
|
|
4
5
|
interface Window {
|
|
@@ -12,5 +13,6 @@ declare global {
|
|
|
12
13
|
) => void;
|
|
13
14
|
xPayOnSrcChainChange?: (chain: string | undefined) => void;
|
|
14
15
|
xPayOnConnectWallet?: () => void;
|
|
16
|
+
xPayWagmiConfig?: Config;
|
|
15
17
|
}
|
|
16
18
|
}
|