Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
IT Security NachrichtenIT Security News Hourly Summary 2026-09-22 08h : 8 posts(22.09.2026 um 08:00 Uhr)
IT Security NachrichtenDeutsche Telekom startet internationale Reise-eSIM T-Travel(22.09.2026 um 07:41 Uhr)
IT Security NachrichtenDrei ergänzende Microsoft-365-Apps werden im Dezember eingestellt(22.09.2026 um 07:42 Uhr)
IT Security NachrichtenRechnungshof: EU nicht genug gegen Cyberangriffe gewappnet(22.09.2026 um 07:42 Uhr)
IT NachrichtenThis UCD expert is building advanced quantum sensing tech(22.09.2026 um 08:00 Uhr)
IT NachrichtenHow to watch BJK Cup Finals 2026: Free Streams & Schedule(22.09.2026 um 08:00 Uhr)
IT Security NachrichtenIT Security News Hourly Summary 2026-09-22 08h : 8 posts(22.09.2026 um 08:00 Uhr)
IT Security NachrichtenDeutsche Telekom startet internationale Reise-eSIM T-Travel(22.09.2026 um 07:41 Uhr)
IT Security NachrichtenDrei ergänzende Microsoft-365-Apps werden im Dezember eingestellt(22.09.2026 um 07:42 Uhr)
IT Security NachrichtenRechnungshof: EU nicht genug gegen Cyberangriffe gewappnet(22.09.2026 um 07:42 Uhr)
IT NachrichtenThis UCD expert is building advanced quantum sensing tech(22.09.2026 um 08:00 Uhr)
IT NachrichtenHow to watch BJK Cup Finals 2026: Free Streams & Schedule(22.09.2026 um 08:00 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

I Spent Hours in the DOM So You Don't Have To

Full source: github.com/tusharpamnani/midnight-wallet-kit When I started building frontends on Midnight, I hit a wall that nobody warned me about. The contracts were working. The proof server was running. The TypeScript SDK was…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Full source: github.com/tusharpamnani/midnight-wallet-kit



When I started building frontends on Midnight, I hit a wall that nobody warned me about.



The contracts were working. The proof server was running. The TypeScript SDK was integrated. And then I needed to connect a wallet.



There was no proper documentation for Lace's Midnight provider. No fixed window.ethereum-style standard to follow. Just two browser extensions injecting objects into the DOM under different keys, with different method signatures, inconsistent behavior, and no specification to read.



I spent hours inspecting window objects, console-logging provider payloads, and reverse-engineering what each wallet actually exposed before I could make a single connection work reliably. Every Midnight frontend developer hits this exact wall. Nobody should have to climb it twice.



That's why I built midnight-wallet-kit.






What the Problem Actually Looks Like



If you've built on Ethereum, you know window.ethereum. It's a standard. You call eth_requestAccounts, you get addresses, you sign. Every wallet implements the same interface.



Midnight doesn't have this yet. Lace injects under window.lace. 1AM injects under window.midnight. The methods exist but aren't documented. The payload shapes vary. And because Midnight uses ZK proofs and shielded transactions, the signing flow is more complex than EVM; you're not just signing a hash, you're signing an intent that the proof server will process.



Without a proper abstraction layer, every developer ends up writing the same fragile, bespoke integration code:




// What you end up writing without a kit
const provider = (window as any).lace?.midnight;
if (!provider) throw new Error("Lace not found?");
const accounts = await provider.enable?.();
// hope this works, documentation doesn't exist






Then you do the same thing for 1AM. Then you handle the case where neither is installed. Then you handle session persistence across page refreshes. Then you write tests that require a real browser extension to be installed. By the time you're done, you've written a wallet library, except it only works for your specific app and breaks when the extension updates.






What Midnight Wallet Kit Gives You



midnight-wallet-kit is a production-grade abstraction layer for Lace and 1AM on Midnight. Install it, register your adapters, wrap your app in a provider, and you're done.




npm install midnight-wallet-kit









Setup






import { WalletManager, InjectedWalletAdapter } from 'midnight-wallet-kit';

const manager = new WalletManager();

manager
.register(new InjectedWalletAdapter({ name: 'Lace', providerKey: 'lace' }))
.register(new InjectedWalletAdapter({ name: '1AM', providerKey: 'midnight' }));









import { WalletProvider } from 'midnight-wallet-kit/react';

function App({ children }) {
return (
<WalletProvider
manager={manager}
autoConnect={['1AM', 'Lace']} // priority fallback order
autoRestore={true} // reconnect last-used wallet on refresh
>
{children}
</WalletProvider>
);
}






That's the entire integration. Everything below this point is application code.






The Four Hooks






useWallet(): connection state






const { address, isConnected, connectionState, error } = useWallet();






connectionState gives you the full lifecycle: idle → connecting → connected, with restoring, error, disconnecting, and disconnected as intermediate states. No more boolean isConnected that doesn't tell you why a connection failed.



address returns the user's Midnight unshielded address — the same mn_addr_... format used throughout the contract layer. coinPublicKey and encryptionPublicKey are also available if your dApp needs them.






useConnect(): connection management






const { connect, disconnect, isLoading, adapters } = useConnect();

// Connect to a specific wallet
await connect('1AM');

// Or let the kit try in priority order
// (handled automatically via WalletProvider autoConnect)






adapters gives you the list of all registered adapter names; useful for rendering a wallet selection UI without hardcoding names.






useIntent(): signing






const { buildAndSign, signMessage } = useIntent();

// Sign a contract intent
const result = await buildAndSign({
contractAddress: '...',
circuitId: 'buy',
args: [n, maxCost]
});

// Sign an arbitrary message (login flows, proofs of ownership)
const signed = await signMessage("Login to My DApp");
// Timestamping and normalization handled automatically






buildAndSign validates intent parameters with Zod before sending anything to the wallet; you get a typed InvalidIntentError before the extension even opens, not a cryptic failure deep in the proof pipeline.



signMessage handles the multi-step probing for data-signing support across different wallet versions, adds proper prefixes, and generates unique timestamps automatically.






useBalance(): balance polling






const { balance, isLoading, error, refetch } = useBalance();
// balance: { tDUST: bigint; shielded: bigint } | null






Automatically polls every 15 seconds when connected. refetch() is available for manual triggers after a transaction. Uses the Midnight indexer under the hood; if the indexer query fails, you get a typed BalanceFetchError, not a silent null.






The Architecture: Why It's Built This Way






Adapters normalize the provider chaos



Every wallet integration lives in an adapter that implements MidnightWallet. The InjectedWalletAdapter handles the DOM-level provider probing, the part I spent hours figuring out manually. It exhaustively searches for working RPC methods across different provider standards and payload formats, so if Lace updates their injection key or 1AM changes their method signature, you update one adapter, not every component in your app.



Wallet modes are explicitly typed:





  • intent-signing: supports the full signIntent() flow, standard for DApps


  • tx-only: direct transaction balancing and submission only


  • unknown: handled defensively as a fallback






WalletManager handles the lifecycle



The WalletManager is the orchestrator. It manages adapter registration, connection state transitions, fallback chains, middleware, and session persistence.



Fallback chains are the feature I wish I'd had from day one:




await manager.connectWithFallback(['1AM', 'Lace']);






Try 1AM first. If it's not installed or the user rejects, try Lace. If both fail, throw FallbackExhaustedError. One line. No manual try-catch chains.



Session persistence via autoRestore stores the last-connected wallet name in localStorage and attempts to reconnect on page load. Users stay connected across refreshes without re-approving the extension every time.






Middleware for observability






manager.use(async (ctx, next) => {
console.log(`Starting ${ctx.operation} on ${ctx.adapterName}`);
await next();
if (ctx.error) {
analytics.track('wallet_error', {
operation: ctx.operation,
error: ctx.error.message
});
}
});






Every wallet operation; connect, disconnect, signIntent, signMessage - passes through the middleware chain. The context object gives you the operation type, adapter name, intent payload, result, and any error. Useful for logging, analytics, and debugging production issues without adding instrumentation to every component.






Typed Errors: No More catch (e: any)



Every error from the kit is a typed class inheriting from MidnightWalletError. You can branch on error type rather than parsing message strings:




import { 
ProviderNotFoundError,
ConnectionRejectedError,
FallbackExhaustedError,
NetworkMismatchError
} from 'midnight-wallet-kit';

try {
await connect('Lace');
} catch (e) {
if (e instanceof ProviderNotFoundError) {
showInstallPrompt('lace');
} else if (e instanceof ConnectionRejectedError) {
showRejectedMessage();
} else if (e instanceof NetworkMismatchError) {
showNetworkSwitchPrompt();
}
}






NetworkMismatchError in particular is one you'll hit in the wild, if a user switches their wallet to mainnet while your dApp is pointed at preprod, the session breaks silently without this check. The kit detects and surfaces it explicitly.






Testing Without a Browser Extension



This is the part that usually breaks dApp test suites. Testing wallet integration normally requires a real browser extension to be installed and configured, which makes CI impossible.




import { MockWalletAdapter } from 'midnight-wallet-kit/testing';

const adapter = new MockWalletAdapter({
name: 'TestWallet',
address: 'mn_addr1_test...',
coinPublicKey: 'test_cpk',
signatureOverride: '0xmocksignature',
signDelay: 100, // simulate realistic latency
shouldRejectSign: false
});

manager.register(adapter);






You can simulate connection failures, signing rejections, latency, and specific return values. No browser, no extension, no environment setup; just a mock that implements the same MidnightWallet interface as the real adapters.




// Test the rejection flow
const failAdapter = new MockWalletAdapter({
name: 'RejectingWallet',
shouldRejectConnect: true
});

await expect(manager.connect('RejectingWallet'))
.rejects.toThrow(ConnectionRejectedError);









SSR and Next.js



While building Midnight Club in Next.js, window.lace and window.midnight were being accessed during server-side rendering, causing window is not defined crashes that were silent in development but broke production builds.



The React hooks are SSR-safe. Provider detection (window.lace, window.midnight) only runs on the client; no window is not defined errors during Next.js server-side rendering. WalletProvider guards all DOM access behind a mounted check, so your app hydrates cleanly without injecting wallet state during SSR.






What's Next



The kit currently supports Lace and 1AM via InjectedWalletAdapter. Hardware wallet support is the natural next step as the Midnight ecosystem matures and physical signing devices become available.



If you're building on Midnight and hit something the kit doesn't handle, an edge case in the provider, a new wallet, a signing flow that doesn't fit the current API - issues and PRs are open at github.com/tusharpamnani/midnight-wallet-kit

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten I Spent Hours in the DOM So You Don't Have To

Thematisch verwandte Begriffe: Spent, Hours, Dont, Have · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-61647 | NotebookLM MCP is an MCP server and HTTP service for interacting with Go…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick