@openzeppelin/contracts-ui-builder-adapter-evm
Version:
EVM Adapter for Contracts UI Builder
135 lines (92 loc) • 8.27 kB
Markdown
# EVM Adapter (`/contracts-ui-builder-adapter-evm`)
This package provides the `ContractAdapter` implementation for EVM-compatible blockchains (Ethereum, Polygon, BSC, etc.) for the UI Builder.
It is responsible for:
- Implementing the `ContractAdapter` interface from `/contracts-ui-builder-types`.
- Defining and exporting specific EVM network configurations (e.g., Ethereum Mainnet, Sepolia Testnet) as `EvmNetworkConfig` objects. These are located in `src/networks/` and include details like RPC URLs, Chain IDs, explorer URLs, and native currency information.
- Loading contract ABIs (from JSON strings or via Etherscan, using the `apiUrl` from the provided `EvmNetworkConfig`).
- Mapping EVM-specific data types to the form field types used by the builder app.
- Parsing user input (including complex types like structs and arrays) into EVM-compatible transaction data, according to the `EvmNetworkConfig`.
- Formatting results from view function calls.
- **Transaction Execution**: Handling the signing and broadcasting of transactions via different strategies (EOA, Relayer).
- Interacting with EVM wallets (via Wagmi/Viem) using the `wallet` module.
- Providing other EVM-specific configurations and validation for execution methods.
---
## Transaction Execution
The EVM adapter uses an **Execution Strategy** pattern to handle transaction submissions. This decouples the core `signAndBroadcast` logic from the specific implementation of each execution method.
### Supported Strategies
1. **EOA (Externally Owned Account)**: The default method. It directly uses the user's connected wallet (via Wagmi) to sign and broadcast the transaction.
2. **Relayer**: Allows for gasless transactions by sending the transaction to the OpenZeppelin Relayer service. This strategy uses the `/relayer-sdk`.
The adapter selects the appropriate strategy at runtime based on the `ExecutionConfig` provided by the user.
### Configuration
In the UI Builder, the execution method is configured in the "Customize" step. The UI provides options to select between `EOA` and `Relayer` and configure their specific parameters (e.g., Relayer API credentials, EOA address restrictions).
This configuration is then passed to the `EvmAdapter`'s `signAndBroadcast` method, which uses a factory to instantiate the correct execution strategy.
---
## Wallet Integration & UI
All wallet integration logic, UI components, facade hooks, and the UI context provider (e.g., `EvmBasicUiContextProvider` for Wagmi) for EVM-compatible chains are located in the [`src/wallet/`](./src/wallet/) module of this adapter.
The `EvmAdapter` implements the optional UI facilitation methods from the `ContractAdapter` interface (`getEcosystemReactUiContextProvider`, `getEcosystemReactHooks`, `getEcosystemWalletComponents`). These capabilities are consumed by the `builder` application's `WalletStateProvider`, which manages the global wallet state and makes these hooks and components accessible to the rest of the application via the `useWalletState()` hook.
**For full documentation on the `src/wallet/` module, its exports, configuration, and usage examples, see [`src/wallet/README.md`](./src/wallet/README.md).**
---
This adapter generally follows the standard module structure outlined in the main project [Adapter Architecture Guide](../../docs/ADAPTER_ARCHITECTURE.md).
## Package Structure
```text
adapter-evm/
├── src/
│ ├── abi/ # ABI fetching and parsing utilities
│ ├── config/ # Adapter-specific configuration
│ ├── mapping/ # Type mapping utilities
│ ├── networks/ # EVM network configurations
│ ├── query/ # View function execution
│ ├── transaction/ # Transaction execution system
│ │ ├── components/ # React components for configuration
│ │ ├── strategies/ # Execution strategy implementations
│ ├── validation/ # Validation utilities
│ ├── wallet/ # Wallet integration (see wallet/README.md)
│ │ ├── providers/ # Wallet context providers
│ │ ├── hooks/ # Wallet interaction hooks
│ │ ├── components/ # Wallet UI components
│ │ ├── implementation/ # Wagmi implementation details
│ │ ├── types/ # Wallet-specific types
│ │ ├── utils/ # Wallet utilities
│ │ ├── README.md # Detailed wallet documentation
│ ├── adapter.ts # Main EvmAdapter class implementation
│ └── index.ts # Public package exports
├── package.json
├── tsconfig.json
├── tsup.config.ts
├── vitest.config.ts
└── README.md
```
---
## Usage (Adapter Instantiation)
The `EvmAdapter` class is instantiated with a specific `EvmNetworkConfig` object, making it aware of the target network from its creation:
```typescript
import { ethereumSepolia, EvmAdapter } from '@openzeppelin/contracts-ui-builder-adapter-evm';
// Or any other exported EvmNetworkConfig
const networkConfig = ethereumSepolia;
const evmAdapter = new EvmAdapter(networkConfig);
// Now use evmAdapter for operations on the Ethereum Sepolia testnet
```
Network configurations for various EVM chains (mainnets and testnets) are exported from `src/networks/index.ts` within this package (e.g., `ethereumMainnet`, `polygonMainnet`, `ethereumSepolia`, `polygonAmoy`). The full list of available networks is exported as `evmNetworks`.
## RPC URL Configuration
The `EvmNetworkConfig` objects defined in `src/networks/` (e.g., `ethereumMainnet`) each specify a default public `rpcUrl`.
This default RPC URL can be overridden at runtime by the consuming application (either the main UI Builder app or an exported app) through the central `AppConfigService`. This service loads configurations from environment variables (for the builder app) or a `public/app.config.json` file (for exported apps).
To override an RPC URL, the application's configuration should define an entry in the `rpcEndpoints` section, keyed by the network's string ID (e.g., `"ethereum-mainnet"`). For example:
In `.env` for the builder app:
`VITE_APP_CFG_RPC_ENDPOINT_ETHEREUM_MAINNET="https://your-custom-mainnet-rpc.io/key"`
In `public/app.config.json` for an exported app:
```json
{
// ... other configs ...
"rpcEndpoints": {
"ethereum-mainnet": "https://your-custom-mainnet-rpc.io/key"
}
}
```
The `EvmAdapter`, when performing operations like view function queries (specifically its fallback public client) or when initializing its underlying Wagmi configuration for wallet interactions, will prioritize these runtime-configured RPC URLs.
### Wagmi `defaultSupportedChains` and RPC Overrides
The `src/wallet/implementation/wagmi-implementation.ts` file configures Wagmi with a `defaultSupportedChains` array (e.g., Mainnet, Sepolia, Polygon). For RPC overrides from `AppConfigService` to apply to these chains within Wagmi's transports, a mapping is maintained in `viemChainIdToAppNetworkId` within `wagmi-implementation.ts`. If new chains are added to `defaultSupportedChains` and their RPCs need to be overridable, this internal map must also be updated to link the Viem chain ID to your application's string-based network ID (e.g., `[polygon.id]: 'polygon-mainnet'`).
## Network Configurations
Network configurations for various EVM chains (mainnets and testnets) are exported from `src/networks/index.ts` within this package (e.g., `ethereumMainnet`, `polygonMainnet`, `ethereumSepolia`, `polygonAmoy`). Each `EvmNetworkConfig` includes:
- `id`: A unique string identifier for the network (e.g., "ethereum-mainnet").
- `primaryExplorerApiIdentifier`: A string key (e.g., "etherscan-mainnet") used by `AppConfigService` to fetch a specific API key for this network's explorer from `networkServiceConfigs`.
- It also includes a default public `rpcUrl`, Chain ID, `apiUrl` for explorers, `explorerUrl`, and native currency information.