Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

CIPD - Cosmos Injected Provider Discovery

A standardized way to discover Cosmos wallet extensions in the browser, inspired by EIP-6963 for Ethereum.

Why?

The Cosmos ecosystem lacks a standardized way to discover wallet extensions. Currently, dApps need to:

  • Check for specific global variables (window.keplr, window.leap, etc.)
  • Hardcode wallet detection logic for each wallet
  • Deal with race conditions when wallets inject at different times
  • Maintain a growing list of wallet-specific detection code

CIPD solves this by providing an event-based discovery protocol that:

  • Works with any wallet that implements the protocol
  • Handles race conditions automatically
  • Provides a consistent API for wallet discovery
  • Includes a polyfill for existing wallets that don't yet support CIPD natively

What?

CIPD defines two custom events:

  • cosmos:requestProvider - Dispatched by dApps to request wallet announcements
  • cosmos:announceProvider - Dispatched by wallets to announce their presence

Each wallet announcement includes:

interfaceCosmosProviderDetail{info: {uuid: string// Unique identifier for this provider instancename: string// Human-readable wallet name (e.g., "Keplr")icon: string// Data URL of the wallet iconrdns: string// Reverse domain name ID (e.g., "app.keplr")}provider: CosmosProvider// The wallet's Cosmos provider interface}

Installation

npm install @luknyb/cipd
# or
pnpm add @luknyb/cipd
# or
yarn add @luknyb/cipd

Usage

Basic Usage

import{createStore}from'@luknyb/cipd'// Create a store to manage discovered walletsconststore=createStore()// Subscribe to wallet changesstore.subscribe((providers)=>{console.log('Available wallets:',providers.map(p=>p.info.name))})// Get all currently discovered walletsconstwallets=store.getProviders()// Find a specific wallet by RDNSconstkeplr=store.findProvider('app.keplr')if(keplr){awaitkeplr.provider.enable('cosmoshub-4')constkey=awaitkeplr.provider.getKey('cosmoshub-4')console.log('Address:',key.bech32Address)}

With Svelte

<scriptlang="ts">import { onMount } from'svelte'import { createStore, typeCosmosProviderDetail } from'@luknyb/cipd'let wallets =$state<CosmosProviderDetail[]>([])onMount(() => {const store =createStore()returnstore.subscribe((providers) => {wallets= [...providers] }, { emitImmediately: true })})</script>
{#eachwalletsaswallet}
<buttononclick={() =>connect(wallet)}>
<imgsrc={wallet.info.icon} alt={wallet.info.name} />
{wallet.info.name}
</button>
{/each}

With React

import{useEffect,useState}from'react'import{createStore,typeCosmosProviderDetail}from'@luknyb/cipd'functionWalletList(){const[wallets,setWallets]=useState<CosmosProviderDetail[]>([])useEffect(()=>{conststore=createStore()returnstore.subscribe((providers)=>{setWallets([...providers])},{emitImmediately: true})},[])return(<div>{wallets.map((wallet)=>(<buttonkey={wallet.info.uuid}onClick={()=>connect(wallet)}><imgsrc={wallet.info.icon}alt={wallet.info.name}/>{wallet.info.name}</button>))}</div>)}

With Vue

<script setup lang="ts">import { ref, onMounted, onUnmounted } from'vue'import { createStore, typeCosmosProviderDetail } from'@luknyb/cipd'const wallets =ref<CosmosProviderDetail[]>([])let unsubscribe: (() =>void) |undefinedonMounted(() => {const store =createStore()unsubscribe=store.subscribe((providers) => {wallets.value= [...providers] }, { emitImmediately: true })})onUnmounted(() =>unsubscribe?.())</script>
<template>
<buttonv-for="wallet in wallets":key="wallet.info.uuid"@click="connect(wallet)">
<img:src="wallet.info.icon":alt="wallet.info.name" />
{{ wallet.info.name }}
</button>
</template>

API Reference

createStore(options?)

Creates a store for managing discovered wallet providers.

interfaceCreateStoreOptions{polyfill?: boolean// Whether to detect existing wallets (default: true)}conststore=createStore({polyfill: true})

Store Methods

MethodDescription
subscribe(listener, options?)Subscribe to provider changes. Returns unsubscribe function.
getProviders()Get all currently discovered providers.
findProvider(rdns)Find a provider by its RDNS identifier.
reset()Clear and re-request providers.
clear()Clear all providers from the store.
destroy()Destroy the store and remove all listeners.

requestProviders()

Manually request all wallets to announce themselves.

import{requestProviders}from'@luknyb/cipd'requestProviders()

announceProvider(detail)

Manually announce a wallet provider (useful for wallet developers).

import{announceProvider}from'@luknyb/cipd'announceProvider({info: {uuid: crypto.randomUUID(),name: 'My Wallet',icon: 'data:image/svg+xml;base64,...',rdns: 'com.mywallet',},provider: myCosmosProvider,})

Supported Wallets

The polyfill automatically detects these wallets:

WalletRDNS
Keplrapp.keplr
Leapio.leapwallet
Cosmostationio.cosmostation
XDEFIio.xdefi
Falconio.falconwallet
Coin98io.coin98

For Wallet Developers

To natively support CIPD in your wallet extension:

// Listen for discovery requestswindow.addEventListener('cosmos:requestProvider',()=>{announceWallet()})// Announce on loadannounceWallet()functionannounceWallet(){window.dispatchEvent(newCustomEvent('cosmos:announceProvider',{detail: {info: {uuid: crypto.randomUUID(),name: 'My Wallet',icon: 'data:image/svg+xml;base64,...',rdns: 'com.mywallet',},provider: window.myWallet,},}))}

TypeScript

Full TypeScript support with exported types:

importtype{CosmosProvider,CosmosProviderDetail,CosmosProviderInfo,Key,OfflineSigner,ChainInfo,Store,}from'@luknyb/cipd'

License

MIT

About

Cosmos Injected Provider Discovery - Event-based wallet discovery for Cosmos, inspired by EIP-6963

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages