Skip to content

Commit 12c135a

Browse files
committed
docs(ecosystem-adapters): keep parent ecosystem nav on adapter routes
Use lastEcosystem for /ecosystem-adapters like relayer/monitor; drop standalone ecosystemAdaptersTree. Add tab url rules and midnight context. Polish MDX prose; document viem isAddress for EVM addressing.
1 parent 8fd2fec commit 12c135a

14 files changed

Lines changed: 265 additions & 240 deletions

content/ecosystem-adapters/architecture.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Architecture
33
---
44

5-
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 — if needed — build your own adapter.
5+
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.
66

77
## Package Topology
88

@@ -54,7 +54,7 @@ Tier isolation is enforced physically through sub-path exports, not tree-shaking
5454
- **Tier 2** modules may import from Tier 1
5555
- **Tier 3** modules may import from Tier 1 and Tier 2
5656

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

5959
### Capability Reference
6060

@@ -76,11 +76,11 @@ This means importing `@openzeppelin/adapter-evm/addressing` will never pull in w
7676

7777
## Profiles
7878

79-
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`.
79+
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`.
8080

81-
Each profile is a strict superset of Declarative — higher profiles add capabilities incrementally:
81+
Each profile is a strict superset of Declarative. Higher profiles add capabilities incrementally:
8282

83-
### ProfileCapability Matrix
83+
### Profile-Capability Matrix
8484

8585
| Capability | Declarative | Viewer | Transactor | Composer | Operator |
8686
| --- | --- | --- | --- | --- | --- |
@@ -138,11 +138,11 @@ sequenceDiagram
138138

139139
### Dispose Contract
140140

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

147147
## Execution Strategies
148148

@@ -172,14 +172,14 @@ The EVM and Stellar adapters ship with both EOA and Relayer strategies. Adapter
172172
Each adapter publishes every implemented capability and profile as a dedicated sub-path export:
173173

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

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

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

185185
// Profile runtimes

content/ecosystem-adapters/building-an-adapter.mdx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,17 @@ Start with the four stateless capabilities that every adapter must provide:
8585
```ts
8686
// capabilities/addressing.ts
8787
import type { AddressingCapability } from '@openzeppelin/ui-types';
88+
import { isAddress } from 'viem';
8889

8990
export function createAddressing(): AddressingCapability {
9091
return {
9192
isValidAddress(address: string): boolean {
92-
// Your chain's address validation logic
93-
return /^0x[0-9a-fA-F]{40}$/.test(address);
93+
// EVM: prefer viem's isAddress (as in @openzeppelin/adapter-evm) over a hand-rolled regex;
94+
// it covers checksums and library-maintained rules.
95+
// Other chains, for example:
96+
// Stellar StrKey (account): /^G[A-Z0-9]{55}$/ (simplified; use StrKey helpers in production)
97+
// Polkadot SS58: @polkadot/util-crypto validateAddress / decodeAddress
98+
return isAddress(address);
9499
},
95100
};
96101
}
@@ -292,7 +297,7 @@ import { createExecution } from '@openzeppelin/adapter-evm-core/execution';
292297
import { createQuery } from '@openzeppelin/adapter-evm-core/query';
293298
```
294299

295-
This is exactly what `adapter-polkadot` does — it delegates ABI loading, queries, transaction execution, and wallet infrastructure to the shared EVM core while adding Polkadot-specific metadata and network configurations.
300+
This is exactly what `adapter-polkadot` does. It delegates ABI loading, queries, transaction execution, and wallet infrastructure to the shared EVM core while adding Polkadot-specific metadata and network configurations.
296301

297302
## Lazy Capability Factories
298303

content/ecosystem-adapters/getting-started.mdx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pnpm add @openzeppelin/adapter-stellar @openzeppelin/ui-types
2828
pnpm add @openzeppelin/adapter-polkadot @openzeppelin/ui-types
2929
```
3030

31-
If you're consuming multiple ecosystems, install all of them — each adapter is independent and tree-shakeable.
31+
If you're consuming multiple ecosystems, install all of them. Each adapter is independent and tree-shakeable.
3232

3333
## Quick Start
3434

@@ -56,7 +56,7 @@ const network = ecosystemDefinition.networks[0]; // e.g., Ethereum Mainnet
5656
const runtime = ecosystemDefinition.createRuntime('viewer', network);
5757
```
5858

