Skip to content

Commit

Permalink
feat: add compass wallet support
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronCQL committed Dec 28, 2023
1 parent 235279a commit f767aed
Showing 11 changed files with 119 additions and 7 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Changelog

## `v0.0.48`

### Features

- Added Compass wallet support to execute txs via Compass extension on Sei network (*does not support wallet connect yet*)

## `v0.0.47`

### Features

- Added `MetamaskInjective` wallet to execute txs via MetaMask extension on Injective network (*does not support wallet connect yet*)
- Added MetaMask wallet support to execute txs via MetaMask extension on Injective network (*does not support wallet connect yet*)

### Improvements

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -131,6 +131,7 @@ This directory is a [Cosmos Kit](https://cosmoskit.com) alternative to interact
- [Keplr](https://www.keplr.app/)
- [Leap](https://www.leapwallet.io/)
- [Cosmostation](https://wallet.cosmostation.io/)
- [Compass](https://compasswallet.io/) (for Sei only)
- [MetaMask](https://metamask.io/) (for Injective only)

**Features**:
18 changes: 13 additions & 5 deletions examples/solid-vite/src/App.tsx
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ import { createStore } from "solid-js/store";

import { MsgSend } from "cosmes/client";
import {
CompassController,
ConnectedWallet,
CosmostationController,
KeplrController,
@@ -17,7 +18,7 @@ import {

const WC_PROJECT_ID = "2b7d5a2da89dd74fed821d184acabf95";
const SIGN_ARBITRARY_MSG =
"Hi from Coinhall! This is a test message just to prove that the wallet is working.";
"Hi from CosmeES! This is a test message just to prove that the wallet is working.";
const TX_MEMO = "signed via cosmes";

const CHAINS: Record<string, string> = {
@@ -29,12 +30,14 @@ const CHAINS: Record<string, string> = {
"neutron-1": "Neutron",
"migaloo-1": "Migaloo",
"injective-1": "Injective",
"pacific-1": "Sei",
};
const WALLETS: Record<WalletName, string> = {
[WalletName.KEPLR]: "Keplr",
[WalletName.COSMOSTATION]: "Cosmostation",
[WalletName.STATION]: "Terra Station",
[WalletName.LEAP]: "Leap",
[WalletName.COMPASS]: "Compass",
[WalletName.METAMASK_INJECTIVE]: "MetaMask",
};
const TYPES: Record<WalletType, string> = {
@@ -45,6 +48,7 @@ const CONTROLLERS: Record<string, WalletController> = {
[WalletName.STATION]: new StationController(),
[WalletName.KEPLR]: new KeplrController(WC_PROJECT_ID),
[WalletName.LEAP]: new LeapController(WC_PROJECT_ID),
[WalletName.COMPASS]: new CompassController(),
[WalletName.COSMOSTATION]: new CosmostationController(WC_PROJECT_ID),
[WalletName.METAMASK_INJECTIVE]: new MetamaskInjectiveController(),
};
@@ -67,6 +71,8 @@ function getRpc(chain: string): string {
return "https://migaloo-rpc.polkachu.com";
case "injective-1":
return "https://injective-rpc.polkachu.com";
case "pacific-1":
return "https://rpc-sei-ia.cosmosia.notional.ventures";
default:
throw new Error("Unknown chain");
}
@@ -90,6 +96,8 @@ function getGasPrice(chain: string): { amount: string; denom: string } {
return { amount: "0.25", denom: getDenom(chain) };
case "injective-1":
return { amount: "500000000", denom: getDenom(chain) };
case "pacific-1":
return { amount: "0.1", denom: getDenom(chain) };
default:
throw new Error("Unknown chain");
}
@@ -112,16 +120,16 @@ function getDenom(chain: string): string {
return "uwhale";
case "injective-1":
return "inj";
case "pacific-1":
return "usei";
default:
throw new Error("Unknown chain");
}
}

const App: Component = () => {
const [chain, setChain] = createSignal<string>("injective-1");
const [wallet, setWallet] = createSignal<WalletName>(
WalletName.METAMASK_INJECTIVE
);
const [chain, setChain] = createSignal<string>("pacific-1");
const [wallet, setWallet] = createSignal<WalletName>(WalletName.COMPASS);
const [wallets, setWallets] = createStore<Record<string, ConnectedWallet>>(
{}
);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cosmes",
"version": "0.0.47",
"version": "0.0.48",
"private": false,
"packageManager": "pnpm@8.3.0",
"sideEffects": false,
1 change: 1 addition & 0 deletions src/wallet/constants/WalletName.ts
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ export const WalletName = {
STATION: "station",
KEPLR: "keplr",
LEAP: "leap",
COMPASS: "compass",
COSMOSTATION: "cosmostation",
METAMASK_INJECTIVE: "metamask-injective",
} as const;
1 change: 1 addition & 0 deletions src/wallet/index.ts
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ export {
type ChainInfo,
type EventCallback,
} from "./wallets/WalletController";
export { CompassController } from "./wallets/compass/CompassController";
export { CosmostationController } from "./wallets/cosmostation/CosmostationController";
export { KeplrController } from "./wallets/keplr/KeplrController";
export { LeapController } from "./wallets/leap/LeapController";
4 changes: 4 additions & 0 deletions src/wallet/wallets/WalletController.ts
Original file line number Diff line number Diff line change
@@ -116,6 +116,10 @@ export abstract class WalletController {
* `onAccountChange` event.
*/
protected changeAccount(walletType: WalletType) {
// Ignore if controller does not have any connected wallets
if (this.connectedWallets.size === 0) {
return;
}
// Find all wallets that were connected via the given `walletType`
const wallets = [...this.connectedWallets.values()].filter(
(wallet) => wallet.type === walletType
77 changes: 77 additions & 0 deletions src/wallet/wallets/compass/CompassController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Secp256k1PubKey } from "cosmes/client";

import { WalletName } from "../../constants/WalletName";
import { WalletType } from "../../constants/WalletType";
import { onWindowEvent } from "../../utils/window";
import { WalletConnectV1 } from "../../walletconnect/WalletConnectV1";
import { WalletConnectV2 } from "../../walletconnect/WalletConnectV2";
import { ConnectedWallet } from "../ConnectedWallet";
import { ChainInfo, WalletController } from "../WalletController";
import { CompassExtension } from "./CompassExtension";

export class CompassController extends WalletController {
constructor() {
super(WalletName.COMPASS);
this.registerAccountChangeHandlers();
}

public async isInstalled(type: WalletType) {
return type === WalletType.EXTENSION ? "compass" in window : false;
}

protected async connectWalletConnect<T extends string>(
_chains: ChainInfo<T>[]
): Promise<{
wallets: Map<T, ConnectedWallet>;
wc: WalletConnectV1 | WalletConnectV2;
}> {
// Compass does not support WC yet
throw new Error("WalletConnect not supported");
}

protected async connectExtension<T extends string>(chains: ChainInfo<T>[]) {
const wallets = new Map<T, ConnectedWallet>();
const ext = window.compass;
if (!ext) {
throw new Error("Compass extension is not installed");
}
await ext.enable(chains.map(({ chainId }) => chainId));
for (const { chainId, rpc, gasPrice } of Object.values(chains)) {
const { bech32Address, pubKey, isNanoLedger } = await ext.getKey(chainId);
const key = new Secp256k1PubKey({
key: pubKey,
});
wallets.set(
chainId,
new CompassExtension(
this.id,
ext,
chainId,
key,
bech32Address,
rpc,
gasPrice,
isNanoLedger
)
);
}
return wallets;
}

protected registerAccountChangeHandlers() {
/**
* ! IMPORTANT !
*
* Since Leap also uses the same event key, this causes issues when a user
* has both leap and compass wallets connected simultaneously. For example,
* a change in Leap's keystore will trigger Compass to emit this event as
* well, leading to a race condition when `changeAccount` is called.
*
* The Compass team has been notified to possibly change this event emitted
* to `compass_keystorechange` instead.
*/
onWindowEvent("leap_keystorechange", () =>
this.changeAccount(WalletType.EXTENSION)
);
}
}
4 changes: 4 additions & 0 deletions src/wallet/wallets/compass/CompassExtension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { LeapExtension } from "../leap/LeapExtension";

// Compass's API is similar to Leap.
export const CompassExtension = LeapExtension;
8 changes: 8 additions & 0 deletions src/wallet/wallets/compass/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Leap } from "../leap/types";

// Type is similar to Leap
export type Compass = Leap;

export type Window = {
compass?: Compass | undefined;
};
2 changes: 2 additions & 0 deletions src/wallet/wallets/window.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Window as KeplrWindow } from "cosmes/registry";

import { Window as CompassWindow } from "./compass/types";
import { Window as CosmostationWindow } from "./cosmostation/types";
import { Window as LeapWindow } from "./leap/types";
import { Window as EthereumWindow } from "./metamask-injective/types";
@@ -11,5 +12,6 @@ declare global {
CosmostationWindow,
StationWindow,
LeapWindow,
CompassWindow,
EthereumWindow {}
}

0 comments on commit f767aed

Please sign in to comment.