Skip to content

feat(zns): Zcash Name System integration - #132

Draft
craftsoldier wants to merge 14 commits into
chainapsis:mainfrom
zcashme:feat/zcashnames
Draft

feat(zns): Zcash Name System integration#132
craftsoldier wants to merge 14 commits into
chainapsis:mainfrom
zcashme:feat/zcashnames

Conversation

@craftsoldier

@craftsoldier craftsoldier commented May 21, 2026

Copy link
Copy Markdown

Hey Thunini! Here's what we built 👋

What's included

  • Forward lookup in the send screen - type alice.zcash, get a Zcash Unified Address
  • Reverse lookup in the activity detail screen - sent transactions show the recipient's ZNS name above their address
  • ZNS identity easter egg - rename your account to your ZNS name, your profile picture background turns gold

What we changed

  • send_screen.dart - ZNS resolution wired into the address field, _ZnsStatus enum, debounce, staleness guard, tappable resolved name label
  • send_review_screen.dart, send_status_screen.dart - resolvedName threaded through SendReviewArgs via recipientLabel
  • activity_transaction_status_screen.dart - reverse lookup on sent transactions, name shown above address in "To" block
  • zns_provider.dart - ZnsResolver with resolveName, reverseResolve, isOwnedByAccount, session-scoped _nameCache
  • rust/src/wallet/keys.rs - is_address_from_account, O(1) Orchard FVK ownership check
  • rust/src/api/wallet.rs - FRB wrapper exposing it to Dart
  • accounts_screen.dart, settings_screen.dart - _checkZnsEasterEgg fires after successful rename
  • profile_pictures.dart, app_profile_picture.dart - zns- prefix support, gold background Color(0xFFFFB800)

What we did not change

  • AccountNameModal - untouched, no new parameters
  • Received transactions - sender is private in shielded Zcash, nothing to look up
  • Send flow - proposal, fee estimation, and broadcast unchanged

How we did this

Forward lookup triggers on a conjunction: Rust validateAddress rejects the input AND the input matches a ZNS protocol identifier (.zcash, .zec). Rust fires first as the authoritative local validator - ZNS only activates on explicit rejection. Full input is lowercased before the check so Alice.ZCASH and alice.zcash are equivalent. The existing _addressSeq staleness guard covers ZNS too.

Reverse lookup uses ZnsResolver.reverseResolve - calls resolveAddress on the SDK, takes the earliest-registered name, appends .zcash. Session-scoped _nameCache on the provider means repeated lookups for the same address are instant. containsKey rather than null check since null is a valid cached value (address has no registration).

Ownership check - is_address_from_account in Rust extracts the diversifier d from the UA's Orchard receiver and verifies [ivk] × d == pk_d against the account's Orchard FVK. O(1), no iteration over diversifier space, works for any diversified address.

Easter egg - zns- prefixed profilePictureId stored in secure storage. AppProfilePicture renders gold background when prefix is present, strips it before asset lookup so the avatar is unchanged.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9cf92ee49f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread macos/Runner.xcodeproj/project.pbxproj Outdated
"$(inherited)",
"@executable_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.julian.vizor;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Revert production bundle identifier override

This commit hard-codes PRODUCT_BUNDLE_IDENTIFIER = com.julian.vizor, which overrides the shared AppInfo.xcconfig identifier (com.keplr.vizor) for Runner build configurations. Shipping macOS builds with a different bundle ID changes app identity (updates, existing installs, keychain/entitlement continuity) and can break upgrade paths for current users.

Useful? React with 👍 / 👎.

await ref.read(accountProvider.notifier).renameAccount(uuid, name);
if (!mounted) return;
_closeModal();
unawaited(_checkZnsEasterEgg(uuid, name));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Catch errors from fire-and-forget ZNS ownership check

This unawaited call starts _checkZnsEasterEgg, but that function performs async network/FFI work without internal error handling; if ZNS lookup or ownership verification throws (e.g., connectivity issues or decode failures), the exception is unhandled and bubbles to the global async error handler during account rename. Please wrap the checker body in try/catch (or otherwise handle the returned Future) so rename does not emit uncaught errors.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b498e3449

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

Future<void> _checkZnsEasterEgg(String uuid, String name) async {
final owned = await ref.read(znsResolverProvider).isOwnedByAccount(name, uuid);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize account names before ZNS ownership checks

This rename flow passes the raw UI name directly into isOwnedByAccount, but account names are free-form while ZNS resolution elsewhere in this commit is normalized first (lowercased and .zcash/.zec stripped). As a result, a user who renames to a natural label like Alice.zcash can fail the ownership check even when they own that name, so the gold-profile easter egg does not activate (the same raw-name call is also present in settings_screen.dart).

Useful? React with 👍 / 👎.

@craftsoldier
craftsoldier marked this pull request as draft June 13, 2026 20:40
@craftsoldier

Copy link
Copy Markdown
Author

Marking this as a draft for now.

Before we move forward, we need to make sure this PR properly covers address book support and related account/contact management concerns. Converting to draft so the remaining work can be completed and reviewed without blocking the queue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant