Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion campaign-launcher/client/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ VITE_APP_RECORDING_ORACLE_ADDRESS=replace-me
VITE_APP_REPUTATION_ORACLE_ADDRESS=replace-me

VITE_APP_DOCS_URL=replace-me
VITE_APP_TERMS_URL=replace-me
VITE_APP_PRIVACY_URL=replace-me
VITE_APP_STAKING_DASHBOARD_URL=replace-me
Comment thread
flopez7 marked this conversation as resolved.

# Social Media Links
Expand All @@ -16,4 +18,4 @@ VITE_FOOTER_LINK_GITHUB="replace-me-if-needed"
VITE_FOOTER_LINK_LINKEDIN="replace-me-if-needed"
VITE_FOOTER_LINK_TELEGRAM="replace-me-if-needed"
VITE_FOOTER_LINK_X="replace-me-if-needed"
VITE_REQUEST_EXCHANGE_FORM_URL="replace-me-if-needed"
VITE_REQUEST_EXCHANGE_FORM_URL="replace-me-if-needed"
5 changes: 3 additions & 2 deletions campaign-launcher/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@
"@emotion/styled": "^11.11.5",
"@hookform/resolvers": "^5.2.2",
"@human-protocol/sdk": "^7.1.0",
"@metamask/sdk": "~0.34.0",
"@mui/icons-material": "^7.3.6",
"@mui/material": "^7.3.6",
"@mui/x-data-grid": "^8.21.0",
"@mui/x-date-pickers": "^8.21.0",
"@reown/appkit": "^1.8.19",
"@reown/appkit-adapter-wagmi": "^1.8.19",
"@tanstack/react-query": "^5.90.21",
Comment thread
flopez7 marked this conversation as resolved.
"@walletconnect/ethereum-provider": "^2.23.5",
"@wagmi/core": "^3.4.2",
"axios": "^1.13.2",
"chart.js": "^4.5.1",
"chartjs-plugin-annotation": "^3.1.0",
Expand Down
184 changes: 38 additions & 146 deletions campaign-launcher/client/src/components/ConnectWallet/index.tsx
Original file line number Diff line number Diff line change
@@ -1,166 +1,58 @@
import { type FC, useState, type MouseEvent } from 'react';
import { type FC, useEffect, useRef } from 'react';

import CloseIcon from '@mui/icons-material/Close';
import { Button, Popover, Box, Typography, IconButton } from '@mui/material';
import {
useConnect,
useConnectors,
useDisconnect,
type Connector,
} from 'wagmi';
import { Button } from '@mui/material';
import { useAppKit } from '@reown/appkit/react';
import { useConnection } from 'wagmi';

import coinbaseSvg from '@/assets/coinbase.svg';
import metaMaskSvg from '@/assets/metamask.svg';
import walletConnectSvg from '@/assets/walletconnect.svg';
import BaseModal from '@/components/modals/BaseModal';
import { useIsMobile } from '@/hooks/useBreakpoints';
import { useActiveAccount } from '@/providers/ActiveAccountProvider';
import { useWeb3Auth } from '@/providers/Web3AuthProvider';

const WALLET_ICONS: Record<string, string> = {
metaMask: metaMaskSvg,
coinbaseWalletSDK: coinbaseSvg,
walletConnect: walletConnectSvg,
};

const ConnectWallet: FC = () => {
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);

const connect = useConnect();
const connectors = useConnectors();
const { open } = useAppKit();
const { isConnecting } = useActiveAccount();
const { setShowSignInPrompt } = useWeb3Auth();
const disconnect = useDisconnect();
const { isConnected } = useConnection();
const isMobile = useIsMobile();

