Skip to main content
All CollectionsHana WalletDevelopers
Hana Wallet Cosmos Integration Guide

Hana Wallet Cosmos Integration Guide

Integrate Hana Wallet into your Cosmos-based dApp using Keplr-compatible methods for wallet access, signing, and transactions.

David avatar
Written by David
Updated over a week ago

Important: Keplr Compatibility

Hana Wallet emulates the Keplr Wallet API.
If your dApp already integrates with Keplr Wallet, it will work with Hana Wallet with minimal or no changes.

Use window.keplr to interact with Hana Wallet. Hana injects itself as keplr in the browser window object and implements the Keplr interface.

Supported Chains

Network

Mainnet

Testnet

Cosmos Hub

cosmoshub-4

theta-testnet-001

Osmosis

osmosis-1

osmo-test-5

Neutron

neutron-1

pion-1

Archway

archway-1

constantine-3

Injective

injective-1

injective-888

To support other Cosmos chains, use the experimentalSuggestChain method.


Prerequisites

  • A web application (React or other JavaScript framework)

  • Installed dependency: @cosmjs/stargate


Basic Integration

1. Detecting Hana Wallet

const checkForHanaWallet = async () => {
if (window.keplr) {
console.log('Wallet detected');
return true;
} else {
console.log('No wallet detected');
return false;
}
};

2. Connecting to a Chain

const connectToChain = async (chainId) => {
if (!window.keplr) {
alert("Please install Hana Wallet");
return;
}

try {
await window.keplr.enable(chainId);
const offlineSigner = window.keplr.getOfflineSigner(chainId);
const accounts = await offlineSigner.getAccounts();
const address = accounts[0].address;
console.log(`Connected to ${chainId} with address: ${address}`);
return { offlineSigner, address };
} catch (err) {
console.error(`Failed to connect: ${err.message}`);
}
};

3. Getting the User's Address

const getUserAddress = async (chainId) => {
try {
await window.keplr.enable(chainId);
const key = await window.keplr.getKey(chainId);
return key.bech32Address;
} catch (err) {
console.error(`Error getting address: ${err.message}`);
throw err;
}
};

4. Signing an Arbitrary Message

const signArbitraryMessage = async (chainId, address, message) => {
try {
await window.keplr.enable(chainId);
const signature = await window.keplr.signArbitrary(chainId, address, message);
console.log("Signature:", signature);
return signature;
} catch (err) {
console.error(`Signing failed: ${err.message}`);
throw err;
}
};

5. Sending Tokens

const sendTokens = async (chainId, recipientAddress, amount) => {
try {
await window.keplr.enable(chainId);
const offlineSigner = window.keplr.getOfflineSigner(chainId);
const accounts = await offlineSigner.getAccounts();
const senderAddress = accounts[0].address;

let rpcEndpoint;
if (chainId === "cosmoshub-4") {
rpcEndpoint = "https://rpc.cosmos.network";
} else if (chainId === "osmosis-1") {
rpcEndpoint = "https://rpc.osmosis.zone";
} else if (chainId === "neutron-1") {
rpcEndpoint = "https://rpc-neutron.keplr.app";
} else if (chainId === "archway-1") {
rpcEndpoint = "https://rpc.mainnet.archway.io";
} else if (chainId === "injective-1") {
rpcEndpoint = "https://rpc-injective.keplr.app";
}

const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, offlineSigner);

let denom = "uatom";
if (chainId.includes("osmosis")) {
denom = "uosmo";
} else if (chainId.includes("neutron")) {
denom = "untrn";
} else if (chainId.includes("archway")) {
denom = "aarch";
} else if (chainId.includes("injective")) {
denom = "inj";
}

const amountToSend = {
denom: denom,
amount: amount,
};

const fee = {
amount: [{ denom: denom, amount: "5000" }],
gas: "200000",
};

const result = await client.sendTokens(senderAddress, recipientAddress, [amountToSend], fee, "");
console.log("Transaction hash:", result.transactionHash);
return result;
} catch (err) {
console.error(`Token transfer failed: ${err.message}`);
throw err;
}
};


Adding Custom Chains

const suggestChain = async (chainInfo) => {
try {
await window.keplr.experimentalSuggestChain(chainInfo);
console.log(`Chain ${chainInfo.chainId} added successfully`);
return true;
} catch (err) {
console.error(`Failed to add chain: ${err.message}`);
throw err;
}
};

Example chain info for Osmosis Testnet:

const osmosisTestnet = {
chainId: "osmo-test-5",
chainName: "Osmosis Testnet",
rpc: "https://rpc.testnet.osmosis.zone",
rest: "https://lcd.testnet.osmosis.zone",
stakeCurrency: {
coinDenom: "OSMO",
coinMinimalDenom: "uosmo",
coinDecimals: 6
},
bip44: {
coinType: 118
},
bech32Config: {
bech32PrefixAccAddr: "osmo",
bech32PrefixAccPub: "osmopub",
bech32PrefixValAddr: "osmovaloper",
bech32PrefixValPub: "osmovaloperpub",
bech32PrefixConsAddr: "osmovalcons",
bech32PrefixConsPub: "osmovalconspub"
},
currencies: [
{
coinDenom: "OSMO",
coinMinimalDenom: "uosmo",
coinDecimals: 6
}
],
feeCurrencies: [
{
coinDenom: "OSMO",
coinMinimalDenom: "uosmo",
coinDecimals: 6,
gasPriceStep: {
low: 0.01,
average: 0.025,
high: 0.04
}
}
],
coinType: 118,
beta: true
};


Technical Details

Hana Wallet implements the following Keplr interfaces:

  • getOfflineSigner: Returns a signer for Amino and Direct signing

  • getOfflineSignerOnlyAmino: For Ledger compatibility

  • getOfflineSignerAuto: Automatically chooses the right mode

  • signAmino: Sign a transaction in Amino format

  • signDirect: Sign in Direct signing format

  • signArbitrary: Sign arbitrary messages (ADR-36)

  • experimentalSuggestChain: Suggest new chains


Tips for dApp Developers

  1. Always use enable() first before accessing account info

  2. Handle rejections and errors to give users clear feedback

  3. Support multiple chains by dynamically adjusting denom and fees

  4. Use reliable RPC endpoints per chain

  5. Use verifyArbitrary() on the backend if you care about verifying signatures

Did this answer your question?