diff --git a/sdk/dapp-sdk/README.md b/sdk/dapp-sdk/README.md index 121cc194f..888025b1d 100644 --- a/sdk/dapp-sdk/README.md +++ b/sdk/dapp-sdk/README.md @@ -7,7 +7,7 @@ ## Features -- **Wallet Discovery** — Remote gateways, `window.*` namespace scanning, EIP-6963-style `canton:announceProvider` events, and pluggable adapters +- **Wallet Discovery** — Remote gateways, EIP-6963-style `canton:announceProvider` events, and pluggable adapters - **Wallet Picker UI** — Built-in, framework-agnostic Web Component that lets users choose a wallet, enter custom gateway URLs, and manage recently used connections - **Wallet Connectivity** — Connect, disconnect, and monitor connection status - **Account Management** — List accounts and respond to account changes @@ -74,22 +74,22 @@ The SDK is built around three layers: ┌──────────────────────────────────────────────┐ │ DappClient │ │ Thin wrapper: typed RPC helpers, events, │ -│ window.canton injection, session persist │ +│ session persist │ ├──────────────────────────────────────────────┤ │ DiscoveryClient │ │ Adapter registry, session restore, │ │ wallet picker integration │ ├──────────────────────────────────────────────┤ │ ProviderAdapter implementations │ -│ ExtensionAdapter, InjectedAdapter │ -│ (browser / postMessage, window.* inject) │ +│ ExtensionAdapter (announce protocol) │ +│ (browser / postMessage) │ │ RemoteAdapter (HTTP/SSE gateway) │ └──────────────────────────────────────────────┘ ``` ## Wallet providers -Wallet and extension authors: see **[Wallet providers (discovery)](https://github.com/canton-network/wallet-gateway/blob/main/docs/dapp-building/dapp-sdk/provider.md)** in the dApp Building docs for how to appear in the picker (`RemoteAdapter`, `window.*` scan, `canton:announceProvider`, and `additionalAdapters`). +Wallet and extension authors: see **[Wallet providers (discovery)](https://github.com/canton-network/wallet-gateway/blob/main/docs/dapp-building/dapp-sdk/provider.md)** in the dApp Building docs for how to appear in the picker (`RemoteAdapter`, `canton:announceProvider`, and `additionalAdapters`). ## Usage @@ -163,23 +163,6 @@ const client = new DappClient(provider) const result = await client.connect() ``` -### Provider API - -The SDK also exposes a CIP-103 provider on `window.canton` (injected by default when a `DappClient` is created): - -```typescript -const provider = window.canton - -const result = await provider.request({ method: 'connect' }) -const accounts = await provider.request({ method: 'listAccounts' }) - -provider.on('statusChanged', (event) => { - console.log('Status:', event.connection.isConnected) -}) - -provider.removeListener('statusChanged', listener) -``` - ## API Reference ### DappClient @@ -203,7 +186,6 @@ provider.removeListener('statusChanged', listener) | Option | Type | Default | Description | | -------------- | -------------- | ---------- | ------------------------------------------------------------------------- | -| `injectGlobal` | `boolean` | `true` | Inject the provider into `window.canton` | | `providerType` | `ProviderType` | `'remote'` | Affects `open()` routing (`'browser'` uses postMessage, others use popup) | ### DiscoveryClient @@ -221,11 +203,10 @@ provider.removeListener('statusChanged', listener) ### Built-in Adapters -| Adapter | Provider Type | Transport | Description | -| ------------------ | ------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ExtensionAdapter` | `'browser'` | `postMessage` | Browser extensions (announced wallets or dApp-registered; optional explicit slot). | -| `InjectedAdapter` | `'browser'` | in-page `window` | Created when namespace scan finds a provider on `window` ([Wallet providers guide](https://github.com/canton-network/wallet-gateway/blob/main/docs/dapp-building/dapp-sdk/provider.md)). | -| `RemoteAdapter` | `'remote'` | HTTP/SSE | CIP-103 Wallet Gateways over the network. | +| Adapter | Provider Type | Transport | Description | +| ------------------ | ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ExtensionAdapter` | `'browser'` | `postMessage` | Browser extensions discovered via `canton:announceProvider` ([Wallet providers guide](https://github.com/canton-network/wallet-gateway/blob/main/docs/dapp-building/dapp-sdk/provider.md)). | +| `RemoteAdapter` | `'remote'` | HTTP/SSE | CIP-103 Wallet Gateways over the network. | ## Documentation diff --git a/sdk/dapp-sdk/src/adapter/index.ts b/sdk/dapp-sdk/src/adapter/index.ts index aa2110490..444439861 100644 --- a/sdk/dapp-sdk/src/adapter/index.ts +++ b/sdk/dapp-sdk/src/adapter/index.ts @@ -5,7 +5,6 @@ export * from './types' export * from './errors' export * from './events' export { ExtensionAdapter } from './extension-adapter' -export { InjectedAdapter } from './injected-adapter' export { RemoteAdapter } from './remote-adapter' export type { RemoteAdapterConfig } from './remote-adapter' export { WalletConnectAdapter } from './walletconnect-adapter' diff --git a/sdk/dapp-sdk/src/adapter/injected-adapter.ts b/sdk/dapp-sdk/src/adapter/injected-adapter.ts deleted file mode 100644 index 88a12d6fb..000000000 --- a/sdk/dapp-sdk/src/adapter/injected-adapter.ts +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -import type { Provider } from '@canton-network/core-splice-provider' -import type { RpcTypes as DappRpcTypes } from '@canton-network/core-wallet-dapp-rpc-client' -import type { - ProviderAdapter, - WalletInfo, -} from '@canton-network/core-wallet-discovery' -import type { - ProviderId, - ProviderType, -} from '@canton-network/core-wallet-dapp-rpc-client' - -export type InjectedAdapterConfig = { - id: string - name: string - provider: Provider - icon?: string | undefined - description?: string | undefined -} - -export class InjectedAdapter implements ProviderAdapter { - readonly providerId: ProviderId - readonly name: string - readonly type: ProviderType = 'browser' - readonly icon: string | undefined - - private providerInstance: Provider - private description?: string | undefined - - constructor(config: InjectedAdapterConfig) { - this.providerId = `browser:${config.id}` as ProviderId - this.name = config.name - this.icon = config.icon - this.providerInstance = config.provider - this.description = config.description - } - - getInfo(): WalletInfo { - return { - providerId: this.providerId, - name: this.name, - type: this.type, - description: - this.description ?? - 'Connect via an injected CIP-103 provider (window namespace)', - icon: this.icon, - } - } - - async detect(): Promise { - return true - } - - provider(): Provider { - return this.providerInstance - } - - teardown(): void { - // No cleanup needed; the provider lifecycle is owned by the wallet. - } - - async restore(): Promise | null> { - try { - const status = await this.providerInstance.request({ - method: 'status', - }) - if (status.connection.isConnected) { - return this.providerInstance - } - } catch { - // best-effort - } - return null - } -} diff --git a/sdk/dapp-sdk/src/client.ts b/sdk/dapp-sdk/src/client.ts index 4d67ee43b..dda8a7205 100644 --- a/sdk/dapp-sdk/src/client.ts +++ b/sdk/dapp-sdk/src/client.ts @@ -5,7 +5,6 @@ import type { Provider, EventListener, } from '@canton-network/core-splice-provider' -import { injectProvider } from '@canton-network/core-provider-dapp' import { WalletEvent, type SpliceMessage } from '@canton-network/core-types' import type { AccountsChangedEvent, @@ -27,8 +26,6 @@ import { popup } from '@canton-network/core-wallet-ui-components' import { clearAllLocalState } from './util' export interface DappClientOptions { - /** Inject provider into `window.canton`. Defaults to true. */ - injectGlobal?: boolean | undefined /** Provider type hint — affects `open()` routing. Defaults to `'remote'`. */ providerType?: ProviderType | undefined /** Optional routing key for extension open messages. */ @@ -40,7 +37,7 @@ export interface DappClientOptions { * `Provider`. * * It exposes typed RPC helpers, event subscription shortcuts, - * `window.canton` injection, and session-persistence listeners. + * and session-persistence listeners. * * How to obtain a provider is **not** this class's concern. * Use `DiscoveryClient` + the wallet picker, or construct any @@ -56,10 +53,6 @@ export class DappClient { ) { this.provider = provider this.options = options - - if (options.injectGlobal !== false) { - injectProvider(provider) - } } // ── Provider access ─────────────────────────────────── diff --git a/sdk/dapp-sdk/src/index.ts b/sdk/dapp-sdk/src/index.ts index 0c790d6d9..f4591cd1b 100644 --- a/sdk/dapp-sdk/src/index.ts +++ b/sdk/dapp-sdk/src/index.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Import global Window augmentation for the DappProvider injection +// Import global Window augmentation for `window.canton` import '@canton-network/core-provider-dapp' // ── Asset exports (icons for wallet adapters) ── diff --git a/sdk/dapp-sdk/src/injected-discovery.ts b/sdk/dapp-sdk/src/injected-discovery.ts deleted file mode 100644 index 05998a089..000000000 --- a/sdk/dapp-sdk/src/injected-discovery.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -import type { Provider } from '@canton-network/core-splice-provider' -import type { RpcTypes as DappRpcTypes } from '@canton-network/core-wallet-dapp-rpc-client' - -export type DiscoveredInjectedProvider = { - id: string - provider: Provider - sourceRoot: string -} - -const DEFAULT_ROOTS = ['canton'] as const - -/** - * Checks if an object is a CIP-103 provider-like object. - * @param obj - The object to check. - * @returns True if the object is a provider-like object, false otherwise. - */ -const isProviderLike = (obj: unknown): obj is Provider => { - if (typeof obj !== 'object' || obj === null) return false - const p = obj as Record - return ( - typeof p.request === 'function' && - typeof p.on === 'function' && - typeof p.emit === 'function' && - typeof p.removeListener === 'function' - ) -} - -export function discoverInjectedProviders( - roots: readonly string[] = DEFAULT_ROOTS -): DiscoveredInjectedProvider[] { - if (typeof window === 'undefined') return [] - - const discovered: DiscoveredInjectedProvider[] = [] - const seen = new Set() - const win = window as unknown as Record - - for (const root of roots) { - const candidate = win[root] - if (candidate === undefined || candidate === null) continue - - if (isProviderLike(candidate) && !seen.has(candidate)) { - seen.add(candidate) - discovered.push({ - id: root, - provider: candidate, - sourceRoot: root, - }) - continue - } - - if (typeof candidate === 'object') { - for (const [key, value] of Object.entries( - candidate as Record - )) { - if (isProviderLike(value) && !seen.has(value)) { - seen.add(value) - discovered.push({ - id: `${root}.${key}`, - provider: value, - sourceRoot: root, - }) - } - } - } - } - - return discovered -} diff --git a/sdk/dapp-sdk/src/sdk.ts b/sdk/dapp-sdk/src/sdk.ts index 11423558c..b62ca26b0 100644 --- a/sdk/dapp-sdk/src/sdk.ts +++ b/sdk/dapp-sdk/src/sdk.ts @@ -43,7 +43,6 @@ import type { } from '@canton-network/core-wallet-dapp-rpc-client' import { DappClient } from './client' import { ExtensionAdapter } from './adapter/extension-adapter' -import { InjectedAdapter } from './adapter/injected-adapter' import { RemoteAdapter, type RemoteAdapterConfig, @@ -52,7 +51,6 @@ import * as storage from './storage' import { clearAllLocalState } from './util' import defaultGatewayList from './gateways.json' import { CANTON_LOGO_PNG } from './assets' -import { discoverInjectedProviders } from './injected-discovery' import { requestAnnouncedProviders } from './announce-discovery' export interface DappSDKConnectOptions< @@ -107,30 +105,6 @@ export class DappSDK { } } - private async registerInjectedNamespaceAdapters( - discovery: DiscoveryClient - ): Promise { - const existingIds = new Set( - discovery.listAdapters().map((a) => a.providerId as string) - ) - - const injected = discoverInjectedProviders() - for (const item of injected) { - const id = `browser:${item.id}` - if (existingIds.has(id)) continue - - const key = `${item.id} (injected)` - const adapter = new InjectedAdapter({ - id: item.id, - name: key, - provider: item.provider, - description: `Injected provider from window.${item.id}`, - }) - discovery.registerAdapter(adapter) - existingIds.add(id) - } - } - private async registerAnnouncedAdapters( discovery: DiscoveryClient ): Promise { @@ -173,8 +147,7 @@ export class DappSDK { await this.registerAdapters(this.discovery, initAdapters) } - // These can appear after initial create() (injected providers, extensions). - await this.registerInjectedNamespaceAdapters(this.discovery) + // Extensions can announce after initial create(). await this.registerAnnouncedAdapters(this.discovery) await this.discovery.restorePersistedSessionIfNeeded() @@ -362,7 +335,6 @@ export class DappSDK { } const discovery = this.discovery! - await this.registerInjectedNamespaceAdapters(discovery) await this.registerAnnouncedAdapters(discovery) clearAllLocalState()