A website-based multi-chain crypto wallet for Polkadot & Kusama ecosystem
Coong Wallet Website • Coong Wallet App • Example Playground Dapp
- No need for extra steps to install browser extensions or mobile apps, Coong Wallet is just a website running on your browser
- Works on both desktop and mobile devices
- Compatible with Polkadot.js extension API, integrate Coong Wallet into your dapp within just a few steps
- One seed phrase to recover all created accounts (excluding imported accounts/private keys)
- Private keys and seed phrase are encrypted with a user chosen wallet password
- Desktop: https://youtu.be/9fIcAlpx_UI
- Mobile: https://youtu.be/F8S2fmQFRWQ
The Polkadot and Kusama ecosystems currently offers several wallet solutions with excellent UI/UX, such as SubWallet, NovaWallet, Talisman. However, on desktop, most of these solutions are browser extension-based wallets, requiring users to install an extension to interact with dapps and networks. On mobile, since most browsers do not support extensions, users need to install wallet mobile apps and access dapps through a built-in Dapp Browser within the wallets (SubWallet, Nova). This creates an inconsistent experience between desktop and mobile, which poses a barrier for onboarding new users to the ecosystem, especially those who are new to or less familiar with cryptocurrencies.
As users, we love the website-based wallet experience provided by the NEAR wallet in the NEAR ecosystem. It allows users to connect to dapps using their preferred browsers and access their wallets smoothly within the same browser on both desktop and mobile platforms.
With that inspiration, we propose building Coong Wallet, a website-based multi-chain wallet, to offer a similar experience in the Polkadot and Kusama ecosystems. We believe that Coong Wallet will bring significant benefits to both users and the ecosystems as a whole.
- Install NodeJS
- Install dependencies:
yarn install
- Start the development server:
yarn start
- We can now access the local application at:
http://localhost:3030
- Make sure you have Docker installed
- Build an image of the wallet:
docker build -t coong-wallet .
- Run it:
docker run -dp 3030:3030 coong-wallet
- Install
@coong/sdk
to your dapp:
# via yarn
yarn add @coong/sdk
# via npm
npm install --save @coong/sdk
- Inject API & interact with Coong Wallet using the Polakdot{.js} extension API
import CoongSdk from '@coong/sdk';
// Inject Coong Wallet API
const initializeCoongWallet = async () => {
const sdk = new CoongSdk()
await sdk.initialize();
return sdk;
}
await initializeCoongWallet();
// We can now interact with the wallet using the similar Polkadot{.js} extension API
const connectCoongWallet = async () => {
const injected = await window['injectedWeb3']['coongwallet'].enable('Awesome Dapp');
const connectedAccounts = await injected.accounts.get();
return { injected, connectedAccounts }
}
await connectCoongWallet();
- Add/remove connected accounts
// Initilize wallet
const { injected } = await connectCoongWallet();
// This will open a Coong Wallet window allowing users
// to add/remove accounts connecting to dapp
const updatedAccounts = await injected.accounts.update();
- Sign out & clear up connected accounts
const signOut = () => {
window['injectedWeb3']['coongwallet'].disable();
}
signOut();
Notes:
- By default, the SDK will connect to Coong Wallet at the offical URL
https://app.coongwallet.io
. - You can also connect to a different URL of the wallet by customizing SDK options:
const sdk = new CoongSdk({ walletUrl: 'https://beta.coongwallet.io' });
await sdk.initialize();
After running initialization (via initialize()
), the SDK will inject injectedWeb3
into the window
global object exposing the following:
// Reference: https://github.com/polkadot-js/extension#injection-information
window.injectedWeb3 = {
// this is the name of this wallet, there could be multiples injected,
// each with their own keys, here `coongwallet` is for this wallet
'coongwallet': {
// semver of the wallet
version: '0.1.0',
// call this to enable the injection, and returns an injected
// object containing the accounts, signer (or it will reject if not authorized)
enable (originName: string): Promise<Injected>,
// call this to sign out and clear up all connected accounts
disable (): void
}
}
The Injected
API, as returned after calling enable(originName)
, contains the following information:
// Reference: https://github.com/polkadot-js/extension#api-interface
interface Injected {
// the interface for Accounts, as detailed below
readonly accounts: Accounts;
// the standard Signer interface for the API, as detailed below
readonly signer: CoongSigner;
}
// exposes accounts
interface Accounts {
// retrieves the list of connected accounts
get: () => Promise<InjectedAccount[]>;
// subscribe to all accounts, updating as they change
subscribe: (cb: (accounts: Account[]) => any) => () => void
// [NEW] asking for updating connected accounts
update: () => Promise<InjectedAccount[]>
}
// a signer that communicates with the extension via sendMessage
interface CoongSigner extends SignerInterface {
// signs an extrinsic payload from a serialized form
signPayload?: (payload: SignerPayloadJSON) => Promise<SignerResult>;
// signs a raw payload, only the bytes data as supplied
signRaw?: (raw: SignerPayloadRaw) => Promise<SignerResult>;
}
interface InjectedAccount {
// ss-58 encoded address
readonly address: string;
// the genesisHash for this account (empty if applicable to all)
readonly genesisHash?: string;
// (optional) name for display
readonly name?: string;
// Keypair type: 'ed25519' | 'sr25519' | 'ecdsa' | 'ethereum'
readonly type?: string;
};
Coong SDK uses window.open
to fire up Coong Wallet windows/popups allowing users to interact with the wallet (e.g: Request to access wallet accounts, request to sign a transaction...), browsers might block this open popup API depending on various reasons. Below is a few practices to help prevent this blocking popups issue from happening.
- Call APIs that opens a wallet popup from a user interaction (clicks/touches)
// initialize Coong Wallet API
const sdk = new CoongSdk()
await sdk.initialize();
// Trigger connect to Coong Wallet when users hit the connect button
const onClickConnectWallet = async () => {
await window['injectedWeb3']['coongwallet'].enable('Awesome Dapp');
}
- For actions that might take time (asynchronously) to complete (transfer balance ...), launch a waiting wallet instance (
CoongSdk.newWaitingWalletInstance()
) first thing on user interaction.
// Connect to Polkadot Network
const wsProvider = new WsProvider('wss://rpc.polkadot.io');
const api = await ApiPromise.create({ provider: wsProvider });
// initialize Coong Wallet API
const sdk = new CoongSdk()
await sdk.initialize();
// connect to Coong Wallet
const injected = await window['injectedWeb3']['coongwallet'].enable('Awesome Dapp');
const onClickTransferBalance = async () => {
// Launch a waiting wallet instance first thing when user clicking the Transfer button
// The signer will then later a send message to this wallet instance to asking for signing transaction
await sdk.newWaitingWalletInstance();
const fromAddress = 0x000...;
const destinationAddress = 0x000...;
const hash = await api.tx.balances
.transferKeepAlive(destinationAddress, 1_000_000_000_000)
.signAndSend(fromAddress, { signer: injected.signer });
}
await onClickTransferBalance();
Integration example can be found in the playground dapp source code in this repository.
- Set up the development environment.
- Simply run
yarn test
to trigger testing for all packages