feat(wallet): native Phantom Solana integration#155
Merged
Conversation
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
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
window.phantom.solana, mirroring the existing Solflare wiring.WalletConnectMechanism.EVM_PHANTOM, theMetaMaskWalletclass, and the entiresrc/networks/evm/directory — neither path was exposed to users, so no deprecation window is needed.isSolflare === true/isPhantom === trueprovider-identity guards.Closes #154.
Changes
connectPhantom.tsrewritten to mirrorconnectSolflare.ts; constructsSolanaWallet("phantom"), persistsSOL_PHANTOM, callsIntercomService.load(addr, "phantom"). NewauthenticatePhantomfactory inWalletFactory.tsparallelingauthenticateSolFlare.SolanaWalletparameterized: constructor takes a requiredprovider: "solflare" | "phantom"argument.getProvider()readswindow.solflareorwindow.phantom?.solanaand validates the identity flag — defends against wallet-aggregator placeholder injection.WalletConnectMechanism.EVM_PHANTOM→SOL_PHANTOM = "sol_phantom".WalletActions.CONNECT_EVM_PHANTOM→CONNECT_SOL_PHANTOM = "CONNECT_SOL_PHANTOM"(member name AND string value).src/networks/evm/{wallet,wallet.test,sign,sign.test,index}.tsdeleted along with the corresponding per-file coverage thresholds invitest.config.ts.walletProtocolFilter.ts,WalletConnect.ts,WalletInfo.vue,webmcp/tools.tsupdated.walletActionMapnow exported for the new end-to-end wiring test.NolusWalletOverride.getGasInfodocumenting that thepubkey: Pubkeyparameter is load-bearing for the Solana Ed25519 path.Test coverage added
signDirectthrows (pinned).provider.signMessageare byte-equal toSignDoc.encode(signDoc).finish()— locks the wire format.AuthInfo.signerInfos[0].publicKey.typeUrl === "/cosmos.crypto.ed25519.PubKey"— locks Ed25519 over secp256k1.isPhantom/isSolflarestrict-equality guards (placeholder providers throw).WalletConnectMechanismvalue has a registered, callable Pinia action.MECHANISM_BY_LABEL/ACTION_BY_MECHANISMmap consistency, plus a source-grep that locks the absence ofEVM_PHANTOM/CONNECT_EVM_PHANTOM/MetaMaskWallet.Verification
npx tsc --noEmitclean.npm run lintclean.npm run format:checkclean.npx vitest run— 760/760 passing (down from 782 because 22 EVM-only tests were deleted with the directory).npm run buildclean.grep -rn "EVM_PHANTOM\|evm_phantom\|CONNECT_EVM_PHANTOM\|MetaMaskWallet\|@/networks/evm" src/ vitest.config.ts— only allowed hits are anti-drift assertions insidewebmcp/tools.test.tsthat verify the strings do NOT appear intools.ts.Notes
localStorage.wallet_connect_mechanismvalue transitions from"evm_phantom"to"sol_phantom".WalletManager.getWalletConnectMechanismalready self-heals unknown values via itsObject.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.0is now an orphan dependency inpackage.json(the only consumer wasMetaMaskWallet). Tracked as a follow-up; the issue scope excludedpackage.jsoncleanup.isKeplr === trueguard forWalletUtils.getKeplrExtensionwould be a sensible follow-up — same defense the Solana path now has.Follow-ups (out of scope)
ethersfrompackage.json.isKeplr === trueguard on the Keplr injection path.