@kadena/wallet-adapter-core v0.0.1-beta.2
Kadena Wallet Adapter Core
wallet-adapter-core is the foundation for integrating wallet providers into
your Kadena dApps. It implements standardized JSON-RPC methods from KIP 15, 17
and 37 through KIP 40 while also extending functionality with convenient helper
methods that are not part of the JSON-RPC 2.0 spec. The package provides a
robust, framework-agnostic foundation for integrating multiple Kadena wallet
adapters into your applications. It standardizes wallet communication by
defining a common Provider interface, a reusable abstract base class, and a
client for managing multiple adapters.
What It Implements
KIP 37–40 (Account & Network Management):
- kadena_getAccount_v1: Retrieve the active account.
- kadena_getAccounts_v2: Retrieve all managed accounts.
- kadena_getNetwork_v1: Get the currently active network.
- kadena_getNetworks_v1: Get all supported networks.
Extended Methods (Not in JSON-RPC 2.0):
- kadena_connect / kadena_disconnect: These methods provide a consistent way to start or end a wallet session. (They are not defined in JSON-RPC 2.0.)
- onAccountChange / onNetworkChange:
These allow your app to subscribe to changes in the wallet’s state.
KIP 15 & KIP 17 (Transaction Signing):
- kadena_quicksign_v1 (alias: signCommand):
Supports signing multiple transactions (or commands) at once. - kadena_sign_v1 (alias: signTransaction):
Supports signing a single transaction.
These enable flexible and efficient signing workflows.
- kadena_quicksign_v1 (alias: signCommand):
JSON-RPC Error Codes
When interacting with wallet adapters, the following error codes might be returned:
| Code | Message |
|---|---|
| -32001 | Resource not found |
| -32002 | Resource unavailable |
| -32003 | Transaction rejected |
| -32004 | The requested method is not implemented |
| -32005 | Could not return account information |
| -32006 | Requested network does not exist |
| -32601 | Method not found |
| -32602 | Invalid method parameter(s) |
| -32603 | Internal server error |
Why It Matters
Unified Interface:
By mapping various wallet-specific APIs to a standard set of"kadena_"‑prefixed methods, Wallet Adapter Core ensures your dApp works seamlessly with multiple wallet providers.Enhanced Developer Experience:
Extended methods likeconnect,disconnect, and event subscriptions abstract provider-specific details so you can focus on building your application.Flexible Signing Workflows:
With separate commands for signing and quicksigning, your dApp can handle a variety of use cases independently.
Usage Examples
Connecting to a Wallet
import { WalletAdapterClient } from '@kadena/wallet-adapter-core';
import { EckoWalletAdapter } from 'wallet-adapter-ecko';
// Create an instance of your wallet adapter
const eckoAdapter = new EckoWalletAdapter();
// Create a client managing one or more wallet adapters
const client = new WalletAdapterClient([eckoAdapter]);
// Connect to the wallet using the standardized 'connect' method.
client.connect('Ecko').then((account) => {
console.log('Connected account:', account.accountName);
});Signing a Transaction
Use the signTransaction method (alias for kadena_sign_v1) to sign a single
transaction:
// Assuming transactionData is defined as per the signing API
client.signTransaction('Ecko', transactionData).then((signedCommand) => {
console.log('Signed transaction:', signedCommand);
});Signing Commands (QuickSign)
The signCommand method (alias for kadena_quicksign_v1) lets you sign multiple
commands independently:
// Assume commandData is defined as per the quicksign request schema.
client.signCommand('Ecko', commandData).then((signedCommand) => {
console.log('Signed command:', signedCommand);
});Disconnecting from the Wallet
Disconnect from the wallet using the standardized disconnect method:
client.disconnect('Ecko').then(() => {
console.log('Wallet disconnected');
});Listening for State Changes
Subscribe to account or network changes to react to state updates:
eckoAdapter.onAccountChange((newAccount) => {
console.log('Account changed:', newAccount.accountName);
});
eckoAdapter.onNetworkChange((newNetwork) => {
console.log('Network changed to:', newNetwork.name);
});Framework Wrappers
While wallet-adapter-core can be used directly (ideal for vanilla JavaScript/TypeScript projects), dedicated wrappers are available for popular frameworks:
- wallet-adapter-react – For React applications.
These wrappers simplify integration with their respective ecosystems.
Kadena Wallet Adapter Development Guide
This comprehensive guide is designed for wallet developers looking to create a
Kadena wallet adapter that conforms to the Kadena Improvement Proposals (KIPs),
specifically KIP-15, KIP-17, and KIP-37 through KIP-40. These KIPs define a
standardized JSON-RPC interface for wallet and decentralized application (dApp)
communication within the Kadena ecosystem. By following this guide, you’ll learn
how to build an adapter using the @kadena/wallet-adapter-core package,
implement the required functionality, and integrate it into dApps.
Introduction
The Kadena wallet adapter framework provides a standardized way to integrate
wallets into Kadena-based dApps. The @kadena/wallet-adapter-core package
offers a foundation with the BaseWalletAdapter class, which you can extend to
create a custom adapter for your wallet. This guide walks you through the
process step-by-step, ensuring your adapter supports essential features like
account management, network handling, and transaction signing while adhering to
Kadena’s KIP specifications.
Prerequisites
- Knowledge: Familiarity with TypeScript, JSON-RPC, and Kadena’s blockchain concepts (e.g., Pact, Chainweb).
- Tools: Node.js, npm or yarn, and a code editor.
- Dependencies: Install
@kadena/wallet-adapter-core.
npm install @kadena/wallet-adapter-coreStep-by-Step Guide to Creating a Wallet Adapter
Step 1: Set Up Your Project
Initialize a New Project
Create a new directory for your wallet adapter and initialize it with npm:mkdir wallet-adapter-my-wallet cd wallet-adapter-my-wallet npm init -yInstall Dependencies
Add the core dependencies and development tools:npm install @kadena/wallet-adapter-core npm install --save-dev typescript vitestConfigure TypeScript
Createtsconfig.jsonfor ES modules and CommonJS builds:{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "lib": ["DOM", "ES2020"], "moduleResolution": "Node", "esModuleInterop": true, "strict": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "dist", "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }Create
tsconfig.esm.jsonandtsconfig.cjs.jsonfor dual builds:tsconfig.esm.json:{ "extends": "./tsconfig.json", "compilerOptions": { "module": "ESNext", "outDir": "dist/esm", "declaration": true, "declarationDir": "dist/esm" } }tsconfig.cjs.json:{ "extends": "./tsconfig.json", "compilerOptions": { "module": "CommonJS", "outDir": "dist/cjs", "declaration": false } }
Update
package.json
Define your package metadata and scripts:{ "name": "@kadena/wallet-adapter-my-wallet", "version": "1.0.0", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", "exports": { "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js" }, "scripts": { "build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json", "test": "vitest" }, "dependencies": { "@kadena/wallet-adapter-core": "^0.42.1" }, "devDependencies": { "typescript": "5.4.5", "vitest": "^1.6.0" } }Create Source Directory
Set up your source files:mkdir src touch src/index.ts src/MyWalletAdapter.ts src/provider.ts
Step 2: Define the Provider Interface
Your wallet likely injects a provider object into the browser’s window object
(e.g., window.kadena). Define an interface that extends the core Provider
type to match your wallet’s API.
Create
provider.ts
Define the provider interface and detection logic:import { IProvider } from '@kadena/wallet-adapter-core'; // Extend the base Provider interface with your wallet-specific properties export interface MyWalletProvider extends IProvider { isMyWallet?: boolean; // Optional flag to identify your wallet } // Extend the Window interface to include your provider interface KadenaWindow extends Window { kadena?: MyWalletProvider; } // Detect the provider in the browser export async function detectMyWalletProvider< T = MyWalletProvider, >(): Promise<T | null> { if (typeof window !== 'undefined') { const kadenaProvider = (window as KadenaWindow).kadena; if (kadenaProvider) { return kadenaProvider as T; } } return null; }- Purpose: This code checks if your wallet provider is available in the browser and returns it if found.
- KIP Compliance: Ensures compatibility with browser-based wallet detection, a common practice in blockchain ecosystems.
Step 3: Implement the Adapter Factory
- Create
walletAdapterFactory.ts
import type {
IBaseWalletFactoryOptions,
AdapterFactoryCreator,
} from '@kadena/wallet-adapter-core';
export const myWalletAdapter = ((options?: IBaseWalletFactoryOptions) => {
return {
name: 'MyWallet',
detect: async () => {
return await detectMyWalletProvider();
},
adapter: async (provider) => {
const { MyWalletAdapter } = await import('./MyWalletAdapter');
return new MyWalletAdapter({ ...options, provider });
},
};
}) satisfies AdapterFactoryCreator;
export { MyWalletAdapter } from './MyWalletAdapter';
export { detectMyWalletProvider } from './provider';Step 4: Implement the Wallet Adapter
Extend the BaseWalletAdapter class to implement your wallet’s functionality.
This involves overriding methods to match your wallet’s API while adhering to
KIP standards.
Create
MyWalletAdapter.ts
Implement the adapter:import { BaseWalletAdapter } from '@kadena/wallet-adapter-core'; import type { IAccountInfo, INetworkInfo, IUnsignedCommand, ICommand, IBaseWalletAdapterOptions, } from '@kadena/wallet-adapter-core'; import { detectMyWalletProvider, MyWalletProvider } from './provider'; export class MyWalletAdapter extends BaseWalletAdapter { public name = 'MyWallet'; // Display name of your wallet public constructor(options: IBaseWalletAdapterOptions) { super(options); } }- Key Methods: (available in base-wallet-adapter)
connect(): Establishes a session.disconnect(): Ends a session.getActiveAccount(): Returns the active account per KIP-37.getAccounts(): Returns all managed accounts per KIP-38.getActiveNetwork(): Returns the current network per KIP-39.getNetworks(): Lists all supported networks per KIP-40.signTransaction(): Signs a single transaction per KIP-17.signCommand(): Signs multiple commands per KIP-15.
- Key Methods: (available in base-wallet-adapter)
Export in
index.ts
Make your adapter available:export { MyWalletAdapter } from './MyWalletAdapter'; export { detectMyWalletProvider } from './provider';
Step 5: Build and Publish
Build the Project
Compile your TypeScript code:npm run buildPublish to npm
If you’re sharing your adapter:npm publish --access public
Using Your Adapter
In a Vanilla JavaScript/TypeScript Project
Instantiate the Adapter
import { myWalletAdapter } from '@kadena/wallet-adapter-my-wallet'; import { WalletAdapterClient } from '@kadena/wallet-adapter-core'; const client = new WalletAdapterClient([myWalletAdapter]); await client.init(); client.connect('MyWallet').then((account) => { console.log('Connected:', account.accountName); });Sign a Transaction
const transaction: IUnsignedCommand = { cmd: '...', sigs: [] }; client.signTransaction('MyWallet', transaction).then((signed) => { console.log('Signed:', signed); });
In a React Application
Set Up with
KadenaWalletProviderimport React from 'react'; import ReactDOM from 'react-dom/client'; import { KadenaWalletProvider } from '@kadena/wallet-adapter-react'; import { myWalletAdapter } from '@kadena/wallet-adapter-my-wallet'; import App from './App'; ReactDOM.createRoot(document.getElementById('root')!).render( <KadenaWalletProvider adapters={[myWalletAdapter]}> <App /> </KadenaWalletProvider>, );Use the Hook
import { useKadenaWallet } from '@kadena/wallet-adapter-react'; const App = () => { const { client, adapters } = useKadenaWallet(); const handleConnect = async () => { const account = await client.connect('MyWallet'); console.log('Connected:', account); }; return ( <div> <h1>My Kadena dApp</h1> <button onClick={handleConnect}>Connect MyWallet</button> </div> ); }; export default App;
Best Practices
- Error Handling: Return JSON-RPC 2.0-compliant errors (e.g.,
-32603for internal errors). - Security: Never expose private keys; use
OptionalKeyPairto omitsecretKey. - Optional Event Handling: Implement
onAccountChangeandonNetworkChangefor real-time updates.
Happy coding
Use the @kadena/wallet-adapter-core tools to streamline development, making it
fully compatible with Kadena dApps, and test thoroughly to ensure reliability.
Happy coding!