State Stores
Zustand stores in @chainportal/sdk -- transaction history and multi-chain wallet state, with selector hooks.
State Stores
The SDK ships two Zustand stores. Import them from the
stores sub-path (or the package root):
Writing your own derived selector? Under zustand v5's strict useSyncExternalStore, a
selector that returns a new reference every call (e.g. state.transactions.filter(...))
makes React re-render on every commit and throws "Maximum update depth exceeded" (React
#185). Wrap derived selectors in useShallow so an unchanged result keeps a stable reference:
The built-in selector hooks below already do this for you.
Transaction store
useTransactionStore persists transaction history to IndexedDB (key
chainportal-transactions), capped at the 1000 most recent entries. State is shared across tabs
on the same origin.
State
| Field | Type | Description |
|---|---|---|
transactions | Transaction[] | All recorded transactions, newest first |
isLoading | boolean | Loading flag for async hydration |
error | Error | null | Last error, if any |
The Transaction shape
| Field | Type | Description |
|---|---|---|
id | string | Generated unique id |
hash | string | On-chain transaction hash |
type | TransactionType | token_create | nft_create | nft_collection_create | nft_mint | token_transfer | nft_transfer | token_burn | nft_burn |
chainType | ChainType | evm | solana | cosmos | aptos | sui | near |
chainId | number | string | Chain ID |
chainName | string | Display name of the chain |
name | string | Asset name |
symbol? | string | Asset symbol |
contractAddress? | string | Deployed contract address |
creatorAddress | string | Address that created the transaction |
timestamp | number | Creation time (ms epoch) |
status | TransactionStatus | pending | confirming | success | failed |
explorerUrl? | string | Block explorer URL |
metadata? | Record<string, unknown> | Arbitrary extra data |
Actions
Read these off the store hook (useTransactionStore((s) => s.addTransaction)):
| Action | Signature | Description |
|---|---|---|
addTransaction | (tx: Omit<Transaction,'id'|'timestamp'>) => string | Add a tx (returns the new id) |
updateTransaction | (id, updates: Partial<Transaction>) => void | Update by id |
updateTransactionByHash | (hash, updates) => void | Update by hash |
removeTransaction | (id) => void | Remove by id |
clearTransactions | () => void | Clear all history |
getTransactionById | (id) => Transaction | undefined | Lookup by id |
getTransactionByHash | (hash) => Transaction | undefined | Lookup by hash |
getTransactionsByCreator | (address) => Transaction[] | Filter by creator |
getFilteredTransactions | (filter: TransactionFilter) => Transaction[] | Filter by type/chain/status/creator |
getPendingTransactions | () => Transaction[] | Pending + confirming |
setLoading / setError | (value) => void | Set loading / error flags |
Derived selector hooks
These return stable references (useShallow-wrapped) and are safe to use directly:
| Hook | Returns |
|---|---|
useTransactions() | All transactions |
usePendingTransactions() | Transactions that are pending or confirming |
useTransactionsByType(type) | Transactions of a given TransactionType |
useTransactionsByChain(chainId) | Transactions on a given chain |
useRecentTransactions(limit = 10) | The most recent limit transactions |
Multi-chain store
useMultiChainStore tracks the active ecosystem, the active chain per ecosystem, and per-ecosystem
wallet connections. It persists activeEcosystem + activeChainIds to localStorage
(chainportal-multichain-storage) and uses skipHydration (hydrate on the client to avoid SSR
mismatch).
State
| Field | Type | Description |
|---|---|---|
activeEcosystem | ChainEcosystem | Currently active ecosystem |
activeChainIds | Record<ChainEcosystem, number | string | null> | Active chain per ecosystem |
connections | Record<ChainEcosystem, WalletConnection | null> | Connection per ecosystem |
isWalletModalOpen | boolean | Wallet connect modal open state |
isChainSelectorOpen | boolean | Chain selector dropdown open state |
Actions
| Action | Signature |
|---|---|
setActiveEcosystem | (ecosystem) => void |
setActiveChain | (ecosystem, chainId) => void |
setConnection | (ecosystem, connection | null) => void |
disconnect / disconnectAll | (ecosystem) => void / () => void |
getActiveConnection | () => WalletConnection | null |
getActiveChainId | () => number | string | null |
setWalletModalOpen / setChainSelectorOpen | (open: boolean) => void |
Selector hooks
| Hook | Returns |
|---|---|
useActiveEcosystem() | The active ChainEcosystem |
useActiveChainId() | The active chain ID for the active ecosystem |
useActiveConnection() | The active WalletConnection, or null |
useEVMConnection() | The EVM WalletConnection, or null |
useSolanaConnection() | The Solana WalletConnection, or null |
See also
- Types Reference —
WalletConnection,TransactionResult, and more - Hooks — higher-level hooks that write to these stores