PollarPollarDemo

Products

AuthenticationWalletTransactions

Integrations

KYCSoonRampNewSwapNewEarnNew

Wallet Adapters

Stellar Wallets KitPrivyNewCosmos WalletNew

Adapters

Trustless Work

Built with Pollar

LumenWipeNew
OverviewSetupTest

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 for window.cosmosWallet, NOT cosmosWallet.isConnected() — in this wallet isConnected means 'this origin is already approved', which is false before the first login and would send Pollar straight to wallet_not_installed.
  • The extension keeps its own network setting. The adapter is built per network and connect() compares getNetwork().networkPassphrase with the app's, failing with a readable message instead of an opaque SEP-10 rejection.
  • signStellarMessage is deliberately NOT implemented: the wallet signs the raw utf8 message bytes, not the SEP-53 digest SHA-256("Stellar Signed Message:\n" || msg) that Pollar verifies, so ownership proofs would be rejected.
  • signAuthEntry is 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.