Build once across Ethereum, Solana, and every chain that comes next.
OmniKit is no longer just a wallet toolkit. It is a chain-abstracted development framework for JavaScript and TypeScript applications. Developers write against one predictable SDK while adapters translate Ethereum gas, Solana compute, wallet standards, contract ABIs, program IDLs, confirmations, balances, and future chain models behind the scenes.
One API
Wallets, balances, transactions, contracts, events, React hooks, and server utilities now share the same chain-agnostic vocabulary.
Adapter-first
Core contains orchestration only. Every chain plugs in through a strict ChainAdapter contract, so new networks do not require SDK rewrites.
Less Web3 glue
Teams stop maintaining separate Ethereum, Solana, and future-chain integration paths for the same product workflow.
No core changes
Sui, Aptos, Starknet, Cosmos, Bitcoin L2s, and other systems can be added by registering adapters and capabilities.
Quick Start
Install the core package, the adapters you need, and the React or server package for your runtime. The public API stays stable as you add chains.
npm install @watchupltd/omnikit @watchupltd/omnikit-types
npm install @watchupltd/omnikit-ethereum @watchupltd/omnikit-solana
npm install @watchupltd/omnikit-react @watchupltd/omnikit-serverimport { createOmniKit } from '@watchupltd/omnikit';
const omnikit = createOmniKit({
chains: ['ethereum', 'solana'],
storage: { type: 'localStorage', prefix: 'myapp' },
autoConnect: true
});
const wallet = await omnikit.wallet.connect();
const [account] = wallet.accounts;
const balance = await omnikit.wallet.balance({
chain: account.chain,
account: account.address
});
const tx = await omnikit.transaction.create({
chain: account.chain,
to: 'recipient-address',
value: '0.01'
});
const receipt = await tx.send();
await tx.wait();The Universal API
Application code should not ask whether it is dealing with an EVM transaction, a Solana transaction, or a future Move-based transaction. It should describe intent. OmniKit maps that intent to the active chain.
| Workflow | Before OmniKit | With OmniKit |
|---|---|---|
| Wallets | MetaMask, Phantom, WalletConnect, injected providers, mobile wallet branches | omnikit.wallet.connect() |
| Balances | ethers providers, Solana connections, token account parsing | omnikit.wallet.balance({ chain, account, token }) |
| Transactions | Gas, nonces, blockhashes, fee payers, compute units, serialization | omnikit.transaction.create(...).send().wait() |
| Contracts | ethers.Contract vs Anchor Program vs future contract clients | omnikit.contract(...).read() / write() |
| Server jobs | Different indexers, RPC pools, relayers, and watchers per chain | createOmniServer().watchTransfers(...) |
const wallet = await omnikit.wallet.connect();
const accounts = await omnikit.wallet.accounts();
const signature = await omnikit.wallet.signMessage({ message: 'Sign in' });
const balance = await omnikit.wallet.balance({ account: accounts[0].address });Architecture
OmniKit is split into a functional core and chain adapters. The core package owns state, routing, transaction handles, contract clients, and registry behavior. Chain packages own the details that should never leak into app code.
@watchupltd/omnikit-types
Defines ChainAdapter, UniversalTransactionRequest, TransactionReceipt, ContractDescriptor, BalanceResult, and shared primitives.
@watchupltd/omnikit
Provides OmniClient, OmniKit, ChainAdapterRegistry, transaction handles, and wallet-adapter bridging.
@watchupltd/omnikit-ethereum
Translates EIP-1193 wallets, EVM transactions, ABI reads and writes, gas, and confirmations.
@watchupltd/omnikit-solana
Translates Phantom/Solflare, Solana transactions, program instructions, blockhashes, compute fees, and SPL balances.
@watchupltd/omnikit-react
Exposes unified hooks. No public Ethereum-only or Solana-only hooks are required for product code.
@watchupltd/omnikit-server
Adds RPC pooling, relaying, caching, transfer watching, and indexing utilities for backend workflows.
React Integration
The React package now mirrors the universal runtime. Components ask for wallet state, balances, transactions, and contracts without branching on Ethereum or Solana.
import { OmniKitProvider, useWallet, useTransaction, useContract } from '@watchupltd/omnikit-react';
import { createOmniKit } from '@watchupltd/omnikit';
const omnikit = createOmniKit({ chains: ['ethereum', 'solana'] });
export function Providers({ children }) {
return <OmniKitProvider config={omnikit}>{children}</OmniKitProvider>;
}
function CheckoutButton() {
const { connectWallet, address, chain, isConnected } = useWallet();
const tx = useTransaction();
async function pay() {
if (!isConnected) await connectWallet();
await tx.send({ chain, to: 'merchant-address', value: '0.01' });
}
return <button onClick={pay}>{address ? 'Pay now' : 'Connect'}</button>;
}Server SDK
The new server package gives backend services the same abstraction layer: RPC pools, rate limiting, transaction relaying, event subscriptions, caching, and indexing workflows.
import { createOmniServer } from '@watchupltd/omnikit-server';
import { ethereumAdapter, solanaAdapter } from './adapters';
const server = createOmniServer({
adapters: [ethereumAdapter, solanaAdapter],
rpc: {
ethereum: ['https://eth.llamarpc.com'],
solana: ['https://api.mainnet-beta.solana.com']
},
rateLimit: { maxConcurrent: 16 },
cacheTtlMs: 15000
});
await server.watchTransfers({
chain: 'ethereum',
address: treasuryAddress,
onTransfer: async (event) => saveTransfer(event)
});
await server.relay({ chain: 'solana', to, value: '1' });Adding Future Chains
A new blockchain integration should require a new adapter, not a new application architecture. Implement the ChainAdapter contract, declare capabilities, and register it with OmniKit.
import type { ChainAdapter } from '@watchupltd/omnikit-types';
export const suiAdapter: ChainAdapter = {
id: 'sui-wallet',
metadata: {
id: 'sui',
namespace: 'move',
name: 'Sui',
nativeCurrency: { name: 'Sui', symbol: 'SUI', decimals: 9 }
},
capabilities: {
wallets: true, transactions: true, messages: true, contracts: true,
events: true, tokens: true, nfts: true, networkSwitching: true,
localAccounts: false
},
async connectWallet() { /* native wallet -> UniversalWalletConnection */ },
async getBalance() { /* native balance -> BalanceResult */ },
async createTransaction(request) { /* universal request -> native tx */ },
async sendTransaction(transaction) { /* native hash -> TransactionReceipt */ },
async waitForTransaction(hash) { /* native finality -> TransactionReceipt */ },
async readContract(request) { /* ABI, IDL, or Move call -> value */ },
async writeContract(request) { /* native write -> TransactionReceipt */ }
};Type System
The most important type in the new architecture is ChainAdapter. It is the boundary between chain-specific code and the universal developer experience.
interface ChainAdapter {
readonly id: AdapterId;
readonly metadata: ChainMetadata;
readonly capabilities: ChainCapabilities;
connectWallet(request?: WalletConnectionRequest): Promise<UniversalWalletConnection>;
disconnectWallet(): Promise<void>;
getAccounts(): Promise<readonly UniversalAccount[]>;
signMessage(request: SignMessageRequest): Promise<SignatureResult>;
getBalance(request?: BalanceRequest): Promise<BalanceResult>;
createTransaction(request: UniversalTransactionRequest): Promise<PreparedTransaction>;
sendTransaction(tx: UniversalTransactionRequest | PreparedTransaction | SignedTransaction): Promise<TransactionReceipt>;
waitForTransaction(hash: string, options?: TransactionWaitOptions): Promise<TransactionReceipt>;
readContract?<TResult = unknown>(request: ContractReadRequest): Promise<TResult>;
writeContract?(request: ContractWriteRequest): Promise<TransactionReceipt>;
}Migration Notes
Existing wallet-adapter APIs still work, but new application code should move to the universal API. This lets teams keep shipping while they migrate product surfaces one workflow at a time.
| Legacy | Preferred | Reason |
|---|---|---|
omnikit.connect('ethereum') | omnikit.wallet.connect({ chain: 'ethereum' }) | Returns normalized wallet connection data. |
omnikit.getBalance() | omnikit.wallet.balance({ chain, account }) | Works for native and token balances across chains. |
omnikit.sendTransaction(rawTx) | omnikit.transaction.create(request).send() | Normalizes preparation, sending, waiting, fees, and receipt shape. |
ethers.Contract / Anchor Program | omnikit.contract(descriptor) | Keeps ABI, IDL, and future contract systems behind adapters. |