SDK Architecture
A public SDK for web3 applications: an embeddable integration surface covering authentication, wallet connectivity and notifications. The work here is the architecture behind that SDK — the client core, the API layer, backend-driven configuration, and the long game of evolving a public API without breaking integrations that already depend on it.
What it is
The platform ships as a set of packages:
- a framework-agnostic TypeScript client core that owns authentication, signing and API logic
- thin framework bindings (React first) that adapt the core to a UI
- a GraphQL API layer with generated types instead of hand-maintained request and response models
Architecture
Client core
A standalone TypeScript class — no framework dependency — owning the auth state machine, wallet signing adapters, the API layer and token lifecycle. It runs anywhere JavaScript runs, including non-UI environments such as scripts and background workers.
Framework bindings
Each framework gets a thin adapter over the core rather than a reimplementation of it. Adding a framework does not duplicate business logic, and adding a chain does not touch UI code.
API layer
The transport moved from REST with hand-written types to GraphQL with code generation against the schema. Generated types cannot drift from the API, and cross-team schema changes stop being a manual synchronization exercise.
Configuration
Integration configuration is backend-driven: a tenant-level config document tells the client which capabilities, chains and UI entry points to expose. That keeps partner-specific behaviour out of the package and lets configuration change without a release.
Wallet connectivity
Wallet support is abstracted behind provider adapters, so the SDK can follow wallet ecosystem standards without rewriting signing logic each time a wallet changes.
Productizing the SDK
An embeddable SDK was not always enough. Some integrations needed a complete web experience that could be handed to a customer, branded for them, connected to their tenant configuration and deployed without rebuilding the application from scratch.
The response was a reusable full-page Next.js baseline rather than a collection of one-off customer apps. The stable parts — authentication flow, notification subscriptions, SDK wiring and deployment shape — stay in the template. The parts that vary by integration are explicit configuration points: tenant credentials, subscription configuration, chain, copy and branding.
Wallet support became its own boundary for the same reason. Different customers can require different chains and wallets, but the application should not need a new authentication architecture for each one. A dedicated wallet-provider package normalizes connection, key formats and signing behind one React-facing contract while adapters absorb chain-specific behaviour.
Together these pieces turn the SDK from a library into a repeatable integration platform: customers can embed the SDK directly, start from a public full-page example, or self-host a customized deployment without forking the core product logic.
Story
The SDK began as a single React hook bundling API calls, signing, auth state and business logic — a deliberate time-to-market trade-off. As the product grew to support ten-plus chains and multiple frameworks, the hook became the bottleneck: framework-locked, hard to test, and impossible to reuse outside React. The response was a phased extraction into the framework-agnostic core described above, run with zero downtime for existing integrations.
Journal
When reusable architecture becomes an executable workflow
How a customer integration template, wallet abstraction, explicit decision rules and evals turned repeated implementation work into an agent-operable workflow.
Modernizing wallet connectivity with EIP-6963
A wallet extension stopped injecting its custom global and the connect flow broke. Fixing it meant moving the whole wallet layer to standard discovery.
Designing unified error handling for a public SDK
A GraphQL API has two different error channels. An SDK that only surfaces one of them is lying by omission — here is how we unified both behind a single error type.
Building backend-configured actions without coupling the SDK to a blockchain
How I designed SmartLink so backend-defined interactive actions could render through the SDK while wallet connection, signing and transaction submission stayed under host-application control.
Turning an SDK into a reusable customer integration template
How a library-first integration model evolved into a configurable full-page application that could be branded, deployed and self-hosted without rebuilding the same product for every customer.
Designing a pluggable wallet layer for multi-chain integrations
How a shared wallet provider isolated chain-specific connection, key and signing behavior so customer applications could change wallets without changing their authentication architecture.
From React hooks to a framework-agnostic SDK client
How a React-first SDK optimized for time to market evolved into a reusable domain client as customer integrations expanded beyond React.
Open Source
Notifi DApp Example
A reusable full-page integration baseline for customer-hosted Notifi experiences.
Notifi Wallet Provider
A unified React wallet layer for multi-chain Notifi integrations.