Skip to content

feat(wallet): native Phantom Solana integration#155

Merged
kostovster merged 4 commits into
mainfrom
feat/phantom-native-solana
May 8, 2026
Merged

feat(wallet): native Phantom Solana integration#155
kostovster merged 4 commits into
mainfrom
feat/phantom-native-solana

Conversation

@kostovster
Copy link
Copy Markdown
Member

Summary

  • Replaces the Phantom EVM-compat path with native Solana provider integration via window.phantom.solana, mirroring the existing Solflare wiring.
  • Removes WalletConnectMechanism.EVM_PHANTOM, the MetaMaskWallet class, and the entire src/networks/evm/ directory — neither path was exposed to users, so no deprecation window is needed.
  • Hardens both Solflare and the new Phantom path with strict isSolflare === true / isPhantom === true provider-identity guards.

Closes #154.

Changes

  • Native Phantom: connectPhantom.ts rewritten to mirror connectSolflare.ts; constructs SolanaWallet("phantom"), persists SOL_PHANTOM, calls IntercomService.load(addr, "phantom"). New authenticatePhantom factory in WalletFactory.ts paralleling authenticateSolFlare.
  • SolanaWallet parameterized: constructor takes a required provider: "solflare" | "phantom" argument. getProvider() reads window.solflare or window.phantom?.solana and validates the identity flag — defends against wallet-aggregator placeholder injection.
  • Enum rename (atomic): WalletConnectMechanism.EVM_PHANTOMSOL_PHANTOM = "sol_phantom". WalletActions.CONNECT_EVM_PHANTOMCONNECT_SOL_PHANTOM = "CONNECT_SOL_PHANTOM" (member name AND string value).
  • EVM stack removed: src/networks/evm/{wallet,wallet.test,sign,sign.test,index}.ts deleted along with the corresponding per-file coverage thresholds in vitest.config.ts.
  • Routing wired: walletProtocolFilter.ts, WalletConnect.ts, WalletInfo.vue, webmcp/tools.ts updated. walletActionMap now exported for the new end-to-end wiring test.
  • Defensive comment on NolusWalletOverride.getGasInfo documenting that the pubkey: Pubkey parameter is load-bearing for the Solana Ed25519 path.

Test coverage added

  • signDirect throws (pinned).
  • Bytes passed to provider.signMessage are byte-equal to SignDoc.encode(signDoc).finish() — locks the wire format.
  • Signed AuthInfo.signerInfos[0].publicKey.typeUrl === "/cosmos.crypto.ed25519.PubKey" — locks Ed25519 over secp256k1.
  • isPhantom/isSolflare strict-equality guards (placeholder providers throw).
  • End-to-end mechanism→action wiring: every WalletConnectMechanism value has a registered, callable Pinia action.
  • WebMCP MECHANISM_BY_LABEL / ACTION_BY_MECHANISM map consistency, plus a source-grep that locks the absence of EVM_PHANTOM / CONNECT_EVM_PHANTOM / MetaMaskWallet.

Verification

  • npx tsc --noEmit clean.
  • npm run lint clean.
  • npm run format:check clean.
  • npx vitest run — 760/760 passing (down from 782 because 22 EVM-only tests were deleted with the directory).
  • npm run build clean.
  • grep -rn "EVM_PHANTOM\|evm_phantom\|CONNECT_EVM_PHANTOM\|MetaMaskWallet\|@/networks/evm" src/ vitest.config.ts — only allowed hits are anti-drift assertions inside webmcp/tools.test.ts that verify the strings do NOT appear in tools.ts.

Notes

  • localStorage.wallet_connect_mechanism value transitions from "evm_phantom" to "sol_phantom". WalletManager.getWalletConnectMechanism already self-heals unknown values via its Object.values(WalletConnectMechanism).includes(...) validator — testers carrying "evm_phantom" get cleared and reconnect once. Per Migrate Phantom from EVM compat to native Solana provider #154 scope, no migration shim is added.
  • ethers ^6.16.0 is now an orphan dependency in package.json (the only consumer was MetaMaskWallet). Tracked as a follow-up; the issue scope excluded package.json cleanup.
  • A symmetric isKeplr === true guard for WalletUtils.getKeplrExtension would be a sensible follow-up — same defense the Solana path now has.

Follow-ups (out of scope)

  • Drop orphan ethers from package.json.
  • Add isKeplr === true guard on the Keplr injection path.
  • Devnet broadcast smoke for Phantom and Solflare (deferred to Solana go-live).

kostovster added 4 commits May 8, 2026 11:59
Move Phantom from the EVM-bridge code path to the native Solana provider:
both Phantom and Solflare now go through SolanaWallet, which signs Cosmos
SignDocs with Ed25519 via window.phantom.solana / window.solflare.

Atomic rename — every consumer of the old surface flips in this commit:
- WalletConnectMechanism.EVM_PHANTOM -> SOL_PHANTOM (string value sol_phantom)
- WalletActions.CONNECT_EVM_PHANTOM  -> CONNECT_SOL_PHANTOM
- connectPhantom rewritten on top of SolanaWallet("phantom")
- WalletFactory: drop authenticateEvmPhantom, add authenticatePhantom
- walletProtocolFilter, WalletConnect, WalletInfo.vue, webmcp/tools.ts
  updated to the new mechanism + action names
- WalletConnect.walletActionMap exported for the end-to-end wiring guard
- EVM stack (src/networks/evm/) and its vitest coverage thresholds removed
- NolusWalletOverride.getGasInfo gains a defensive comment that the pubkey
  parameter is load-bearing for the Solana Ed25519 path

No localStorage migration shim — hard rename. Sessions persisted under
evm_phantom must reconnect.
The webmcp scope-guard regex banned imports from `@/networks/{cosm,evm,sol}/*Wallet`.
With `src/networks/evm/` removed in the prior commit, the `evm` arm matches nothing.
Removing it keeps the guard reflecting reality; if EVM is ever reintroduced, this
guard and the docs reference it should update together.
Mirrors the isPhantom/isSolflare strict-equality guards added to
SolanaWallet.getProvider() — defends against wallet-aggregator extensions that
inject a window.keplr shim without identifying as Keplr. An object at
window.keplr that does not satisfy isKeplr === true now resolves to undefined,
which the existing connect path surfaces as "Keplr is not installed".
ethers ^6.16.0 was a dependency of the EIP-191 signing path in
src/networks/evm/, which was removed in the prior commit. No remaining source
file imports ethers — verified by grep across src/. Removing it shrinks the
client bundle and stops Dependabot alerts on a library with no production
callers. Lockfile shrinks by ~100 lines (transitive deps gone).
@kostovster kostovster merged commit f1725fd into main May 8, 2026
2 checks passed
@kostovster kostovster deleted the feat/phantom-native-solana branch May 8, 2026 09:45
kostovster added a commit that referenced this pull request May 8, 2026
The isKeplr === true strict-equality guard added in #155 rejected real Keplr
as "not installed" on app-dev. Root cause: isKeplr is declared on Keplr's
EthereumProvider interface (the EVM bridge), NOT on the main Cosmos Keplr
interface that window.keplr resolves to. Pattern-matching from the
isPhantom/isSolflare guards on Solana wallets does not generalise — Keplr's
Cosmos provider exposes no equivalent identity flag.

Restores the original window.keplr-existence check. Adds a comment block
explaining the asymmetry so a future contributor does not re-add a marker
check without a verified Cosmos-side signal.
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.

Migrate Phantom from EVM compat to native Solana provider

1 participant