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
12 changes: 6 additions & 6 deletions apps/builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,18 @@
"@creit.tech/stellar-wallets-kit": "^1.9.5",
"@hookform/resolvers": "^4.1.3",
"@icons-pack/react-simple-icons": "^12.9.0",
"@openzeppelin/adapter-evm": "^2.0.2",
"@openzeppelin/adapter-evm": "^2.3.0",
"@openzeppelin/adapter-midnight": "^2.0.1",
"@openzeppelin/adapter-polkadot": "^2.0.2",
"@openzeppelin/adapter-solana": "^2.0.0",
"@openzeppelin/adapter-stellar": "^2.0.2",
"@openzeppelin/ui-components": "^3.0.1",
"@openzeppelin/ui-react": "^3.0.0",
"@openzeppelin/ui-renderer": "^3.0.0",
"@openzeppelin/ui-components": "^3.8.0",
"@openzeppelin/ui-react": "^3.3.0",
"@openzeppelin/ui-renderer": "^3.4.0",
"@openzeppelin/ui-storage": "^1.2.2",
"@openzeppelin/ui-styles": "^1.1.0",
"@openzeppelin/ui-types": "^3.1.1",
"@openzeppelin/ui-utils": "^3.0.1",
"@openzeppelin/ui-types": "^3.3.0",
"@openzeppelin/ui-utils": "^3.3.0",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-dialog": "^1.1.15",
Expand Down
29 changes: 20 additions & 9 deletions apps/builder/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useCallback, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';

import { Footer, NetworkErrorNotificationProvider, Toaster } from '@openzeppelin/ui-components';
import { AnalyticsProvider, RuntimeProvider, WalletStateProvider } from '@openzeppelin/ui-react';
import type { NativeConfigLoader } from '@openzeppelin/ui-types';
import type { CreateRuntimeOptions, NativeConfigLoader } from '@openzeppelin/ui-types';

import { Header } from './components/Common/Header';
import { NetworkErrorHandler } from './components/Common/NetworkErrorHandler';
Expand All @@ -11,8 +11,9 @@ import { UIBuilder } from './components/UIBuilder';
import { useUIBuilderState } from './components/UIBuilder/hooks';
import { AliasLabelBridge } from './contexts/AliasLabelBridge';
import { ContractUIStorageProvider } from './contexts/ContractUIStorageProvider';
import { NameResolverBridge } from './contexts/NameResolverBridge';
import { StorageOperationsProvider } from './contexts/StorageOperationsContext';
import { getNetworkById, getRuntime } from './core/ecosystemManager';
import { getNetworkById, getRuntime, RUNTIME_CREATION_OPTIONS } from './core/ecosystemManager';

// Use Vite's import.meta.glob to find all potential kit config files.
// Expecting them to be .ts files as per convention.
Expand Down Expand Up @@ -87,22 +88,32 @@ function App() {
}
}, []);

const runtimeCreationOptions = useMemo((): CreateRuntimeOptions => RUNTIME_CREATION_OPTIONS, []);

const resolveRuntime = useCallback(
(networkConfig: Parameters<typeof getRuntime>[0]) =>
getRuntime(networkConfig, runtimeCreationOptions),
[runtimeCreationOptions]
);

