Cosmos Wallet adapter
Add the CosmosPay browser extension as a Pollar login. No package to install: the adapter is ~60 lines of app code.
With @pollar/react, pass the same instance in the client's walletAdapters. Because the adapter's meta carries no group, Cosmos Wallet renders as its own button in the login modal (next to Privy), not behind the shared Wallet gateway.
Notes
isAvailable()checks forwindow.cosmosWallet, NOTcosmosWallet.isConnected()— in this walletisConnectedmeans 'this origin is already approved', which is false before the first login and would send Pollar straight towallet_not_installed.- The extension keeps its own network setting. The adapter is built per network and
connect()comparesgetNetwork().networkPassphrasewith the app's, failing with a readable message instead of an opaque SEP-10 rejection. signStellarMessageis deliberately NOT implemented: the wallet signs the raw utf8 message bytes, not the SEP-53 digestSHA-256("Stellar Signed Message:\n" || msg)that Pollar verifies, so ownership proofs would be rejected.signAuthEntryis not exposed by the provider, so Soroban auth-entry signing is unavailable with this wallet. Login and classic payments are unaffected.- Expect two approval windows on login: one for
getAddress()(connect) and one for signing the SEP-10 challenge. After the origin is approved,getAddress()stops prompting; signing always prompts.
cosmos-wallet-adapter.ts— the whole integration
import type { ConnectWalletResponse, SignTransactionOptions, SignTransactionResponse, WalletAdapter, } from '@pollar/core'; function getCosmosWallet() { if (typeof window === 'undefined') return null; return (window as any).cosmosWallet ?? null; } export class CosmosWalletAdapter implements WalletAdapter { readonly type = 'cosmos-wallet'; readonly meta = { label: 'Cosmos Wallet', iconUrl: '/cosmos.png' }; readonly custody = 'external' as const; // Presence of the provider — NOT cosmosWallet.isConnected(), which means // "this origin is already approved". async isAvailable(): Promise<boolean> { return getCosmosWallet() !== null; } async connect(): Promise<ConnectWalletResponse> { const wallet = getCosmosWallet(); if (!wallet) throw new Error('Cosmos Wallet is not installed'); const { address } = await wallet.getAddress(); // opens the approval window if (!address) throw new Error('Cosmos Wallet returned no address'); return { address }; } async disconnect(): Promise<void> { // no programmatic disconnect, same as Freighter } // Non-prompting: only report an address when the origin is already approved. async getPublicKey(): Promise<string | null> { const wallet = getCosmosWallet(); if (!wallet) return null; try { if (!(await wallet.isConnected())) return null; const { address } = await wallet.getAddress(); return address ?? null; } catch { return null; } } async signTransaction( xdr: string, options?: SignTransactionOptions, ): Promise<SignTransactionResponse> { const wallet = getCosmosWallet(); if (!wallet) throw new Error('Cosmos Wallet is not installed'); const opts: { networkPassphrase?: string; address?: string } = {}; if (options?.networkPassphrase) { opts.networkPassphrase = options.networkPassphrase; } if (options?.accountToSign) opts.address = options.accountToSign; const { signedTxXdr } = await wallet.signTransaction(xdr, opts); if (!signedTxXdr) throw new Error('Cosmos Wallet returned no signature'); return { signedTxXdr }; } }
@pollar/react— hooks & components
import { PollarProvider } from '@pollar/react'; import { CosmosWalletAdapter } from './cosmos-wallet-adapter'; // Stable instance — built once, outside render. const cosmos = new CosmosWalletAdapter(); export function Providers({ children }: { children: React.ReactNode }) { return ( <PollarProvider client={{ apiKey: 'pub_testnet_…', stellarNetwork: 'testnet', walletAdapters: [cosmos], }} > {children} </PollarProvider> ); } // usePollar().login({ provider: 'cosmos-wallet' }) — or just click its button // in the login modal.