C2X Wallet Provider
Library to make React dApps easier using C2X Station Extension or C2X Station Mobile.
Quick Start
Use templates to get your projects started quickly
Code Sandbox
If you want to test features quickly, you can simply run them on CodeSandbox without having to download Templates.
And if you need to start your project from local computer, use the templates below. 👇
Create React App
npx terra-templates get wallet-provider:create-react-app your-app-name
cd your-app-name
yarn install
yarn start
https://github.com/c2x-station/wallet-provider/tree/main/templates/create-react-app
Next.js
npx terra-templates get wallet-provider:next your-app-name
cd your-app-name
yarn install
yarn run dev
https://github.com/c2x-station/wallet-provider/tree/main/templates/next
Other templates
You can find more templates in https://templates.terra.money. (This is the beginning stage, so it may not be enough yet)
If you make a different type of template, you can register here.
Basic Usage
First, please add <meta name="c2x-wallet" />
on your html page.
Since then, browser extensions (e.g. Terra Station chrome extension) will not attempt to connect in a Web app where this <meta name="c2x-wallet">
tag is not found.
<html lang="en">
<head>
<meta name="c2x-wallet" />
</head>
</html>
If you have used react-router-dom
's <BrowserRouter>
, useLocation()
, you can easily understand it.
import {
NetworkInfo,
WalletProvider,
WalletStatus,
getChainOptions,
} from '@c2x-station/wallet-provider';
import React from 'react';
import ReactDOM from 'react-dom';
getChainOptions().then((chainOptions) => {
ReactDOM.render(
<WalletProvider {...chainOptions}>
<YOUR_APP />
</WalletProvider>,
document.getElementById('root'),
);
});
First, you need to wrap your React App with the <WalletProvider>
component.
import { useWallet } from '@c2x-station/wallet-provider';
import React from 'react';
function Component() {
const { status, network, wallets } = useWallet();
return (
<div>
<section>
<pre>
{JSON.stringify(
{
status,
network,
wallets,
},
null,
2,
)}
</pre>
</section>
</div>
);
}
Afterwards, you can use React Hooks such as useWallet()
, useConnectedWallet()
and useLCDClient()
anywhere in your app.
API
<WalletProvider>
import {
WalletProvider,
NetworkInfo,
ReadonlyWalletSession,
} from '@c2x-station/wallet-provider';
const mainnet: NetworkInfo = {
name: 'mainnet',
chainID: 'columbus-5',
lcd: 'https://lcd.terra.dev',
};
const testnet: NetworkInfo = {
name: 'testnet',
chainID: 'bombay-12',
lcd: 'https://bombay-lcd.terra.dev',
};
const walletConnectChainIds: Record<number, NetworkInfo> = {
0: testnet,
1: mainnet,
};
async function createReadonlyWalletSession(): Promise<ReadonlyWalletSession> {
const terraAddress = prompt('YOUR TERRA ADDRESS');
return {
network: mainnet,
terraAddress,
};
}
const connectorOpts: IWalletConnectOptions | undefined = undefined;
const pushServerOpts: IPushServerOptions | undefined = undefined;
const waitingChromeExtensionInstallCheck: number | undefined = undefined;
ReactDOM.render(
<WalletProvider
defaultNetwork={mainnet}
walletConnectChainIds={walletConnectChainIds}
createReadonlyWalletSession={createReadonlyWalletSession}
connectorOpts={connectorOpts}
pushServerOpts={pushServerOpts}
waitingChromeExtensionInstallCheck={waitingChromeExtensionInstallCheck}
>
<YOUR_APP />
</WalletProvider>,
document.getElementById('root'),
);
useWallet()
This is a React Hook that can receive all the information. (Other hooks are functions for the convenience of Wrapping
this useWallet()
)
packages/src/@c2x-station/use-wallet/useWallet.ts
export interface Wallet {
status: WalletStatus;
network: NetworkInfo;
availableConnectTypes: ConnectType[];
availableConnections: Connection[];
connection: Connection | undefined;
connect: (type?: ConnectType, identifier?: string) => void;
connectReadonly: (terraAddress: string, network: NetworkInfo) => void;
availableInstallTypes: ConnectType[];
availableInstallations: Installation[];
install: (type: ConnectType) => void;
wallets: WalletInfo[];
disconnect: () => void;
refetchStates: () => void;
recheckStatus: () => void;
supportFeatures: Set<
'post' | 'sign' | 'sign-bytes' | 'cw20-token' | 'network'
>;
post: (tx: CreateTxOptions, terraAddress?: string) => Promise<TxResult>;
sign: (tx: CreateTxOptions, terraAddress?: string) => Promise<SignResult>;
signBytes: (bytes: Buffer, terraAddress?: string) => Promise<SignBytesResult>;
hasCW20Tokens: (
chainID: string,
...tokenAddrs: string[]
) => Promise<{
[tokenAddr: string]: boolean;
}>;
addCW20Tokens: (
chainID: string,
...tokenAddrs: string[]
) => Promise<{
[tokenAddr: string]: boolean;
}>;
hasNetwork: (network: Omit<NetworkInfo, 'name'>) => Promise<boolean>;
addNetwork: (network: NetworkInfo) => Promise<boolean>;
isChromeExtensionCompatibleBrowser: () => boolean;
}
useConnectedWallet()
import { useConnectedWallet } from '@c2x-station/wallet-provider'
function Component() {
const connectedWallet = useConnectedWallet()
const postTx = useCallback(async () => {
if (!connectedWallet) return
console.log('walletAddress is', connectedWallet.walletAddress)
console.log('network is', connectedWallet.network)
console.log('connectType is', connectedWallet.connectType)
const result = await connectedWallet.post({...})
}, [])
return (
<button disabled={!connectedWallet || !connectedWallet.availablePost} onClick={() => postTx}>
Post Tx
</button>
)
}
useLCDClient()
import { useLCDClient } from '@c2x-station/wallet-provider';
function Component() {
const lcd = useLCDClient();
const [result, setResult] = useState('');
useEffect(() => {
lcd.treasury.taxRate().then((taxRate) => {
setResult(taxRate.toString());
});
}, []);
return <div>Result: {result}</div>;
}
Projects for reference
Links
Trouble-shooting guide
wallet-provider contains the original source codes in sourcemaps.
You can check src/@c2x-station/wallet-provider/
in the Chrome Devtools / Sources Tab, and you can also use breakpoints
here for debug.
(It may not be visible depending on your development settings such as Webpack.)
For Chrome Extension compatible wallet developers
Chrome Extension compatible wallet development guide
1. Create dApp for test
There is the dangerously__chromeExtensionCompatibleBrowserCheck
option to allow you to create a test environment for
wallet development.
By declaring the dangerously__chromeExtensionCompatibleBrowserCheck
, you can make your wallet recognized as the chrome
extension.
<WalletProvider
dangerously__chromeExtensionCompatibleBrowserCheck={(userAgent) =>
/YourWallet/.test(userAgent)
}
>
...
</WalletProvider>
2. Register your wallet as default allow
If your wallet has been developed,
Please send me your wallet App link (Testlight version is OK)
And send me Pull Request by modifying DEFAULT_CHROME_EXTENSION_COMPATIBLE_BROWSER_CHECK
in
the packages/src/@c2x-station/wallet-provider/env.ts
file. (or just make an issue is OK)
export const DEFAULT_CHROME_EXTENSION_COMPATIBLE_BROWSER_CHECK = (userAgent: string) => {
- return /MathWallet\//.test(userAgent);
+ return /MathWallet\//.test(userAgent) || /YourWallet/.test(userAgent);
}