59-
The `createRuntime` call is **synchronous** — it assembles capability instances immediately. Expensive initialization (RPC connections, wallet discovery) happens lazily on first use.
59+
The `createRuntime` call is **synchronous**. It assembles capability instances immediately. Expensive initialization (RPC connections, wallet discovery) happens lazily on first use.
6060

6161
If you request a profile the adapter doesn't fully support, `createRuntime` throws an `UnsupportedProfileError` listing the missing capabilities.
6262

@@ -65,10 +65,10 @@ If you request a profile the adapter doesn't fully support, `createRuntime` thro
6565
Access capabilities directly from the runtime object:
6666

6767
```ts
68-
// Validate an address (Tier 1 instant, no network call)
68+
// Validate an address (Tier 1: instant, no network call)
6969
const isValid = runtime.addressing.isValidAddress('0x1234...');
7070

71-
// Read contract state (Tier 2 triggers RPC on first call)
71+
// Read contract state (Tier 2: triggers RPC on first call)
7272
const result = await runtime.query.queryViewFunction(
7373
'0xContractAddress',
7474
'balanceOf',
@@ -149,7 +149,7 @@ export default mergeConfig(
149149
);
150150
```
151151

152-
This centralizes `resolve.dedupe`, `optimizeDeps`, `ssr.noExternal`, and any adapter-specific Vite plugins — adapters remain the source of truth for their own build requirements.
152+
This centralizes `resolve.dedupe`, `optimizeDeps`, `ssr.noExternal`, and any adapter-specific Vite plugins. Adapters remain the source of truth for their own build requirements.
153153

154154
## Network Switching
155155

@@ -194,7 +194,7 @@ Adapters integrate with React through three layers: a **wallet context provider*
194194

195195
### Wallet Context Provider
196196

197-
Each adapter exports a root React component via `getEcosystemReactUiContextProvider()`. This component wraps your application (or the relevant subtree) and bootstraps the wallet SDK context — for example, EVM adapters render `WagmiProvider` and `QueryClientProvider` internally, while the Stellar adapter renders its own `StellarWalletContext.Provider`.
197+
Each adapter exports a root React component via `getEcosystemReactUiContextProvider()`. This component wraps your application (or the relevant subtree) and bootstraps the wallet SDK context. For example, EVM adapters render `WagmiProvider` and `QueryClientProvider` internally, while the Stellar adapter renders its own `StellarWalletContext.Provider`.
198198

199199
You don't render these providers yourself. Instead, pass the runtime to a shared `WalletStateProvider` from `@openzeppelin/ui-react`, which delegates to the correct ecosystem provider automatically:
200200

