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
22 changes: 21 additions & 1 deletion allowListManagerFaucet/frontend/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
import { SignClientTypes } from "@walletconnect/types";
import { BrowserWalletConnector, WalletConnectConnector } from '@concordium/wallet-connectors';
import { ephemeralConnectorType } from '@concordium/react-components';

export const REGISTRY_CONTRACT_REGISTRY_METADATA_RETURN_VALUE_SCHEMA =
'FAADAAAADwAAAGlzc3Vlcl9tZXRhZGF0YRQAAgAAAAMAAAB1cmwWAQQAAABoYXNoFQIAAAAEAAAATm9uZQIEAAAAU29tZQEBAAAAHiAAAAAPAAAAY3JlZGVudGlhbF90eXBlFAABAAAADwAAAGNyZWRlbnRpYWxfdHlwZRYAEQAAAGNyZWRlbnRpYWxfc2NoZW1hFAABAAAACgAAAHNjaGVtYV9yZWYUAAIAAAADAAAAdXJsFgEEAAAAaGFzaBUCAAAABAAAAE5vbmUCBAAAAFNvbWUBAQAAAB4gAAAA';

const WALLET_CONNECT_PROJECT_ID = '76324905a70fe5c388bab46d3e0564dc';

const WALLET_CONNECT_OPTS: SignClientTypes.Options = {
projectId: WALLET_CONNECT_PROJECT_ID,
relayUrl: 'wss://relay.walletconnect.com',
metadata: {
name: 'Token Distribution dApp',
description: 'Compliance token distribution using Concordium ID',
url: typeof window !== 'undefined' ? window.location.origin : 'https://localhost:5173',
icons: ['https://walletconnect.com/walletconnect-logo.png'],
},
};

export const BROWSER_WALLET = ephemeralConnectorType(BrowserWalletConnector.create);

export const VERIFIER_URL = 'http://localhost:8080';
export const WALLET_CONNECT = ephemeralConnectorType(
WalletConnectConnector.create.bind(undefined, WALLET_CONNECT_OPTS)
);
1,787 changes: 798 additions & 989 deletions allowListManagerFaucet/frontend/package-lock.json

Large diffs are not rendered by default.

11 changes: 4 additions & 7 deletions allowListManagerFaucet/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
"license": "Apache-2.0",
"version": "0.1.0",
"dependencies": {
"@concordium/browser-wallet-api-helpers": "3.0.1",
"@concordium/web-sdk": "10.0.0.alpha.4",
"@concordium/react-components": "^0.6.1",
"@concordium/wallet-connectors": "^0.6.1",
"@concordium/web-sdk": "^11.0.0",
"@protobuf-ts/grpcweb-transport": "^2.9.1",
"@walletconnect/qrcode-modal": "^1.8.0",
"@walletconnect/sign-client": "^2.1.5",
"@walletconnect/types": "^2.1.5",
"buffer": "^6.0.3",
"json-bigint": "^1.0.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-select": "^5.7.0"
Expand All @@ -31,4 +28,4 @@
"build": "vite build",
"preview": "vite preview"
}
}
}
13 changes: 13 additions & 0 deletions allowListManagerFaucet/frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { WithWalletConnector, Network, TESTNET } from '@concordium/react-components';
import AllowListDApp from './components/AllowListDApp';

