@xswap-link/sdk 0.3.5 → 0.4.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/.eslintrc.json +9 -5
- package/CHANGELOG.md +10 -0
- package/README.md +2 -1
- package/dist/index.d.mts +106 -20
- package/dist/index.d.ts +106 -20
- package/dist/index.global.js +963 -164
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +105 -3564
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +105 -3534
- package/dist/index.mjs.map +1 -0
- package/nodemon.json +1 -1
- package/package.json +16 -9
- package/postcss.config.js +8 -1
- package/src/{components → assets}/icons/ArrowDownIcon.tsx +1 -2
- package/src/assets/icons/ArrowDownLongIcon.tsx +12 -0
- package/src/{components → assets}/icons/ArrowLeftIcon.tsx +1 -5
- package/src/{components → assets}/icons/ArrowRightIcon.tsx +1 -5
- package/src/assets/icons/ArrowUpIcon.tsx +12 -0
- package/src/{components → assets}/icons/ArrowUpRightIcon.tsx +1 -5
- package/src/assets/icons/CashbacklIcon.tsx +28 -0
- package/src/{components → assets}/icons/CheckIcon.tsx +1 -5
- package/src/assets/icons/ChevronDownIcon.tsx +12 -0
- package/src/assets/icons/ChevronUpIcon.tsx +7 -0
- package/src/{components → assets}/icons/CircularProgressIcon.tsx +1 -2
- package/src/assets/icons/CloseIcon.tsx +15 -0
- package/src/{components → assets}/icons/CoinsIcon.tsx +0 -2
- package/src/assets/icons/CopyIcon.tsx +15 -0
- package/src/assets/icons/DotGreenIcon.tsx +12 -0
- package/src/{components → assets}/icons/DownArrorIcon.tsx +0 -2
- package/src/{components → assets}/icons/ErrorIcon.tsx +0 -1
- package/src/assets/icons/ErrorModalStatusIcon.tsx +31 -0
- package/src/assets/icons/HelpIcon.tsx +21 -0
- package/src/assets/icons/HistoryGradientBgIcon.tsx +32 -0
- package/src/assets/icons/HistoryIcon.tsx +12 -0
- package/src/{components → assets}/icons/HourGlassIcon.tsx +1 -5
- package/src/assets/icons/Icon.tsx +5 -0
- package/src/{components → assets}/icons/InfoIcon.tsx +0 -1
- package/src/assets/icons/LinkExternalIcon.tsx +15 -0
- package/src/{components → assets}/icons/PercentageIcon.tsx +0 -1
- package/src/assets/icons/RankIcon.tsx +28 -0
- package/src/assets/icons/SettingsGradientBgIcon.tsx +32 -0
- package/src/assets/icons/SettingsIcon.tsx +12 -0
- package/src/{components → assets}/icons/SignIcon.tsx +0 -2
- package/src/{components → assets}/icons/SuccessIcon.tsx +0 -1
- package/src/assets/icons/SuccessModalStatusIcon.tsx +31 -0
- package/src/assets/icons/ThumbUpRoundedIcon.tsx +15 -0
- package/src/{components → assets}/icons/TimerIcon.tsx +0 -1
- package/src/assets/icons/TokensIcon.tsx +16 -0
- package/src/assets/icons/WaitingIcon.tsx +15 -0
- package/src/{components → assets}/icons/XMarkIcon.tsx +1 -5
- package/src/assets/icons/XPowerIcon.tsx +28 -0
- package/src/{components → assets}/icons/index.ts +16 -0
- package/src/components/Alert/index.tsx +1 -1
- package/src/components/Button/index.tsx +57 -0
- package/src/components/MessageBar/SnackMessage.tsx +32 -0
- package/src/components/MessageBar/index.tsx +44 -0
- package/src/components/Modal/index.tsx +52 -0
- package/src/components/PoweredBy/index.tsx +12 -0
- package/src/components/SafeInput/index.tsx +51 -0
- package/src/components/Skeleton/index.tsx +5 -9
- package/src/components/Spinner/index.tsx +6 -8
- package/src/components/Swap/Header/Controls/index.tsx +57 -0
- package/src/components/Swap/Header/index.tsx +16 -0
- package/src/components/Swap/HistoryView/index.tsx +34 -0
- package/src/components/Swap/SettingsView/Delivery/index.tsx +42 -0
- package/src/components/Swap/SettingsView/Slippage/index.tsx +80 -0
- package/src/components/Swap/SettingsView/index.tsx +11 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +13 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Header/index.tsx +37 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Steps/index.tsx +145 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/SwapPanel/index.tsx +61 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +291 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxResult/TokenItem/index.tsx +24 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxResult/index.tsx +84 -0
- package/src/components/Swap/SwapView/ConfirmationView/index.tsx +17 -0
- package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +25 -0
- package/src/components/Swap/SwapView/FeesPanel/Fee/index.tsx +18 -0
- package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +71 -0
- package/src/components/Swap/SwapView/FeesPanel/index.tsx +67 -0
- package/src/components/Swap/SwapView/SwapButton/index.tsx +154 -0
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +23 -0
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +56 -0
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +70 -0
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +62 -0
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +74 -0
- package/src/components/Swap/SwapView/SwapPanel/MaxPanel/index.tsx +35 -0
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +40 -0
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +62 -0
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +399 -0
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +104 -0
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +42 -0
- package/src/components/Swap/SwapView/index.tsx +20 -0
- package/src/components/Swap/index.tsx +34 -0
- package/src/components/TextInput/index.tsx +67 -0
- package/src/components/Timer/index.tsx +57 -0
- package/src/components/ToggleButton/index.tsx +24 -0
- package/src/components/{UnknownTokenLogo/UnknownTokenLogo.tsx → TokenLogo/Unknown/index.tsx} +3 -4
- package/src/components/TokenLogo/WithChain/index.tsx +34 -0
- package/src/components/TokenLogo/index.tsx +22 -0
- package/src/components/Tooltip/index.tsx +108 -0
- package/src/components/TxConfigForm/index.tsx +63 -42
- package/src/components/TxDataCard/TokenDetails/index.tsx +30 -0
- package/src/components/TxDataCard/TxDataCardUI/index.tsx +133 -0
- package/src/components/TxDataCard/index.tsx +30 -0
- package/src/components/TxStatusButton/index.tsx +64 -108
- package/src/components/global.css +115 -4
- package/src/components/index.ts +18 -1
- package/src/config/fonts.ts +114 -0
- package/src/config/global.d.ts +4 -0
- package/src/config/init.tsx +35 -31
- package/src/constants/crosschainEstimationTimes.ts +52 -0
- package/src/constants/index.ts +8 -0
- package/src/context/GlobalDataProvider.tsx +165 -0
- package/src/context/HistoryProvider.tsx +339 -0
- package/src/context/ModalProvider.tsx +47 -0
- package/src/context/SwapProvider.tsx +664 -0
- package/src/context/TransactionProvider.tsx +86 -0
- package/src/context/TxUIWrapper.tsx +388 -0
- package/src/context/index.ts +5 -0
- package/src/contracts/abi/CustomXSwapRouter.json +953 -0
- package/src/contracts/abi/StakingStableAPR.json +1438 -0
- package/src/contracts/abi/XSwapRouter.json +1242 -0
- package/src/contracts/abi/XSwapTokenFeeDistributor.json +350 -0
- package/src/contracts/abi/index.ts +8 -0
- package/src/contracts/addresses.ts +24 -6
- package/src/fonts/Satoshi-Black.woff2 +0 -0
- package/src/fonts/Satoshi-BlackItalic.woff2 +0 -0
- package/src/fonts/Satoshi-Bold.woff2 +0 -0
- package/src/fonts/Satoshi-BoldItalic.woff2 +0 -0
- package/src/fonts/Satoshi-Light.woff2 +0 -0
- package/src/fonts/Satoshi-LightItalic.woff2 +0 -0
- package/src/fonts/Satoshi-Medium.woff2 +0 -0
- package/src/fonts/Satoshi-MediumItalic.woff2 +0 -0
- package/src/fonts/Satoshi-Regular.woff2 +0 -0
- package/src/fonts/Satoshi-RegularItalic.woff2 +0 -0
- package/src/fonts/Satoshi-Variable.woff2 +0 -0
- package/src/fonts/Satoshi-VariableItalic.woff2 +0 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/networkManagement/clientToSigner.tsx +17 -0
- package/src/hooks/networkManagement/useNetworks.ts +51 -0
- package/src/hooks/useBatchQuery.ts +46 -0
- package/src/hooks/useDebounce.tsx +28 -0
- package/src/hooks/useEvmContractApi.ts +85 -0
- package/src/hooks/usePortal.ts +79 -0
- package/src/hooks/useXPower.ts +58 -0
- package/src/models/Addresses.ts +8 -2
- package/src/models/TokenData.ts +13 -0
- package/src/models/TransactionHistory.ts +2 -0
- package/src/models/TxUIWrapper.ts +51 -0
- package/src/models/XSwapConfig.ts +1 -0
- package/src/models/index.ts +1 -0
- package/src/models/payloads/GetBalancesPayload.ts +3 -0
- package/src/models/payloads/GetFinishedLeaderboardQuestsPayload.ts +3 -0
- package/src/models/payloads/GetLeaderboardChangePayload.ts +4 -0
- package/src/models/payloads/{GetSwapTxPayload.ts → ModalIntegrationPayload.ts} +3 -1
- package/src/models/payloads/index.ts +5 -2
- package/src/services/api.ts +34 -5
- package/src/services/integrations/monitoring.ts +49 -37
- package/src/services/integrations/transactions.ts +50 -6
- package/src/utils/contracts.ts +29 -0
- package/src/utils/index.ts +3 -3
- package/src/utils/numbers.ts +14 -0
- package/src/utils/parseWeb3Error.ts +7 -3
- package/tailwind.config.js +15 -5
- package/tsconfig.json +7 -7
- package/tsup.config.ts +61 -0
- package/xswap.config.ts +1 -0
- package/dist/index.css +0 -1
- package/src/components/TxConfigForm/BalanceComponent.tsx +0 -52
- package/src/components/TxConfigForm/Button.tsx +0 -20
- package/src/components/TxConfigForm/ChainListElement.tsx +0 -36
- package/src/components/TxConfigForm/ConfirmationAmount.tsx +0 -91
- package/src/components/TxConfigForm/ConfirmationView/ErrorView.tsx +0 -38
- package/src/components/TxConfigForm/ConfirmationView/SuccessView.tsx +0 -159
- package/src/components/TxConfigForm/ConfirmationView/index.tsx +0 -149
- package/src/components/TxConfigForm/ConnectWalletPrompt.tsx +0 -21
- package/src/components/TxConfigForm/Description.tsx +0 -17
- package/src/components/TxConfigForm/ErrorField.tsx +0 -19
- package/src/components/TxConfigForm/FeesDetails.tsx +0 -117
- package/src/components/TxConfigForm/Form.tsx +0 -574
- package/src/components/TxConfigForm/History.tsx +0 -131
- package/src/components/TxConfigForm/HistoryCard.tsx +0 -182
- package/src/components/TxConfigForm/PoweredBy.tsx +0 -12
- package/src/components/TxConfigForm/Settings.tsx +0 -143
- package/src/components/TxConfigForm/Summary.tsx +0 -105
- package/src/components/TxConfigForm/SwapPanel.tsx +0 -185
- package/src/components/TxConfigForm/TokenPicker.tsx +0 -176
- package/src/components/TxConfigForm/TopBar.tsx +0 -58
- package/src/components/TxConfigForm/UsdPrice.tsx +0 -44
- package/src/components/icons/ChevronDownIcon.tsx +0 -15
- package/src/components/icons/ChevronUpIcon.tsx +0 -10
- package/src/components/icons/CloseIcon.tsx +0 -15
- package/src/components/icons/HistoryIcon.tsx +0 -16
- package/src/components/icons/SettingsIcon.tsx +0 -16
- /package/src/{components → assets}/icons/ChainlinkCCIPIcon.tsx +0 -0
- /package/src/{components → assets}/icons/SearchIcon.tsx +0 -0
- /package/src/{components → assets}/icons/XSwapBadgeIcon.tsx +0 -0
- /package/src/{components → assets}/icons/XSwapLogo.tsx +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates DOM element to be used as React root.
|
|
5
|
+
*/
|
|
6
|
+
function createRootElement(id: string): HTMLElement {
|
|
7
|
+
const rootContainer = document.createElement("div");
|
|
8
|
+
rootContainer.setAttribute("id", id);
|
|
9
|
+
return rootContainer;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Appends element as last child of body.
|
|
14
|
+
*/
|
|
15
|
+
function addRootElement(rootElem: Element): void {
|
|
16
|
+
document.body.insertBefore(
|
|
17
|
+
rootElem,
|
|
18
|
+
document.body.lastElementChild!.nextElementSibling,
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Hook to create a React Portal.
|
|
24
|
+
* Automatically handles creating and tearing-down the root elements (no SRR
|
|
25
|
+
* makes this trivial), so there is no need to ensure the parent target already
|
|
26
|
+
* exists.
|
|
27
|
+
* @example
|
|
28
|
+
* const target = usePortal(id, [id]);
|
|
29
|
+
* return createPortal(children, target);
|
|
30
|
+
* @param {string} id The id of the target container, e.g 'modal' or 'spotlight'
|
|
31
|
+
* @returns {HTMLElement} The DOM node to use as the Portal target.
|
|
32
|
+
*/
|
|
33
|
+
export function usePortal(id: string): HTMLElement {
|
|
34
|
+
const rootElemRef = useRef<HTMLElement | null>(null);
|
|
35
|
+
|
|
36
|
+
useEffect(
|
|
37
|
+
function setupElement() {
|
|
38
|
+
// Look for existing target dom element to append to
|
|
39
|
+
const existingParent = document.querySelector(`#${id}`);
|
|
40
|
+
// Parent is either a new root or the existing dom element
|
|
41
|
+
const parentElem = existingParent || createRootElement(id);
|
|
42
|
+
|
|
43
|
+
// If there is no existing DOM element, add a new one.
|
|
44
|
+
if (!existingParent) {
|
|
45
|
+
addRootElement(parentElem);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Add the detached element to the parent
|
|
49
|
+
parentElem.appendChild(rootElemRef.current!);
|
|
50
|
+
|
|
51
|
+
return function removeElement() {
|
|
52
|
+
rootElemRef.current!.remove();
|
|
53
|
+
if (!parentElem.childElementCount) {
|
|
54
|
+
parentElem.remove();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
[id],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* It's important we evaluate this lazily:
|
|
63
|
+
* - We need first render to contain the DOM element, so it shouldn't happen
|
|
64
|
+
* in useEffect. We would normally put this in the constructor().
|
|
65
|
+
* - We can't do 'const rootElemRef = useRef(document.createElement('div))',
|
|
66
|
+
* since this will run every single render (that's a lot).
|
|
67
|
+
* - We want the ref to consistently point to the same DOM element and only
|
|
68
|
+
* ever run once.
|
|
69
|
+
* @link https://reactjs.org/docs/hooks-faq.html#how-to-create-expensive-objects-lazily
|
|
70
|
+
*/
|
|
71
|
+
function getRootElem(): HTMLElement {
|
|
72
|
+
if (!rootElemRef.current) {
|
|
73
|
+
rootElemRef.current = document.createElement("div");
|
|
74
|
+
}
|
|
75
|
+
return rootElemRef.current;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return getRootElem();
|
|
79
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ADDRESSES, StakingStableAPRAbi } from "@src/contracts";
|
|
2
|
+
import { useBatchQuery } from "./useBatchQuery";
|
|
3
|
+
import { BigNumber, ethers } from "ethers";
|
|
4
|
+
import { useCallback } from "react";
|
|
5
|
+
|
|
6
|
+
const iface = new ethers.utils.Interface(StakingStableAPRAbi);
|
|
7
|
+
|
|
8
|
+
export const useXPower = (chainId: string) => {
|
|
9
|
+
const { batchQuery } = useBatchQuery();
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
getXPower: useCallback(
|
|
13
|
+
async (address: string) => {
|
|
14
|
+
if (
|
|
15
|
+
!ADDRESSES[chainId]?.StakingCosmicCadets ||
|
|
16
|
+
!ADDRESSES[chainId]?.StakingSolarDivision ||
|
|
17
|
+
!ADDRESSES[chainId]?.StakingIntergalacticCommand
|
|
18
|
+
) {
|
|
19
|
+
return "0";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const stakingAddresses: string[] = [
|
|
23
|
+
ADDRESSES[chainId]?.StakingCosmicCadets,
|
|
24
|
+
ADDRESSES[chainId]?.StakingSolarDivision,
|
|
25
|
+
ADDRESSES[chainId]?.StakingIntergalacticCommand,
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const calldata = iface.encodeFunctionData("getStaker", [address]);
|
|
29
|
+
const responses = await batchQuery(
|
|
30
|
+
chainId,
|
|
31
|
+
stakingAddresses,
|
|
32
|
+
stakingAddresses.map(() => calldata),
|
|
33
|
+
);
|
|
34
|
+
if (responses) {
|
|
35
|
+
return responses
|
|
36
|
+
.map(
|
|
37
|
+
(stakerResponse) =>
|
|
38
|
+
ethers.utils.defaultAbiCoder.decode(
|
|
39
|
+
[
|
|
40
|
+
"address",
|
|
41
|
+
"uint256",
|
|
42
|
+
"uint256",
|
|
43
|
+
"uint256",
|
|
44
|
+
"uint256",
|
|
45
|
+
"uint256",
|
|
46
|
+
],
|
|
47
|
+
stakerResponse,
|
|
48
|
+
)[1],
|
|
49
|
+
)
|
|
50
|
+
.reduce((prev, curr) => prev.add(curr), BigNumber.from(0))
|
|
51
|
+
.toString();
|
|
52
|
+
}
|
|
53
|
+
return "0";
|
|
54
|
+
},
|
|
55
|
+
[batchQuery, chainId],
|
|
56
|
+
),
|
|
57
|
+
};
|
|
58
|
+
};
|
package/src/models/Addresses.ts
CHANGED
|
@@ -2,12 +2,18 @@ export type Addresses = {
|
|
|
2
2
|
[chainId: string]: Contracts;
|
|
3
3
|
};
|
|
4
4
|
|
|
5
|
-
export type Contracts = {
|
|
5
|
+
export type Contracts = Partial<{
|
|
6
6
|
[contractName in ContractName]: string;
|
|
7
|
-
}
|
|
7
|
+
}>;
|
|
8
8
|
|
|
9
9
|
export enum ContractName {
|
|
10
|
+
USDC = "USDC",
|
|
10
11
|
BatchQuery = "BatchQuery",
|
|
12
|
+
CustomXSwapRouter = "CustomXSwapRouter",
|
|
11
13
|
FeeCollector = "FeeCollector",
|
|
14
|
+
StakingCosmicCadets = "StakingCosmicCadets",
|
|
15
|
+
StakingSolarDivision = "StakingSolarDivision",
|
|
16
|
+
StakingIntergalacticCommand = "StakingIntergalacticCommand",
|
|
12
17
|
XSwapRouter = "XSwapRouter",
|
|
18
|
+
XSwapToken = "XSwapToken",
|
|
13
19
|
}
|
package/src/models/TokenData.ts
CHANGED
|
@@ -43,3 +43,16 @@ export type TokenPrices = {
|
|
|
43
43
|
export type TokenBalances = {
|
|
44
44
|
[tokenAddress: string]: BigNumber | undefined;
|
|
45
45
|
};
|
|
46
|
+
|
|
47
|
+
export type TokenOption = Token & {
|
|
48
|
+
chainId: string;
|
|
49
|
+
disabled?: boolean;
|
|
50
|
+
balance?: BigNumber;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type ImportedTokenData = {
|
|
54
|
+
address: string;
|
|
55
|
+
symbol: string;
|
|
56
|
+
name: string;
|
|
57
|
+
decimals: number;
|
|
58
|
+
};
|
|
@@ -8,6 +8,7 @@ export type HistoryTransaction = {
|
|
|
8
8
|
transferId: string;
|
|
9
9
|
transferType: TransferType;
|
|
10
10
|
walletAddress: string;
|
|
11
|
+
messageId: string;
|
|
11
12
|
// ExecutorRunFailed
|
|
12
13
|
failed: boolean;
|
|
13
14
|
// MessageSent
|
|
@@ -41,6 +42,7 @@ export type TransactionStatus =
|
|
|
41
42
|
| "NOT_FOUND";
|
|
42
43
|
|
|
43
44
|
export type Transaction = {
|
|
45
|
+
messageId?: string;
|
|
44
46
|
hash: string;
|
|
45
47
|
timestamp: number;
|
|
46
48
|
sourceChainId: string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { TransactionResponse } from "@ethersproject/providers";
|
|
2
|
+
import { EvmHandlers } from "@src/context";
|
|
3
|
+
import { Ecosystem } from "@src/models";
|
|
4
|
+
import { Dispatch, SetStateAction } from "react";
|
|
5
|
+
|
|
6
|
+
export type EnqueueTxProps = {
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
+
executeTransaction: () => Promise<TransactionResponse> | undefined;
|
|
9
|
+
txStatus: TxStatus;
|
|
10
|
+
txMsg?: string;
|
|
11
|
+
handlers?: EvmHandlers;
|
|
12
|
+
network?: Ecosystem;
|
|
13
|
+
showDefaultSuccessMessage?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type TxUIWrapperState = {
|
|
17
|
+
enqueueTransaction: (props: EnqueueTxProps) => number;
|
|
18
|
+
closeTransactionModal: (nonce: number) => void;
|
|
19
|
+
isTxModalOpen: boolean;
|
|
20
|
+
setTxModalOpen: Dispatch<SetStateAction<boolean>>;
|
|
21
|
+
loading: boolean;
|
|
22
|
+
txStatus: TxStatus;
|
|
23
|
+
setTxStatus: Dispatch<SetStateAction<TxStatus>>;
|
|
24
|
+
txExplorerUrl: string;
|
|
25
|
+
txHash: string;
|
|
26
|
+
txError: string;
|
|
27
|
+
txMsg: string;
|
|
28
|
+
setTxMsg: Dispatch<SetStateAction<string>>;
|
|
29
|
+
setTxError: Dispatch<SetStateAction<string>>;
|
|
30
|
+
txNeedsApproval: boolean;
|
|
31
|
+
setTxNeedsApproval: Dispatch<SetStateAction<boolean>>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* make sure there's always appropriate CONFIRMATION status following the SIGNING one
|
|
36
|
+
* see setTxStatus((prevStatus) => prevStatus + 1) at TxUIWrapper.tsx -> addUILogicToHandlersEVM
|
|
37
|
+
*/
|
|
38
|
+
export enum TxStatus {
|
|
39
|
+
SWAP_INIT,
|
|
40
|
+
SIGNING_APPROVAL,
|
|
41
|
+
CONFIRMING_APPROVAL,
|
|
42
|
+
SIGNING_TX,
|
|
43
|
+
CONFIRMING_TX,
|
|
44
|
+
COMPLETED,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type TxStats = {
|
|
48
|
+
points?: string;
|
|
49
|
+
rank?: string;
|
|
50
|
+
cashback?: string;
|
|
51
|
+
};
|
package/src/models/index.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ContractCall } from "@src/models";
|
|
2
2
|
|
|
3
|
-
export type
|
|
3
|
+
export type ModalIntegrationPayload = {
|
|
4
4
|
integratorId: string;
|
|
5
5
|
dstChain: string;
|
|
6
6
|
dstToken: string;
|
|
7
|
+
srcChain?: string;
|
|
8
|
+
srcToken?: string;
|
|
7
9
|
customContractCalls?: ContractCall[];
|
|
8
10
|
desc?: string;
|
|
9
11
|
returnTransactions?: boolean;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export * from "./GetRoutePayload";
|
|
2
1
|
export * from "./AddReferralPayload";
|
|
3
|
-
export * from "./
|
|
2
|
+
export * from "./GetBalancesPayload";
|
|
3
|
+
export * from "./GetFinishedLeaderboardQuestsPayload";
|
|
4
|
+
export * from "./GetLeaderboardChangePayload";
|
|
4
5
|
export * from "./GetPricesPayload";
|
|
6
|
+
export * from "./GetRoutePayload";
|
|
7
|
+
export * from "./ModalIntegrationPayload";
|
package/src/services/api.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import xSwapConfig from "../../xswap.config";
|
|
2
2
|
import {
|
|
3
|
-
BridgeToken,
|
|
4
3
|
Chain,
|
|
5
4
|
Ecosystem,
|
|
5
|
+
GetFinishedLeaderboardQuestsPayload,
|
|
6
|
+
GetLeaderboardChangePayload,
|
|
6
7
|
GetPricesPayload,
|
|
7
8
|
GetRoutePayload,
|
|
9
|
+
GetTokenBalancesPayload,
|
|
8
10
|
Route,
|
|
9
11
|
Token,
|
|
10
12
|
TokenPrices,
|
|
@@ -97,10 +99,6 @@ export async function getTokens(
|
|
|
97
99
|
);
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
export async function getBridgeTokens(): Promise<BridgeToken[]> {
|
|
101
|
-
return _sendRequest<BridgeToken[]>(`/bridgeTokens`);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
102
|
export async function getHistory(payload: { walletAddress: string }) {
|
|
105
103
|
return await _sendRequest<TransactionHistory>(
|
|
106
104
|
`/history?${new URLSearchParams({
|
|
@@ -117,6 +115,15 @@ export async function getPrices(payload: GetPricesPayload) {
|
|
|
117
115
|
);
|
|
118
116
|
}
|
|
119
117
|
|
|
118
|
+
export async function getBalances(payload: GetTokenBalancesPayload) {
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
120
|
+
return _sendRequest<any>(
|
|
121
|
+
`/tokenBalances?${new URLSearchParams({
|
|
122
|
+
data: JSON.stringify(payload),
|
|
123
|
+
})}`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
120
127
|
export async function getTxStatus(payload: { transferId: string }) {
|
|
121
128
|
return await _sendRequest<{ status: TransactionStatus }>(
|
|
122
129
|
`/getTxStatus?${new URLSearchParams({
|
|
@@ -124,3 +131,25 @@ export async function getTxStatus(payload: { transferId: string }) {
|
|
|
124
131
|
})}`,
|
|
125
132
|
);
|
|
126
133
|
}
|
|
134
|
+
|
|
135
|
+
export async function getLeaderboardChange(
|
|
136
|
+
payload: GetLeaderboardChangePayload,
|
|
137
|
+
) {
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
139
|
+
return _sendRequest<any>(
|
|
140
|
+
`/leaderboardChange?${new URLSearchParams({
|
|
141
|
+
data: JSON.stringify(payload),
|
|
142
|
+
})}`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function getFinishedLeaderboardQuests(
|
|
147
|
+
payload: GetFinishedLeaderboardQuestsPayload,
|
|
148
|
+
) {
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
|
+
return _sendRequest<any>(
|
|
151
|
+
`/getFinishedLeaderboardQuests?${new URLSearchParams({
|
|
152
|
+
data: JSON.stringify(payload),
|
|
153
|
+
})}`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Chain,
|
|
1
|
+
import { Chain, Token, Transaction, Web3Environment } from "@src/models";
|
|
2
2
|
import { getChains, getTxStatus } from "@src/services";
|
|
3
3
|
import { ethers } from "ethers";
|
|
4
|
-
import { weiToHumanReadable } from "@src/utils";
|
|
5
4
|
import {
|
|
6
|
-
CCIP_EXPLORER,
|
|
7
5
|
MSG_RECEIVED_EVENT_ABI,
|
|
8
6
|
MSG_RECEIVED_EVENT_SIG,
|
|
9
7
|
MSG_SENT_EVENT_ABI,
|
|
@@ -23,9 +21,10 @@ import { getCustomTokenData } from "../blockchain";
|
|
|
23
21
|
export const renderTxStatus = async (
|
|
24
22
|
txChainId: string,
|
|
25
23
|
txHash: string,
|
|
24
|
+
dstTokenAddress?: string,
|
|
25
|
+
dstTokenAmount?: string,
|
|
26
26
|
): Promise<void> => {
|
|
27
27
|
const txReceipt = await getTxReceipt(txChainId, txHash);
|
|
28
|
-
|
|
29
28
|
const supportedChains: Chain[] = (await getChains()).filter(
|
|
30
29
|
({ web3Environment, swapSupported }) =>
|
|
31
30
|
web3Environment === Web3Environment.MAINNET && swapSupported,
|
|
@@ -50,6 +49,9 @@ export const renderTxStatus = async (
|
|
|
50
49
|
`No transaction event arguments found for chain ${txChainId} tx ${txHash}`,
|
|
51
50
|
);
|
|
52
51
|
}
|
|
52
|
+
|
|
53
|
+
const MessageSentEventArgs = decodedMessageSentEvent.args;
|
|
54
|
+
|
|
53
55
|
const srcChain = supportedChains.find(
|
|
54
56
|
(chain) => chain.chainId === txChainId.toString(),
|
|
55
57
|
);
|
|
@@ -57,20 +59,20 @@ export const renderTxStatus = async (
|
|
|
57
59
|
throw new Error(`Unknown src chain ${txChainId}`);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
const
|
|
62
|
+
const srcTokenAddress = MessageSentEventArgs?.token.toString().toLowerCase();
|
|
61
63
|
|
|
62
64
|
let srcToken = srcChain.tokens.find(
|
|
63
|
-
(token) => token.address ===
|
|
65
|
+
(token) => token.address === srcTokenAddress,
|
|
64
66
|
);
|
|
65
67
|
|
|
66
68
|
if (!srcToken) {
|
|
67
|
-
srcToken = await getCustomTokenData(srcChain,
|
|
69
|
+
srcToken = await getCustomTokenData(srcChain, srcTokenAddress);
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
const dstChain = supportedChains.find(
|
|
71
73
|
(chain) =>
|
|
72
74
|
chain.ccipChainId ===
|
|
73
|
-
|
|
75
|
+
MessageSentEventArgs?.destinationChainSelector?.toString(),
|
|
74
76
|
);
|
|
75
77
|
|
|
76
78
|
const dstChainId = dstChain?.chainId;
|
|
@@ -79,26 +81,36 @@ export const renderTxStatus = async (
|
|
|
79
81
|
throw new Error(`Unknown destination chain!`);
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
let dstToken: Token | undefined = undefined;
|
|
85
|
+
if (dstTokenAddress) {
|
|
86
|
+
dstToken = dstChain.tokens.find(
|
|
87
|
+
(token) => token.address === dstTokenAddress.toLowerCase(),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
87
90
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
const timestamp = Date.now() / 1000;
|
|
92
|
+
const transaction: Transaction = {
|
|
93
|
+
hash: txReceipt.transactionHash,
|
|
94
|
+
timestamp,
|
|
95
|
+
sourceChainId: srcChain.chainId,
|
|
96
|
+
targetChainId: dstChain.chainId,
|
|
97
|
+
amountWei: MessageSentEventArgs?.tokenAmount.toString(),
|
|
98
|
+
tokenAddress: srcToken.address,
|
|
99
|
+
tokenOutAddress: dstToken?.address,
|
|
100
|
+
tokenOutAmount: dstTokenAmount,
|
|
101
|
+
estimatedDeliveryTimestamp:
|
|
102
|
+
MessageSentEventArgs?.valueForInstantCcipRecieve.toString() !== "0"
|
|
103
|
+
? timestamp * 1000 + 30 * 1000
|
|
104
|
+
: timestamp * 1000 + 30 * 60 * 1000,
|
|
105
|
+
status: "IN_PROGRESS",
|
|
99
106
|
};
|
|
100
107
|
|
|
101
|
-
addTransactionToRenderedTransactions(
|
|
108
|
+
addTransactionToRenderedTransactions({
|
|
109
|
+
transaction,
|
|
110
|
+
supportedChains,
|
|
111
|
+
dstToken,
|
|
112
|
+
srcToken,
|
|
113
|
+
});
|
|
102
114
|
renderTxStatusButtons();
|
|
103
115
|
|
|
104
116
|
const xSwapRouterOnDestinationAddress = ADDRESSES[dstChainId]?.XSwapRouter;
|
|
@@ -134,20 +146,20 @@ export const renderTxStatus = async (
|
|
|
134
146
|
getTxStatus({ transferId: messageId }).then((response) => {
|
|
135
147
|
if (response.status === "DONE") {
|
|
136
148
|
onSuccess();
|
|
149
|
+
} else {
|
|
150
|
+
setTimeout(
|
|
151
|
+
() =>
|
|
152
|
+
getTxStatus({ transferId: messageId }).then((response) => {
|
|
153
|
+
if (response.status === "DONE") {
|
|
154
|
+
onSuccess();
|
|
155
|
+
}
|
|
156
|
+
}),
|
|
157
|
+
30 * 60 * 1000,
|
|
158
|
+
); // additional check after 30 min
|
|
159
|
+
|
|
160
|
+
xSwapRouterOnDestination.once(msgReceivedEventFilter, () => onSuccess());
|
|
137
161
|
}
|
|
138
162
|
});
|
|
139
|
-
|
|
140
|
-
setTimeout(
|
|
141
|
-
() =>
|
|
142
|
-
getTxStatus({ transferId: messageId }).then((response) => {
|
|
143
|
-
if (response.status === "DONE") {
|
|
144
|
-
onSuccess();
|
|
145
|
-
}
|
|
146
|
-
}),
|
|
147
|
-
30 * 60 * 1000,
|
|
148
|
-
); // additional check after 30 min
|
|
149
|
-
|
|
150
|
-
xSwapRouterOnDestination.once(msgReceivedEventFilter, () => onSuccess());
|
|
151
163
|
};
|
|
152
164
|
|
|
153
165
|
const getTxReceipt = async (txChainId: string, txHash: string) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Chain,
|
|
3
|
-
|
|
3
|
+
ModalIntegrationPayload,
|
|
4
4
|
Transactions,
|
|
5
5
|
Web3Environment,
|
|
6
6
|
} from "@src/models";
|
|
@@ -12,27 +12,38 @@ export const openTransactionModal = async ({
|
|
|
12
12
|
integratorId,
|
|
13
13
|
dstChain,
|
|
14
14
|
dstToken,
|
|
15
|
+
srcChain,
|
|
16
|
+
srcToken,
|
|
15
17
|
customContractCalls = [],
|
|
16
18
|
desc,
|
|
17
19
|
returnTransactions,
|
|
18
20
|
dstDisplayToken,
|
|
19
|
-
}:
|
|
21
|
+
}: ModalIntegrationPayload): Promise<Transactions | undefined> => {
|
|
20
22
|
const supportedChains: Chain[] = (await getChains()).filter(
|
|
21
23
|
({ web3Environment, swapSupported }) =>
|
|
22
24
|
web3Environment === Web3Environment.MAINNET && swapSupported,
|
|
23
25
|
);
|
|
24
26
|
|
|
25
|
-
validateSwapTxData(
|
|
27
|
+
validateSwapTxData(
|
|
28
|
+
integratorId,
|
|
29
|
+
supportedChains,
|
|
30
|
+
dstChain,
|
|
31
|
+
dstToken,
|
|
32
|
+
srcChain,
|
|
33
|
+
srcToken,
|
|
34
|
+
);
|
|
26
35
|
|
|
27
36
|
const route = await openTxConfigForm({
|
|
28
37
|
integratorId,
|
|
29
38
|
dstChainId: dstChain,
|
|
30
39
|
dstTokenAddr: dstToken,
|
|
40
|
+
srcChainId: srcChain,
|
|
41
|
+
srcTokenAddr: srcToken,
|
|
31
42
|
customContractCalls,
|
|
32
43
|
desc,
|
|
33
|
-
supportedChains,
|
|
34
44
|
returnTransactions,
|
|
35
45
|
dstDisplayTokenAddr: dstDisplayToken,
|
|
46
|
+
supportedChains,
|
|
36
47
|
});
|
|
37
48
|
|
|
38
49
|
if (returnTransactions) {
|
|
@@ -41,20 +52,53 @@ export const openTransactionModal = async ({
|
|
|
41
52
|
};
|
|
42
53
|
|
|
43
54
|
const validateSwapTxData = (
|
|
55
|
+
integratorId: string,
|
|
44
56
|
supportedChains: Chain[],
|
|
45
57
|
dstChain: string,
|
|
46
58
|
dstToken: string,
|
|
59
|
+
srcChain?: string,
|
|
60
|
+
srcToken?: string,
|
|
47
61
|
) => {
|
|
62
|
+
if (!integratorId) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"Provide integratorId or contact the team to generate one.",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
48
68
|
const supportedDstChain = supportedChains.find(
|
|
49
69
|
({ chainId }) => chainId === dstChain,
|
|
50
70
|
);
|
|
51
71
|
if (!supportedDstChain) {
|
|
52
72
|
throw new Error(`Provided chain '${dstChain}' is not supported`);
|
|
53
73
|
}
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
if (
|
|
75
|
+
!isETHAddressValid(dstToken) ||
|
|
76
|
+
supportedDstChain.tokens.findIndex(
|
|
77
|
+
({ address }) => address === dstToken,
|
|
78
|
+
) === -1
|
|
79
|
+
) {
|
|
56
80
|
throw new Error(
|
|
57
81
|
`Provided token address ${dstToken} on chain ${dstChain} is invalid`,
|
|
58
82
|
);
|
|
59
83
|
}
|
|
84
|
+
|
|
85
|
+
if (srcChain) {
|
|
86
|
+
const supportedSrcChain = supportedChains.find(
|
|
87
|
+
({ chainId }) => chainId === srcChain,
|
|
88
|
+
);
|
|
89
|
+
if (!supportedSrcChain) {
|
|
90
|
+
throw new Error(`Provided chain '${srcChain}' is not supported`);
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
srcToken &&
|
|
94
|
+
(!isETHAddressValid(dstToken) ||
|
|
95
|
+
supportedSrcChain.tokens.findIndex(
|
|
96
|
+
({ address }) => address === srcToken,
|
|
97
|
+
) === -1)
|
|
98
|
+
) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Provided token address ${srcToken} on chain ${srcChain} is invalid`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
60
104
|
};
|
package/src/utils/contracts.ts
CHANGED
|
@@ -175,3 +175,32 @@ export const findPlaceholderIndex = (
|
|
|
175
175
|
|
|
176
176
|
return result;
|
|
177
177
|
};
|
|
178
|
+
|
|
179
|
+
export const getEventsFromReceipt = async (
|
|
180
|
+
receipt: ethers.providers.TransactionReceipt,
|
|
181
|
+
abi: ethers.ContractInterface,
|
|
182
|
+
rpcUrl: string,
|
|
183
|
+
eventName: string,
|
|
184
|
+
) => {
|
|
185
|
+
const contract = new ethers.Contract(
|
|
186
|
+
receipt.to,
|
|
187
|
+
abi,
|
|
188
|
+
ethers.getDefaultProvider(rpcUrl),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const eventSignature = contract.interface.getEvent(eventName).format();
|
|
192
|
+
|
|
193
|
+
return receipt.logs
|
|
194
|
+
.filter((log) => log.topics[0] === ethers.utils.id(eventSignature))
|
|
195
|
+
.map((log) => contract.interface.parseLog(log));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export const trimTxHash = (hash: string, beginAndEndCharacters: number = 5) => {
|
|
199
|
+
if (!hash) {
|
|
200
|
+
return "";
|
|
201
|
+
}
|
|
202
|
+
return `${hash?.substring(0, beginAndEndCharacters)}...${hash.substring(
|
|
203
|
+
hash.length - beginAndEndCharacters,
|
|
204
|
+
hash.length,
|
|
205
|
+
)}`;
|
|
206
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./contracts";
|
|
2
2
|
export * from "./numbers";
|
|
3
|
-
export * from "./strings";
|
|
4
3
|
export * from "./parseWeb3Error";
|
|
4
|
+
export * from "./strings";
|
|
5
5
|
|
|
6
6
|
import { format } from "date-fns";
|
|
7
7
|
|
|
@@ -27,9 +27,9 @@ export const deepMergeObjects = (
|
|
|
27
27
|
obj2: Record<string, any>,
|
|
28
28
|
) => {
|
|
29
29
|
for (const key in obj2) {
|
|
30
|
-
if (
|
|
30
|
+
if (Object.prototype.hasOwnProperty.call(obj2, key)) {
|
|
31
31
|
if (
|
|
32
|
-
|
|
32
|
+
Object.prototype.hasOwnProperty.call(obj1, key) &&
|
|
33
33
|
typeof obj1[key] === "object" &&
|
|
34
34
|
typeof obj2[key] === "object"
|
|
35
35
|
) {
|
package/src/utils/numbers.ts
CHANGED
|
@@ -30,6 +30,20 @@ export const weiToHumanReadable = ({
|
|
|
30
30
|
return res;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
export const humanReadableToWei = ({
|
|
34
|
+
amount,
|
|
35
|
+
decimals,
|
|
36
|
+
}: {
|
|
37
|
+
amount: string;
|
|
38
|
+
decimals: number;
|
|
39
|
+
}): string => {
|
|
40
|
+
const decimalsFactor = Math.pow(10, decimals);
|
|
41
|
+
const parsedAmount = new BigNumberJS(amount || "0");
|
|
42
|
+
return safeBigNumberFrom(
|
|
43
|
+
parsedAmount.mul(decimalsFactor).toFixed(),
|
|
44
|
+
).toString();
|
|
45
|
+
};
|
|
46
|
+
|
|
33
47
|
export const generateRandomBigNumber = (length: number) => {
|
|
34
48
|
return BigNumber.from(utils.randomBytes(length));
|
|
35
49
|
};
|