@openzeppelin/contracts-ui-builder-adapter-midnight
Version:
Midnight Adapter for Contracts UI Builder
1 lines • 58.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/configuration/execution.ts","../src/types/artifacts.ts","../src/utils/artifacts.ts","../src/utils/schema-parser.ts","../src/utils/validator.ts","../src/configuration/explorer.ts","../src/configuration/rpc.ts","../src/adapter.ts","../src/wallet/components/account/AccountDisplay.tsx","../src/wallet/hooks/useMidnightWallet.ts","../src/wallet/context/MidnightWalletContext.tsx","../src/wallet/hooks/facade-hooks.ts","../src/wallet/utils/SafeMidnightComponent.tsx","../src/wallet/components/connect/ConnectButton.tsx","../src/wallet/components/MidnightWalletProvider.tsx","../src/wallet/midnight-implementation.ts","../src/wallet/connection.ts","../src/networks/testnet.ts","../src/networks/index.ts","../src/config.ts"],"sourcesContent":["export * from './adapter';\nexport { default } from './adapter'; // Default export for convenience\n\n// Re-export adapter-specific types\nexport type { MidnightContractArtifacts } from './types/artifacts';\nexport { isMidnightContractArtifacts } from './types/artifacts';\n\nexport { MidnightAdapter } from './adapter';\nexport {\n midnightNetworks,\n midnightTestnetNetworks,\n // Individual networks\n midnightTestnet,\n} from './networks';\n\n// Export adapter configuration\nexport { midnightAdapterConfig } from './config';\n","import type {\n ExecutionConfig,\n ExecutionMethodDetail,\n} from '@openzeppelin/contracts-ui-builder-types';\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { isValidAddress } from '../utils';\n\n/**\n * @inheritdoc\n * TODO: Implement actual supported methods for Midnight.\n */\nexport function getMidnightSupportedExecutionMethods(): Promise<ExecutionMethodDetail[]> {\n // Placeholder: Assume only EOA is supported for now\n logger.warn(\n 'MidnightExecutionConfig',\n 'getSupportedExecutionMethods is using placeholder implementation.'\n );\n return Promise.resolve([\n {\n type: 'eoa',\n name: 'EOA (Midnight Account)',\n description: 'Execute using a standard Midnight account.',\n },\n ]);\n}\n\n/**\n * @inheritdoc\n * TODO: Implement actual validation logic for Midnight execution configs.\n */\nexport function validateMidnightExecutionConfig(config: ExecutionConfig): Promise<true | string> {\n // Placeholder: Basic validation\n logger.warn(\n 'MidnightExecutionConfig',\n 'validateExecutionConfig is using placeholder implementation.'\n );\n if (config.method === 'eoa') {\n if (!config.allowAny && !config.specificAddress) {\n return Promise.resolve('Specific EOA address is required.');\n }\n if (\n !config.allowAny &&\n config.specificAddress &&\n !isValidAddress(config.specificAddress) // Assuming isValidAddress is moved to utils\n ) {\n return Promise.resolve('Invalid EOA address format for Midnight.');\n }\n return Promise.resolve(true);\n } else {\n // For now, consider other methods unsupported by this placeholder\n return Promise.resolve(\n `Execution method '${config.method}' is not yet supported by this adapter implementation.`\n );\n }\n}\n","/**\n * Midnight-specific contract artifacts interface\n * Defines the structure of data needed to load Midnight contracts\n */\nexport interface MidnightContractArtifacts {\n /** The deployed contract address (required, Bech32m format) */\n contractAddress: string;\n\n /** Unique identifier for private state instance (required) */\n privateStateId: string;\n\n /** TypeScript interface definition from contract.d.ts (required) */\n contractSchema: string;\n\n /** Optional compiled contract code from contract.cjs */\n contractModule?: string;\n\n /** Optional witness functions for zero-knowledge proofs */\n witnessCode?: string;\n}\n\n/**\n * Type guard to check if an object matches MidnightContractArtifacts structure\n */\nexport function isMidnightContractArtifacts(obj: unknown): obj is MidnightContractArtifacts {\n const record = obj as Record<string, unknown>;\n return (\n typeof obj === 'object' &&\n obj !== null &&\n typeof record.contractAddress === 'string' &&\n typeof record.privateStateId === 'string' &&\n typeof record.contractSchema === 'string'\n );\n}\n","/**\n * Utility functions for Midnight contract artifacts validation and conversion\n */\nimport type { MidnightContractArtifacts } from '../types/artifacts';\nimport { isMidnightContractArtifacts } from '../types/artifacts';\n\n/**\n * Validates and converts generic source input to MidnightContractArtifacts\n *\n * @param source - Generic contract source (string address or artifacts object)\n * @returns Validated MidnightContractArtifacts\n * @throws Error if the source is invalid\n */\nexport function validateAndConvertMidnightArtifacts(\n source: string | Record<string, unknown>\n): MidnightContractArtifacts {\n if (typeof source === 'string') {\n throw new Error(\n 'Midnight adapter requires contract artifacts object, not just an address string.'\n );\n }\n\n // Validate that the object has the required structure\n if (!isMidnightContractArtifacts(source)) {\n throw new Error(\n 'Invalid contract artifacts provided. Expected an object with contractAddress, privateStateId, and contractSchema properties.'\n );\n }\n\n return source;\n}\n","import {\n ContractEvent,\n ContractFunction,\n ContractSchema,\n FunctionParameter,\n} from '@openzeppelin/contracts-ui-builder-types';\n\n/**\n * Parses the string content of a Midnight contract's .d.ts file.\n * @param interfaceContent The string content of the .d.ts file.\n * @returns A partial schema containing the functions and types.\n */\nexport function parseMidnightContractInterface(\n interfaceContent: string\n): Pick<ContractSchema, 'functions' | 'events'> {\n const circuits = extractCircuits(interfaceContent);\n const queries = extractQueries(interfaceContent);\n\n const functions = [...Object.values(circuits), ...Object.values(queries)];\n\n // TODO: Extract events from the interface content.\n const events: ContractEvent[] = [];\n\n return { functions, events };\n}\n\nfunction extractCircuits(content: string): Record<string, ContractFunction> {\n const circuits: Record<string, ContractFunction> = {};\n const circuitsMatch = content.match(/export\\s+type\\s+Circuits\\s*<[^>]*>\\s*=\\s*{([^}]*)}/s);\n\n if (circuitsMatch) {\n const circuitsContent = circuitsMatch[1];\n const methodRegex = /(\\w+)\\s*\\(\\s*context\\s*:[^,)]+(?:,\\s*([^)]+))?\\)/g;\n let match;\n while ((match = methodRegex.exec(circuitsContent)) !== null) {\n const name = match[1];\n const paramsText = match[2] || '';\n circuits[name] = {\n id: name, // Simplified ID for now\n name,\n displayName: name.charAt(0).toUpperCase() + name.slice(1),\n inputs: parseParameters(paramsText),\n outputs: [], // Assuming no direct outputs from circuits for now\n modifiesState: true,\n type: 'function',\n };\n }\n }\n return circuits;\n}\n\nfunction extractQueries(content: string): Record<string, ContractFunction> {\n const queries: Record<string, ContractFunction> = {};\n const ledgerMatch = content.match(/export\\s+type\\s+Ledger\\s*=\\s*{([^}]*)}/s);\n\n if (ledgerMatch) {\n const ledgerContent = ledgerMatch[1];\n const propertyRegex = /readonly\\s+(\\w+)\\s*:\\s*([^;]*);/g;\n let match;\n while ((match = propertyRegex.exec(ledgerContent)) !== null) {\n const name = match[1];\n const typeStr = match[2].trim();\n queries[name] = {\n id: name,\n name,\n displayName: name.charAt(0).toUpperCase() + name.slice(1),\n inputs: [],\n outputs: [{ name: 'value', type: typeStr }],\n modifiesState: false,\n type: 'function',\n stateMutability: 'view',\n };\n }\n }\n return queries;\n}\n\nfunction parseParameters(paramsText: string): FunctionParameter[] {\n if (!paramsText.trim()) return [];\n return paramsText.split(',').map((param) => {\n const [name, type] = param.split(':').map((s) => s.trim());\n return { name, type };\n });\n}\n","import { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\n/**\n * Validate a Midnight blockchain address\n * @param _address The address to validate\n * @returns Whether the address is a valid Midnight address\n */\nexport function isValidAddress(_address: string): boolean {\n // TODO: Implement Midnight address validation when chain specs are available\n // For now, return true to avoid blocking development\n logger.warn(\n 'adapter-midnight',\n 'isValidAddress for Midnight is using placeholder implementation.'\n );\n return true;\n}\n","import { NetworkConfig } from '@openzeppelin/contracts-ui-builder-types';\nimport type { UserExplorerConfig } from '@openzeppelin/contracts-ui-builder-types';\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\n/**\n * Gets a blockchain explorer URL for an address on Midnight.\n * Uses the explorerUrl from the network configuration.\n *\n * @param address The address to get the explorer URL for\n * @param networkConfig The network configuration object.\n * @returns A URL to view the address on the configured Midnight explorer, or null.\n */\nexport function getMidnightExplorerAddressUrl(\n address: string,\n networkConfig: NetworkConfig\n): string | null {\n // Placeholder: Implement logic using networkConfig.explorerUrl if available\n if (!address || !networkConfig.explorerUrl) {\n return null;\n }\n // Example construction (adjust path as needed for Midnight)\n const baseUrl = networkConfig.explorerUrl.replace(/\\/+$/, '');\n return `${baseUrl}/address/${address}`; // Assuming similar path to others\n}\n\n/**\n * Gets a blockchain explorer URL for a transaction on Midnight.\n * Uses the explorerUrl from the network configuration.\n *\n * @param txHash - The hash of the transaction to get the explorer URL for\n * @param networkConfig The network configuration object.\n * @returns A URL to view the transaction on the configured Midnight explorer, or null.\n */\nexport function getMidnightExplorerTxUrl(\n txHash: string,\n networkConfig: NetworkConfig\n): string | null {\n // Placeholder: Implement logic using networkConfig.explorerUrl if available\n if (!txHash || !networkConfig.explorerUrl) {\n return null;\n }\n // Example construction (adjust path as needed for Midnight)\n const baseUrl = networkConfig.explorerUrl.replace(/\\/+$/, '');\n return `${baseUrl}/tx/${txHash}`; // Assuming similar path to others\n}\n\n/**\n * Validates an explorer configuration for Midnight networks.\n * @param explorerConfig - The explorer configuration to validate\n * @returns True if the configuration is valid, false otherwise\n */\nexport function validateMidnightExplorerConfig(_explorerConfig: UserExplorerConfig): boolean {\n // TODO: Implement Midnight-specific explorer validation when needed\n logger.info('validateMidnightExplorerConfig', 'Midnight explorer validation not yet implemented');\n return true;\n}\n\n/**\n * Tests the connection to a Midnight explorer API.\n * @param explorerConfig - The explorer configuration to test\n * @returns Connection test results including success status, latency, and any errors\n */\nexport async function testMidnightExplorerConnection(_explorerConfig: UserExplorerConfig): Promise<{\n success: boolean;\n latency?: number;\n error?: string;\n}> {\n // TODO: Implement explorer connection testing for Midnight\n logger.info('testMidnightExplorerConnection', 'TODO: Implement explorer connection testing');\n return { success: true };\n}\n","import type { UserRpcProviderConfig } from '@openzeppelin/contracts-ui-builder-types';\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\n/**\n * Validates an RPC endpoint configuration for Midnight networks.\n * @param rpcConfig - The RPC provider configuration to validate\n * @returns True if the configuration is valid, false otherwise\n */\nexport function validateMidnightRpcEndpoint(_rpcConfig: UserRpcProviderConfig): boolean {\n // TODO: Implement Midnight-specific RPC validation when needed\n logger.info('validateMidnightRpcEndpoint', 'Midnight RPC validation not yet implemented');\n return true;\n}\n\n/**\n * Tests the connection to a Midnight RPC endpoint.\n * @param rpcConfig - The RPC provider configuration to test\n * @returns Connection test results including success status, latency, and any errors\n */\nexport async function testMidnightRpcConnection(_rpcConfig: UserRpcProviderConfig): Promise<{\n success: boolean;\n latency?: number;\n error?: string;\n}> {\n // TODO: Implement RPC connection testing for Midnight\n logger.info('testMidnightRpcConnection', 'TODO: Implement RPC connection testing');\n return { success: true };\n}\n","import {\n testMidnightRpcConnection,\n validateMidnightRpcEndpoint,\n} from 'packages/adapter-midnight/src/configuration';\n\nimport type {\n AvailableUiKit,\n Connector,\n ContractAdapter,\n ContractFunction,\n ContractSchema,\n EcosystemReactUiProviderProps,\n EcosystemSpecificReactHooks,\n EcosystemWalletComponents,\n ExecutionConfig,\n ExecutionMethodDetail,\n FieldType,\n FormFieldType,\n FunctionParameter,\n MidnightNetworkConfig,\n RelayerDetails,\n RelayerDetailsRich,\n UiKitConfiguration,\n UserRpcProviderConfig,\n} from '@openzeppelin/contracts-ui-builder-types';\nimport { isMidnightNetworkConfig } from '@openzeppelin/contracts-ui-builder-types';\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport type { MidnightContractArtifacts } from './types/artifacts';\nimport { CustomAccountDisplay } from './wallet/components/account/AccountDisplay';\nimport { ConnectButton } from './wallet/components/connect/ConnectButton';\nimport { MidnightWalletProvider } from './wallet/components/MidnightWalletProvider';\nimport * as connection from './wallet/connection';\nimport { midnightFacadeHooks } from './wallet/hooks/facade-hooks';\n\nimport { parseMidnightContractInterface, validateAndConvertMidnightArtifacts } from './utils';\n\n/**\n * Midnight-specific adapter.\n *\n * Implements the full ContractAdapter interface to integrate with the builder application.\n * Wallet-related functionalities are implemented, while contract-specific methods\n * are placeholders to be built out in later phases.\n */\nexport class MidnightAdapter implements ContractAdapter {\n readonly networkConfig: MidnightNetworkConfig;\n readonly initialAppServiceKitName: UiKitConfiguration['kitName'];\n private artifacts: MidnightContractArtifacts | null = null;\n\n constructor(networkConfig: MidnightNetworkConfig) {\n if (!isMidnightNetworkConfig(networkConfig)) {\n throw new Error('MidnightAdapter requires a valid Midnight network configuration.');\n }\n this.networkConfig = networkConfig;\n this.initialAppServiceKitName = 'custom';\n logger.info(\n 'MidnightAdapter',\n `Adapter initialized for network: ${networkConfig.name} (ID: ${networkConfig.id})`\n );\n }\n\n public getEcosystemReactUiContextProvider(): React.FC<EcosystemReactUiProviderProps> {\n return MidnightWalletProvider;\n }\n\n public getEcosystemReactHooks(): EcosystemSpecificReactHooks {\n return midnightFacadeHooks;\n }\n\n public getEcosystemWalletComponents(): EcosystemWalletComponents {\n return {\n ConnectButton,\n AccountDisplay: CustomAccountDisplay,\n };\n }\n\n public supportsWalletConnection(): boolean {\n return connection.supportsMidnightWalletConnection();\n }\n\n public async getAvailableConnectors(): Promise<Connector[]> {\n return connection.getMidnightAvailableConnectors();\n }\n\n public connectWallet(\n _connectorId: string\n ): Promise<{ connected: boolean; address?: string; error?: string }> {\n logger.warn(\n 'MidnightAdapter',\n 'The `connectWallet` method is not supported. Use the `ConnectButton` component from `getEcosystemWalletComponents()` instead.'\n );\n return Promise.resolve({ connected: false, error: 'Method not supported.' });\n }\n\n public disconnectWallet(): Promise<{ disconnected: boolean; error?: string }> {\n return connection.disconnectMidnightWallet();\n }\n\n public getWalletConnectionStatus(): { isConnected: boolean; address?: string; chainId?: string } {\n // This method is required by the ContractAdapter interface.\n // In our React-based UI, the connection status is managed reactively by the\n // MidnightWalletProvider. This function provides a non-reactive, one-time\n // status check, which is not the source of truth for the UI components.\n return {\n isConnected: false,\n address: undefined,\n chainId: this.networkConfig.id,\n };\n }\n\n public getContractDefinitionInputs(): FormFieldType[] {\n return [\n {\n id: 'contractAddress',\n name: 'contractAddress',\n label: 'Contract Address',\n type: 'blockchain-address',\n validation: { required: true },\n placeholder: 'ct1q8ej4px...',\n helperText: 'Enter the deployed Midnight contract address (Bech32m format).',\n },\n {\n id: 'privateStateId',\n name: 'privateStateId',\n label: 'Private State ID',\n type: 'text',\n validation: { required: true },\n placeholder: 'my-unique-state-id',\n helperText:\n 'A unique identifier for your private state instance. This ID is used to manage your personal encrypted data.',\n },\n {\n id: 'contractSchema',\n name: 'contractSchema',\n label: 'Contract Interface (.d.ts)',\n type: 'code-editor',\n validation: { required: true },\n placeholder:\n 'export interface MyContract {\\n myMethod(param: string): Promise<void>;\\n // ... other methods\\n}',\n helperText:\n \"Paste the TypeScript interface definition from your contract.d.ts file. This defines the contract's available methods.\",\n codeEditorProps: {\n language: 'typescript',\n placeholder: 'Paste your contract interface here...',\n maxHeight: '400px',\n },\n },\n {\n id: 'contractModule',\n name: 'contractModule',\n label: 'Compiled Contract Module (.cjs)',\n type: 'textarea',\n validation: { required: true },\n placeholder: 'module.exports = { /* compiled contract code */ };',\n helperText:\n \"Paste the compiled contract code from your contract.cjs file. This contains the contract's implementation.\",\n },\n {\n id: 'witnessCode',\n name: 'witnessCode',\n label: 'Witness Functions (Optional)',\n type: 'textarea',\n validation: { required: false },\n placeholder:\n '// Define witness functions for zero-knowledge proofs\\nexport const witnesses = {\\n myWitness: (ctx) => {\\n return [ctx.privateState.myField, []];\\n }\\n};',\n helperText:\n 'Optional: Define witness functions that generate zero-knowledge proofs for your contract interactions. These functions determine what private data is used in proofs.',\n },\n ];\n }\n\n public async loadContract(source: string | Record<string, unknown>): Promise<ContractSchema> {\n // Convert and validate the input\n const artifacts = validateAndConvertMidnightArtifacts(source);\n\n this.artifacts = artifacts;\n logger.info('MidnightAdapter', 'Contract artifacts stored.', this.artifacts);\n\n const { functions, events } = parseMidnightContractInterface(artifacts.contractSchema);\n\n const schema: ContractSchema = {\n name: 'MyMidnightContract', // TODO: Extract from artifacts if possible\n ecosystem: 'midnight',\n address: artifacts.contractAddress,\n functions,\n events,\n };\n\n return schema;\n }\n\n public getWritableFunctions(contractSchema: ContractSchema): ContractFunction[] {\n return contractSchema.functions.filter((fn) => fn.modifiesState);\n }\n\n public mapParameterTypeToFieldType(_parameterType: string): FieldType {\n return 'text';\n }\n\n public getCompatibleFieldTypes(_parameterType: string): FieldType[] {\n return ['text'];\n }\n\n public generateDefaultField(parameter: FunctionParameter): FormFieldType {\n return {\n id: parameter.name,\n name: parameter.name,\n label: parameter.name,\n type: this.mapParameterTypeToFieldType(parameter.type),\n validation: {},\n };\n }\n\n public formatTransactionData(\n _contractSchema: ContractSchema,\n _functionId: string,\n _submittedInputs: Record<string, unknown>,\n _fields: FormFieldType[]\n ): unknown {\n throw new Error('formatTransactionData not implemented for MidnightAdapter.');\n }\n\n public async signAndBroadcast(\n _transactionData: unknown,\n _executionConfig?: ExecutionConfig\n ): Promise<{ txHash: string }> {\n throw new Error('signAndBroadcast not implemented for MidnightAdapter.');\n }\n\n public isViewFunction(functionDetails: ContractFunction): boolean {\n return !functionDetails.modifiesState;\n }\n\n public async queryViewFunction(\n _contractAddress: string,\n _functionId: string,\n _params: unknown[],\n _contractSchema?: ContractSchema\n ): Promise<unknown> {\n throw new Error('queryViewFunction not implemented for MidnightAdapter.');\n }\n\n public formatFunctionResult(decodedValue: unknown): string {\n return JSON.stringify(decodedValue, null, 2);\n }\n\n public async getSupportedExecutionMethods(): Promise<ExecutionMethodDetail[]> {\n return []; // Placeholder\n }\n\n public async validateExecutionConfig(_config: ExecutionConfig): Promise<true | string> {\n return true; // No config to validate yet\n }\n\n public getExplorerUrl(_address: string): string | null {\n return null; // No official explorer yet\n }\n\n public getExplorerTxUrl(_txHash: string): string | null {\n return null; // No official explorer yet\n }\n\n public isValidAddress(_address: string): boolean {\n // Placeholder - add real Bech32m validation later\n return true;\n }\n\n async getAvailableUiKits(): Promise<AvailableUiKit[]> {\n return [\n {\n id: 'custom',\n name: 'OpenZeppelin Custom',\n configFields: [],\n },\n ];\n }\n\n public async getRelayers(_serviceUrl: string, _accessToken: string): Promise<RelayerDetails[]> {\n logger.warn('MidnightAdapter', 'getRelayers is not implemented for the Midnight adapter yet.');\n return Promise.resolve([]);\n }\n\n public async getRelayer(\n _serviceUrl: string,\n _accessToken: string,\n _relayerId: string\n ): Promise<RelayerDetailsRich> {\n logger.warn('MidnightAdapter', 'getRelayer is not implemented for the Midnight adapter yet.');\n return Promise.resolve({} as RelayerDetailsRich);\n }\n\n /**\n * @inheritdoc\n */\n public async validateRpcEndpoint(rpcConfig: UserRpcProviderConfig): Promise<boolean> {\n // TODO: Implement Midnight-specific RPC validation when needed\n return validateMidnightRpcEndpoint(rpcConfig);\n }\n\n /**\n * @inheritdoc\n */\n public async testRpcConnection(rpcConfig: UserRpcProviderConfig): Promise<{\n success: boolean;\n latency?: number;\n error?: string;\n }> {\n // TODO: Implement Midnight-specific RPC validation when needed\n return testMidnightRpcConnection(rpcConfig);\n }\n}\n\n// Also export as default\nexport default MidnightAdapter;\n","import { LogOut } from 'lucide-react';\nimport React from 'react';\n\nimport type { BaseComponentProps } from '@openzeppelin/contracts-ui-builder-types';\nimport { Button } from '@openzeppelin/contracts-ui-builder-ui';\nimport { cn, truncateMiddle } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useAccount, useDisconnect } from '../../hooks/facade-hooks';\nimport { SafeMidnightComponent } from '../../utils/SafeMidnightComponent';\n\n/**\n * A component that displays the connected account address and network.\n * Also includes a disconnect button.\n */\nexport const CustomAccountDisplay: React.FC<BaseComponentProps> = ({ className }) => {\n // Use the SafeMidnightComponent with null fallback\n return (\n <SafeMidnightComponent fallback={null}>\n <AccountDisplayContent className={className} />\n </SafeMidnightComponent>\n );\n};\n\n/**\n * The inner component that contains the actual UI and uses the hooks.\n */\nconst AccountDisplayContent: React.FC<{ className?: string }> = ({ className }) => {\n const { address, isConnected } = useAccount();\n const { disconnect } = useDisconnect();\n\n if (!isConnected || !address || !disconnect) {\n return null;\n }\n\n return (\n <div className={cn('flex items-center gap-2', className)}>\n <div className=\"flex flex-col\">\n <span className=\"text-xs font-medium\">{truncateMiddle(address, 4, 4)}</span>\n <span className=\"text-[9px] text-muted-foreground -mt-0.5\">Midnight Network</span>\n </div>\n <Button\n onClick={() => disconnect()}\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-6 p-0\"\n title=\"Disconnect wallet\"\n >\n <LogOut className=\"size-3.5\" />\n </Button>\n </div>\n );\n};\n","import { useContext } from 'react';\n\nimport { MidnightWalletContext, MidnightWalletContextType } from '../context/MidnightWalletContext';\n\n/**\n * Custom hook to access the Midnight wallet context.\n *\n * @returns The wallet context, including state and actions.\n * @throws If used outside of a `MidnightWalletProvider`.\n */\nexport const useMidnightWallet = (): MidnightWalletContextType => {\n const context = useContext(MidnightWalletContext);\n if (context === undefined) {\n throw new Error('useMidnightWallet must be used within a MidnightWalletProvider');\n }\n return context;\n};\n","import type { DAppConnectorWalletAPI } from '@midnight-ntwrk/dapp-connector-api';\nimport { createContext } from 'react';\n\n/**\n * Defines the shape of the state and actions for the Midnight wallet context.\n */\nexport interface MidnightWalletContextType {\n isConnected: boolean;\n isConnecting: boolean;\n address?: string;\n api: DAppConnectorWalletAPI | null;\n error: Error | null;\n connect: () => void;\n disconnect: () => Promise<void>;\n}\n\n/**\n * React Context for the Midnight wallet.\n *\n * It's initialized with `undefined` and will be provided a value by `MidnightWalletProvider`.\n * A custom hook (`useMidnightWallet`) will ensure the context is accessed correctly\n * within the provider's component tree.\n */\nexport const MidnightWalletContext = createContext<MidnightWalletContextType | undefined>(\n undefined\n);\n","import { useMidnightWallet } from './useMidnightWallet';\n\n/**\n * Facade hook to expose connection status and the connect action.\n * Adheres to the `DerivedConnectStatus` interface expected by the builder app.\n */\nexport const useConnect = () => {\n const { connect, isConnecting, error } = useMidnightWallet();\n // The adapter currently only supports Lace, so we return a static connector list.\n const connectors = [{ id: 'mnLace', name: 'Lace (Midnight)' }];\n\n return {\n connect: connect,\n connectors,\n isConnecting,\n error,\n pendingConnector: undefined, // This adapter doesn't have a concept of a pending connector.\n };\n};\n\n/**\n * Facade hook to expose disconnection status and the disconnect action.\n * Adheres to the `DerivedDisconnectStatus` interface expected by the builder app.\n */\nexport const useDisconnect = () => {\n const { disconnect } = useMidnightWallet();\n return {\n disconnect,\n isDisconnecting: false, // This adapter doesn't track disconnecting state.\n error: null,\n };\n};\n\n/**\n * Facade hook to expose the current account state.\n * Adheres to the `Account` interface expected by the builder app.\n */\nexport const useAccount = () => {\n const { address, isConnected, isConnecting } = useMidnightWallet();\n\n return {\n address,\n isConnected,\n isConnecting,\n isDisconnected: !isConnected && !isConnecting,\n isReconnecting: false, // This adapter doesn't have a concept of reconnecting.\n status: isConnected ? 'connected' : isConnecting ? 'connecting' : 'disconnected',\n };\n};\n\n/**\n * An object containing all the facade hooks for the Midnight adapter.\n * This is the primary export that will be consumed by the builder application.\n */\nexport const midnightFacadeHooks = {\n useAccount,\n useConnect,\n useDisconnect,\n // Other hooks like useBalance, useSwitchChain, etc., can be added here\n // in the future. For now, we only need the core connection hooks.\n};\n","import React, { useContext } from 'react';\n\nimport { MidnightWalletContext } from '../context/MidnightWalletContext';\n\n/**\n * A wrapper component that safely renders children that use Midnight hooks.\n * It checks if the MidnightWalletContext is available and renders a fallback\n * if it's not, preventing crashes when switching adapters.\n */\nexport const SafeMidnightComponent = ({\n children,\n fallback = null,\n}: {\n children: React.ReactNode;\n fallback?: React.ReactNode;\n}) => {\n const context = useContext(MidnightWalletContext);\n\n // If the context is not available, it means the MidnightWalletProvider\n // is not in the tree. Render the fallback to prevent a crash.\n if (!context) {\n return <>{fallback}</>;\n }\n\n // If the context is available, render the actual component.\n return <>{children}</>;\n};\n","import { Loader2, Wallet } from 'lucide-react';\nimport React from 'react';\n\nimport type { BaseComponentProps } from '@openzeppelin/contracts-ui-builder-types';\nimport { Button } from '@openzeppelin/contracts-ui-builder-ui';\nimport { cn } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useAccount, useConnect } from '../../hooks/facade-hooks';\nimport { SafeMidnightComponent } from '../../utils/SafeMidnightComponent';\n\n/**\n * A button that allows users to connect their wallet.\n * @param hideWhenConnected - Whether to hide the button when wallet is connected (default: true)\n */\nexport interface ConnectButtonProps extends BaseComponentProps {\n hideWhenConnected?: boolean;\n}\n\nexport const ConnectButton: React.FC<ConnectButtonProps> = ({\n className,\n hideWhenConnected = true,\n}) => {\n const unavailableButton = (\n <div className={cn('flex items-center', className)}>\n <Button disabled={true} variant=\"outline\" size=\"sm\" className=\"h-8 px-2 text-xs\">\n <Wallet className=\"size-3.5 mr-1\" />\n Wallet Unavailable\n </Button>\n </div>\n );\n\n return (\n <SafeMidnightComponent fallback={unavailableButton}>\n <ConnectButtonContent className={className} hideWhenConnected={hideWhenConnected} />\n </SafeMidnightComponent>\n );\n};\n\n/**\n * The inner component that contains the actual UI and uses the hooks.\n */\nconst ConnectButtonContent: React.FC<{\n className?: string;\n hideWhenConnected: boolean;\n}> = ({ className, hideWhenConnected }) => {\n const { isConnected } = useAccount();\n const { connect, isConnecting, connectors, error: connectError } = useConnect();\n\n const handleConnectClick = () => {\n if (connect && !isConnected) {\n connect();\n }\n };\n\n if (isConnected && hideWhenConnected) {\n return null;\n }\n\n const showButtonLoading = isConnecting;\n const hasWallet = connectors.length > 0;\n\n // Determine button text based on connection state\n let buttonText = 'Connect Wallet';\n if (!hasWallet) {\n buttonText = 'No Wallet Found';\n } else if (showButtonLoading) {\n buttonText = 'Connecting...';\n } else if (connectError) {\n buttonText = 'Connect Wallet'; // Or 'Try Again'\n }\n\n return (\n <div className={cn('flex flex-col items-start gap-1', className)}>\n <div className=\"flex items-center\">\n <Button\n onClick={handleConnectClick}\n disabled={showButtonLoading || isConnected || !hasWallet}\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8 px-2 text-xs\"\n >\n {showButtonLoading ? (\n <Loader2 className=\"size-3.5 animate-spin mr-1\" />\n ) : (\n <Wallet className=\"size-3.5 mr-1\" />\n )}\n {buttonText}\n </Button>\n </div>\n\n {connectError && !isConnecting && (\n <p className=\"text-xs text-red-500 px-2\">\n {connectError.message || 'Error connecting wallet'}\n </p>\n )}\n </div>\n );\n};\n","// #####################################################################\n// DEVELOPER NOTE: On the Midnight Wallet Connection Flow\n//\n// The Midnight wallet's `.enable()` API exhibits unconventional behavior that\n// requires a specific connection strategy. Standard `async/await` flows\n// will not work as expected due to two main issues:\n//\n// 1. **Immediate Promise Resolution**: Unlike many other wallets, the\n// `enable()` promise resolves *immediately* when the connection pop-up\n// is displayed, not after the user approves or rejects it. This\n// returns a \"pre-flight\" API object that is not yet fully authorized.\n//\n// 2. **State Not Immediately Ready**: Calling `.state()` on the pre-flight\n// API object immediately after it's returned will fail, because the\n// user has not yet granted permission.\n//\n// The correct and robust solution, implemented below, is a **state-polling\n// mechanism**:\n//\n// - `handleConnect` first calls `implementation.connect()` to get the\n// \"pre-flight\" API object.\n// - A polling loop then repeatedly calls `.state()` on this object. This\n// is the part that effectively waits for user approval.\n// - Once the user approves, the `.state()` call succeeds, the poll is\n// stopped, and the UI is updated.\n// - A failsafe timeout is used to clean up the process if the user\n// rejects or ignores the connection prompt.\n// #####################################################################\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { EcosystemReactUiProviderProps } from '@openzeppelin/contracts-ui-builder-types';\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { MidnightWalletContext } from '../context/MidnightWalletContext';\nimport * as implementation from '../midnight-implementation';\nimport type { ExtendedDAppConnectorWalletAPI } from '../types';\n\nexport const MidnightWalletProvider: React.FC<EcosystemReactUiProviderProps> = ({ children }) => {\n const [api, setApi] = useState<ExtendedDAppConnectorWalletAPI | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [address, setAddress] = useState<string | undefined>(undefined);\n const [isConnecting, setIsConnecting] = useState<boolean>(false);\n const [isInitializing, setIsInitializing] = useState<boolean>(true);\n\n const pollIntervalRef = useRef<NodeJS.Timeout | null>(null);\n\n const isConnected = !!address && !!api;\n\n const cleanupTimer = useCallback(() => {\n if (pollIntervalRef.current) {\n clearInterval(pollIntervalRef.current);\n pollIntervalRef.current = null;\n }\n }, []);\n\n // Effect to attempt auto-reconnection on mount\n useEffect(() => {\n const attemptAutoConnect = async () => {\n // Do not auto-reconnect if the user has explicitly disconnected.\n if (localStorage.getItem('midnight-hasExplicitlyDisconnected') === 'true') {\n setIsInitializing(false);\n return;\n }\n\n try {\n const alreadyEnabled = await implementation.isEnabled();\n if (alreadyEnabled) {\n const preflightApi = await implementation.connect();\n const state = await preflightApi.state();\n setApi(preflightApi);\n setAddress(state.address);\n }\n } catch (err) {\n logger.warn('MidnightWalletProvider', 'Auto-reconnect failed:', err);\n } finally {\n setIsInitializing(false);\n }\n };\n\n attemptAutoConnect();\n }, []);\n\n const handleConnect = useCallback(async () => {\n if (isConnecting || isInitializing) return;\n\n // When the user explicitly tries to connect, clear the disconnect flag.\n localStorage.removeItem('midnight-hasExplicitlyDisconnected');\n\n setIsConnecting(true);\n setError(null);\n\n try {\n // 1. Get the \"pre-flight\" API. This does not wait for user approval.\n const preflightApi = await implementation.connect();\n\n // 2. Poll the .state() method, which is the part that waits for approval.\n pollIntervalRef.current = setInterval(async () => {\n try {\n const state = await preflightApi.state();\n\n // Success! User approved.\n cleanupTimer();\n setApi(preflightApi);\n setAddress(state.address);\n setIsConnecting(false);\n } catch {\n // Ignore polling errors; they are expected while the user is deciding.\n }\n }, 2000); // Poll every 2 seconds.\n\n // 3. Failsafe timeout for the entire process.\n setTimeout(() => {\n if (pollIntervalRef.current) {\n cleanupTimer();\n setError(new Error('Connection timed out. Please try again.'));\n setIsConnecting(false);\n }\n }, 90000); // 90-second timeout\n } catch (initialError) {\n // This catches initial errors, e.g., if the wallet extension isn't found.\n setError(\n initialError instanceof Error ? initialError : new Error('Failed to initiate connection.')\n );\n setIsConnecting(false);\n }\n }, [isConnecting, isInitializing, cleanupTimer]);\n\n const handleDisconnect = useCallback(async () => {\n implementation.disconnect();\n setApi(null);\n setAddress(undefined);\n setError(null);\n cleanupTimer();\n\n // DEVELOPER NOTE: On Explicit Disconnection\n // CIP-30 wallets like Lace do not provide a programmatic `disconnect` or\n // \"revoke permissions\" function. The dApp cannot sever the connection.\n // To respect the user's choice to disconnect from this specific dApp session,\n // we set a flag in localStorage. This flag is checked on page load to\n // prevent auto-reconnection. This is the standard and recommended\n // workaround for this wallet API limitation.\n localStorage.setItem('midnight-hasExplicitlyDisconnected', 'true');\n }, [cleanupTimer]);\n\n // Cleanup on unmount\n useEffect(() => {\n return cleanupTimer;\n }, [cleanupTimer]);\n\n // Effect to handle account changes after a successful connection\n useEffect(() => {\n if (api && typeof api.onAccountChange === 'function') {\n const handleAccountChange = (addresses: string[]) => {\n setAddress(addresses[0]);\n };\n\n api.onAccountChange(handleAccountChange);\n\n return () => {\n if (typeof api.offAccountChange === 'function') {\n api.offAccountChange(handleAccountChange);\n }\n };\n }\n }, [api]);\n\n const contextValue = useMemo(\n () => ({\n isConnected,\n isConnecting: isConnecting || isInitializing,\n isConnectPending: isConnecting || isInitializing,\n address,\n api,\n error,\n connect: handleConnect,\n disconnect: handleDisconnect,\n }),\n [\n isConnected,\n isConnecting,\n isInitializing,\n address,\n api,\n error,\n handleConnect,\n handleDisconnect,\n ]\n );\n\n return (\n <MidnightWalletContext.Provider value={contextValue}>{children}</MidnightWalletContext.Provider>\n );\n};\n","import type { DAppConnectorWalletAPI } from '@midnight-ntwrk/dapp-connector-api';\n\n// This file contains the core implementation for interacting with the Lace wallet's\n// CIP-30 style API (window.midnight.lace). It's responsible for all direct\n// communication with the wallet extension.\n\nlet enabledApi: DAppConnectorWalletAPI | null = null;\n\n/**\n * Checks if the wallet is already enabled (i.e., if the dApp has permission).\n * This method should not trigger a UI pop-up.\n * @returns A Promise that resolves with a boolean.\n */\nexport const isEnabled = (): Promise<boolean> => {\n if (typeof window === 'undefined' || !window.midnight?.mnLace) {\n return Promise.resolve(false);\n }\n return window.midnight.mnLace.isEnabled();\n};\n\n/**\n * Calls the wallet's enable() method to initiate a connection.\n *\n * DEVELOPER NOTE: This method is non-blocking and resolves *immediately*\n * with a \"pre-flight\" API object. It does not wait for user approval.\n * The `MidnightWalletProvider` handles the subsequent state polling required\n * to confirm the connection is fully established.\n *\n * @returns A Promise that resolves with the pre-flight Lace wallet API object.\n */\nexport const connect = async (): Promise<DAppConnectorWalletAPI> => {\n if (typeof window === 'undefined' || !window.midnight?.mnLace) {\n return Promise.reject(new Error('Lace wallet not found.'));\n }\n\n const api = await window.midnight.mnLace.enable();\n enabledApi = api;\n return api;\n};\n\n/**\n * Disconnects by clearing the stored API object. This is critical for\n * ensuring the next connection attempt requires user approval.\n */\nexport const disconnect = (): void => {\n enabledApi = null;\n};\n\n/**\n * Synchronously returns the currently connected Lace API instance.\n * This is the non-blocking function used by the polling mechanism.\n * @returns The Lace API object or `null` if not connected.\n */\nexport const getApi = (): DAppConnectorWalletAPI | null => {\n return enabledApi;\n};\n\n// Functions below are not yet implemented and are placeholders.\n// They are not part of the core connection flow.\n\nexport const signTx = async (): Promise<void> => {\n throw new Error('signTx is not implemented yet.');\n};\n\n/**\n * Placeholder for submitting a transaction.\n * @throws Not implemented.\n */\nexport const submitTx = async (): Promise<void> => {\n throw new Error('submitTx is not implemented yet.');\n};\n","import type { Connector } from '@openzeppelin/contracts-ui-builder-types';\n\n// This file will contain facade functions that provide a clean, high-level API\n// for wallet connection operations. It will use the raw functions from\n// midnight-implementation.ts to orchestrate connecting, disconnecting, and\n// checking wallet status.\n\n/**\n * Checks if a Midnight-compatible wallet (Lace) is available.\n * @returns `true` if the wallet extension is detected.\n */\nexport const supportsMidnightWalletConnection = (): boolean => {\n return typeof window !== 'undefined' && !!window.midnight?.mnLace;\n};\n\n/**\n * Returns a list of available Midnight wallet connectors.\n * @returns An array of `Connector` objects, currently only Lace.\n */\nexport const getMidnightAvailableConnectors = async (): Promise<Connector[]> => {\n if (!supportsMidnightWalletConnection()) {\n return [];\n }\n return [{ id: 'mnLace', name: 'Lace (Midnight)' }];\n};\n\n/**\n * Disconnects from the Midnight wallet.\n */\nexport async function disconnectMidnightWallet(): Promise<{\n disconnected: boolean;\n}> {\n return { disconnected: true };\n}\n","import { MidnightNetworkConfig } from '@openzeppelin/contracts-ui-builder-types';\n\nexport const midnightTestnet: MidnightNetworkConfig = {\n id: 'midnight-testnet',\n exportConstName: 'midnightTestnet',\n name: 'Midnight Testnet',\n ecosystem: 'midnight',\n network: 'midnight-testnet',\n type: 'testnet',\n isTestnet: true,\n // Add Midnight-specific fields here when known\n // explorerUrl: '...',\n // apiUrl: '...',\n};\n\n// Has been deprecated in favor of midnightTestnet\n// export const midnightDevnet: MidnightNetworkConfig = {\n// id: 'midnight-devnet',\n// exportConstName: 'midnightDevnet',\n// name: 'Midnight Devnet',\n// ecosystem: 'midnight',\n// network: 'midnight-devnet',\n// type: 'devnet',\n// isTestnet: true,\n// // Add Midnight-specific fields here when known\n// // explorerUrl: '...',\n// };\n","import { MidnightNetworkConfig } from '@openzeppelin/contracts-ui-builder-types';\n\nimport { midnightTestnet } from './testnet';\n\n// All testnet/devnet networks\nexport const midnightTestnetNetworks: MidnightNetworkConfig[] = [midnightTestnet];\n\n// All Midnight networks - for now, this is just testnets\nexport const midnightNetworks: MidnightNetworkConfig[] = [...midnightTestnetNetworks];\n\n// Export individual networks as well\nexport { midnightTestnet };\n","/**\n * Configuration for the Midnight adapter\n *\n * This file defines the dependencies required by the Midnight adapter\n * when generating exported projects. It follows the AdapterConfig\n * interface to provide a structured approach to dependency management.\n */\nexport const midnightAdapterConfig = {\n /**\n * Default app name to display in the wallet connection UI.\n */\n appName: 'OpenZeppelin Contracts UI Builder',\n\n /**\n * Dependencies required by the Midnight adapter\n * These will be included in exported projects that use this adapter\n */\n dependencies: {\n // TODO: Review and update with real, verified dependencies and versions before production release\n\n // Runtime dependencies\n runtime: {\n // Core Midnight protocol libraries\n '@midnight-protocol/sdk': '^0.8.2',\n '@midnight-protocol/client': '^0.7.0',\n\n // Encryption and privacy utilities\n 'libsodium-wrappers': '^0.7.11',\n '@openzeppelin/contracts-upgradeable': '^4.9.3',\n\n // Additional utilities for Midnight\n 'js-sha256': '^0.9.0',\n 'bn.js': '^5.2.1',\n\n '@midnight-ntwrk/dapp-connector-api': '^3.0.0',\n },\n\n // Development dependencies\n dev: {\n // Testing utilities for Midnight\n '@midnight-protocol/testing': '^0.5.0',\n\n // Type definitions\n '@types/libsodium-wrappers': '^0.7.10',\n '@types/bn.js': '^5.1.1',\n },\n },\n};\n"],"mappings":"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