diff --git a/apps/cli/src/commands/licenses/generate-revenue-report.ts b/apps/cli/src/commands/licenses/generate-revenue-report.ts new file mode 100644 index 000000000..f0fcbd9de --- /dev/null +++ b/apps/cli/src/commands/licenses/generate-revenue-report.ts @@ -0,0 +1,15 @@ +import Vorpal from "vorpal"; +import { generateRevenueReport as generateRevenueReportCore } from "@sentry/core"; + +/** + * Function to generate the revenue report. + * @param cli - Vorpal instance + */ +export function generateRevenueReport(cli: Vorpal) { + cli + .command('generate-revenue-report', 'Generates the revenue report.') + .action(async function (this: Vorpal.CommandInstance) { + this.log(`Generating revenue report...`); + await generateRevenueReportCore(); + }); +} diff --git a/apps/cli/src/commands/operator-control/operator-runtime.ts b/apps/cli/src/commands/operator-control/operator-runtime.ts index 831bd64b4..3eacb2a3b 100644 --- a/apps/cli/src/commands/operator-control/operator-runtime.ts +++ b/apps/cli/src/commands/operator-control/operator-runtime.ts @@ -1,5 +1,5 @@ import Vorpal from "vorpal"; -import { getSignerFromPrivateKey, operatorRuntime } from "@sentry/core"; +import { getSignerFromPrivateKey, operatorRuntime, listOwnersForOperator } from "@sentry/core"; /** * Starts a runtime of the operator. @@ -17,6 +17,7 @@ export function bootOperator(cli: Vorpal) { message: 'Enter the private key of the operator:', mask: '*' }; + const { walletKey } = await this.prompt(walletKeyPrompt); if (!walletKey || walletKey.length < 1) { @@ -25,10 +26,45 @@ export function bootOperator(cli: Vorpal) { const { signer } = getSignerFromPrivateKey(walletKey); + const whitelistPrompt: Vorpal.PromptObject = { + type: 'confirm', + name: 'useWhitelist', + message: 'Do you want to use a whitelist for the operator runtime?', + default: false + }; + + const { useWhitelist } = await this.prompt(whitelistPrompt); + + // If useWhitelist is false, selectedOwners will be undefined + let selectedOwners; + if (useWhitelist) { + + const operatorAddress = await signer.getAddress(); + const owners = await listOwnersForOperator(operatorAddress); + + const ownerPrompt: Vorpal.PromptObject = { + type: 'checkbox', + name: 'selectedOwners', + message: 'Select the owners for the operator to run for:', + choices: [operatorAddress, ...owners] + }; + + const result = await this.prompt(ownerPrompt); + selectedOwners = result.selectedOwners; + + console.log("selectedOwners", selectedOwners); + + if (!selectedOwners || selectedOwners.length < 1) { + throw new Error("No owners selected. Please select at least one owner.") + } + } + + stopFunction = await operatorRuntime( signer, undefined, - (log) => this.log(log) + (log) => this.log(log), + selectedOwners, ); return new Promise((resolve, reject) => { }); // Keep the command alive diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index 03c1f8946..cffb1a46a 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -42,6 +42,7 @@ import { setOrAddPricingTiersCommand } from './commands/licenses/set-or-add-pric import { addPromoCode } from './commands/licenses/add-promo-code.js'; import { removePromoCode } from './commands/licenses/remove-promo-code.js'; import { eventListener } from './commands/event-listener.js'; +import { generateRevenueReport } from './commands/licenses/generate-revenue-report.js'; const cli = new Vorpal(); @@ -89,6 +90,7 @@ setReferralDiscountAndRewardPercentages(cli); setRollupAddress(cli); toggleAssertionChecking(cli); totalSupply(cli); +generateRevenueReport(cli); cli .delimiter('sentry-node$') diff --git a/apps/sentry-client-desktop/src/components/AssignKeysFromNewWallet.tsx b/apps/sentry-client-desktop/src/components/AssignKeysFromNewWallet.tsx index 8017f8884..9fd60ed23 100644 --- a/apps/sentry-client-desktop/src/components/AssignKeysFromNewWallet.tsx +++ b/apps/sentry-client-desktop/src/components/AssignKeysFromNewWallet.tsx @@ -4,6 +4,7 @@ import {useSetAtom} from "jotai"; import {AiFillWarning} from "react-icons/ai"; import {useOperator} from "@/features/operator"; import {modalStateAtom, ModalView} from "@/features/modal/ModalManager"; +import {XaiButton} from "@sentry/ui"; export function AssignKeysFromNewWallet() { const setDrawerState = useSetAtom(drawerStateAtom); @@ -25,14 +26,14 @@ export function AssignKeysFromNewWallet() { Add wallets to assign keys to the Sentry

- +

Don't own any keys? diff --git a/apps/sentry-client-desktop/src/features/drawer/DrawerManager.tsx b/apps/sentry-client-desktop/src/features/drawer/DrawerManager.tsx index de7879a16..83bd2a641 100644 --- a/apps/sentry-client-desktop/src/features/drawer/DrawerManager.tsx +++ b/apps/sentry-client-desktop/src/features/drawer/DrawerManager.tsx @@ -6,12 +6,14 @@ import {ViewKeysDrawer} from "../home/modals/view-keys/ViewKeysDrawer"; import {ActionsRequiredNotAccruingDrawer} from "../home/modals/actions-required/ActionsRequiredNotAccruingDrawer"; import {ExportSentryDrawer} from "../home/modals/ExportSentryDrawer"; import {ImportSentryDrawer} from "../home/modals/ImportSentryDrawer"; +import {WhitelistDrawer} from "@/features/drawer/WhitelistDrawer"; export enum DrawerView { ActionsRequiredBuy, ActionsRequiredNotAccruing, BuyKeys, ViewKeys, + Whitelist, ImportSentry, ExportSentry, } @@ -23,7 +25,7 @@ export function DrawerManager() { return (

@@ -43,6 +45,10 @@ export function DrawerManager() { )} + {drawerState === DrawerView.Whitelist && ( + + )} + {drawerState === DrawerView.ImportSentry && ( )} diff --git a/apps/sentry-client-desktop/src/features/drawer/WhitelistDrawer.tsx b/apps/sentry-client-desktop/src/features/drawer/WhitelistDrawer.tsx new file mode 100644 index 000000000..efdbe6054 --- /dev/null +++ b/apps/sentry-client-desktop/src/features/drawer/WhitelistDrawer.tsx @@ -0,0 +1,145 @@ +import {useAtomValue, useSetAtom} from "jotai"; +import {drawerStateAtom} from "@/features/drawer/DrawerManager"; +import {chainStateAtom} from "@/hooks/useChainDataWithCallback"; +import {XaiCheckbox} from "@sentry/ui"; +import {useEffect, useState} from "react"; +import {useStorage} from "@/features/storage"; +import {useOperatorRuntime} from "@/hooks/useOperatorRuntime"; +import {useOperator} from "@/features/operator"; + +export function WhitelistDrawer() { + const setDrawerState = useSetAtom(drawerStateAtom); + const {owners} = useAtomValue(chainStateAtom); + const {data, setData} = useStorage(); + const [selected, setSelected] = useState([]); + const {sentryRunning, stopRuntime} = useOperatorRuntime(); + const {publicKey: operatorAddress} = useOperator(); + + const disableButton = selected.length <= 0 || !stopRuntime; + + useEffect(() => { + if (data && data.whitelistedWallets) { + setSelected(data.whitelistedWallets); + } + }, []); + + const toggleSelected = (wallet: string) => { + setSelected((prevSelected) => prevSelected.includes(wallet) + ? prevSelected.filter((item) => item !== wallet) + : [...prevSelected, wallet] + ); + }; + + const getOperatorItem = () => { + if (operatorAddress) { + return ( +
+
+ toggleSelected(operatorAddress)} + condition={selected.includes(operatorAddress)} + > + {operatorAddress} + +
+
+ ) + } + } + + const getDropdownItems = () => ( +
+ {owners.map((wallet, i) => ( +
+ toggleSelected(wallet)} + condition={selected.includes(wallet)} + > + {wallet} + +
+ ))} +
+ ); + + async function handleSubmit() { + await setData({ + ...data, + whitelistedWallets: selected, + }); + + setDrawerState(null); + if (stopRuntime) { + void stopRuntime(); + } + } + + return ( +
+
+

Allowed Wallet

+
+ +
+

+ Below are the wallets assigned to your Sentry Wallet ({operatorAddress}). Select the wallets + you'd like to enable. +

+

+ Note: Gas fees will be covered using your Sentry Wallet funds whenever an enabled wallet is eligible + to participate in a challenge. +

+
+

Your Sentry Wallet

+ {getOperatorItem()} +

Assigned Wallets

+ {getDropdownItems()} +
+
+ +
+

+ Applying changes will restart your sentry +

+ +
+ + + {sentryRunning && ( + + )} +
+
+
+ ); +} + + + diff --git a/apps/sentry-client-desktop/src/features/footer/Footer.tsx b/apps/sentry-client-desktop/src/features/footer/Footer.tsx deleted file mode 100644 index e7867f75c..000000000 --- a/apps/sentry-client-desktop/src/features/footer/Footer.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import {ReactComponent as XaiLogo} from "@/svgs/xai-logo-full.svg"; -import {FaDiscord, FaTelegram} from "react-icons/fa"; -import {SiGitbook} from "react-icons/si"; -import {FaXTwitter} from "react-icons/fa6"; - -const bodyContent = { - socials: [ - { - label: "Discord", - link: "https://discord.com/invite/xaigames", - icon: , - }, - { - label: "X", - link: "https://twitter.com/xai_games", - icon: , - // icon: , - }, - { - label: "Gitbook", - link: "https://xai-foundation.gitbook.io/xai-network/xai-blockchain/sentry-node-purchase-and-setup", - icon: , - }, - { - label: "Telegram", - link: "https://t.me/XaiSentryNodes", - icon: , - }, - ], -}; - -export function Footer() { - function createSocialElement(item: any) { - function _onClickHelper() { - window.open(item.link, "_blank", "noopener noreferrer"); - } - - return ( -
-
-
- {item.icon} -
-
-
- ); - } - - return ( - - ); -} diff --git a/apps/sentry-client-desktop/src/features/home/GetSentryNode.tsx b/apps/sentry-client-desktop/src/features/home/GetSentryNode.tsx index 6fc96cd0a..e31ffc245 100644 --- a/apps/sentry-client-desktop/src/features/home/GetSentryNode.tsx +++ b/apps/sentry-client-desktop/src/features/home/GetSentryNode.tsx @@ -4,6 +4,7 @@ import {drawerStateAtom, DrawerView} from "../drawer/DrawerManager"; import {useSetAtom} from "jotai"; import {AiOutlineInfoCircle} from "react-icons/ai"; import {GetSentryNodeTooltip} from "@/features/keys/GetSentryNodeTooltip"; +import {XaiButton} from "@sentry/ui"; // import {useState} from "react"; const body = [ @@ -63,13 +64,14 @@ export function GetSentryNode() { Purchase a key to begin earning esXAI
- + +

setDrawerState(DrawerView.ViewKeys)} diff --git a/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx b/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx index ea48e6444..046e970ff 100644 --- a/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx +++ b/apps/sentry-client-desktop/src/features/home/SentryWallet.tsx @@ -24,6 +24,7 @@ import {chainStateAtom, useChainDataRefresh} from "@/hooks/useChainDataWithCallb import {accruingStateAtom} from "@/hooks/useAccruingInfo"; import {AssignKeysSentryNotRunning} from "@/components/AssignKeysSentryNotRunning"; import {GrRefresh} from "react-icons/gr"; +import {LuListChecks} from "react-icons/lu"; // TODO -> replace with dynamic value later export const recommendedFundingBalance = ethers.parseEther("0.005"); @@ -32,11 +33,9 @@ export function SentryWallet() { const [drawerState, setDrawerState] = useAtom(drawerStateAtom); const setModalState = useSetAtom(modalStateAtom); const {ownersLoading, owners, licensesLoading, licensesList} = useAtomValue(chainStateAtom); - const queryClient = useQueryClient(); const {hasAssignedKeys} = useAtomValue(accruingStateAtom); - const {isLoading: operatorLoading, publicKey: operatorAddress} = useOperator(); const {data: balance} = useBalance(operatorAddress); @@ -264,7 +263,9 @@ export function SentryWallet() { {sentryRunning ? ( + +

diff --git a/apps/sentry-client-desktop/src/features/home/modals/DisableBodyModal.tsx b/apps/sentry-client-desktop/src/features/home/modals/DisableBodyModal.tsx new file mode 100644 index 000000000..6493a95c9 --- /dev/null +++ b/apps/sentry-client-desktop/src/features/home/modals/DisableBodyModal.tsx @@ -0,0 +1,5 @@ +export function DisableBodyModal() { + return ( +
+ ) +} diff --git a/apps/sentry-client-desktop/src/features/home/modals/RemoveWalletModal.tsx b/apps/sentry-client-desktop/src/features/home/modals/RemoveWalletModal.tsx index d190e17c9..663693f82 100644 --- a/apps/sentry-client-desktop/src/features/home/modals/RemoveWalletModal.tsx +++ b/apps/sentry-client-desktop/src/features/home/modals/RemoveWalletModal.tsx @@ -25,7 +25,7 @@ export function RemoveWalletModal({onClose, selectedWallet, isWalletAssignedMap} if (indexToRemove !== -1) { userWallets.splice(indexToRemove, 1); } - setData({...data, addedWallets: userWallets}); + void setData({...data, addedWallets: userWallets}); setSuccess(true) setTimeout(() => { window.location.reload(); diff --git a/apps/sentry-client-desktop/src/features/home/modals/actions-required/ActionsRequiredNotAccruingDrawer.tsx b/apps/sentry-client-desktop/src/features/home/modals/actions-required/ActionsRequiredNotAccruingDrawer.tsx index 914102bbe..b8cdfa641 100644 --- a/apps/sentry-client-desktop/src/features/home/modals/actions-required/ActionsRequiredNotAccruingDrawer.tsx +++ b/apps/sentry-client-desktop/src/features/home/modals/actions-required/ActionsRequiredNotAccruingDrawer.tsx @@ -11,13 +11,13 @@ import {KycRequiredCard} from "./KycRequiredCard"; import {BarStepItem} from "@/components/BarStepItem"; import {accruingStateAtom} from "@/hooks/useAccruingInfo"; import {chainStateAtom} from "@/hooks/useChainDataWithCallback"; -import {useCombinedOwners} from "@/hooks/useCombinedOwners"; +import {useStorage} from "@/features/storage"; export function ActionsRequiredNotAccruingDrawer() { const setDrawerState = useSetAtom(drawerStateAtom); - const {owners, ownersKycMap, combinedWalletsKycMap} = useAtomValue(chainStateAtom); - const {combinedOwners} = useCombinedOwners(owners); + const {ownersKycMap} = useAtomValue(chainStateAtom); const {accruing, kycRequired} = useAtomValue(accruingStateAtom); + const {data} = useStorage(); return (
@@ -81,71 +81,60 @@ export function ActionsRequiredNotAccruingDrawer() { - + - {combinedOwners?.map((owner, i) => { - return ( - - + {kycRequired ? ( + + - - ); - })} -
-
- - {accruing && ( -
- {kycRequired ? ( - - -

- You must pass KYC within 180 days of accruing esXAI to claim accrued node rewards. - Check back in - 48 hours if all docs submitted. Check your inbox (including spam) for updates. For - KYC issues, - contact window.electron.openExternal(`https://help.blockpass.org/hc/en-us/requests/new`)} - > Blockpass. If not completed, continue submission here. -

-
- ) : ( - - -

- You have successfully completed your KYC on all wallets assigned to the Sentry. -

-
- )} - - {owners?.map((owner, i) => { - return ( - - + You must pass KYC within 180 days of accruing esXAI to claim accrued node + rewards. + Check back in + 48 hours if all docs submitted. Check your inbox (including spam) for updates. + For + KYC issues, + contact window.electron.openExternal(`https://help.blockpass.org/hc/en-us/requests/new`)} + > Blockpass. If not completed, continue submission here. +

+ + ) : ( + + -
- ); - })} +

+ You have successfully completed your KYC on all wallets assigned to the Sentry. +

+ + )} + + {data?.whitelistedWallets?.map((owner, i) => { + return ( + + + + ); + })} +
- )} + ); diff --git a/apps/sentry-client-desktop/src/features/home/modals/actions-required/AssignedKeysCard.tsx b/apps/sentry-client-desktop/src/features/home/modals/actions-required/AssignedKeysCard.tsx index 6765bff3a..c31406198 100644 --- a/apps/sentry-client-desktop/src/features/home/modals/actions-required/AssignedKeysCard.tsx +++ b/apps/sentry-client-desktop/src/features/home/modals/actions-required/AssignedKeysCard.tsx @@ -1,12 +1,13 @@ import {IconLabel} from "@/components/IconLabel"; import {SquareCard} from "@/components/SquareCard"; import {IoMdCloseCircle} from "react-icons/io"; -import {LuExternalLink} from "react-icons/lu"; import {AiFillCheckCircle} from "react-icons/ai"; import {useOperator} from "@/features/operator"; import {modalStateAtom, ModalView} from "@/features/modal/ModalManager"; import {useAtomValue, useSetAtom} from "jotai"; import {accruingStateAtom} from "@/hooks/useAccruingInfo"; +import {BiLinkExternal} from "react-icons/bi"; +import {XaiButton} from "@sentry/ui"; export function AssignedKeysCard() { const setModalState = useSetAtom(modalStateAtom); @@ -43,13 +44,14 @@ export function AssignedKeysCard() { At least one key must be assigned to accrue esXAI

- + + )} diff --git a/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx b/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx index d5c6f78cc..8509e924c 100644 --- a/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx +++ b/apps/sentry-client-desktop/src/features/keys/HasKeys.tsx @@ -46,7 +46,6 @@ export function HasKeys({combinedOwners, combinedLicensesMap, statusMap, isWalle const {data: earnedEsxaiBalance} = useGetWalletBalance(combinedOwners); const {data: singleWalletBalance} = useGetSingleWalletBalance(selectedWallet); - function startAssignment() { if (!isOperatorLoading) { setModalState(ModalView.TransactionInProgress); diff --git a/apps/sentry-client-desktop/src/features/modal/ModalManager.tsx b/apps/sentry-client-desktop/src/features/modal/ModalManager.tsx index 734be32e4..56b745807 100644 --- a/apps/sentry-client-desktop/src/features/modal/ModalManager.tsx +++ b/apps/sentry-client-desktop/src/features/modal/ModalManager.tsx @@ -1,24 +1,23 @@ import classNames from "classnames"; -import {atom, useAtom, useSetAtom} from "jotai"; -import {ExitAlertModal} from "@/features/home/modals/ExitAlertModal"; +import {atom, useAtom} from "jotai"; import {useState} from "react"; import {PurchaseCompleteModal} from "@/features/home/modals/PurchaseCompleteModal"; -import {drawerStateAtom} from "@/features/drawer/DrawerManager"; +import {drawerStateAtom, DrawerView} from "@/features/drawer/DrawerManager"; import {AssignWalletTransactionInProgressModal} from "@/features/home/modals/AssignWalletTransactionInProgressModal"; import {useNavigate} from "react-router-dom"; +import {DisableBodyModal} from "@/features/home/modals/DisableBodyModal"; export enum ModalView { - Exit, PurchaseSuccessful, TransactionInProgress, - RemoveWallet + RemoveWallet, } export const modalStateAtom = atom(null); export function ModalManager() { const [modalState, setModalState] = useAtom(modalStateAtom); - const setDrawerState = useSetAtom(drawerStateAtom); + const [drawerState, setDrawerState] = useAtom(drawerStateAtom); const [purchaseSuccessful, setPurchaseSuccessful] = useState<{ show: boolean, txHash: string }>({show: false, txHash: ""}); const navigate = useNavigate(); @@ -31,12 +30,9 @@ export function ModalManager() { }); return ( -
- {modalState === ModalView.Exit && ( - alert("wow")}/> - )} {modalState === ModalView.PurchaseSuccessful && ( )} + + {drawerState === DrawerView.Whitelist && ( + + )}
); } diff --git a/apps/sentry-client-desktop/src/features/sidebar/SidebarRoot.tsx b/apps/sentry-client-desktop/src/features/sidebar/SidebarRoot.tsx index 052046af0..eaf182cfa 100644 --- a/apps/sentry-client-desktop/src/features/sidebar/SidebarRoot.tsx +++ b/apps/sentry-client-desktop/src/features/sidebar/SidebarRoot.tsx @@ -96,11 +96,11 @@ export function Sidebar() {
-
+

v{import.meta.env.APP_VERSION}

window.open("https://xai.games/sentrynodeagreement/", "_blank", "noopener noreferrer")} + className="text-[#F30919] cursor-pointer hover:underline" + onClick={() => window.electron.openExternal("https://xai.games/sentrynodeagreement")} > Sentry Node Agreement diff --git a/apps/sentry-client-desktop/src/features/storage/useStorage.tsx b/apps/sentry-client-desktop/src/features/storage/useStorage.tsx index 82aeb6852..d075926b5 100644 --- a/apps/sentry-client-desktop/src/features/storage/useStorage.tsx +++ b/apps/sentry-client-desktop/src/features/storage/useStorage.tsx @@ -5,13 +5,14 @@ const dataAtom = atom(undefined); export type IData = Partial<{ addedWallets: string[]; + whitelistedWallets: string[]; kycStartedWallets: string[]; sentryRunning: boolean; }>; interface IUseStorageResponse { data?: IData; - setData: (data: IData) => void; + setData: (data: IData) => Promise; removeData: () => void; loading: boolean; getFilePath: () => Promise; diff --git a/apps/sentry-client-desktop/src/hooks/useChainDataWithCallback.ts b/apps/sentry-client-desktop/src/hooks/useChainDataWithCallback.ts index deb4cf221..f63295e42 100644 --- a/apps/sentry-client-desktop/src/hooks/useChainDataWithCallback.ts +++ b/apps/sentry-client-desktop/src/hooks/useChainDataWithCallback.ts @@ -53,8 +53,6 @@ export function useChainDataWithCallback() { const {isLoading: ownersKycLoading, statusMap: combinedWalletsKycMap} = useKycStatusesWithCallback(combinedOwners, chainStateRefresh); const {isLoading: licensesLoading, licensesMap: combinedLicensesMap} = useListNodeLicensesWithCallback(combinedOwners, chainStateRefresh); - console.log(combinedOwners); - // set default state useEffect(() => { setChainState(defaultChainState); diff --git a/apps/sentry-client-desktop/src/hooks/useListOwnersForOperatorWithCallback.ts b/apps/sentry-client-desktop/src/hooks/useListOwnersForOperatorWithCallback.ts index 744b12984..6a8ddb196 100644 --- a/apps/sentry-client-desktop/src/hooks/useListOwnersForOperatorWithCallback.ts +++ b/apps/sentry-client-desktop/src/hooks/useListOwnersForOperatorWithCallback.ts @@ -2,7 +2,6 @@ import {useEffect, useState} from "react"; import {listOwnersForOperator} from "@sentry/core"; export function useListOwnersForOperatorWithCallback(operatorAddress: string | undefined, initialLoadingState = false, refresh = 0) { - const [loading, setLoading] = useState(initialLoadingState); const [owners, setOwners] = useState([]); diff --git a/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts b/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts index 1c4eb1841..bb46abd36 100644 --- a/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts +++ b/apps/sentry-client-desktop/src/hooks/useOperatorRuntime.ts @@ -16,6 +16,7 @@ export function useOperatorRuntime() { const [runtimeLogs, setRuntimeLogs] = useAtom(runtimeLogsAtom); const [, setRerender] = useState(0); const {data, setData} = useStorage(); + const whitelistedWallets = data?.whitelistedWallets; // start sentry on launch / restart sentry useEffect(() => { @@ -38,10 +39,10 @@ export function useOperatorRuntime() { async function startRuntime() { if (!sentryRunning && stop === undefined) { setSentryRunning(true); - setData({...data, sentryRunning: true}); + await setData({...data, sentryRunning: true}); // @ts-ignore - stop = await operatorRuntime(signer, setNodeLicenseStatusMap, writeLog); + stop = await operatorRuntime(signer, setNodeLicenseStatusMap, writeLog, whitelistedWallets); setRerender((_number) => _number + 1); } } @@ -55,7 +56,7 @@ export function useOperatorRuntime() { await _stop(); setNodeLicenseStatusMap(new Map()); setSentryRunning(false); - setData({...data, sentryRunning: false}); + await setData({...data, sentryRunning: false}); } } diff --git a/apps/web-connect/src/features/checkout/XaiBanner.tsx b/apps/web-connect/src/features/checkout/XaiBanner.tsx index 66b3cbe31..1a2cecef3 100644 --- a/apps/web-connect/src/features/checkout/XaiBanner.tsx +++ b/apps/web-connect/src/features/checkout/XaiBanner.tsx @@ -3,10 +3,10 @@ import {MdVerifiedUser} from "react-icons/md"; export function XaiBanner() { return (
-

+

You are on the official

Xai.games

website -

+

Purchases from Xai will only ever occur on Xai.games. Check that you are on Xai.games whenever purchasing from Xai. diff --git a/apps/web-connect/src/features/checkout/hooks/useListClaimableAmount.ts b/apps/web-connect/src/features/checkout/hooks/useListClaimableAmount.ts new file mode 100644 index 000000000..be6395e6b --- /dev/null +++ b/apps/web-connect/src/features/checkout/hooks/useListClaimableAmount.ts @@ -0,0 +1,17 @@ +import {useQuery} from "react-query"; +import {listClaimableAmount} from "@sentry/core"; + +export function useListClaimableAmount(address: string | undefined) { + return useQuery({ + queryKey: ["list-claimable-amount", address], + queryFn: async () => { + const claimableAmount = await listClaimableAmount(address!); + return { + claimableAmount, + } + }, + staleTime: Infinity, + cacheTime: 0, + enabled: address != undefined && address.length > 0, + }); +} diff --git a/apps/web-connect/src/features/header/Header.tsx b/apps/web-connect/src/features/header/Header.tsx index ed13f61d3..83029bc55 100644 --- a/apps/web-connect/src/features/header/Header.tsx +++ b/apps/web-connect/src/features/header/Header.tsx @@ -5,7 +5,7 @@ export function Header() { const navigate = useNavigate(); return (

-
+
navigate("/")} diff --git a/apps/web-connect/src/features/router/AppRoutes.tsx b/apps/web-connect/src/features/router/AppRoutes.tsx index 604b33875..5595050c8 100644 --- a/apps/web-connect/src/features/router/AppRoutes.tsx +++ b/apps/web-connect/src/features/router/AppRoutes.tsx @@ -1,7 +1,6 @@ import {HashRouter as Router, Navigate, Route, Routes} from 'react-router-dom'; import {QueryClient, QueryClientProvider} from "react-query"; import {Checkout} from "../checkout"; -import {ConnectWallet} from "../wallet/routes/ConnectWallet.js"; import {AssignWallet} from "../wallet/routes/AssignWallet.js"; import {UnassignWallet} from "@/features/wallet/routes/UnassignWallet"; import {Header} from "@/features/header/Header"; @@ -9,6 +8,9 @@ import {useEffect, useState} from "react"; import axios from "axios"; import {BiLoaderAlt} from "react-icons/bi"; import {Footer} from "@/features/footer/Footer"; +import {DropClaim} from "@/features/wallet/routes/DropClaim"; +import {ClaimToken} from "@/features/wallet/routes/ClaimToken"; +import {TermsAndConditions} from "@/features/wallet/routes/TermsAndConditions"; enum IpBanType { INVALID_IP = "INVALID_IP", @@ -46,7 +48,7 @@ export function AppRoutes() { setLoading(false); } - if (!!invalidIp || !!ofacSanction) { + if (!!invalidIp || !!ofacSanction || data.country === "US") { setBlocked(true); setLoading(false); } @@ -76,9 +78,11 @@ export function AppRoutes() {
}/> - }/> }/> }/> + }/> + }/> + }/> }/>