export default function App() {
let NETWORK: Network;
NETWORK = TESTNET;

return (
<WithWalletConnector network={NETWORK}>
{(props) => <AllowListDApp {...props} />}
</WithWalletConnector>
);
}
157 changes: 91 additions & 66 deletions allowListManagerFaucet/frontend/src/components/AllowListDApp.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState, MouseEventHandler } from 'react';
import { useEffect, useState } from 'react';
import {
CredentialStatements,
AtomicStatementV2,
Expand All @@ -7,7 +7,13 @@ import {
VerifiablePresentation,
HexString,
} from '@concordium/web-sdk';
import { BrowserWalletProvider, WalletProvider } from '../services/wallet-connection';
import {
useConnection,
useConnect,
WalletConnectionProps,
TESTNET,
} from '@concordium/react-components';
import { BROWSER_WALLET, WALLET_CONNECT } from '../../constants';
import { Buffer } from 'buffer';

declare global {
Expand All @@ -24,9 +30,16 @@ const TOKEN_ID = window.runtimeConfig?.TOKEN_ID || 'EUDemo';
const BACKEND_URL = window.runtimeConfig?.BACKEND_URL || 'http://localhost:3001';
const VERIFIER_URL = window.runtimeConfig?.VERIFIER_URL || 'https://web3id-verifier.testnet.concordium.com';

export default function AllowListDApp() {
const [provider, setProvider] = useState<WalletProvider>();
const [selectedAccount, setSelectedAccount] = useState<string>();
export default function AllowListDApp(props: WalletConnectionProps) {

const { connection, setConnection, account } = useConnection(
props.connectedAccounts,
props.genesisHashes
);
const { connect, isConnecting } = useConnect(
props.activeConnector,
setConnection
);
const [proofStatus, setProofStatus] = useState<string>('');
const [isLoading, setIsLoading] = useState(false);
const [message, setMessage] = useState<string>('');
Expand All @@ -37,40 +50,18 @@ export default function AllowListDApp() {
const [balanceLoading, setBalanceLoading] = useState(false);
const [isOnAllowList, setIsOnAllowList] = useState<boolean | null>(null);
const [allowListChecking, setAllowListChecking] = useState(false);

useEffect(() => {
if (provider !== undefined) {
provider.on('accountChanged', (account) => {
setSelectedAccount(account);
// Fetch balance when account changes
if (account) {
fetchTokenBalance(account);
checkAllowListStatus(account);
} else {
setTokenBalance('');
setIsOnAllowList(null);
}
});
return () => {
provider?.disconnect?.().then(() => provider.removeAllListeners());
};
}
}, [provider]);

// Fetch token balance when account is connected
const [intentedConnectorType, setIntentedConnectorType] = useState<typeof BROWSER_WALLET | typeof WALLET_CONNECT | null>(null);

useEffect(() => {
if (selectedAccount && provider) {
fetchTokenBalance(selectedAccount);
checkAllowListStatus(selectedAccount);
if (account) {
fetchTokenBalance(account);
checkAllowListStatus(account);
} else {
setTokenBalance('');
setIsOnAllowList(null);
}
}, [selectedAccount, provider]);

const connectProvider = async (provider: WalletProvider) => {
const accounts = await provider.connect();
setProvider(provider);
setSelectedAccount(accounts?.[0]);
};

}, [account]);

const fetchTokenBalance = async (accountAddress: string) => {
if (!accountAddress) return;

Expand Down Expand Up @@ -114,7 +105,7 @@ export default function AllowListDApp() {
};

const requestCitizenshipProof = async () => {
if (!provider || !selectedAccount) {
if (!connection || !account) {
setMessage('Please connect wallet first');
return;
}
Expand Down Expand Up @@ -150,7 +141,7 @@ export default function AllowListDApp() {
// Request verifiable presentation from wallet
let proof: VerifiablePresentation;
try {
proof = await provider.requestVerifiablePresentation(challenge, credentialStatements);
proof = await connection.requestVerifiablePresentation(challenge, credentialStatements);
setCurrentProof(proof.toString());
} catch (err: any) {
if (err instanceof Error) {
Expand Down Expand Up @@ -191,21 +182,11 @@ export default function AllowListDApp() {
}
};

const handleConnectBrowser: MouseEventHandler<HTMLButtonElement> = async () => {
try {
const browserProvider = await BrowserWalletProvider.getInstance();
await connectProvider(browserProvider);
setMessage('Connected to browser wallet');
} catch (error: any) {
setMessage(`Failed to connect: ${error.message}`);
}
};

const handleDisconnect = async () => {
if (provider) {
await provider.disconnect?.();
setProvider(undefined);
setSelectedAccount(undefined);
if (connection) {
await connection.disconnect();
setConnection(undefined);
setIntentedConnectorType(null);
setTokenBalance('');
setIsOnAllowList(null);
setMessage('Disconnected from wallet');
Expand All @@ -216,8 +197,30 @@ export default function AllowListDApp() {
}
};

useEffect(() => {
console.log('=== DEBUGGING WALLET CONNECT ==='); //DEBUG LINES
console.log('Props genesisHashes:', Array.from(props.genesisHashes));
console.log('Props activeConnectorType:', props.activeConnectorType);
console.log('Props activeConnector:', props.activeConnector);
console.log('TESTNET from constants:', TESTNET);

// Auto-connect only when the active connector matches what user clicked
if (
props.activeConnector &&
!connection &&
!isConnecting &&
connect &&
intentedConnectorType &&
props.activeConnectorType === intentedConnectorType
) {
console.log('About to connect with connector:', props.activeConnector);
connect();
setIntentedConnectorType(null); // Reset after connecting
}
}, [props.activeConnector, props.activeConnectorType, connection, isConnecting, connect, intentedConnectorType]);

const startTokenDistribution = async () => {
if (!provider || !selectedAccount) {
if (!connection || !account) {
setMessage('Missing required data for token distribution');
return;
}
Expand All @@ -232,7 +235,7 @@ export default function AllowListDApp() {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userAccount: selectedAccount,
userAccount: account,
tokenId: TOKEN_ID
}),
});
Expand Down Expand Up @@ -280,8 +283,8 @@ export default function AllowListDApp() {
}

setIsOnAllowList(true);
if (selectedAccount) {
setTimeout(() => fetchTokenBalance(selectedAccount), 2000);
if (account) {
setTimeout(() => fetchTokenBalance(account), 2000);
}
return;
} else if (status.status === 'failed') {
Expand Down Expand Up @@ -329,7 +332,7 @@ export default function AllowListDApp() {
};

const getButtonState = () => {
if (!provider || isLoading) {
if (!connection || isLoading) {
return { disabled: true, text: isLoading ? 'Processing...' : `Verify EU Nationality & Get ${TOKEN_ID}` };
}

Expand Down Expand Up @@ -377,13 +380,35 @@ export default function AllowListDApp() {
<div className="d-grid gap-3">
<button
className="btn btn-outline-dark py-3"
onClick={handleConnectBrowser}
disabled={provider !== undefined}
onClick={() => {
setIntentedConnectorType(BROWSER_WALLET);
props.setActiveConnectorType(BROWSER_WALLET);
}}
disabled={connection !== undefined}
>
<i className="bi bi-laptop me-2"></i>Browser Wallet
</button>
<button
className="btn btn-outline-primary py-3"
onClick={() => {
setIntentedConnectorType(WALLET_CONNECT);
props.setActiveConnectorType(WALLET_CONNECT);
}}
disabled={connection !== undefined || isConnecting}
>
{isConnecting ? (
<>
<span className="spinner-border spinner-border-sm me-2" role="status"></span>
Connecting...
</>
) : (
<>
<i className="bi bi-phone me-2"></i>Mobile Wallet (WalletConnect)
</>
)}
</button>
</div>
{provider && selectedAccount && (
{connection && account && (
<div className="mt-4">
<div className="alert alert-success border-0">
<div className="d-flex align-items-center">
Expand All @@ -392,7 +417,7 @@ export default function AllowListDApp() {
<strong>Connected</strong>
<div className="mt-1">
<code className="text-success" style={{ fontSize: '0.85rem' }}>
{selectedAccount}
{account}
</code>
</div>
</div>
Expand Down Expand Up @@ -432,8 +457,8 @@ export default function AllowListDApp() {
</div>
<button
className="btn btn-sm btn-outline-secondary"
onClick={() => selectedAccount && checkAllowListStatus(selectedAccount)}
disabled={allowListChecking || !selectedAccount}
onClick={() => account && checkAllowListStatus(account)}
disabled={allowListChecking || !account}
>
<i className="bi bi-arrow-clockwise"></i>
</button>
Expand Down Expand Up @@ -473,8 +498,8 @@ export default function AllowListDApp() {
</div>
<button
className="btn btn-sm btn-outline-secondary"
onClick={() => selectedAccount && fetchTokenBalance(selectedAccount)}
disabled={balanceLoading || !selectedAccount}
onClick={() => account && fetchTokenBalance(account)}
disabled={balanceLoading || !account}
>
<i className="bi bi-arrow-clockwise"></i>
</button>
Expand Down
4 changes: 2 additions & 2 deletions allowListManagerFaucet/frontend/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createRoot } from 'react-dom/client';
import AllowListDApp from './components/AllowListDApp';
import App from './App';

const container = document.getElementById('root');

Expand All @@ -8,4 +8,4 @@ if (!container) {
}

const root = createRoot(container);
root.render(<AllowListDApp />);
root.render(<App />);
Loading
Loading