feat(wallet): add wallet address book#1990
feat(wallet): add wallet address book#19900xPepeSilvia wants to merge 2 commits intotari-project:developmentfrom
Conversation
Full-stack implementation of an address book feature:
- SQLite migration for address_book table with unique name constraint
- Diesel storage model + SDK model with reader/writer trait methods
- SDK API layer (AddressBookApi) for CRUD operations
- JSON-RPC handler with address validation (otl_loc_ prefix)
- Server route registration for address_book.{add,list,get,update,delete}
- Rust and JS client methods for all endpoints
- TypeScript bindings for request/response types
- Web UI management page with DataGrid, add/edit/delete dialogs
- Address book integration in token and NFT transfer forms via Autocomplete
- Sidebar navigation entry
Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive address book feature across the wallet daemon, SDK, and web UI. It includes backend handlers, database storage using SQLite, and a new frontend page for managing entries. Additionally, it integrates address book lookups into the NFT and token transfer workflows. A bug was identified in the web UI where the memo field of an address book entry cannot be cleared during an update because empty strings are treated as undefined.
| await updateMutation.mutateAsync({ | ||
| name: editingEntry.name, | ||
| new_name: form.name !== editingEntry.name ? form.name.trim() : undefined, | ||
| address: form.address !== editingEntry.address ? form.address.trim() : undefined, | ||
| memo: form.memo.trim() || undefined, | ||
| }); |
There was a problem hiding this comment.
There's a bug in the handleSave function when updating an address book entry. The memo field cannot be cleared. If a user deletes the text in the memo field, the change is not sent to the backend because form.memo.trim() || undefined results in undefined for an empty string. The memo field should only be sent if it has changed, similar to how new_name and address are handled.
const newMemo = form.memo.trim();
const oldMemo = editingEntry.memo ?? "";
await updateMutation.mutateAsync({
name: editingEntry.name,
new_name: form.name.trim() !== editingEntry.name ? form.name.trim() : undefined,
address: form.address.trim() !== editingEntry.address ? form.address.trim() : undefined,
memo: newMemo !== oldMemo ? newMemo : undefined,
});
Two fixes uncovered during self-audit of the address book PR: 1. crates/wallet/storage_sqlite/src/models/address_book_entry.rs used chrono::NaiveDateTime, which is not a dependency of the storage crate. Every other model uses time::PrimitiveDateTime. Switched to match, restoring compilation. 2. The JSON-RPC handler's validate_address only accepted addresses starting with "otl_loc_", which rejects addresses on every network except LocalNet (MainNet is "otl_", Esmeralda "otl_esm_", etc.). Replaced with OotleAddress::from_str, which parses Bech32 and accepts any recognised HRP. Added tari_ootle_address as a direct dependency of the walletd crate. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Summary
Implements a full-stack wallet address book feature (#1931) allowing users to save named contacts with their Ootle addresses.
Changes
address_bookSQLite table with Diesel migration, model, and reader/writer trait implementationsAddressBookApiwith add/get/list/update/delete operations and dedicated error typeaddress_booknamespace, all gated behindJrpcPermission::Admin, withotl_loc_prefix validation on add/updateWalletDaemonClientfor all 5 operations/address-bookroute with MUI DataGrid, add/edit/delete dialogs, duplicate-name detectionCloses #1931
Test plan
otl_loc_address returns an invalid params error🤖 Generated with Claude Code