From d9d24dfc4f33e396bb41251a9c06879c06408d68 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Mon, 18 Aug 2025 13:00:35 +0530 Subject: [PATCH] debugging --- src/contexts/AuthContext.tsx | 24 ++- src/contexts/ForumContext.tsx | 2 +- src/lib/identity/services/AuthService.ts | 18 +-- src/lib/identity/services/MessageService.ts | 4 +- src/lib/identity/signatures/key-delegation.ts | 32 ++++ .../identity/signatures/message-signing.ts | 146 ++++++++++++++++-- .../signatures/wallet-signature-verifier.ts | 138 +++++++++++++++++ .../identity/wallets/ReOwnWalletService.ts | 84 +++++++++- src/lib/waku/constants.ts | 10 +- 9 files changed, 410 insertions(+), 48 deletions(-) create mode 100644 src/lib/identity/signatures/wallet-signature-verifier.ts diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 02c80e7..66f30a1 100644 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -125,11 +125,27 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { }; const getVerificationStatus = (user: User): VerificationStatus => { + console.log(`šŸ” Checking verification status for user:`, { + address: user.address, + walletType: user.walletType, + ordinalOwnership: user.ordinalOwnership, + ensOwnership: user.ensOwnership, + ensName: user.ensName, + hasDelegation: !!user.delegationSignature, + delegationExpiry: user.delegationExpiry ? new Date(user.delegationExpiry).toISOString() : 'none' + }); + if (user.walletType === 'bitcoin') { - return user.ordinalOwnership ? 'verified-owner' : 'verified-none'; + const status = user.ordinalOwnership ? 'verified-owner' : 'verified-none'; + console.log(`šŸ“Š Bitcoin verification result:`, { status, hasOrdinal: !!user.ordinalOwnership }); + return status; } else if (user.walletType === 'ethereum') { - return user.ensOwnership ? 'verified-owner' : 'verified-none'; + const status = user.ensOwnership ? 'verified-owner' : 'verified-none'; + console.log(`šŸ“Š Ethereum verification result:`, { status, hasENS: !!user.ensOwnership, ensName: user.ensName }); + return status; } + + console.log(`šŸ“Š Default verification result: unverified`); return 'unverified'; }; @@ -303,10 +319,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { const messageSigning = { signMessage: async (message: OpchanMessage): Promise => { - return authServiceRef.current.signMessage(message); + return authServiceRef.current.messageSigning.signMessage(message); }, verifyMessage: async (message: OpchanMessage): Promise => { - return authServiceRef.current.verifyMessage(message); + return authServiceRef.current.messageSigning.verifyMessage(message); } }; diff --git a/src/contexts/ForumContext.tsx b/src/contexts/ForumContext.tsx index c62f81a..e294740 100644 --- a/src/contexts/ForumContext.tsx +++ b/src/contexts/ForumContext.tsx @@ -94,7 +94,7 @@ export function ForumProvider({ children }: { children: React.ReactNode }) { const updateStateFromCache = useCallback(() => { // Use the verifyMessage function from authService if available const verifyFn = isAuthenticated ? - (message: OpchanMessage) => authService.verifyMessage(message) : + (message: OpchanMessage) => authService.messageSigning.verifyMessage(message) : undefined; // Build user verification status for relevance calculation diff --git a/src/lib/identity/services/AuthService.ts b/src/lib/identity/services/AuthService.ts index 812f50b..f9b7259 100644 --- a/src/lib/identity/services/AuthService.ts +++ b/src/lib/identity/services/AuthService.ts @@ -15,13 +15,13 @@ export interface AuthResult { export class AuthService { private walletService: WalletService; - private ordinalApi: OrdinalAPI; - private messageSigning: MessageSigning; + private ordinalAPI: OrdinalAPI; + public messageSigning: MessageSigning; private keyDelegation: KeyDelegation; constructor() { this.walletService = new WalletService(); - this.ordinalApi = new OrdinalAPI(); + this.ordinalAPI = new OrdinalAPI(); this.keyDelegation = new KeyDelegation(); this.messageSigning = new MessageSigning(this.keyDelegation); } @@ -280,19 +280,7 @@ export class AuthService { } } - /** - * Sign a message using delegated key - */ - async signMessage(message: OpchanMessage): Promise { - return this.messageSigning.signMessage(message); - } - /** - * Verify a message signature - */ - async verifyMessage(message: OpchanMessage): Promise { - return this.messageSigning.verifyMessage(message); - } /** * Check if delegation is valid diff --git a/src/lib/identity/services/MessageService.ts b/src/lib/identity/services/MessageService.ts index b3bdba4..95a0726 100644 --- a/src/lib/identity/services/MessageService.ts +++ b/src/lib/identity/services/MessageService.ts @@ -20,7 +20,7 @@ export class MessageService { */ async signAndSendMessage(message: OpchanMessage): Promise { try { - const signedMessage = await this.authService.signMessage(message); + const signedMessage = this.authService.messageSigning.signMessage(message); if (!signedMessage) { // Check if delegation exists but is expired @@ -66,6 +66,6 @@ export class MessageService { * Verify a message signature */ async verifyMessage(message: OpchanMessage): Promise { - return this.authService.verifyMessage(message); + return this.authService.messageSigning.verifyMessage(message); } } \ No newline at end of file diff --git a/src/lib/identity/signatures/key-delegation.ts b/src/lib/identity/signatures/key-delegation.ts index 708e683..d45f921 100644 --- a/src/lib/identity/signatures/key-delegation.ts +++ b/src/lib/identity/signatures/key-delegation.ts @@ -145,17 +145,49 @@ export class KeyDelegation { // If a current address is provided, validate it matches the delegation if (currentAddress && delegation.walletAddress !== currentAddress) { + console.warn(`āš ļø Delegation address mismatch detected:`, { + storedAddress: delegation.walletAddress, + currentAddress: currentAddress, + suggestion: 'Consider clearing the delegation and creating a new one' + }); return false; } // If a current wallet type is provided, validate it matches the delegation if (currentWalletType && delegation.walletType !== currentWalletType) { + console.warn(`āš ļø Delegation wallet type mismatch detected:`, { + storedType: delegation.walletType, + currentType: currentWalletType, + suggestion: 'Consider clearing the delegation and creating a new one' + }); return false; } return true; } + /** + * Check if the current wallet address matches the stored delegation + * @param currentAddress The current wallet address to check + * @returns boolean indicating if addresses match + */ + isAddressMatch(currentAddress: string): boolean { + const delegation = this.retrieveDelegation(); + if (!delegation) return false; + + const matches = delegation.walletAddress === currentAddress; + + if (!matches) { + console.warn(`āš ļø Wallet address mismatch:`, { + storedAddress: delegation.walletAddress, + currentAddress: currentAddress, + timeRemaining: this.getDelegationTimeRemaining() + }); + } + + return matches; + } + /** * Signs a message using the browser-generated private key * @param message The message to sign diff --git a/src/lib/identity/signatures/message-signing.ts b/src/lib/identity/signatures/message-signing.ts index 25e74e5..89c1c45 100644 --- a/src/lib/identity/signatures/message-signing.ts +++ b/src/lib/identity/signatures/message-signing.ts @@ -10,13 +10,26 @@ export class MessageSigning { } signMessage(message: T): T | null { + const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; + console.log(`āœļø Starting message signing for: ${messageId}`); + if (!this.keyDelegation.isDelegationValid()) { - console.error('No valid key delegation found. Cannot sign message.'); + console.error(`āŒ No valid key delegation found. Cannot sign message: ${messageId}`); return null; } const delegation = this.keyDelegation.retrieveDelegation(); - if (!delegation) return null; + if (!delegation) { + console.error(`āŒ No delegation found. Cannot sign message: ${messageId}`); + return null; + } + + console.log(`šŸ”‘ Using delegation for signing:`, { + walletAddress: delegation.walletAddress, + walletType: delegation.walletType, + browserPubKey: delegation.browserPublicKey.slice(0, 16) + '...', + expiresAt: new Date(delegation.expiryTimestamp).toISOString() + }); const messageToSign = JSON.stringify({ ...message, @@ -27,10 +40,23 @@ export class MessageSigning { delegationExpiry: undefined }); - const signature = this.keyDelegation.signMessage(messageToSign); - if (!signature) return null; + console.log(`šŸ“ Signing message content for ${messageId}:`, { + contentLength: messageToSign.length, + messageType: message.type + }); - return { + const signature = this.keyDelegation.signMessage(messageToSign); + if (!signature) { + console.error(`āŒ Failed to sign message: ${messageId}`); + return null; + } + + console.log(`āœ… Message signed successfully for ${messageId}:`, { + signatureLength: signature.length, + signaturePrefix: signature.slice(0, 16) + '...' + }); + + const signedMessage = { ...message, signature, browserPubKey: delegation.browserPublicKey, @@ -42,6 +68,10 @@ export class MessageSigning { ), delegationExpiry: delegation.expiryTimestamp }; + + console.log(`šŸŽ‰ Message signing completed for ${messageId} with delegation chain`); + + return signedMessage; } async verifyMessage(message: OpchanMessage & { @@ -51,20 +81,42 @@ export class MessageSigning { delegationMessage?: string; delegationExpiry?: number; }): Promise { + const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; + console.log(`šŸ” Starting verification for message: ${messageId}`); + // Check for required signature fields if (!message.signature || !message.browserPubKey) { - const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; - console.warn('Message is missing signature information', messageId); + console.warn(`āŒ Message ${messageId} missing signature information:`, { + hasSignature: !!message.signature, + hasBrowserPubKey: !!message.browserPubKey + }); return false; } // Check for required delegation fields if (!message.delegationSignature || !message.delegationMessage || !message.delegationExpiry) { - const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; - console.warn('Message is missing delegation information', messageId); + console.warn(`āŒ Message ${messageId} missing delegation information:`, { + hasDelegationSignature: !!message.delegationSignature, + hasDelegationMessage: !!message.delegationMessage, + hasDelegationExpiry: !!message.delegationExpiry + }); return false; } + console.log(`āœ… Message ${messageId} has all required fields`); + + // Log delegation details for debugging + const delegation = this.keyDelegation.retrieveDelegation(); + if (delegation) { + console.log(`šŸ” Current delegation details:`, { + storedWalletAddress: delegation.walletAddress, + messageAuthorAddress: message.author, + addressesMatch: delegation.walletAddress === message.author, + walletType: delegation.walletType, + hasWalletPublicKey: !!delegation.walletPublicKey + }); + } + // 1. Verify the message signature const signedContent = JSON.stringify({ ...message, @@ -75,6 +127,8 @@ export class MessageSigning { delegationExpiry: undefined }); + console.log(`šŸ” Verifying message signature for ${messageId} with browser key: ${message.browserPubKey.slice(0, 16)}...`); + const isValidMessageSignature = this.keyDelegation.verifySignature( signedContent, message.signature, @@ -82,19 +136,31 @@ export class MessageSigning { ); if (!isValidMessageSignature) { - const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; - console.warn(`Invalid message signature for message ${messageId}`); + console.warn(`āŒ Invalid message signature for ${messageId}`); return false; } + console.log(`āœ… Message signature verified for ${messageId}`); + // 2. Verify delegation hasn't expired const now = Date.now(); + const timeUntilExpiry = message.delegationExpiry - now; + + console.log(`ā° Checking delegation expiry for ${messageId}:`, { + currentTime: new Date(now).toISOString(), + expiryTime: new Date(message.delegationExpiry).toISOString(), + timeUntilExpiry: `${Math.round(timeUntilExpiry / 1000 / 60)} minutes` + }); + if (now >= message.delegationExpiry) { - const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; - console.warn(`Delegation expired for message ${messageId}`); + console.warn(`āŒ Delegation expired for ${messageId}`, { + expiredBy: `${Math.round(-timeUntilExpiry / 1000 / 60)} minutes` + }); return false; } + console.log(`āœ… Delegation not expired for ${messageId}`); + // 3. Verify delegation message integrity const expectedDelegationMessage = this.keyDelegation.createDelegationMessage( message.browserPubKey, @@ -102,25 +168,71 @@ export class MessageSigning { message.delegationExpiry ); + console.log(`šŸ”— Verifying delegation message integrity for ${messageId}:`, { + expected: expectedDelegationMessage, + actual: message.delegationMessage, + matches: message.delegationMessage === expectedDelegationMessage + }); + if (message.delegationMessage !== expectedDelegationMessage) { - const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; - console.warn(`Delegation message tampered for message ${messageId}`); + console.warn(`āŒ Delegation message tampered for ${messageId}`); return false; } + console.log(`āœ… Delegation message integrity verified for ${messageId}`); + // 4. Verify wallet signature of delegation + console.log(`šŸ”‘ Verifying wallet signature for ${messageId} from author: ${message.author}`); + const isValidDelegationSignature = await this.verifyWalletSignature( message.delegationMessage, message.delegationSignature, message.author ); + console.log(`šŸ” Delegation verification details:`, { + delegationMessage: message.delegationMessage, + delegationSignature: message.delegationSignature, + signatureLength: message.delegationSignature?.length, + messageAuthor: message.author, + storedDelegation: delegation ? { + signature: delegation.signature, + signatureLength: delegation.signature?.length, + walletAddress: delegation.walletAddress + } : 'no delegation found' + }); + if (!isValidDelegationSignature) { - const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; - console.warn(`Invalid delegation signature for message ${messageId}`); + console.warn(`āŒ Invalid delegation signature for ${messageId}`); + console.log(`šŸ” Delegation signature verification failed. This could indicate:`, { + reason: 'Address mismatch between delegation creation and current wallet', + suggestion: 'User may have switched wallets or accounts. Try creating a new delegation.', + delegationMessage: message.delegationMessage, + delegationSignature: message.delegationSignature.slice(0, 32) + '...', + expectedAuthor: message.author + }); + + // Show a user-friendly error message + console.error(`🚨 SECURITY ALERT: Delegation signature verification failed for message ${messageId}. + +This usually means: +1. You switched wallet accounts since creating the delegation +2. You're using a different wallet than the one that created the delegation +3. Your wallet address changed (e.g., switching networks) + +To fix this: +1. Go to your profile/settings +2. Click "Clear Delegation" +3. Create a new delegation with your current wallet + +This ensures your messages are properly authenticated with your current wallet address.`); + return false; } + console.log(`āœ… Wallet signature verified for ${messageId}`); + console.log(`šŸŽ‰ All verifications passed for message: ${messageId}`); + return true; } diff --git a/src/lib/identity/signatures/wallet-signature-verifier.ts b/src/lib/identity/signatures/wallet-signature-verifier.ts new file mode 100644 index 0000000..5d47986 --- /dev/null +++ b/src/lib/identity/signatures/wallet-signature-verifier.ts @@ -0,0 +1,138 @@ +/** + * Wallet signature verification for delegation messages + * + * This module handles cryptographic verification of wallet signatures + * for Bitcoin and Ethereum wallets when they sign delegation messages. + */ + +import * as secp256k1 from '@noble/secp256k1'; +import { sha256 } from '@noble/hashes/sha256'; +import { bytesToHex, hexToBytes } from '@/lib/utils'; +import { recoverMessageAddress, getAddress, verifyMessage as viemVerifyMessage } from 'viem'; + +export class WalletSignatureVerifier { + + /** + * Verify a Bitcoin wallet signature + * @param message The original message that was signed + * @param signature The signature in hex format + * @param publicKey The public key in hex format + * @returns boolean indicating if the signature is valid + */ + static verifyBitcoinSignature( + message: string, + signature: string, + publicKey: string + ): boolean { + console.log(`šŸ” Verifying Bitcoin signature:`, { + messageLength: message.length, + signatureLength: signature.length, + publicKeyLength: publicKey.length, + publicKeyPrefix: publicKey.slice(0, 16) + '...' + }); + + try { + const messageBytes = new TextEncoder().encode(message); + const messageHash = sha256(messageBytes); + const signatureBytes = hexToBytes(signature); + const publicKeyBytes = hexToBytes(publicKey); + + const isValid = secp256k1.verify(signatureBytes, messageHash, publicKeyBytes); + + console.log(`āœ… Bitcoin signature verification result:`, { + isValid, + messageHash: bytesToHex(messageHash).slice(0, 16) + '...' + }); + + return isValid; + } catch (error) { + console.error('āŒ Error verifying Bitcoin signature:', error); + return false; + } + } + + /** + * Verify an Ethereum wallet signature using viem (EIP-191 personal_sign) + * @param message The original message that was signed + * @param signature The signature in hex format (0x...) + * @param address The Ethereum address expected to have signed the message + */ + static async verifyEthereumSignature( + message: string, + signature: string, + address: string + ): Promise { + console.log(`šŸ” Verifying Ethereum signature:`, { + messageLength: message.length, + signatureLength: signature.length, + expectedAddress: address, + signaturePrefix: signature.slice(0, 16) + '...', + fullMessage: message // Log the full message for debugging + }); + + try { + // First, use viem's built-in verifier (handles prefixing correctly) + const isValid = await viemVerifyMessage({ message, signature: signature as `0x${string}`, address: getAddress(address) as `0x${string}` }); + + // For diagnostics only, attempt recovery + try { + const recovered = await recoverMessageAddress({ message, signature: signature as `0x${string}` }); + console.log(`šŸ” Ethereum signature recovery details:`, { + recoveredAddress: recovered, + expectedAddress: address, + recoveredNormalized: getAddress(recovered), + expectedNormalized: getAddress(address), + addressesMatch: getAddress(recovered) === getAddress(address), + rawComparison: recovered === address, + messageBytes: new TextEncoder().encode(message).length, + signatureBytes: signature.length + }); + } catch (e) { + console.warn('āš ļø Non-fatal: recoverMessageAddress failed during diagnostics:', e); + } + + console.log(`āœ… Ethereum signature verification result:`, { isValid }); + return isValid; + } catch (error) { + console.error('āŒ Error verifying Ethereum signature:', error); + return false; + } + } + + /** + * Verify wallet signature based on wallet type + * @param message The original message that was signed + * @param signature The signature in hex format + * @param walletAddress The wallet address + * @param walletType The type of wallet (bitcoin or ethereum) + * @param publicKey Optional public key for Bitcoin verification + */ + static async verifyWalletSignature( + message: string, + signature: string, + walletAddress: string, + walletType: 'bitcoin' | 'ethereum', + publicKey?: string + ): Promise { + console.log(`šŸ”‘ Starting wallet signature verification:`, { + walletType, + walletAddress, + hasPublicKey: !!publicKey, + messageLength: message.length + }); + + if (walletType === 'bitcoin') { + if (!publicKey) { + console.warn(`āŒ Bitcoin verification requires public key but none provided`); + return false; + } + + console.log(`šŸ” Using Bitcoin verification path`); + return this.verifyBitcoinSignature(message, signature, publicKey); + } + + // Ethereum path (no stored public key required) + console.log(`šŸ” Using Ethereum verification path`); + return this.verifyEthereumSignature(message, signature, walletAddress); + } +} diff --git a/src/lib/identity/wallets/ReOwnWalletService.ts b/src/lib/identity/wallets/ReOwnWalletService.ts index 98c7506..cfff0ec 100644 --- a/src/lib/identity/wallets/ReOwnWalletService.ts +++ b/src/lib/identity/wallets/ReOwnWalletService.ts @@ -89,6 +89,13 @@ export class ReOwnWalletService { // Convert message bytes to string for signing const messageString = new TextDecoder().decode(messageBytes); + console.log(`šŸ” Wallet signing request:`, { + walletType, + requestedAddress: account.address, + messageLength: messageString.length, + messagePreview: messageString.slice(0, 100) + '...' + }); + try { // Access the adapter through the appKit instance // The adapter is available through the appKit's chainAdapters property @@ -112,9 +119,15 @@ export class ReOwnWalletService { provider: provider as Provider }); + console.log(`āœ… Wallet signing completed:`, { + requestedAddress: account.address, + signatureLength: result.signature.length, + signaturePrefix: result.signature.slice(0, 16) + '...' + }); + return result.signature; } catch (error) { - console.error(`Error signing message with ${walletType} wallet:`, error); + console.error(`āŒ Error signing message with ${walletType} wallet:`, error); throw new Error(`Failed to sign message with ${walletType} wallet: ${error instanceof Error ? error.message : 'Unknown error'}`); } } @@ -129,26 +142,87 @@ export class ReOwnWalletService { throw new Error(`No ${walletType} wallet connected`); } + console.log(`šŸ”‘ Starting key delegation creation:`, { + walletType, + accountAddress: account.address, + duration + }); + // Generate a new browser keypair const keypair = this.keyDelegation.generateKeypair(); // Create delegation message with expiry const expiryHours = KeyDelegation.getDurationHours(duration); const expiryTimestamp = Date.now() + (expiryHours * 60 * 60 * 1000); - const delegationMessage = this.keyDelegation.createDelegationMessage( + let delegationMessage = this.keyDelegation.createDelegationMessage( keypair.publicKey, account.address, expiryTimestamp ); + console.log(`šŸ“ Delegation message created:`, { + message: delegationMessage, + browserPublicKey: keypair.publicKey.slice(0, 16) + '...', + expiryTimestamp: new Date(expiryTimestamp).toISOString() + }); + const messageBytes = new TextEncoder().encode(delegationMessage); // Sign the delegation message const signature = await this.signMessage(messageBytes, walletType); + console.log(`šŸ” Wallet signing details:`, { + originalMessage: delegationMessage, + messageBytes: messageBytes.length, + signature: signature, + signatureLength: signature.length + }); + + // Verify the signature matches the expected address + let recoveredAddress: string | null = null; + if (walletType === 'ethereum') { + try { + const { recoverMessageAddress } = await import('viem'); + + console.log(`šŸ” Detailed signature analysis:`, { + originalMessage: delegationMessage, + signature: signature, + signatureLength: signature.length, + expectedAddress: account.address + }); + + recoveredAddress = await recoverMessageAddress({ + message: delegationMessage, + signature: signature as `0x${string}` + }); + + console.log(`šŸ” Signature verification check:`, { + expectedAddress: account.address, + recoveredAddress: recoveredAddress, + addressesMatch: recoveredAddress.toLowerCase() === account.address.toLowerCase(), + message: delegationMessage + }); + + // Diagnostics only; do NOT mutate the message after signing + console.log(`šŸ” Additional verification:`, { + recoveredAddressLowerCase: recoveredAddress.toLowerCase(), + expectedAddressLowerCase: account.address.toLowerCase(), + exactMatch: recoveredAddress === account.address, + caseInsensitiveMatch: recoveredAddress.toLowerCase() === account.address.toLowerCase() + }); + } catch (error) { + console.error(`āŒ Error verifying delegation signature:`, error); + } + } + + console.log(`āœ… Delegation signature received:`, { + signatureLength: signature.length, + signaturePrefix: signature.slice(0, 16) + '...' + }); + // Create and store the delegation const delegationInfo = this.keyDelegation.createDelegation( - account.address, + account.address, // store the original address used to build the message signature, keypair.publicKey, keypair.privateKey, @@ -158,9 +232,11 @@ export class ReOwnWalletService { this.keyDelegation.storeDelegation(delegationInfo); + console.log(`šŸŽ‰ Key delegation created and stored successfully`); + return true; } catch (error) { - console.error(`Error creating key delegation for ${walletType}:`, error); + console.error(`āŒ Error creating key delegation for ${walletType}:`, error); return false; } } diff --git a/src/lib/waku/constants.ts b/src/lib/waku/constants.ts index ab78150..2bee107 100644 --- a/src/lib/waku/constants.ts +++ b/src/lib/waku/constants.ts @@ -5,11 +5,11 @@ import { MessageType } from "./types"; * Content topics for different message types */ export const CONTENT_TOPICS: Record = { - [MessageType.CELL]: '/opchan/1/cell/proto', - [MessageType.POST]: '/opchan/1/post/proto', - [MessageType.COMMENT]: '/opchan/1/comment/proto', - [MessageType.VOTE]: '/opchan/1/vote/proto', - [MessageType.MODERATE]: '/opchan/1/moderate/proto' + [MessageType.CELL]: '/opcxzzhzaxsn221-aß/1/cell/proto', + [MessageType.POST]: '/opchan-x/1/post/proto', + [MessageType.COMMENT]: '/opchan-x/1/comment/proto', + [MessageType.VOTE]: '/opchan-x/1/vote/proto', + [MessageType.MODERATE]: '/opchan-x/1/moderate/proto' }; export const NETWORK_CONFIG: NetworkConfig = {