@earthworm/wallet-sdk
v0.2.7
Published
EVM wallet utilities for browser DApps
Maintainers
Readme
@earthworm/wallet-sdk
Browser EVM wallet SDK for DApps (MetaMask, Coinbase, TronLink, TokenPocket, contract reads).
Install
pnpm add @earthworm/wallet-sdk ethersQuick start
import {
initWalletSdk,
connectWallet,
disconnectWallet,
isWalletConnected,
walletEvents,
resolveMetaMaskInjectedProvider,
switchToConfiguredNetwork,
isEthereumProvider,
isCoinbaseProvider,
isTokenPocketProvider,
isTronLinkProvider,
} from "@earthworm/wallet-sdk";
initWalletSdk({
usdt: { address: "0x55d398326f99059fF775485246999027B3197955" },
});
const provider = resolveMetaMaskInjectedProvider();
if (!provider) throw new Error("MetaMask not found");
await connectWallet(provider, { chainId: "0x38" });
console.log("Connected:", isWalletConnected());
await disconnectWallet();connectWallet() binds the provider and registers event listeners internally. You do not need to call setWalletEventProvider() separately after connect.
Restore session on page load
Some mobile wallets (e.g. TokenPocket App) reload the page when the user switches address. After reload, in-memory SDK state is lost even though the wallet still has an authorized session.
Call restoreWalletConnection() during initialization. It uses eth_accounts (no authorization popup). If authorized accounts exist, it binds the provider, restores the signer, and optionally switches chain — same as connectWallet() but without eth_requestAccounts.
import {
initWalletSdk,
restoreWalletConnection,
isWalletConnected,
resolveTokenPocketInjectedProvider,
} from "@earthworm/wallet-sdk";
initWalletSdk({
usdt: { address: "0x55d398326f99059fF775485246999027B3197955" },
});
const provider = resolveTokenPocketInjectedProvider();
if (provider) {
const session = await restoreWalletConnection(provider, { chainId: "0x38" });
if (session) {
console.log("Session restored:", session.address);
}
}
console.log("Connected:", isWalletConnected());| API | RPC | Popup | Use when |
| --------------------------- | --------------------- | ---------- | ----------------------------------------------- |
| connectWallet() | eth_requestAccounts | May prompt | User clicks Connect |
| restoreWalletConnection() | eth_accounts | No | Page load / refresh with existing authorization |
Returns null when no authorized accounts are found. Event listeners are registered the same way as connectWallet().
Tip: Persist which wallet the user selected (e.g. localStorage) so after reload you know which resolve*InjectedProvider() to pass in.
Wallet detection
if (isEthereumProvider()) console.log("MetaMask is available");
if (isCoinbaseProvider()) console.log("Coinbase Wallet is available");
if (isTokenPocketProvider()) console.log("TokenPocket is available");
if (isTronLinkProvider()) console.log("TronLink is available");Events
All walletEvents.on(...) listeners receive (wallet, event):
wallet:"metamask" | "coinbase" | "tokenpocket" | "tronlink" | "unknown"event.name: native wallet event name (e.g."accountsChanged","setAccount","disconnectWeb")event.payload: normalized SDK payload for that eventevent.raw: raw provider / postMessage arguments
walletEvents.on("accountsChanged", (wallet, event) => {
console.log(wallet, event.name, event.payload); // string[] — current account address(es)
});
walletEvents.on("chainChanged", (wallet, event) => {
console.log(wallet, event.payload); // hex chainId, e.g. "0x38"
});
walletEvents.on("networkSwitched", (wallet, event) => {
console.log(wallet, event.payload); // { chainId, previousChainId, switched }
});
walletEvents.on("walletDisconnected", (wallet, event) => {
console.log(wallet, event.payload); // { source: "app" | "provider" }
});Event summary
| Event | When it fires |
| -------------------- | ------------------------------------------------------------------------------ |
| accountsChanged | Active account updated (switch account, reconnect after TronLink revoke, etc.) |
| chainChanged | Wallet network changed |
| networkSwitched | SDK invoked switchToConfiguredNetwork() |
| walletDisconnected | Wallet or DApp disconnected |
walletDisconnected
| Source | Trigger |
| -------------------- | ---------------------------------- |
| source: "app" | DApp called disconnectWallet() |
| source: "provider" | Wallet revoked the site connection |
MetaMask
- Site revoked in the extension → empty
accountsChanged→walletDisconnected
TronLink / TokenPocket / Coinbase
On disconnect-like events (empty accountsChanged, disconnect, etc.), the SDK silently calls eth_accounts:
- Still has authorized addresses → sync active account →
accountsChanged(no disconnect) - No authorized addresses → clear connection state →
walletDisconnected
This supports:
- Single address connected, then revoked →
walletDisconnected - Multiple addresses, one revoked but others remain →
accountsChangedwith remaining address - After revoke, switch to another already-connected address →
accountsChanged
When TronLink, TokenPocket, or Coinbase disconnects via provider, the SDK keeps the provider bound so a later account switch can still emit accountsChanged. Calling disconnectWallet() from the DApp performs a full disconnect.
App-initiated disconnect
disconnectWallet() clears local state and, by default, calls wallet_revokePermissions so MetaMask / Coinbase remove the site from connected dApps. TronLink does not support DApp-side revoke; local state is cleared only.
const { revoked } = await disconnectWallet();
console.log(revoked ? "Wallet permission revoked" : "Local disconnect only");Pass { revokePermissions: false } to skip the wallet revoke request.
Switch network
import { switchToConfiguredNetwork } from "@earthworm/wallet-sdk";
await switchToConfiguredNetwork("0x38"); // BSC mainnet