@tuwaio/orbit-core
v0.6.0
Published
L1 core of Orbit Utils (TUWA): zero-dependency, framework-agnostic multi-chain types, CAIP-2, CAIP-10 and CAIP-19 helpers, connector and address helpers, error normalization and SSR-safe connection persistence.
Maintainers
Readme
@tuwaio/orbit-core
@tuwaio/orbit-core is the Layer 1 (L1) package of Orbit Utils, the Stage 1 primitives layer of the TUWA ecosystem. It defines the chain-agnostic types that the Orbit chain packages and the higher TUWA layers (Satellite Connect, Pulsar) share, and ships small helpers for connector naming, address validation, error normalization and SSR-safe connection persistence.
The package has zero runtime dependencies and imports no Web3 SDK, so it runs in any framework, in the browser and on the server.
🏛️ Core Capabilities
- Multi-chain primitives: the
OrbitAdapterenum (evm,solana,starknet), theBaseAdaptercontract,ConnectorTypeidentifiers such as"evm:metamask"or"solana:phantom", andselectAdapterByKeyto pick the adapter of the active chain. - Connector helpers:
getConnectorTypeFromName,getAdapterFromConnectorType,formatConnectorName,formatConnectorChainId,isSolanaChain,setChainIdandgetNetworkData. - Solana chain IDs:
SOLANA_CHAIN_IDSholds the CAIP-2 chain IDs of mainnet, devnet and testnet, made of the genesis hash as CAIP-30 requires.getSolanaChainIdandgetSolanaClusterconvert between these IDs and cluster monikers and read every form in use (devnet,solana:devnet,solana:mainnet-beta, the testnet ID from before the testnet genesis reset).setChainIdandformatConnectorChainIdreturn these IDs for Solana. - CAIP identifiers:
toCaip2ChainIdturns EVM chain numbers intoeip155:<number>and every Solana form into its genesis-hash ID, andtoEvmChainIdreads the number back;formatCaip10AccountIdandformatCaip19AssetIdbuild account and asset IDs (eip155:8453/erc20:0x…,solana:…/token:…,…/slip44:501), and theparse…functions read and validate them. - Validation and errors:
isAddressvalidates EVM (hex) and Solana (Base58) addresses.normalizeErrorturns any wallet, viem or RPC error into a JSON-serializableTuwaErrorStatethat is safe to persist. - Connection persistence:
lastConnectedConnectorHelpersandrecentlyConnectedConnectorsListHelperskeep connection history inlocalStorage, or insessionStorageuntil the tab closes for a wallet the user did not ask to remember ({ remember: false }), and do nothing during SSR. - Runtime utilities:
detectSafeApp(Safe{Wallet} iframe detection),waitFor,delay,filterUniqueByKey, andimpersonatedHelpersfor development and testing.
💾 Installation
pnpm add @tuwaio/orbit-core🚀 Usage
Resolving the active adapter
BaseAdapter describes what an adapter can do; add a key to register it for a chain family:
import { type BaseAdapter, OrbitAdapter, selectAdapterByKey } from '@tuwaio/orbit-core';
type ExplorerAdapter = BaseAdapter & { key: OrbitAdapter };
const adapters: ExplorerAdapter[] = [
{ key: OrbitAdapter.EVM, getExplorerUrl: (path) => `https://etherscan.io/${path ?? ''}` },
{ key: OrbitAdapter.SOLANA, getExplorerUrl: (path) => `https://explorer.solana.com/${path ?? ''}` },
];
const solanaAdapter = selectAdapterByKey({ adapterKey: OrbitAdapter.SOLANA, adapter: adapters });
solanaAdapter?.getExplorerUrl('tx/<signature>'); // "https://explorer.solana.com/tx/<signature>"If no adapter matches the key, selectAdapterByKey falls back to the first adapter in the array and logs a warning.
Persisting the last connection
import { lastConnectedConnectorHelpers } from '@tuwaio/orbit-core';
lastConnectedConnectorHelpers.setLastConnectedConnector({
connectorType: 'evm:metamask',
chainId: 1,
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
});
// Returns undefined on the server and when nothing is stored.
const lastConnected = lastConnectedConnectorHelpers.getLastConnectedConnector();Identifying Solana clusters
import { getSolanaChainId, getSolanaCluster } from '@tuwaio/orbit-core';
getSolanaChainId('devnet'); // "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
getSolanaChainId('solana:mainnet-beta'); // "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
getSolanaCluster('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1'); // "devnet"Use the CAIP-2 ID wherever a chain is identified: SIWX messages, transaction records, APIs. Use the cluster moniker for RPC URLs and for Wallet Standard calls, which name the cluster solana:devnet.
Normalizing errors
import { normalizeError } from '@tuwaio/orbit-core';
declare function sendTransaction(): Promise<void>;
try {
await sendTransaction();
} catch (error) {
// `message` prefers viem's `shortMessage`; `raw` is a JSON-safe copy of the error details.
const { message, raw } = normalizeError(error);
}Validating addresses
import { isAddress } from '@tuwaio/orbit-core';
isAddress('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'); // true (auto-detected as EVM)
isAddress('So11111111111111111111111111111111111111112', 'solana'); // trueisAddress checks the address format only (hex length or Base58 alphabet); it does not verify EVM checksums.
🗄️ Browser Storage
The storage helpers write the following keys. Clear them to reset the connection state of a user:
| Key | Written by | Where |
| --------------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| orbit-core:lastConnectedConnector | lastConnectedConnectorHelpers | localStorage for a remembered wallet (the default); sessionStorage until the tab closes with { remember: false } |
| orbit-core:recentlyConnectedConnectorsListHelpers | recentlyConnectedConnectorsListHelpers | localStorage for remembered wallets; sessionStorage for the others; reading merges both |
| satellite-connect:impersonatedAddress | impersonatedHelpers | localStorage |
📚 API Reference
Every export, with signatures and types generated from the source, is documented at orbit.docs.tuwa.io/packages/orbit-core.
📄 License
Licensed under the Apache-2.0 License. See the LICENSE file for details.
