Discord-first client and abstraction layer for Somnia blockchain development.
somnia-client makes it significantly easier for Discord developers to build Somnia-powered backend applications, bots, automations, wallet trackers, and reactive notification systems.
This is NOT:
- A replacement for Somnia's official SDKs
- A Discord bot framework
- A new blockchain framework
This IS:
- A Discord-first abstraction layer built on top of Somnia's official protocol interfaces
- Chain Management Type-safe network registry for Somnia Mainnet & Shannon Testnet
- Wallet Operations Native token & ERC-20 balance queries, transfers
- Transaction Lifecycle Send, wait, receipt, status normalization
- Contract Interaction Read, write, simulate with any ABI
- Token Helpers ERC-20 metadata, transfer, approve
- Reactivity WebSocket-based event subscriptions (Somnia off-chain reactivity)
- Discord Adapter Ready-to-use embeds and formatters for Discord bots
- Retry System Bounded exponential backoff with retryable classification
- Error System Typed error hierarchy with structured context
- Zero Config Works out of the box with sensible defaults
npm install somnia-clientFor Discord features:
npm install somnia-client discord.jsimport { SomniaClient } from "somnia-client";
// Create a client (defaults to Shannon testnet)
const client = new SomniaClient({
network: "testnet",
// privateKey: "0x..." // for write operations
});
// Connect to the network
client.connect();
// Check a wallet balance
const balance = await client.wallet.getBalance("0x...");
console.log(balance); // bigint in wei
// Get explorer URL
const url = client.explorer.tx("0x...");
console.log(url); // https://shannon-explorer.somnia.network/tx/0x...
// Clean up
await client.close();For Discord bot tokens, custom RPC endpoints, or optional signing keys, refer to the provided .env.example template:
cp .env.example .envSecurity Note: Never commit real private keys, API keys, or bot tokens to version control. Keep
.envstrictly in your local development environment.
import { SomniaClient } from "somnia-client";
import {
createWalletEmbed,
createTransactionEmbed,
formatAddressTruncated,
formatTimestamp,
} from "somnia-client/discord";
// In a slash command handler:
const client = new SomniaClient({ network: "mainnet" }).connect();
const balance = await client.wallet.getBalance(userAddress);
const embed = createWalletEmbed({
address: userAddress,
nativeBalance: balance,
explorerUrl: client.explorer.address(userAddress),
networkName: client.chain.name,
});
await interaction.reply({ embeds: [embed] });const subscription = client.reactivity.subscribe(
{
address: "0x...", // contract address
abi: myContractAbi,
eventName: "Transfer", // specific event
},
(event) => {
console.log("Transfer detected!", event.log);
// Send Discord notification, update database, etc.
},
(error) => {
console.error("Subscription error:", error);
},
);
// Later: clean up
await subscription.unsubscribe();| Network | Chain ID | Token | RPC |
|---|---|---|---|
| Mainnet | 5031 | SOMI | https://api.infra.mainnet.somnia.network/ |
| Shannon Testnet | 50312 | STT | https://api.infra.testnet.somnia.network/ |
| Namespace | Method | Description |
|---|---|---|
wallet |
getBalance(address) |
Get native token balance |
wallet |
getTokenBalance({token, owner}) |
Get ERC-20 balance |
wallet |
transfer({to, amount}) |
Send native tokens |
tx |
get(hash) |
Get transaction by hash |
tx |
receipt(hash) |
Get normalized receipt |
tx |
wait(hash, confirmations?) |
Wait for confirmation |
contract |
read(params) |
Call view/pure function |
contract |
write(params) |
Send state-changing tx |
contract |
simulate(params) |
Dry-run a write |
token |
info(address) |
Get name, symbol, decimals |
token |
transfer({token, to, amount}) |
ERC-20 transfer |
token |
approve({token, spender, amount}) |
ERC-20 approve |
reactivity |
subscribe(options, handler, errorHandler?) |
Subscribe to events |
explorer |
tx(hash) / address(addr) / block(num) / token(addr) |
Explorer URLs |
Formatters: formatAddressCode, formatAddressTruncated, formatAddressLink, formatAmountBold, formatAmountFixed, formatTokenAmountDisplay, formatTimestamp, formatDate, formatNow
Embeds: createSomniaEmbed, createSuccessEmbed, createErrorEmbed, createInfoEmbed, createWarningEmbed, createTransactionEmbed, createTransferEmbed, createWalletEmbed
All errors extend SomniaError with structured context:
try {
await client.wallet.getBalance("invalid");
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.code); // "VALIDATION_ERROR"
console.log(error.operation); // "validateAddress"
console.log(error.retryable); // false
}
}Comprehensive guides and technical documentation are available in the docs/ directory:
- Getting Started Guide — Installation and quickstart examples
- Architecture & Design — Module hierarchy and patterns
- Client Configuration — RPC options, private keys, and logging
- Network Registry — Somnia Mainnet and Testnet endpoints
- Security Best Practices — Key security, permissions, rate limits
- Limitations & Boundaries — Supported vs deferred features
- Compatibility Matrix — Engine and framework support
- Feature Support Matrix — Status and testing provenance
npm install # Install dependencies
npm run typecheck # Type checking
npm run test # Run tests
npm run build # Build for production
npm run lint # Lint with Biome- Node.js >= 22
- TypeScript >= 5.6