const handleConnect = async (connector: Connector) => {
try {
await connect.mutateAsync({ connector });
if (isMobile) {
setShowSignInPrompt(true);
}
} catch (e) {
const err = e as { message?: string; code?: number | string };
if (err.message?.includes('Connector already connected')) {
await disconnect.mutateAsync();
await handleConnect(connector);
}
} finally {
onClose();
const wasConnectedRef = useRef(isConnected);
const promptOnNextConnectRef = useRef(false);

useEffect(() => {
if (
isMobile &&
!wasConnectedRef.current &&
isConnected &&
promptOnNextConnectRef.current
) {
promptOnNextConnectRef.current = false;
setShowSignInPrompt(true);
}
};

const handleConnectWalletButtonClick = (e: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(e.currentTarget);
};
wasConnectedRef.current = isConnected;
}, [isConnected, isMobile, setShowSignInPrompt]);

const onClose = () => setAnchorEl(null);
const handleConnectWalletButtonClick = () => {
if (isMobile) {
promptOnNextConnectRef.current = true;
}

const renderContent = () => {
return (
<>
<Box
width="100%"
display="flex"
flexDirection="column"
gap={1}
mt={{ xs: 2, md: 0 }}
>
{connectors.map((connector) => (
<Button
key={connector.id}
sx={{
display: 'flex',
justifyContent: 'space-between',
px: 3,
py: 2,
bgcolor: 'rgba(255, 255, 255, 0.09)',
color: 'text.primary',
borderRadius: '4px',
}}
onClick={() => {
handleConnect(connector);
if (isMobile) {
onClose();
}
}}
>
<img
src={connector.icon ?? WALLET_ICONS[connector.id]}
alt={connector.id}
width={24}
height={24}
/>
<span>{connector.name}</span>
</Button>
))}
</Box>
<Typography color="text.primary" fontSize={11} mt={1.5}>
By connecting a wallet, you agree to HUMAN Protocol Terms of Service
and consent to its Privacy Policy.
</Typography>
</>
);
void open({ view: 'Connect' }).catch(() => {
if (isMobile) {
promptOnNextConnectRef.current = false;
}
});
};

return (
<>
<Button
variant="contained"
size={isMobile ? 'small' : 'large'}
sx={{ color: 'primary.contrast', height: isMobile ? '30px' : '42px' }}
disabled={isConnecting}
onClick={handleConnectWalletButtonClick}
>
Connect Wallet
</Button>
{isMobile ? (
<BaseModal
open={!!anchorEl}
onClose={onClose}
elevation={4}
sx={{ px: 2 }}
>
{renderContent()}
</BaseModal>
) : (
<Popover
open={!!anchorEl}
onClose={onClose}
anchorEl={anchorEl}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
slotProps={{
paper: {
elevation: 4,
sx: {
mt: 1,
backgroundColor: 'background.default',
boxShadow: '0px 0px 10px 0px rgba(255, 255, 255, 0.15)',
borderRadius: '10px',
p: 2,
width: '320px',
},
},
}}
>
<Box
display="flex"
alignItems="center"
justifyContent="flex-end"
mb={2}
>
<IconButton
sx={{ padding: 1, '&:hover': { bgcolor: 'unset' } }}
onClick={() => setAnchorEl(null)}
>
<CloseIcon sx={{ color: 'primary.main' }} />
</IconButton>
</Box>
{renderContent()}
</Popover>
)}
</>
<Button
variant="contained"
size={isMobile ? 'small' : 'large'}
sx={{ color: 'primary.contrast', height: isMobile ? '30px' : '42px' }}
disabled={isConnecting}
onClick={handleConnectWalletButtonClick}
>
Connect Wallet
</Button>
);
};

Expand Down
111 changes: 71 additions & 40 deletions campaign-launcher/client/src/providers/WagmiProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,82 @@
import type { FC, PropsWithChildren } from 'react';

import { ChainId } from '@human-protocol/sdk';
import { http, createConfig, WagmiProvider as WWagmiProvider } from 'wagmi';
import type { AppKitNetwork } from '@reown/appkit/networks';
import {
localhost as defaultLocalhost,
defineChain,
mainnet,
localhost,
polygon,
polygonAmoy,
sepolia,
} from 'wagmi/chains';
import { walletConnect, coinbaseWallet } from 'wagmi/connectors';
} from '@reown/appkit/networks';
import { AppKitProvider } from '@reown/appkit/react';
import { WagmiAdapter } from '@reown/appkit-adapter-wagmi';
import type { ConnectMethod } from '@reown/appkit-controllers';
import { http, WagmiProvider as WWagmiProvider } from 'wagmi';

import logo from '@/assets/logo.svg';
import { isMainnet } from '@/constants';

const projectId = import.meta.env.VITE_APP_WALLETCONNECT_PROJECT_ID;
const termsUrl = import.meta.env.VITE_APP_TERMS_URL;
const privacyUrl = import.meta.env.VITE_APP_PRIVACY_URL;

const localhost = defineChain({
...defaultLocalhost,
id: ChainId.LOCALHOST,
chainNamespace: 'eip155',
caipNetworkId: `eip155:${ChainId.LOCALHOST}`,
});

const mainnetNetworks: [AppKitNetwork, AppKitNetwork] = [polygon, mainnet];
const testnetNetworks: [AppKitNetwork, AppKitNetwork, AppKitNetwork] = [
polygonAmoy,
sepolia,
localhost,
];

export const config = isMainnet
? createConfig({
chains: [polygon, mainnet],
connectors: [
walletConnect({ projectId }),
coinbaseWallet({ appName: 'HuFi' }),
],
syncConnectedChain: false,
transports: {
[polygon.id]: http(),
[mainnet.id]: http(),
},
})
: createConfig({
chains: [
polygonAmoy,
sepolia,
{
...localhost,
id: ChainId.LOCALHOST,
},
],
connectors: [
walletConnect({ projectId }),
coinbaseWallet({ appName: 'HuFi' }),
],
syncConnectedChain: false,
transports: {
[polygonAmoy.id]: http(),
[sepolia.id]: http(),
[ChainId.LOCALHOST]: http(),
},
});
const networks = isMainnet ? mainnetNetworks : testnetNetworks;

const wagmiAdapter = new WagmiAdapter({
networks,
projectId,
syncConnectedChain: false,
transports: {
[polygon.id]: http(),
[mainnet.id]: http(),
[polygonAmoy.id]: http(),
[sepolia.id]: http(),
[ChainId.LOCALHOST]: http(),
},
});

export const config = wagmiAdapter.wagmiConfig;

const metadata = {
name: 'HuFi',
description: 'HuFi Campaign Launcher',
url: window.location.origin,
icons: [logo],
};

const appKitConfig = {
adapters: [wagmiAdapter],
networks,
projectId,
metadata,
termsConditionsUrl: termsUrl,
privacyPolicyUrl: privacyUrl,
features: {
Comment thread
dnechay marked this conversation as resolved.
email: false,
socials: false as const,
history: false,
swaps: false,
onramp: false,
send: false,
connectMethodsOrder: ['wallet'] as ConnectMethod[],
},
};

const WagmiProvider: FC<PropsWithChildren> = ({ children }) => {
const initialState = {
Expand All @@ -58,9 +87,11 @@ const WagmiProvider: FC<PropsWithChildren> = ({ children }) => {
};

return (
<WWagmiProvider config={config} initialState={initialState}>
{children}
</WWagmiProvider>
<AppKitProvider {...appKitConfig}>
<WWagmiProvider config={config} initialState={initialState}>
{children}
</WWagmiProvider>
</AppKitProvider>
);
};

Expand Down
Loading