return (
<AnalyticsProvider tagId={import.meta.env.VITE_GA_TAG_ID} autoInit={true}>
<NetworkErrorNotificationProvider>
<StorageOperationsProvider>
<ContractUIStorageProvider>
<RuntimeProvider resolveRuntime={getRuntime}>
<RuntimeProvider resolveRuntime={resolveRuntime}>
<WalletStateProvider
initialNetworkId={null}
getNetworkConfigById={getNetworkById}
loadConfigModule={loadAppConfigModule}
>
<AliasLabelBridge>
<AppContent />
{/* Global network error handler - always mounted to handle error toasts */}
<NetworkErrorHandler />
</AliasLabelBridge>
<NameResolverBridge>
<AliasLabelBridge>
<AppContent />
{/* Global network error handler - always mounted to handle error toasts */}
<NetworkErrorHandler />
</AliasLabelBridge>
</NameResolverBridge>
</WalletStateProvider>
</RuntimeProvider>
<Toaster position="top-right" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export function AddressBookDialog({ open, onOpenChange }: AddressBookDialogProps
currentNetworkId={activeNetworkConfig?.id}
filterNetworkIds={filterNetworkIds}
onFilterNetworkIdsChange={setFilterNetworkIds}
enableNameResolution
/>
</DialogContent>
</Dialog>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Control } from 'react-hook-form';
import { DynamicFormField } from '@openzeppelin/ui-renderer';
import type { FormFieldType, FormValues } from '@openzeppelin/ui-types';

import { BlockchainAddressFieldWithRichPreview } from '@/components/fields/BlockchainAddressFieldWithRichPreview';
import type { BuilderRuntime } from '@/core/runtimeAdapter';

interface ContractFormFieldsProps {
Expand All @@ -26,15 +27,31 @@ export function ContractFormFields({
<div className="space-y-6">
{/* Form Fields */}
<div className="space-y-4">
{contractDefinitionInputs.map((field) => (
<DynamicFormField
key={field.id}
field={field}
control={control}
addressing={runtime?.addressing}
typeMapping={runtime?.typeMapping}
/>
))}
{contractDefinitionInputs.map((field) =>
field.type === 'blockchain-address' ? (
<BlockchainAddressFieldWithRichPreview
key={field.id}
id={field.id}
label={field.label}
placeholder={field.placeholder}
helperText={field.helperText}
name={field.name}
control={control}
addressing={runtime?.addressing}
networkId={runtime?.networkConfig.id}
validation={field.validation}
readOnly={field.readOnly}
/>
) : (
<DynamicFormField
key={field.id}
field={field}
control={control}
addressing={runtime?.addressing}
typeMapping={runtime?.typeMapping}
/>
)
)}
</div>

{/* Enhanced Loading Indicator */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export function ContractSuccessStatus({
{proxyInfo?.isProxy && !ignoreProxy && (
<ProxyStatusIndicator
proxyInfo={proxyInfo}
networkId={runtime.networkConfig.id}
proxyExplorerUrl={proxyExplorerUrl}
implementationExplorerUrl={implementationExplorerUrl}
adminExplorerUrl={adminExplorerUrl}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Banner, BooleanField, SelectGroupedField, TextField } from '@openzeppel
import { DynamicFormField } from '@openzeppelin/ui-renderer';
import { FormFieldType } from '@openzeppelin/ui-types';

import { BlockchainAddressFieldWithRichPreview } from '@/components/fields/BlockchainAddressFieldWithRichPreview';
import type { BuilderRuntime } from '@/core/runtimeAdapter';

import { OptionGroup, shouldShowFieldTypeSelector } from './utils/fieldTypeUtils';
Expand Down Expand Up @@ -200,13 +201,26 @@ export function FieldBasicSettings({
Ensure you understand the risks of exposing this value to your users.
</Banner>
)}
<DynamicFormField
key={`hardcoded-${field.id}-${fieldType}`}
field={hardcodedFieldConfig}
control={control}
addressing={runtime?.addressing}
typeMapping={runtime?.typeMapping}
/>
{fieldType === 'blockchain-address' ? (
<BlockchainAddressFieldWithRichPreview
key={`hardcoded-${field.id}-${fieldType}`}
id={hardcodedFieldConfig.id}
label={hardcodedFieldConfig.label}
name="hardcodedValue"
control={control}
addressing={runtime?.addressing}
networkId={runtime?.networkConfig.id}
validation={hardcodedFieldConfig.validation}
/>
) : (
<DynamicFormField
key={`hardcoded-${field.id}-${fieldType}`}
field={hardcodedFieldConfig}
control={control}
addressing={runtime?.addressing}
typeMapping={runtime?.typeMapping}
/>
)}
<BooleanField
id="is-read-only"
name="readOnly"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react';

import { AddressField, RadioField } from '@openzeppelin/ui-components';
import { RadioField } from '@openzeppelin/ui-components';

import { BlockchainAddressFieldWithRichPreview } from '@/components/fields/BlockchainAddressFieldWithRichPreview';

import type { EoaConfigurationProps } from '../types';

Expand Down Expand Up @@ -32,12 +34,13 @@ export function EoaConfiguration({
{/* Specific EOA Address Input - Rendered conditionally */}
{watchedEoaOption === 'specific' && (
<div className="pt-2">
<AddressField
<BlockchainAddressFieldWithRichPreview
id="specific-eoa-address"
label="Specific EOA Address"
name="specificEoaAddress"
control={control}
addressing={runtime?.addressing}
networkId={runtime?.networkConfig.id}
validation={{ required: true }}
placeholder="Enter the required EOA address (e.g., 0x...)"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@openzeppelin/ui-types';
import { logger } from '@openzeppelin/ui-utils';

import { BlockchainAddressFieldWithRichPreview } from '@/components/fields/BlockchainAddressFieldWithRichPreview';
import type { BuilderRuntime } from '@/core/runtimeAdapter';

import { useBuilderAnalytics } from '../../../../hooks/useBuilderAnalytics';
Expand Down Expand Up @@ -115,12 +116,26 @@ export function UiKitSettings({ runtime, onUpdateConfig, currentConfig }: UiKitS
<div className="space-y-4">
{selectedKit.configFields.map((field) => (
<div key={field.id} className="pt-2">
<DynamicFormField
field={field}
control={control}
addressing={runtime?.addressing}
typeMapping={runtime?.typeMapping}
/>
{field.type === 'blockchain-address' ? (
<BlockchainAddressFieldWithRichPreview
id={field.id}
label={field.label}
placeholder={field.placeholder}
helperText={field.helperText}
name={field.name}
control={control}
addressing={runtime?.addressing}
networkId={runtime?.networkConfig.id}
validation={field.validation}
/>
) : (
<DynamicFormField
field={field}
control={control}
addressing={runtime?.addressing}
typeMapping={runtime?.typeMapping}
/>
)}
</div>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { FieldValues } from 'react-hook-form';
import { useWatch } from 'react-hook-form';

import {
AddressFieldWithResolvedPreview,
type AddressFieldProps,
} from '@openzeppelin/ui-components';
import { ResolvedAddressFieldPreviewWithNameResolution } from '@openzeppelin/ui-renderer';
import type { AddressingCapability, NetworkConfig } from '@openzeppelin/ui-types';

type BlockchainAddressFieldWithRichPreviewProps<TFieldValues extends FieldValues> =
AddressFieldProps<TFieldValues> & {
/** Wallet-global network id (builder surfaces always use the active runtime). */
networkId?: string;
/**
* When set, reverse preview resolves against this network's runtime instead of
* the wallet-global active network. Unused today — builder has no per-field
* network selector; reserved for future dialogs with their own network dropdown.
*/
network?: NetworkConfig;
addressing?: AddressingCapability;
};

/**
* Pattern A (wallet-runtime): AddressFieldWithResolvedPreview + renderer bridge for
* async reverse ENS lookup. Parent watches the field and passes previewAddress.
*/
export function BlockchainAddressFieldWithRichPreview<TFieldValues extends FieldValues>({
control,
name,
networkId,
network,
addressing,
...addressFieldProps
}: BlockchainAddressFieldWithRichPreviewProps<TFieldValues>): React.ReactElement {
const previewAddress = useWatch({ control, name }) as string | undefined;
const previewNetworkId = network?.id ?? networkId;

return (
<AddressFieldWithResolvedPreview<TFieldValues>
{...addressFieldProps}
control={control}
name={name}
addressing={addressing}
previewAddress={previewAddress}
previewNetworkId={previewNetworkId}
preview={
<ResolvedAddressFieldPreviewWithNameResolution
address={previewAddress}
networkId={previewNetworkId}
network={network}
addressing={addressing}
/>
}
/>
);
}
Loading
Loading