Skip to content

feat: Basalt Wallet extension integration + perf optimizations#1

Open
0xZunia wants to merge 3 commits intomainfrom
feature/wallet-extension-integration
Open

feat: Basalt Wallet extension integration + perf optimizations#1
0xZunia wants to merge 3 commits intomainfrom
feature/wallet-extension-integration

Conversation

@0xZunia
Copy link
Copy Markdown
Contributor

@0xZunia 0xZunia commented Mar 15, 2026

Summary

  • Integrate Basalt Wallet browser extension via window.basalt provider
  • Auto-detect extension, one-click connect, transaction routing through extension approval flow
  • Performance optimizations for next.config, SWR hooks, chart rendering, and Zustand selectors

Changes

Wallet Integration (6 files):

  • BasaltProvider TypeScript declarations for window.basalt
  • Wallet store: extension detection, connect, event listeners, hydrate guard
  • WalletModal: "Extension" tab with connect button, source badge in connected view
  • WalletButton: green dot indicator for extension connection
  • useTransaction: routes through window.basalt.sendTransaction() when using extension
  • useWallet: compound selector with useShallow (10 subscriptions → 1)

Performance (3 files):

  • next.config: optimizePackageImports for @noble/*, immutable cache headers
  • useTokenBalances: fix tokens.sort() mutation in SWR cache key
  • PriceChart: hoist import('lightweight-charts') to module level

Test plan

  • Load wallet extension in Chrome, create wallet, get faucet tokens
  • Run npm run dev, open /swap, connect via Extension tab
  • Execute a swap — verify extension approval popup appears with simulation
  • Verify receipt polling completes with exponential backoff
  • Switch between local wallet and extension — verify both paths work

0xZunia added 3 commits March 15, 2026 23:58
- Add BasaltProvider TypeScript declarations (window.basalt)
- Detect extension on hydrate, auto-restore previous sessions
- Add "Extension" tab in WalletModal with one-click connect
- Show green dot badge on WalletButton when connected via extension
- Route transactions through window.basalt.sendTransaction() when
  using extension (DEX ops, contract calls, transfers)
- Listen for accountsChanged/disconnect events from extension
- Guard hydrate() against duplicate event listener registration
- Combine 10 Zustand selectors into single compound selector with
  useShallow in useWallet hook
- Add exponential backoff to receipt polling (2s→4s→8s cap)
- Add optimizePackageImports for @noble/* libraries in next.config
- Add immutable cache headers for static assets
- Fix tokens.sort() mutation in useTokenBalances cache key
- Hoist lightweight-charts dynamic import to module level to avoid
  re-importing on every chartData change
@0xZunia 0xZunia requested a review from Copilot March 19, 2026 08:31
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Integrates Basalt Wallet browser extension support across the wallet store/UI and routes transactions through the extension provider, alongside a set of targeted client/perf improvements for Next.js config, SWR key stability, and chart initialization.

Changes:

  • Add Basalt extension provider typings + wallet store support (detect/connect/events, source tracking).
  • Update wallet UI (modal/tab + button indicator) and transaction submission to use the extension flow.
  • Apply perf fixes: Next immutable caching + optimized imports, SWR key immutability, and hoisted chart module import.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/stores/wallet.ts Adds extension detection/connect, tracks wallet source, and wires extension event handling.
src/lib/types/basalt-provider.ts Introduces window.basalt provider type declarations.
src/hooks/useWallet.ts Reduces Zustand subscriptions via a compound selector with useShallow.
src/hooks/useTransaction.ts Adds extension-based submission path + receipt polling backoff.
src/hooks/useTokenBalances.ts Prevents SWR cache-key mutation by avoiding in-place sort().
src/components/wallet/WalletModal.tsx Adds an Extension tab and source badge; hides lock for extension wallets.
src/components/wallet/WalletButton.tsx Adds extension connection indicator dot.
src/components/pool-detail/PriceChart.tsx Hoists dynamic import to cache module load across renders.
next.config.ts Adds immutable caching headers and optimizePackageImports.
Comments suppressed due to low confidence (1)

src/hooks/useTransaction.ts:27

  • The submit(tx, privateKey) API now documents that privateKey is ignored for extension wallets, forcing callers to pass a dummy Uint8Array just to satisfy the signature. Consider changing the signature to make privateKey optional (or overload it) and only require it when source !== 'extension' to keep the hook’s API clear and harder to misuse.
interface UseTransactionReturn {
  /** Submit a transaction. If connected via extension, privateKey is ignored (pass any Uint8Array). */
  submit: (
    tx: UnsignedTransaction,
    privateKey: Uint8Array,
  ) => Promise<ReceiptResponse | null>;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +83 to 85
// Check for local keystore
if (hasKeystore()) {
set({ isLocked: true });
Comment on lines +88 to +104
// Listen for extension events
const provider = getProvider();
if (provider) {
provider.on('accountsChanged', (accounts) => {
const { source } = get();
if (source === 'extension') {
const accs = accounts as string[];
set({ address: accs[0] ?? null, isConnected: accs.length > 0 });
}
});
provider.on('disconnect', () => {
const { source } = get();
if (source === 'extension') {
set({ address: null, isConnected: false, source: null });
}
});
}
attempts++;
if (tryDetect() || attempts >= 10) {
clearInterval(poll);
window.removeEventListener('basalt#initialized', handler);
Comment on lines +79 to 83
const timer = setTimeout(resolve, delay);
controller.signal.addEventListener('abort', () => {
clearTimeout(timer);
resolve();
});
const [modalOpen, setModalOpen] = useState(false);
const [mounted, setMounted] = useState(false);
const { address, isConnected, isLocked, hydrate } = useWalletStore();
const { address, isConnected, isLocked, source, extensionDetected, hydrate } = useWalletStore();

return (
<Modal open={open} onOpenChange={onOpenChange} title="Wallet">
<Tabs.Root defaultValue={defaultTab} className="w-full">
output: 'standalone',
reactStrictMode: true,
experimental: {
optimizePackageImports: ['@noble/ed25519', '@noble/hashes', '@noble/curves'],
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.

2 participants