@@ -266,7 +266,7 @@ await runtime.wallet.disconnectWallet();
266266
```
267267

268268
<Callout type="info">
269-
`connectWallet` and `disconnectWallet` are imperative calls on the runtime — they are independent of the React rendering layer. You can call them from event handlers, effects, or outside React entirely.
269+
`connectWallet` and `disconnectWallet` are imperative calls on the runtime. They are independent of the React rendering layer. You can call them from event handlers, effects, or outside React entirely.
270270
</Callout>
271271

272272
### Hook Facade Pattern
@@ -295,7 +295,7 @@ Each facade object includes these hooks:
295295
| `useChains` | Returns the list of configured chains |
296296
| `useBalance` | Returns the native token balance for the connected account |
297297

298-
In practice, you access facade hooks through the runtime rather than importing them directly — the runtime's `uiKit.getEcosystemReactHooks()` method returns the correct facade for the active ecosystem:
298+
In practice, you access facade hooks through the runtime rather than importing them directly. The runtime's `uiKit.getEcosystemReactHooks()` method returns the correct facade for the active ecosystem:
299299

300300
```tsx
301301
import { useWalletState } from '@openzeppelin/ui-react';
@@ -320,12 +320,12 @@ function AccountInfo() {
320320
```
321321

322322
<Callout type="info">
323-
Hooks that don't apply to a given ecosystem return safe stubs. For example, the Stellar facade's `useSwitchChain` returns `{ switchChain: undefined }` — your components can feature-detect this without conditional imports.
323+
Hooks that don't apply to a given ecosystem return safe stubs. For example, the Stellar facade's `useSwitchChain` returns `{ switchChain: undefined }`. Your components can feature-detect this without conditional imports.
324324
</Callout>
325325

326326
## Multi-Ecosystem Apps
327327

328-
Applications that interact with multiple blockchains create one runtime per ecosystem. Each runtime is independent — it manages its own wallet session, RPC connections, and lifecycle.
328+
Applications that interact with multiple blockchains create one runtime per ecosystem. Each runtime is independent. It manages its own wallet session, RPC connections, and lifecycle.
329329

330330
### Setup
331331

@@ -359,16 +359,16 @@ Instantiate a runtime from each adapter's `ecosystemDefinition`:
359359
import { ecosystemDefinition as evmDefinition } from '@openzeppelin/adapter-evm';
360360
import { ecosystemDefinition as stellarDefinition } from '@openzeppelin/adapter-stellar';
361361

362-
// EVM runtime e.g., Ethereum Mainnet
362+
// EVM runtime (e.g. Ethereum Mainnet)
363363
const evmNetwork = evmDefinition.networks[0];
364364
const evmRuntime = evmDefinition.createRuntime('composer', evmNetwork);
365365

366-
// Stellar runtime e.g., Stellar Mainnet
366+
// Stellar runtime (e.g. Stellar Mainnet)
367367
const stellarNetwork = stellarDefinition.networks[0];
368368
const stellarRuntime = stellarDefinition.createRuntime('viewer', stellarNetwork);
369369
```
370370

371-
Each runtime is fully isolated. The EVM runtime connects to Ethereum via wagmi, the Stellar runtime connects to Horizon/Soroban — they share no state and can be disposed independently:
371+
Each runtime is fully isolated. The EVM runtime connects to Ethereum via wagmi, the Stellar runtime connects to Horizon/Soroban. They share no state and can be disposed independently:
372372

373373
```ts
374374
// Use both runtimes side by side
@@ -385,7 +385,7 @@ evmRuntime.dispose();
385385
```
386386

387387
<Callout type="info">
388-
Wallet sessions are ecosystem-scoped, not runtime-scoped. Disposing an EVM runtime to switch from Mainnet to Sepolia does not disconnect the user's MetaMask — the wallet session persists across runtime recreation within the same ecosystem.
388+
Wallet sessions are ecosystem-scoped, not runtime-scoped. Disposing an EVM runtime to switch from Mainnet to Sepolia does not disconnect the user's MetaMask. The wallet session persists across runtime recreation within the same ecosystem.
389389
</Callout>
390390

391391
## Next Steps

content/ecosystem-adapters/index.mdx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Ecosystem Adapters
33
---
44

5-
**OpenZeppelin Ecosystem Adapters** are a set of modular, chain-specific integration packages that let applications interact with any supported blockchain through a single, unified interface. Built on 13 composable capability interfaces organized in 3 tiers, each adapter encapsulates everything needed — contract loading, type mapping, transaction execution, wallet connection, and network configuration while keeping consuming applications completely chain-agnostic.
5+
**OpenZeppelin Ecosystem Adapters** are a set of modular, chain-specific integration packages that let applications interact with any supported blockchain through a single, unified interface. Built on 13 composable capability interfaces organized in 3 tiers, each adapter encapsulates contract loading, type mapping, transaction execution, wallet connection, and network configuration in one place, while keeping consuming applications completely chain-agnostic.
66

77
<Callout type="info">
88
**Source code**: The adapters are open-source. Browse the implementation, open issues, and contribute at [**github.com/OpenZeppelin/openzeppelin-adapters**](https://github.com/OpenZeppelin/openzeppelin-adapters).
@@ -25,14 +25,14 @@ title: Ecosystem Adapters
2525

2626
## Why Adapters?
2727

28-
Building cross-chain tooling traditionally forces developers into one of two traps: a monolithic abstraction that leaks chain details, or per-chain forks that drift apart over time. Adapters solve this with a **capability-based decomposition** — each chain implements only the interfaces it supports, and consuming applications pull in only what they need.
28+
Building cross-chain tooling traditionally forces developers into one of two traps: a monolithic abstraction that leaks chain details, or per-chain forks that drift apart over time. Adapters solve this with a **capability-based decomposition**. Each chain implements only the interfaces it supports, and consuming applications pull in only what they need.
2929

3030
```mermaid
3131
flowchart LR
3232
App["Your Application"] --> Runtime["EcosystemRuntime"]
33-
Runtime --> T1["Tier 1 Lightweight\n4 capabilities\nAddressing, Explorer, ..."]
34-
Runtime --> T2["Tier 2 Schema\n4 capabilities\nContractLoading, Query, ..."]
35-
Runtime --> T3["Tier 3 Runtime\n5 capabilities\nExecution, Wallet, ..."]
33+
Runtime --> T1["Tier 1 (Lightweight)\n4 capabilities\nAddressing, Explorer, ..."]
34+
Runtime --> T2["Tier 2 (Schema)\n4 capabilities\nContractLoading, Query, ..."]
35+
Runtime --> T3["Tier 3 (Runtime)\n5 capabilities\nExecution, Wallet, ..."]
3636
3737
style T1 fill:#e3f2fd,stroke:#1976d2,color:#000
3838
style T2 fill:#fff3e0,stroke:#f57c00,color:#000
@@ -41,10 +41,10 @@ flowchart LR
4141

4242
## Key Design Principles
4343

44-
- **Pay for what you use.** Tier 1 capabilities are stateless and never pull in wallet SDKs or RPC clients. Import `addressing` and you get only address validationnothing more.
44+
- **Pay for what you use.** Tier 1 capabilities are stateless and never pull in wallet SDKs or RPC clients. Import `addressing` and you get only address validation; nothing else is bundled.
4545
- **Profiles simplify consumption.** Five pre-composed profiles (Declarative, Viewer, Transactor, Composer, Operator) match common application archetypes so you don't have to assemble capabilities manually.
46-
- **Adapters own their chains.** All chain-specific logic ABI parsing, Soroban type mapping, ZK proof orchestration stays inside the adapter package. The consuming application never touches it.
47-
- **Runtime lifecycle is explicit.** Runtimes are immutable and network-scoped. Switching networks means disposing the old runtime and creating a new one no hidden state mutations.
46+
- **Adapters own their chains.** All chain-specific logic (ABI parsing, Soroban type mapping, ZK proof orchestration) stays inside the adapter package. The consuming application never touches it.
47+
- **Runtime lifecycle is explicit.** Runtimes are immutable and network-scoped. Switching networks means disposing the old runtime and creating a new one. There are no hidden state mutations.
4848

4949
## Packages
5050

@@ -63,10 +63,10 @@ flowchart LR
6363

6464
Adapters are consumed by several OpenZeppelin products:
6565

66-
- [**UI Builder**](https://github.com/OpenZeppelin/ui-builder) full-featured smart contract interaction UI
67-
- [**OpenZeppelin UI**](https://github.com/OpenZeppelin/openzeppelin-ui) shared UI components and React integration
68-
- [**UIKit example app (live)**](https://openzeppelin-ui.netlify.app) hosted demo of OpenZeppelin UI with ecosystem adapters
69-
- [**Role Manager**](https://github.com/OpenZeppelin/role-manager) role and permission management tool
70-
- [**RWA Wizard**](https://github.com/OpenZeppelin/rwa-wizard) real-world asset token generation
66+
- [**UI Builder**](https://github.com/OpenZeppelin/ui-builder): full-featured smart contract interaction UI
67+
- [**OpenZeppelin UI**](https://github.com/OpenZeppelin/openzeppelin-ui): shared UI components and React integration
68+
- [**UIKit example app (live)**](https://openzeppelin-ui.netlify.app): hosted demo of OpenZeppelin UI with ecosystem adapters
69+
- [**Role Manager**](https://github.com/OpenZeppelin/role-manager): role and permission management tool
70+
- [**RWA Wizard**](https://github.com/OpenZeppelin/rwa-wizard): real-world asset token generation
7171

7272
Any TypeScript application that needs chain-agnostic blockchain interaction can use adapters directly.

0 commit comments

Comments
 (0)