feat: adapter architecture phase 3 — escape hatches, read-only surface, hardening#449
feat: adapter architecture phase 3 — escape hatches, read-only surface, hardening#449fernandomg wants to merge 50 commits intofeat/adapter-architecture-phases-1-2from
Conversation
…PreStep, executeAllPreSteps)
Extend createNotificationLifecycle with onReplace handler, optional ChainRegistry for explorer URLs, and shortMessage extraction for viem errors. Add createSigningNotificationLifecycle factory for wallet signing toasts. Wire both lifecycle instances in __root.tsx via DAppBoosterProvider config, removing the legacy TransactionNotificationProvider wrapper.
…based TransactionButton Migrate MintUSDC, ERC20ApproveAndTransferButton, NativeToken, and parent TransactionButton demo to use the new adapter-based TransactionButton with TransactionParams + lifecycle props. Replace useWeb3StatusConnected with useWallet, WalletStatusVerifier with WalletGuard, and getExplorerLink with getExplorerUrl. Optimism cross-domain messenger demo gets a partial migration (keeps LegacyTransactionButton with local TransactionNotificationProvider wrapper) since useL1CrossDomainMessengerProxy returns Promise<Hash> rather than TransactionParams.
Remove 39 files from the old code paths that have been superseded by the SDK adapter architecture: - src/hooks/ legacy hooks (useWeb3Status, useWalletStatus, useTokens) - src/providers/ (Web3Provider, TransactionNotificationProvider) - src/components/sharedComponents/ duplicates (TransactionButton, SignButton, WalletStatusVerifier, SwitchNetwork, NotificationToast, TokenSelect, TokenDropdown, TokenInput) - src/wallet/connectors/*.config.tsx (connectkit, rainbowkit, reown) - src/wallet/providers/Web3Provider.tsx (dead code after config deletion) Files kept because they're still used by the Optimism and SignMessage demos: wallet/hooks/*, wallet/types.ts, wallet/components/WalletStatusVerifier, transactions/providers/*, transactions/components/LegacyTransactionButton.
…te bundle in react layer - Core adapter (src/sdk/core/evm/wallet.ts) returns WalletAdapter directly, no React imports, no Provider/useConnectModal. Exposes wagmiConfig on return. - React bundle (src/sdk/react/evm/wallet-bundle.tsx) wraps core adapter with WagmiProvider + QueryClientProvider + connector WalletProvider. - EvmConnectorConfig (React-specific) moved from core/evm/types to react/evm/types. - Connector files (connectkit, rainbowkit, reown) moved from core to react layer. - All consumers updated: __root.tsx uses createEvmWalletBundle, wagmi.config.ts imports connector from react layer. - Tests updated: unit + integration tests use EvmCoreConnectorConfig stub, new test verifies adapter is returned directly (not as bundle).
…er props Remove Chakra UI imports from SDK components. WalletGuard now accepts renderConnect and renderSwitchChain render props (fallback kept but deprecated). ConnectWalletButton accepts a render prop receiving wallet state and action callbacks. Chakra-styled wrappers in src/chakra/ compose the headless components with styled buttons. Demos and wallet/providers re-export from the Chakra layer so consumers see no behavioral change.
…or display Port generic error formatting: extractViemErrorMessage (walks cause chain), sanitizeErrorMessage (strips hex, addresses, technical blocks), and formatErrorMessage (maps common patterns like user rejection, insufficient funds, execution reverted). Wire into lifecycle toasts and transaction adapter prepare() reason. Replace all inline shortMessage checks.
… (Aave V3) Aave V3 pool on Sepolia has frozen reserves. Switch all transaction demos to Base Sepolia where the pool is active. Update USDC token address, Pool address, and Faucet address to Base Sepolia deployments. Add baseSepolia to the chain config.
…ro address reverts
…action Restores escape hatch levels 3 and 4 for the transaction surface. resolveAdapters(chainId) gives raw adapter access for one-off customization. Explicit transactionAdapter/walletAdapter options bypass provider resolution entirely.
… WalletAdapterBundle
useReadOnly<TClient> now accepts an optional `factory` prop that bypasses provider-level readClientFactories resolution (Level 4 escape hatch). Default generic stays `unknown` for backward compat.
…annotations across SDK
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Phase 3 of the adapter architecture: completes escape-hatch coverage, introduces a typed read-only client surface (core + React), decouples EVM connectors from app env via connector factories, and hardens runtime DbC/guards while migrating the app away from legacy wallet hooks/providers.
Changes:
- Added typed read-only client factories/utilities (core + React hooks) and auto-contribution via wallet bundles.
- Refactored EVM connector integration to factory pattern + introduced
createEvmWalletBundleReact wrapper; removed legacy wallet/provider surfaces. - Hardened runtime guards and error/lifecycle handling (new error formatting, notification lifecycles, prepare signer support).
Reviewed changes
Copilot reviewed 159 out of 159 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/wallet/types.ts | Removed legacy re-exported wallet types. |
| src/wallet/providers/Web3Provider.tsx | Removed legacy Web3Provider wrapper. |
| src/wallet/providers.ts | Repointed ConnectWalletButton export to Chakra wrapper. |
| src/wallet/hooks/useWeb3Status.tsx | Removed legacy wagmi-based status hook. |
| src/wallet/hooks/useWalletStatus.ts | Removed legacy wallet readiness hook. |
| src/wallet/hooks/useWalletStatus.test.ts | Removed tests for legacy hook. |
| src/wallet/hooks.ts | Removed barrel exports for legacy hooks. |
| src/wallet/connectors/wagmi.config.ts | Switched to connector factory call with metadata. |
| src/wallet/connectors/reown.config.tsx | Removed legacy connector config file. |
| src/wallet/connectors/rainbowkit.config.tsx | Removed legacy connector config file. |
| src/wallet/connectors/connectkit.config.tsx | Removed legacy connector config file. |
| src/wallet/components/WalletStatusVerifier.tsx | Removed legacy WalletStatusVerifier wrapper. |
| src/wallet/components/SwitchNetwork.tsx | Migrated to SDK wallet status + wagmi walletClient. |
| src/wallet/components.ts | Removed exports for deleted verifier. |
| src/utils/getExplorerLink.ts | Changed invalid input behavior to return null. |
| src/utils/getExplorerLink.test.ts | Updated tests for null-on-invalid behavior. |
| src/transactions/providers/TransactionNotificationProvider.test.tsx | Removed legacy notification provider tests. |
| src/transactions/providers.ts | Removed legacy provider barrel exports. |
| src/transactions/components/TransactionButton.test.tsx | Updated mocks for new useTransaction return shape. |
| src/transactions/components/LegacyTransactionButton.tsx | Removed wagmi-hook-based legacy transaction button. |
| src/transactions/components.ts | Removed legacy TransactionButton export. |
| src/tokens/hooks/useTokens.ts | Migrated from legacy wallet hooks to SDK useWallet. |
| src/tokens/hooks/useTokens.migration.test.ts | Added “no legacy import” migration assertion. |
| src/tokens/components/TokenSelect/TokenSelect.migration.test.ts | Added migration assertions for TokenSelect. |
| src/tokens/components/TokenSelect/List/AddERC20TokenButton.tsx | Migrated to SDK useWallet + wagmi useWalletClient. |
| src/tokens/components/TokenSelect/List/AddERC20TokenButton.migration.test.ts | Added migration assertions for AddERC20TokenButton. |
| src/tokens/components/TokenSelect/index.tsx | Migrated chain/account sourcing to SDK registry + wallet. |
| src/sdk/react/provider/index.ts | Exported useProviderContext from provider barrel. |
| src/sdk/react/provider/DAppBoosterProvider.tsx | Auto-collected/deduped read client factories from bundles. |
| src/sdk/react/provider/DAppBoosterProvider.test.tsx | Added tests for auto-contributed readClientFactories behavior. |
| src/sdk/react/provider/context.ts | Tightened readClientFactories typing to unknown generic. |
| src/sdk/react/provider/context.test.tsx | Added test coverage for provider barrel export + context behavior. |
| src/sdk/react/lifecycle/index.ts | Exported signing notification lifecycle types + factory. |
| src/sdk/react/lifecycle/createNotificationLifecycle.ts | Added explorer URL suffixing, replace handling, and signing lifecycle. |
| src/sdk/react/internal/walletLifecycle.ts | Centralized lifecycle dispatch + wrapping for wallet signing. |
| src/sdk/react/index.ts | Exported new evm surface from react package. |
| src/sdk/react/hooks/useWallet.ts | Switched to shared wallet lifecycle wrapper; doc label updates. |
| src/sdk/react/hooks/useReadOnly.ts | Added generic typed client + address + explorer URL support + factory bypass. |
| src/sdk/react/hooks/useMultiWallet.ts | Expanded return to include helpers + connectedAddresses; refactored lifecycle wrapping. |
| src/sdk/react/hooks/index.ts | Re-exported additional transaction-related types. |
| src/sdk/react/evm/wallet-bundle.tsx | Added React wallet bundle factory (wagmi + query + connector provider stack). |
| src/sdk/react/evm/wallet-bundle.test.tsx | Added integration-style tests for bundle composition and guards. |
| src/sdk/react/evm/types.ts | Added app metadata and React connector config types. |
| src/sdk/react/evm/read-only.ts | Added typed useEvmReadOnly hook using EVM read client factory. |
| src/sdk/react/evm/read-only.test.tsx | Added tests for typed EVM read-only hook behavior. |
| src/sdk/react/evm/index.ts | New EVM React barrel exports (connectors, hooks, bundle). |
| src/sdk/react/evm/connectors/reown.tsx | Added Reown connector factory taking app metadata. |
| src/sdk/react/evm/connectors/rainbowkit.tsx | Added RainbowKit connector factory taking app metadata. |
| src/sdk/react/evm/connectors/index.ts | Added connector factory barrel. |
| src/sdk/react/evm/connectors/connectors.test.ts | Added factory connector smoke tests. |
| src/sdk/react/evm/connectors/connectkit.tsx | Added ConnectKit connector factory taking app metadata. |
| src/sdk/react/components/index.ts | Exported ConnectWalletButton render-props type; expanded WalletGuard types. |
| src/sdk/react/components/ConnectWalletButton.tsx | Converted ConnectWalletButton to headless render-prop component. |
| src/sdk/react/components/ConnectWalletButton.test.tsx | Added tests for headless ConnectWalletButton render contract. |
| src/sdk/core/utils/wrap-adapter.ts | Added transform hooks (beforeCall/afterCall) and updated ordering semantics. |
| src/sdk/core/utils/wrap-adapter.test.ts | Added coverage for transform hooks and execution order. |
| src/sdk/core/utils/index.ts | Exported WrapAdapterHooks type. |
| src/sdk/core/read-client.ts | Added core non-React read client helpers (typed + resolver). |
| src/sdk/core/read-client.test.ts | Added tests for new read client utilities. |
| src/sdk/core/index.ts | Exported core read-client utilities from SDK core index. |
| src/sdk/core/evm/wallet.ts | Removed React/provider concerns; returns adapter + wagmiConfig; added runtime guards. |
| src/sdk/core/evm/wallet.integration.test.ts | Updated integration tests for new wallet adapter return type/config. |
| src/sdk/core/evm/types.ts | Removed React connector config from core types (React types moved to react layer). |
| src/sdk/core/evm/transaction.ts | Added runtime guards, signer-aware prepare, and formatted error reasons. |
| src/sdk/core/evm/transaction.test.ts | Added tests for new guards and updated prepare behavior. |
| src/sdk/core/evm/server-wallet.ts | Added private key runtime validation; doc label update. |
| src/sdk/core/evm/server-wallet.test.ts | Added tests for private key validation. |
| src/sdk/core/evm/read-client.ts | Added EVM read client factory implementation. |
| src/sdk/core/evm/read-client.test.ts | Added tests for EVM read client factory. |
| src/sdk/core/evm/index.ts | Exported EVM read client factory and updated wallet exports. |
| src/sdk/core/evm/connectors/reown.tsx | Removed env-coupled singleton connector. |
| src/sdk/core/evm/connectors/rainbowkit.tsx | Removed env-coupled singleton connector. |
| src/sdk/core/evm/connectors/index.ts | Removed core connector barrel. |
| src/sdk/core/evm/connectors/connectors.test.ts | Removed singleton connector tests. |
| src/sdk/core/evm/connectors/connectkit.tsx | Removed env-coupled singleton connector. |
| src/sdk/core/errors/index.ts | Re-exported new error formatting utilities. |
| src/sdk/core/errors/format.ts | Added user-friendly error formatting/sanitization utilities. |
| src/sdk/core/errors/format.test.ts | Added tests for error formatting helpers. |
| src/sdk/core/chain/explorer.ts | Updated JSDoc annotations to @expects. |
| src/sdk/core/adapters/transaction.ts | Updated adapter interface: prepare(params, signer?). |
| src/sdk/core/adapters/provider.ts | Added readClientFactory to bundles; made ReadClientFactory generic. |
| src/sdk/core/adapters/index.test.ts | Updated type-level tests for generic ReadClientFactory. |
| src/routes/__root.tsx | Migrated app shell to wallet bundle + global lifecycles; removed legacy notification provider. |
| src/providers/Web3Provider.tsx | Removed duplicate legacy Web3Provider. |
| src/main.tsx | Added BigInt JSON serialization polyfill for React 19 dev tooling. |
| src/hooks/useWeb3Status.tsx | Removed legacy app-level wallet status hook. |
| src/hooks/useWeb3Status.test.ts | Removed tests for legacy hook. |
| src/hooks/useWalletStatus.ts | Removed legacy app-level wallet status wrapper. |
| src/hooks/useWalletStatus.test.ts | Removed tests for legacy wrapper. |
| src/core/utils/getExplorerLink.ts | Changed invalid input behavior to return null (core copy). |
| src/core/ui/NotificationToast.tsx | Removed wallet status gating; toast always mounts. |
| src/core/ui/ExplorerLink.tsx | Added null fallback handling (currently '#'). |
| src/core/config/networks.config.ts | Added Base Sepolia chain + transport config. |
| src/contracts/definitions.ts | Added Base Sepolia AaveFaucet address and keying via chain IDs. |
| src/components/sharedComponents/WalletStatusVerifier.tsx | Removed legacy verifier component. |
| src/components/sharedComponents/WalletStatusVerifier.test.tsx | Removed tests for legacy verifier component. |
| src/components/sharedComponents/TransactionButton.tsx | Removed legacy shared TransactionButton wrapper. |
| src/components/sharedComponents/TokenSelect/utils.tsx | Removed legacy TokenSelect utilities. |
| src/components/sharedComponents/TokenSelect/types.ts | Removed legacy Networks type. |
| src/components/sharedComponents/TokenSelect/TopTokens/Item.tsx | Removed legacy TopTokens item. |
| src/components/sharedComponents/TokenSelect/TopTokens/index.tsx | Removed legacy TopTokens component. |
| src/components/sharedComponents/TokenSelect/styles.ts | Removed legacy TokenSelect styles. |
| src/components/sharedComponents/TokenSelect/Search/NetworkButton.tsx | Removed legacy TokenSelect search UI. |
| src/components/sharedComponents/TokenSelect/Search/Input.tsx | Removed legacy TokenSelect search UI. |
| src/components/sharedComponents/TokenSelect/Search/index.tsx | Removed legacy TokenSelect search UI. |
| src/components/sharedComponents/TokenSelect/List/VirtualizedList.tsx | Removed legacy virtualized list. |
| src/components/sharedComponents/TokenSelect/List/TokenBalance.tsx | Removed legacy balance display component. |
| src/components/sharedComponents/TokenSelect/List/Row.tsx | Removed legacy token row component. |
| src/components/sharedComponents/TokenSelect/List/index.tsx | Removed legacy token list component. |
| src/components/sharedComponents/TokenSelect/List/AddERC20TokenButton.tsx | Removed legacy add-token button (sharedComponents copy). |
| src/components/sharedComponents/TokenInput/useTokenInput.tsx | Removed legacy token input hook. |
| src/components/sharedComponents/TokenInput/styles.ts | Removed legacy token input styles. |
| src/components/sharedComponents/TokenDropdown.tsx | Removed legacy token dropdown component. |
| src/components/sharedComponents/SwitchNetwork.tsx | Removed legacy SwitchNetwork component. |
| src/components/sharedComponents/SwitchNetwork.test.tsx | Removed legacy SwitchNetwork tests. |
| src/components/sharedComponents/SignButton.tsx | Removed legacy sign button component. |
| src/components/sharedComponents/NotificationToast.tsx | Removed legacy NotificationToast component. |
| src/components/sharedComponents/ExplorerLink.tsx | Added null fallback handling (currently '#'). |
| src/components/pageComponents/home/Examples/demos/TransactionButton/NativeToken.tsx | Migrated demo to adapter-based TransactionButton on Base Sepolia. |
| src/components/pageComponents/home/Examples/demos/TransactionButton/index.tsx | Replaced legacy verifier with Chakra WalletGuard. |
| src/components/pageComponents/home/Examples/demos/TransactionButton/index.test.tsx | Updated mocks for WalletGuard. |
| src/components/pageComponents/home/Examples/demos/TransactionButton/ERC20ApproveAndTransferButton/MintUSDC.tsx | Migrated mint flow to adapter TransactionButton params. |
| src/components/pageComponents/home/Examples/demos/TransactionButton/ERC20ApproveAndTransferButton/index.tsx | Migrated demo to Base Sepolia + adapter params. |
| src/components/pageComponents/home/Examples/demos/TransactionButton/ERC20ApproveAndTransferButton/ERC20ApproveAndTransferButton.tsx | Migrated approve/transfer flow to adapter TransactionButton + SDK explorer URLs. |
| src/components/pageComponents/home/Examples/demos/TokenInput/index.tsx | Migrated wallet connection check to SDK useWallet. |
| src/components/pageComponents/home/Examples/demos/TokenInput/index.test.tsx | Updated wallet mocks to SDK hook. |
| src/components/pageComponents/home/Examples/demos/SwitchNetwork/index.tsx | Migrated to SDK useWallet and updated Networks typing import. |
| src/components/pageComponents/home/Examples/demos/SwitchNetwork/index.test.tsx | Updated mocks to SDK useWallet. |
| src/components/pageComponents/home/Examples/demos/SignMessage/index.tsx | Replaced legacy verifier with Chakra WalletGuard. |
| src/components/pageComponents/home/Examples/demos/SignMessage/index.test.tsx | Updated mocks to SDK hooks + WalletGuard. |
| src/components/pageComponents/home/Examples/demos/OptimismCrossDomainMessenger/index.tsx | Refactored demo to adapter transaction execution + error formatting + SDK explorer URLs. |
| src/components/pageComponents/home/Examples/demos/HashHandling/index.tsx | Migrated wallet state reads to SDK useWallet. |
| src/components/pageComponents/home/Examples/demos/HashHandling/index.test.tsx | Updated mocks to SDK useWallet. |
| src/components/pageComponents/home/Examples/demos/HashHandling/Hash.tsx | Updated explorer URL handling for nullable links. |
| src/components/pageComponents/home/Examples/demos/EnsName/index.tsx | Adjusted ENS error rendering message. |
| src/chakra/WalletGuard.tsx | Added Chakra-styled wrapper around headless WalletGuard. |
| src/chakra/index.ts | Added Chakra barrel exports. |
| src/chakra/ConnectWalletButton.tsx | Added Chakra-styled wrapper around headless ConnectWalletButton. |
| CLAUDE.md | Documented @precondition vs @expects enforcement convention. |
Comments suppressed due to low confidence (1)
src/core/utils/getExplorerLink.ts:54
- This helper now returns
nullfor invalid inputs, but it can still produce URLs like"undefined/address/..."when neitherexplorerUrlnorchain.blockExplorers?.default.urlis set. That contradicts the JSDoc and will generate broken links. Consider computing abaseUrlfirst and either throwing (as the docs imply) or returning null when no explorer URL is available.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * Transform hooks (`beforeCall`, `afterCall`) propagate errors and can modify args/results. | ||
| * Returning `void` from a transform hook passes the original value through. | ||
| */ |
There was a problem hiding this comment.
The docstring says transform hooks can return void for pass-through, but beforeCall/afterCall are typed to return values and the implementation uses the return value directly. If a hook accidentally returns undefined (e.g. JS consumer or any), effectiveArgs becomes undefined and .apply() will throw. Either update the docs to require returning the original value, or harden the implementation to fall back to the original args/result when the transform hook returns undefined (and consider loosening the types to unknown[] | void / unknown | void to match behavior).
| // BigInt is not serializable by JSON.stringify. React 19 dev mode tries to serialize | ||
| // component props for dev tools logging, which crashes when props contain BigInt values | ||
| // (e.g., TransactionParams with value: parseEther('0.1')). This polyfill prevents the crash. | ||
| ;(BigInt.prototype as unknown as { toJSON: () => string }).toJSON = function () { | ||
| return this.toString() | ||
| } |
There was a problem hiding this comment.
This mutates BigInt.prototype.toJSON unconditionally and creates an enumerable property, which can have unexpected side-effects (and may conflict with other polyfills). Consider guarding it (only define if missing) and using Object.defineProperty to add a non-enumerable toJSON, and/or restricting it to dev-only environments.
| <chakra.a | ||
| href={getExplorerLink(props)} | ||
| href={getExplorerLink(props) ?? '#'} | ||
| rel="noopener noreferrer" | ||
| target="_blank" | ||
| > |
There was a problem hiding this comment.
When getExplorerLink returns null, falling back to href="#" while still using target="_blank" creates a broken link that opens a blank tab and is confusing for keyboard/screen-reader users. Prefer conditionally rendering nothing / a <span> when the URL is missing, or disable the link semantics (no href, aria-disabled, and prevent default).
| <chakra.a | ||
| href={getExplorerLink(props)} | ||
| href={getExplorerLink(props) ?? '#'} | ||
| rel="noopener noreferrer" | ||
| target="_blank" | ||
| > |
There was a problem hiding this comment.
When getExplorerLink returns null, falling back to href="#" while still using target="_blank" creates a broken link that opens a blank tab and is confusing for keyboard/screen-reader users. Prefer conditionally rendering nothing / a <span> when the URL is missing, or disable the link semantics (no href, aria-disabled, and prevent default).
| export const getExplorerLink = ({ chain, explorerUrl, hashOrAddress }: GetExplorerUrlParams) => { | ||
| const baseUrl = explorerUrl ?? chain.blockExplorers?.default.url | ||
|
|
||
| if (!baseUrl) { | ||
| throw new Error('No block explorer URL available for this chain') | ||
| } | ||
|
|
||
| if (isAddress(hashOrAddress)) { | ||
| return `${baseUrl}/address/${hashOrAddress}` | ||
| } | ||
| if (isHash(hashOrAddress)) { | ||
| return `${baseUrl}/tx/${hashOrAddress}` | ||
| } | ||
|
|
||
| throw new Error('Invalid hash or address') | ||
| return null | ||
| } |
There was a problem hiding this comment.
The JSDoc still says this function throws when the hash/address is invalid, but it now returns null in that case. Please update the documentation to match the new behavior (throws only when no explorer URL is available).
| interface ConnectWalletButtonProps extends UseWalletOptions { | ||
| render: (props: ConnectWalletButtonRenderProps) => ReactElement | ||
| } | ||
|
|
||
| /** | ||
| * Styled connect/account button that works with any connector. | ||
| * Headless connect/account button that works with any connector. | ||
| * | ||
| * Resolves the wallet adapter via `useWallet(options)` and opens the | ||
| * adapter-specific connect modal. In a multi-wallet setup, pass `chainType` | ||
| * Resolves the wallet adapter via `useWallet(options)` and delegates all | ||
| * rendering to the `render` prop. In a multi-wallet setup, pass `chainType` | ||
| * or `chainId` to target a specific adapter's modal. | ||
| */ | ||
| export const ConnectWalletButton: FC<UseWalletOptions & { label?: string }> = ({ | ||
| label = 'Connect', | ||
| ...walletOptions | ||
| }) => { | ||
| export const ConnectWalletButton: FC<ConnectWalletButtonProps> = ({ render, ...walletOptions }) => { | ||
| const { status, openConnectModal, openAccountModal } = useWallet(walletOptions) |
There was a problem hiding this comment.
ConnectWalletButton is exported from the public @/src/sdk/react surface, but its props changed from an optional label to a required render prop. That is a breaking API change for existing consumers importing the SDK component directly. If this is intentional, it should be called out as breaking (and/or provide a backward-compatible overload/default render).
Description:
Phase 3 of the adapter architecture — completes the escape hatch progression across all SDK surfaces, adds the typed read-only client system, and hardens DbC enforcement and connector decoupling.
Three work tracks in 66 commits:
Escape Hatch Fixes (11 commits)
Restores the five-level escape hatch progression (
styled component → hook → raw adapter → explicit adapter → core) across every SDK surface:useTransaction()now exposesresolveAdapters(chainId)for raw adapter access and accepts explicittransactionAdapter/walletAdapteroptions to bypass provider resolutionWalletGuardacceptsadapterprop (matchesConnectWalletButton)useProviderContextexported from public API for cross-cutting accesscreateEvmWalletAdapterandcreateEvmTransactionAdapterforchains.length >= 1Read-Only Escape Hatch (7 commits)
Completes the read-only surface from 40% to 100%:
ReadClientFactory<TClient>generic interface,evmReadClientFactoryconcrete implementation,createReadClient()andresolveReadClient()utilities for CLI/agent/backend useuseReadOnly<TClient>()generic hook with factory bypass option (L4),useEvmReadOnly()typed hook returningPublicClient(L2)readClientFactory, provider collects them automatically — zero config for apps with adaptersPhase 3 Hardening (6 commits)
Hardens the SDK for Phase 4:
@preconditionvs@expectsconvention: 39 unenforced@preconditionannotations relabeled to@expects. Rule:@precondition= enforced at runtime, always.@expects= documented assumption.ConnectorAppMetadata— SDK has zero@/src/envimportscreateEvmWalletBundleintegration tests with real wagmiSteps:
pnpm installcp .env.example .env.localand fill in required varspnpm dev— verify app runspnpm test— 382 SDK tests passpnpm lint— cleanpnpm tsc --noEmit— cleanNote:
wagmi.config.tsnow callscreateConnectkitConnector(metadata)instead of using the old singleton. If you had a custom connector import, update to the factory pattern.Type of change:
How Has This Been Tested?
382 tests across 28 test files. TDD throughout — every feature was red-green-commit. Integration tests use real wagmi with mock connector (no wagmi mocking).
Remember to check that:
Screenshots
N/A — SDK-only changes, no UI modifications.