Skip to content

feat(wallet+sdk): Nido passkey wallet support — wallets-kit v2 + smart-account activation#26

Merged
Dgetsylver merged 4 commits into
mainfrom
feat/nido-wallet
Jun 11, 2026
Merged

feat(wallet+sdk): Nido passkey wallet support — wallets-kit v2 + smart-account activation#26
Dgetsylver merged 4 commits into
mainfrom
feat/nido-wallet

Conversation

@Dgetsylver

Copy link
Copy Markdown
Contributor

Closes #22.

What this does

Nido (https://github.com/theahaco/nido) users can now connect their passkey smart wallet on Authline and activate assets. Nido accounts are Soroban C-addresses — they cannot hold classic trustlines or source transactions — so this PR is two things: the wallet connector, and first-class smart-account support through the whole stack.

Wallet plumbing

  • stellar-wallets-kit 1.9.5 → 2.3.0 (required by Nido's module; supersedes dependabot Bump @creit.tech/stellar-wallets-kit from 1.9.5 to 2.0.1 #5): static-singleton API, explicit module list, subpath module imports.
  • Nido module via pinned-SHA sync — npm can't install monorepo subpaths as git deps, so scripts/sync-nido-module.sh fetches packages/stellar-wallets-kit-module from theahaco/nido at an enforced pinned commit at build time (source stays out of this repo; Apache-2.0 NOTICE committed). Its only @g2c/passkey-sdk import is satisfied by a committed 5-line StrKey shim, avoiding the upstream SDK's stellar-sdk@15 tree.
  • Registered (and shown in the modal) on testnet only — Nido's hosted wallet is testnet-only today. PUBLIC_NIDO_BASE overrides the default nido.fyi.
  • Connect hardening: disconnect-before-setWallet (clears Nido's cached account → account switching works) and full pairing rollback on a failed connect (no wrong-module signing; "Try again" re-opens the picker).

Smart-account (C-address) support

  • SDK 0.5.0getActivationStatus is holder-kind-aware: holderKind: "account" | "contract"; contract holders skip the trustline read entirely and the SAC authorized() view is authoritative (defaults verified on-chain: open → authorized, AUTH_REQUIRED → not). The documented non-throwing contract now actually holds (a C-address used to throw out of the SDK and crash connect). buildOnboardTx gained feeSource — required for contract holders.
  • dApp flow — the activation is pre-built in the background when a smart account lands on "ready" (session friendbot fee payer + prepared tx), so clicking Activate opens the Nido sign popup within the browser's transient-user-activation window (built after the click, the popup gets blocked — caught in review). The wallet passkey-signs the smart account's auth entry; the fee payer signs the envelope; the dApp submits. TrustlineOnly for a contract holder reports as the failure it is (nothing changed on-chain).
  • UI renders the truthful smart-account state everywhere (status rows, ?address= preview incl. C-addresses, success/already copy, contract explorer links).

On-chain verification (testnet, before building)

  • SAC authorized(C): AUTH_REQUIRED → false, open → true
  • authorizer-stub authorize_trustline(C) works for contract holders with no balance entry
  • router onboard(sac, C)Authorized with exactly one auth entry — the one the Nido popup signs

Test plan

  • 47 unit tests (holder-kind status matrix, no-throw guarantees, feeSource validation)
  • 9 real-chain testnet e2e — incl. the new smart-account suite: SAC-view status for both asset classes, contract-source refusal, and the fee-payer-sourced onboard tx carrying exactly the smart account's address-credential auth entry
  • 14 Playwright tests — incl. smart-account ?address= previews against the real chain (regulated → "not authorized", open → "all set") and the Nido row in the wallet modal
  • typecheck · eslint · prettier · build — green
  • Adversarial multi-agent review (23 agents): 17 confirmed findings fixed, incl. the critical popup-activation-window issue

Limits / notes

  • The full passkey popup ceremony is exercised manually (it needs the hosted Nido wallet + a real WebAuthn credential); everything around it is tested. Covered upstream in nido's own e2e.
  • CI now fetches the module source from codeload.github.com at build time (public repo, pinned SHA).
  • Nido popup allows 300s but the onboard envelope expires after 180s — a very slow ceremony surfaces as a clean retryable error.

🤖 Generated with Claude Code

…nt (C-address) activation

Closes #22.

Wallet plumbing:
- @creit.tech/stellar-wallets-kit 1.9.5 -> 2.3.0 (static-singleton API,
  explicit module list, module classes from subpath exports).
- Nido (passkey smart wallet) module synced verbatim from theahaco/nido at a
  pinned, ENFORCED commit by scripts/sync-nido-module.sh (npm cannot install
  monorepo subpaths as git deps; the script is the dependency, src/dist stay
  out of this repo). Its sole @g2c/passkey-sdk import is satisfied by a
  committed five-line StrKey shim. Apache-2.0 NOTICE committed. Registered
  only on testnet (Nido is testnet-only today); "Nido" row in the modal.
- connect(): disconnect-before-setWallet (clears Nido's cached account, so
  reconnect can switch accounts) and full pairing rollback on a failed
  connect — "Try again" with no address re-opens the picker instead of
  signing via the wrong module.

Smart-account (C-address) support:
- @theaha/authline 0.5.0: getActivationStatus is holder-kind-aware —
  contract holders have no trustline; the SAC authorized() view (simulated
  with the asset issuer as dummy source, Address-encoded for G and C) is
  authoritative. The documented non-throwing contract now actually holds
  (key construction moved inside the try). buildOnboardTx gained feeSource
  (required for contract holders — a contract cannot source a transaction).
- dApp: smart-account flow end to end — status/phases/StatusRows/preview/
  copy handle contract holders truthfully; activation pre-builds in the
  background (session friendbot fee payer + prepared onboard tx) so the
  Nido sign popup opens within the click's transient-user-activation
  window; the wallet passkey-signs the smart account's auth entry, the fee
  payer signs the envelope, the dApp submits. TrustlineOnly for a contract
  holder is reported as the failure it is (nothing changed on-chain).

Verified on-chain (testnet): SAC authorized(C) defaults false/true for
AUTH_REQUIRED/open assets; the authorizer-stub authorizes contract holders;
router onboard(sac, C) returns Authorized with exactly one auth entry —
the entry the Nido popup signs.

Tests: 47 unit (holder-kind status matrix, non-throwing guarantees), 9
real-chain e2e (new smart-account suite: SAC-view status both asset
classes, feeSource refusal, fee-payer-sourced tx carrying the smart
account's address-credential auth entry), 14 Playwright (smart-account
?address= previews against the real chain, Nido in the modal).
@socket-security

socket-security Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​creit.tech/​stellar-wallets-kit@​1.9.5 ⏵ 2.3.084 +310098 -193100

View full report

@socket-security

socket-security Bot commented Jun 11, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm @solana-program/system is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/@creit.tech/stellar-wallets-kit@2.3.0npm/@solana-program/system@0.10.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@solana-program/system@0.10.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm @walletconnect/sign-client is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/@creit.tech/stellar-wallets-kit@2.3.0npm/@walletconnect/sign-client@2.23.7

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@walletconnect/sign-client@2.23.7. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Deprecated by its maintainer: npm @safe-global/safe-gateway-typescript-sdk

Reason: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

From: package-lock.jsonnpm/@creit.tech/stellar-wallets-kit@2.3.0npm/@safe-global/safe-gateway-typescript-sdk@3.23.1

ℹ Read more on: This package | This alert | What is a deprecated package?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Research the state of the package and determine if there are non-deprecated versions that can be used, or if it should be replaced with a new, supported solution.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@safe-global/safe-gateway-typescript-sdk@3.23.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

…hipped nested typescript

The published @creit.tech/stellar-wallets-kit tarball ships its own
node_modules (incl. typescript@4.9.5). npm 11 omits shipped nested
packages from the lock; CI's npm 10 requires the entry and failed
npm ci with 'Missing: typescript@4.9.5'. Regenerated with npm@10;
verified npm ci --dry-run clean under both npm 10 and 11.
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://theahaco.github.io/stellar-assets/pr-preview/pr-26/

Built to branch gh-pages at 2026-06-11 22:13 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

…xt) into an actionable hint

An OZ smart account whose policy-less default rule lists N passkeys is
N-of-N — a single-passkey wallet ceremony can never authorize it, and the
user only saw a raw 'HostError: Error(Auth, InvalidAction)'. Diagnosed on
a real account (rule 0 with two External passkey signers, no policy): the
error screen now explains the cause and the fix (remove the extra passkey
or add a 1-of-N threshold policy in the Nido wallet).

Refs #22.
@Dgetsylver

Copy link
Copy Markdown
Contributor Author

Field-testing note: a real-device run surfaced Error(Contract, #3002) UnvalidatedContext — diagnosed as an account-side condition, not an integration bug: the tester's smart account had two passkeys on its policy-less default rule, which OZ treats as N-of-N (all must sign), so any single-passkey ceremony fails. Upstream issue with full evidence + suggested fixes: nidohq/nido#87. This PR now decodes that error into an actionable hint on the error screen (03b45e9); accounts with a single passkey on the default rule (the factory default) are unaffected.

Wallets that cache the account selection (Nido picks at CONNECT time; the
sign popup is bound to it — nidohq/nido#89) gave users no way to switch
accounts without a page reload. The connected address pill is now a
button: disconnect (clears the module's cached account), reset the
per-connection state, and reopen the wallet picker. Disabled mid-
transaction. e2e: seam-connect, pill click reopens the picker.

Refs #22, nidohq/nido#89.
@Dgetsylver Dgetsylver merged commit c14b32f into main Jun 11, 2026
5 checks passed
@Dgetsylver Dgetsylver deleted the feat/nido-wallet branch June 11, 2026 23:13
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.

Nido (passkey smart wallet) support: kit v2 migration, connector, and smart-account (C-address) activation

1 participant