Events¶
The wallet emits events for every state change the node pushes through. Register Python callbacks on the wallet; its event multiplexer forwards relevant events to them, and you react — update a UI, trigger the next send, log a maturity, handle a reorg.
For the "what happened in this account?" view that reads stored transaction records, see Transaction History.
Callbacks must be synchronous
The dispatcher invokes callbacks via callback(*args, event, **kwargs) —
a direct synchronous call. If you pass an async def function, it
returns a coroutine that is never awaited: the body silently does
not run. Use a regular def and offload async work with
asyncio.create_task(...) from inside the callback.
Listener API¶
The wallet exposes add_event_listener and remove_event_listener:
def add_event_listener(event, callback, *args, **kwargs) -> None
def remove_event_listener(event, callback=None) -> None
event— aWalletEventType, its kebab-case string name ("balance","sync-state"), or"all"/WalletEventType.Allfor every event.callback— invoked ascallback(*args, event, **kwargs). Must be synchronous (see warning above).args/kwargs— forwarded verbatim to every invocation. Handy for routing context (account id, channel) without closures.remove_event_listener(event)with no callback clears every listener for that event. With"all"and no callback, clears every listener globally.
A minimal subscriber¶
from kaspa import Resolver, Wallet, WalletEventType
def on_event(event):
print(event["type"], event.get("data"))
wallet = Wallet(network_id="testnet-10", resolver=Resolver())
wallet.add_event_listener(WalletEventType.All, on_event)
await wallet.start()
await wallet.connect()
Each event is a dict with at least a type key (the kebab-case kind
name, e.g. "balance", "sync-state", "fee-rate") and an optional
data payload specific to that event.
Event taxonomy¶
| Group | Events |
|---|---|
| Connection | Connect, Disconnect, ServerStatus, UtxoIndexNotEnabled |
| Wallet file | WalletList, WalletStart, WalletHint, WalletOpen, WalletCreate, WalletReload, WalletClose, WalletError |
| Key & account state | PrvKeyDataCreate, AccountCreate, AccountActivation, AccountDeactivation, AccountSelection, AccountUpdate |
| Sync & runtime | SyncState, UtxoProcStart, UtxoProcStop, UtxoProcError, DaaScoreChange, Metrics, FeeRate |
| UTXO movement | Pending, Maturity, Reorg, Stasis, Discovery, Balance |
| Catch-all | All, Error |
Event payloads¶
Every event is {"type": <kebab-case>, "data": <dict>}. The data
shapes below come from kaspa-wallet-core::events. Field names that
appear in camelCase are camel-cased on the wire; snake_case fields
are passed through as-is.
UTXO movement¶
| Event | data fields |
|---|---|
Balance |
balance: {mature, pending, outgoing, mature_utxo_count, pending_utxo_count, stasis_utxo_count} \| None, id: <utxo_context_id> (see Balance) |
Pending |
record: TransactionRecord — UTXO seen, not yet mature. |
Maturity |
record: TransactionRecord — UTXO crossed the maturity threshold; spendable. |
Reorg |
record: TransactionRecord — pending UTXO unwound by a reorg. |
Stasis |
record: TransactionRecord — coinbase output unwound during stasis. Safe to ignore. |
Discovery |
record: TransactionRecord — UTXO discovered during the initial scan of an account. When using the runtime Wallet, you can usually rely on the transaction history instead. |
A TransactionRecord carries id, unixtimeMsec, value,
binding, blockDaaScore, network, data (the per-kind
transaction body), and optional note / metadata strings.
Sync & runtime¶
| Event | data fields |
|---|---|
SyncState |
syncState: {type, data} — see Sync State → payloads. |
UtxoProcStart |
(no data) |
UtxoProcStop |
(no data) |
UtxoProcError |
message: str |
DaaScoreChange |
currentDaaScore: int |
Metrics |
networkId: str, metrics: MetricsUpdate |
FeeRate |
priority: {feerate, seconds}, normal: {...}, low: {...} |
Key & account state¶
| Event | data fields |
|---|---|
PrvKeyDataCreate |
prvKeyDataInfo:PrvKeyDataInfo |
AccountCreate |
accountDescriptor:AccountDescriptor |
AccountActivation |
ids: list[AccountId] |
AccountDeactivation |
ids: list[AccountId] |
AccountSelection |
id:AccountId\| None |
AccountUpdate |
accountDescriptor:AccountDescriptor — fires when a new address is generated, etc. |
Wallet file¶
| Event | data fields |
|---|---|
WalletList |
walletDescriptors: list[WalletDescriptor] |
WalletStart |
(no data) — fires once after start(). |
WalletHint |
hint: str \| None — anti-phishing hint stored on the wallet file. |
WalletOpen |
walletDescriptor:WalletDescriptor\| None, accountDescriptors: list[AccountDescriptor] \| None |
WalletCreate |
walletDescriptor:WalletDescriptor, storageDescriptor: StorageDescriptor |
WalletReload |
walletDescriptor:WalletDescriptor\| None, accountDescriptors: list[AccountDescriptor] \| None |
WalletClose |
(no data) |
WalletError |
message: str |
Connection¶
| Event | data fields |
|---|---|
Connect |
networkId: str, url: str \| None |
Disconnect |
networkId: str, url: str \| None |
ServerStatus |
networkId: str, serverVersion: str, isSynced: bool, url: str \| None |
UtxoIndexNotEnabled |
url: str \| None |
When each event fires¶
Common subscriptions:
SyncState— progress while theUtxoProcessorcatches up. Pair withwallet.is_synced— see Sync State.Balance— fires when aUtxoContextbalance changes. The right signal for live UI updates.Pending— a new UTXO landed for a tracked address but isn't yet spendable.Maturity— a previously-pending UTXO crossed the maturity depth and is now spendable. The strongest gate for "send-then-wait" flows — don't trigger the nextaccounts_sendonPendingalone.Reorg/Stasis— a UTXO was unwound or coinbase-locked. Defensive code for high-value flows.AccountActivation/AccountDeactivation— react toaccounts_activate/wallet_close.
Targeted subscriptions¶
wallet.add_event_listener("balance", on_balance)
wallet.add_event_listener("maturity", on_maturity)
wallet.add_event_listener(WalletEventType.SyncState, on_sync)
To pass context to a generic callback:
wallet.add_event_listener("balance", on_change, account.account_id, label="primary")
# callback receives: on_change(account.account_id, event, label="primary")
Cleanup¶
Listeners outlive the wallet's open file but not its runtime. Pair a
permanent registration with an explicit removal on shutdown, or use
"all" to clear in one call via remove_event_listener:
Where to next¶
- Transaction History — stored records, notes, and metadata.
- Send Transaction —
Maturityas the right wait condition. - Architecture — what's actually generating these events.
- Lifecycle — when each event group fires.
- Wallet SDK → UTXO Processor — the lower-level event surface beneath the managed wallet.