Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
4c93eb6
feat(ecosystem-adapters): add comprehensive documentation for OpenZep…
cursoragent Apr 7, 2026
92be4d6
fix(ecosystem-adapters): replace unsupported block-beta Mermaid synta…
cursoragent Apr 7, 2026
657c053
fix(ecosystem-adapters): compact tier diagrams to reduce visual footp…
cursoragent Apr 7, 2026
9fa1590
fix(ecosystem-adapters): replace messy profiles flowchart with clean …
cursoragent Apr 7, 2026
ed372e5
fix(ecosystem-adapters): replace At a Glance diagram with compact sum…
cursoragent Apr 7, 2026
38ec4f5
feat(ecosystem-adapters): add React integration and multi-ecosystem docs
cursoragent Apr 7, 2026
b55bff2
Merge pull request #3 from pasevin/cursor/ecosystem-adapters-document…
pasevin Apr 7, 2026
588d11d
feat(navigation): add Ecosystem Adapters to all ecosystem sidebars
cursoragent Apr 7, 2026
aa64693
Merge pull request #4 from pasevin/cursor/ecosystem-adapters-document…
pasevin Apr 7, 2026
beb44ec
docs(uikit): add comprehensive UIKit documentation pages
cursoragent Apr 7, 2026
873f1dd
docs(navigation): add UIKit section to Ethereum & EVM sidebar
cursoragent Apr 7, 2026
539de70
docs(uikit): add source code callout linking to GitHub repo
cursoragent Apr 7, 2026
15e4677
docs(uikit): rewrite Mermaid diagrams for clean layout
cursoragent Apr 7, 2026
feac888
docs(uikit): fix capability tiers chart to be readable
cursoragent Apr 7, 2026
b796b8e
docs(uikit): remove legacy reference and consolidate capability tables
cursoragent Apr 7, 2026
9e5a355
docs(uikit): remove multisig from execution strategies diagram
cursoragent Apr 7, 2026
79cacab
docs(uikit): add screenshots from the live example app
cursoragent Apr 7, 2026
fea8f03
docs(uikit): replace broken contract state screenshots with clean ones
cursoragent Apr 7, 2026
d69ecfe
docs(uikit): clean up screenshots — keep only working ones
cursoragent Apr 8, 2026
1afad58
docs(uikit): add ContractStateWidget GIF with side-by-side layout
cursoragent Apr 8, 2026
5b77596
docs(uikit): retake screenshots with fully loaded pages
cursoragent Apr 8, 2026
c98fe77
docs(uikit): remove main screenshot from UIKit index page
cursoragent Apr 8, 2026
4b54197
docs(uikit): replace TransactionForm screenshot with new image
cursoragent Apr 8, 2026
21bf5c2
docs(uikit): replace contract state widget GIF with PNG, fix text ove…
cursoragent Apr 8, 2026
a458a93
docs(uikit): remove old contract-state-widget.gif
cursoragent Apr 8, 2026
63de35b
docs(uikit): update contract state widget PNG with reduced padding
cursoragent Apr 8, 2026
74980f2
docs(uikit): reduce contract state widget image width
cursoragent Apr 8, 2026
4d30d13
docs(uikit): add AddressBookWidget section, dedicated storage page, a…
cursoragent Apr 8, 2026
118a1a2
docs(uikit): remove two-column layout from AddressBookWidget section
cursoragent Apr 8, 2026
956492b
docs(uikit): move AddressBookWidget heading below image
cursoragent Apr 8, 2026
a79642f
docs(uikit): improve provider tree diagram styling
cursoragent Apr 9, 2026
6f97e6d
docs(uikit): fix provider tree diagram text cutoff
cursoragent Apr 9, 2026
d2bd19b
docs(uikit): shorten provider tree diagram labels to fix text cutoff
cursoragent Apr 9, 2026
b511bae
docs(uikit): restore full provider descriptions in Provider Tree diagram
cursoragent Apr 9, 2026
bb49431
docs(uikit): switch Provider Tree to TD layout for readable node text
cursoragent Apr 9, 2026
1d8ef5f
docs(uikit): fix node text truncation with classDef width override
cursoragent Apr 9, 2026
421a37b
docs(uikit): fix incorrect API references in code examples
cursoragent Apr 9, 2026
f3b34b2
docs(uikit): fix cn import — comes from @openzeppelin/ui-utils
cursoragent Apr 9, 2026
51e95fd
docs(uikit): fix useRuntimeContext example — isLoading is inside getR…
cursoragent Apr 9, 2026
71c8536
docs(uikit): add 'Why Use the Storage Plugin' section with real-world…
cursoragent Apr 9, 2026
195b2d9
docs(uikit): add account alias plugin screenshot to storage page
cursoragent Apr 9, 2026
de9d53e
docs(uikit): use side-by-side layout for account alias plugin image
cursoragent Apr 9, 2026
1e2386b
docs(uikit): document React hook factories (createRepositoryHook, cre…
cursoragent Apr 9, 2026
2ad538b
docs(uikit): add missing UI primitives and form field types to Compon…
cursoragent Apr 9, 2026
6c5d935
merge: resolve conflict in react-integration.mdx — keep TD layout fix…
cursoragent Apr 9, 2026
d64d55b
Merge pull request #8 from pasevin/cursor/uikit-storage-why-section-6e41
pasevin Apr 9, 2026
b8d3f8f
Merge pull request #7 from pasevin/cursor/fix-uikit-provider-tree-dia…
pasevin Apr 9, 2026
f3945c6
docs(uikit): fix broken adapter docs links
pasevin Apr 9, 2026
f347a4c
Reorder nav: place UIKit directly below Role Manager
cursoragent Apr 10, 2026
349abe4
Merge pull request #9 from pasevin/cursor/uikit-nav-order-feab
pasevin Apr 10, 2026
8fd2fec
docs(ecosystem-adapters): add Netlify UIKit example app links
pasevin Apr 20, 2026
96ae0b9
docs(uikit): add Netlify example app links
pasevin Apr 20, 2026
12c135a
docs(ecosystem-adapters): keep parent ecosystem nav on adapter routes
pasevin Apr 27, 2026
58a41d2
Merge main: resolve nav conflicts with Zama and ecosystem adapters
pasevin Apr 27, 2026
b74b05b
Merge ecosystem-adapters doc branch: nav + patterns for UIKit work
pasevin Apr 27, 2026
40d0469
docs(uikit): polish pages and share dev libraries nav
pasevin Apr 27, 2026
7bd1f0d
docs(uikit): point adapter links to ecosystem docs, tidy AddressBook …
pasevin Apr 27, 2026
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
192 changes: 192 additions & 0 deletions content/ecosystem-adapters/architecture.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
---
title: Architecture
---

This page describes the capability-based architecture that underpins all OpenZeppelin Ecosystem Adapters. Understanding this architecture will help you choose the right profile for your application, consume capabilities efficiently, and build your own adapter if you need to.

## Package Topology

The adapter system is split across several packages with clear dependency boundaries:

```mermaid
flowchart TD
App["Consumer Application"] --> Runtime["EcosystemRuntime"]
Runtime --> Caps["Capability Interfaces\n(@openzeppelin/ui-types)"]

Caps --> Evm["adapter-evm"]
Caps --> Polkadot["adapter-polkadot"]
Caps --> Stellar["adapter-stellar"]
Caps --> Midnight["adapter-midnight"]
Caps --> Solana["adapter-solana"]

App --> Vite["adapters-vite"]

Evm --> Core["adapter-evm-core"]
Polkadot --> Core
Core --> Utils["adapter-runtime-utils"]
Stellar --> Utils

style Caps fill:#e8eaf6,stroke:#3f51b5,color:#000
style Utils fill:#e0f2f1,stroke:#00897b,color:#000
style Core fill:#fff3e0,stroke:#ef6c00,color:#000
```

- **`@openzeppelin/ui-types`** defines all 13 capability interfaces. It is the single source of truth.
- **`adapter-runtime-utils`** provides profile composition, lazy capability instantiation, and staged disposal.
- **`adapter-evm-core`** centralizes reusable EVM implementations shared by `adapter-evm` and `adapter-polkadot`.
- Each public adapter exposes an `ecosystemDefinition` conforming to `EcosystemExport`.

## Capability Tiers

Adapter functionality is decomposed into **13 capability interfaces** organized across **3 tiers**. The tiers reflect increasing levels of runtime requirements: stateless metadata, network-aware schema operations, and stateful wallet-dependent interactions.

| Tier | Category | Network | Wallet | Capabilities |
| --- | --- | --- | --- | --- |
| **1** | Lightweight | No | No | `Addressing`, `Explorer`, `NetworkCatalog`, `UiLabels` |
| **2** | Schema | Yes | No | `ContractLoading`, `Schema`, `TypeMapping`, `Query` |
| **3** | Runtime | Yes | Yes | `Execution`, `Wallet`, `UiKit`, `Relayer`, `AccessControl` |

### Tier Import Rules

Tier isolation is enforced physically through sub-path exports, not tree-shaking:

- **Tier 1** modules must not import from Tier 2 or Tier 3 modules
- **Tier 2** modules may import from Tier 1
- **Tier 3** modules may import from Tier 1 and Tier 2

This means importing `@openzeppelin/adapter-evm/addressing` will never pull in wallet SDKs, RPC clients, or access control code, regardless of your bundler configuration.

### Capability Reference

| Capability | Interface | Tier | Key Methods |
| --- | --- | --- | --- |
| Addressing | `AddressingCapability` | 1 | `isValidAddress` |
| Explorer | `ExplorerCapability` | 1 | `getExplorerUrl`, `getExplorerTxUrl` |
| NetworkCatalog | `NetworkCatalogCapability` | 1 | `getNetworks` |
| UiLabels | `UiLabelsCapability` | 1 | `getUiLabels` |
| ContractLoading | `ContractLoadingCapability` | 2 | `loadContract`, `getContractDefinitionInputs` |
| Schema | `SchemaCapability` | 2 | `isViewFunction`, `getWritableFunctions` |
| TypeMapping | `TypeMappingCapability` | 2 | `mapParameterTypeToFieldType`, `getTypeMappingInfo` |
| Query | `QueryCapability` | 2 | `queryViewFunction`, `formatFunctionResult`, `getCurrentBlock` |
| Execution | `ExecutionCapability` | 3 | `signAndBroadcast`, `formatTransactionData`, `validateExecutionConfig` |
| Wallet | `WalletCapability` | 3 | `connectWallet`, `disconnectWallet`, `getWalletConnectionStatus` |
| UiKit | `UiKitCapability` | 3 | `getAvailableUiKits`, `configureUiKit` |
| Relayer | `RelayerCapability` | 3 | `getRelayers`, `getNetworkServiceForms` |
| AccessControl | `AccessControlCapability` | 3 | `registerContract`, `grantRole`, and 17 more |

## Profiles

Profiles are pre-composed bundles of capabilities that match common application archetypes. They exist for convenience. You can always consume individual capabilities directly via the `CapabilityFactoryMap`.

Each profile is a strict superset of Declarative. Higher profiles add capabilities incrementally:

### Profile-Capability Matrix

| Capability | Declarative | Viewer | Transactor | Composer | Operator |
| --- | --- | --- | --- | --- | --- |
| `Addressing` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `Explorer` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `NetworkCatalog` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `UiLabels` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `ContractLoading` | | ✅ | ✅ | ✅ | ✅ |
| `Schema` | | ✅ | ✅ | ✅ | ✅ |
| `TypeMapping` | | ✅ | ✅ | ✅ | ✅ |
| `Query` | | ✅ | | ✅ | ✅ |
| `Execution` | | | ✅ | ✅ | ✅ |
| `Wallet` | | | ✅ | ✅ | ✅ |
| `UiKit` | | | | ✅ | ✅ |
| `Relayer` | | | | ✅ | |
| `AccessControl` | | | | | ✅ |

### Profile Selection Guide

| If your application needs to… | Choose |
| --- | --- |
| Validate addresses, list networks, link to explorers | **Declarative** |
| Read contract state without sending transactions | **Viewer** |
| Send transactions without reading contract state first | **Transactor** |
| Build full contract interaction UIs with relayer support | **Composer** |
| Manage contract roles and permissions | **Operator** |

## Runtime Lifecycle

Runtimes are **immutable** and **network-scoped**. When a user switches networks, the consuming application must dispose the current runtime and create a new one.

```mermaid
sequenceDiagram
participant App as Application
participant ES as EcosystemExport
participant RT as EcosystemRuntime
participant Cap as Capabilities

App->>ES: createRuntime('composer', networkA)
ES->>RT: Compose capabilities with shared state
RT-->>App: runtime (immutable)

App->>RT: runtime.query.queryViewFunction(...)
RT->>Cap: Lazy-init Query capability
Cap-->>RT: result

Note over App,RT: User switches to networkB

App->>RT: runtime.dispose()
RT->>Cap: Staged cleanup (listeners → subscriptions → capabilities → RPC)
App->>ES: createRuntime('composer', networkB)
ES->>RT: New runtime with fresh state
RT-->>App: newRuntime
```

### Dispose Contract

- `dispose()` is **idempotent**: calling it multiple times is a no-op
- After `dispose()`, any method or property access throws `RuntimeDisposedError`
- Pending async operations (e.g., in-flight `signAndBroadcast`) are rejected with `RuntimeDisposedError`
- Cleanup follows a staged order: mark disposed → reject pending operations → clean up listeners and subscriptions → dispose capabilities → release wallet and RPC resources
- Runtime disposal does **not** disconnect the wallet. Disconnect is always an explicit user action

## Execution Strategies

The Execution capability uses a **strategy pattern** to support multiple transaction submission methods. Each adapter can provide its own set of strategies.

```mermaid
flowchart TD
Exec["ExecutionCapability\nsignAndBroadcast()"] --> Config{"executionConfig.method"}
Config -->|"EOA"| EOA["EoaExecutionStrategy\nDirect wallet signing"]
Config -->|"Relayer"| Relay["RelayerExecutionStrategy\nOpenZeppelin Relayer"]

EOA --> Wallet["Wallet signs tx"]
Relay --> RelayerSvc["Relayer service submits tx"]

Wallet --> Confirm["waitForTransactionConfirmation()"]
RelayerSvc --> Confirm

style Exec fill:#e8eaf6,stroke:#3f51b5,color:#000
style EOA fill:#e8f5e9,stroke:#388e3c,color:#000
style Relay fill:#fff3e0,stroke:#f57c00,color:#000
```

The EVM and Stellar adapters ship with both EOA and Relayer strategies. Adapter authors can implement custom strategies by conforming to the `AdapterExecutionStrategy` interface.

## Sub-Path Exports

Each adapter publishes every implemented capability and profile as a dedicated sub-path export:

```ts
// Tier 1: no wallet, no RPC, no heavy dependencies
import { createAddressing } from '@openzeppelin/adapter-stellar/addressing';
import { createExplorer } from '@openzeppelin/adapter-stellar/explorer';

// Tier 2: network-aware
import { createQuery } from '@openzeppelin/adapter-stellar/query';

// Tier 3: wallet-dependent
import { createExecution } from '@openzeppelin/adapter-stellar/execution';

// Profile runtimes
import { createRuntime } from '@openzeppelin/adapter-stellar/profiles/composer';

// Metadata and networks
import { networks } from '@openzeppelin/adapter-stellar/networks';
```

This structure ensures that a Declarative-profile consumer never bundles wallet SDKs, and that individual capabilities can be tested in isolation.
Loading
Loading