From f2b107fc5f0f8a9fa2c250174147cc5e44eab920 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 1 Mar 2026 13:56:35 -0500 Subject: [PATCH] fix stale smirk and amount bug --- docs/INTEGRATION.md | 27 +++++++++++++++++++++++++-- html/js/network/socketHandlers.js | 20 ++++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index f65ccf8..3bde935 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -11,8 +11,9 @@ Smirk injects a `window.smirk` API (similar to MetaMask's `window.ethereum`) tha 1. Request wallet connection (get public keys) 2. Request message signatures (for authentication) 3. Get wallet addresses (for payouts) +4. Request payments (send WOW directly from extension) -Wownerogue uses the WOW (Wownero) key for authentication via a challenge-response signature flow. +Wownerogue uses the WOW (Wownero) key for authentication via a challenge-response signature flow, and `requestPayment()` for in-extension payment prompts. --- @@ -174,6 +175,27 @@ const addrs = await window.smirk.getAddresses(); // addrs.grin - "grin1..." (bech32 slatepack address) ``` +### `smirk.requestPayment(options)` -> `Promise` + +Prompts the user to send a payment from their Smirk wallet. Opens an approval popup showing the recipient address, amount, and description. Resolves when the user confirms and the TX is broadcast; rejects if the user denies or the extension context is invalid. + +```javascript +const result = await window.smirk.requestPayment({ + address: 'Wo3MWeLE...', // Recipient address + amount: '1', // Human-readable amount (NOT atomic units) + asset: 'wow', // Asset ticker (lowercase) + description: 'Single game entry' // Shown in approval popup +}); +// result.txid - Transaction hash (hex) +// result.amount - Amount sent (string) +``` + +**Important:** The `amount` field must be the human-readable value (e.g. `"1"` for 1 WOW), not atomic units. The extension handles conversion internally. + +**Error cases:** +- User clicks "Deny" → rejects with user cancellation error +- Extension context invalidated (browser reloaded extension) → rejects with `"Extension context invalidated"`. The page must be refreshed to re-establish the connection. + ### `smirk.isConnected()` -> `Promise` Check if the current origin is connected (approved). @@ -190,12 +212,13 @@ Get public keys without prompting (only works if already connected). Returns `nu ## Client-Side Implementation -See `html/js/network/smirkAuth.js` for the full implementation. Key points: +See `html/js/network/smirkAuth.js` for auth and `html/js/network/socketHandlers.js` (`_trySmirkPayment`) for payments. Key points: - The `SmirkAuth` module is initialized after DOM ready and socket connection - It checks `SocketHandlers._smirkEnabled` (set by server's `game_mode_info` event) to gate the feature - On successful auth, it calls `smirk.getAddresses()` to auto-set the payout address via `socket.emit('address:update')` - The button shows install link if extension is not detected, connect button if it is +- When a Smirk-connected user triggers a payment, `_trySmirkPayment()` calls `smirk.requestPayment()` with the human-readable amount. If the user confirms, the TX is broadcast and the server's existing mempool monitoring detects it. If the user denies or the extension context is stale, it falls back to the normal address/QR payment modal. --- diff --git a/html/js/network/socketHandlers.js b/html/js/network/socketHandlers.js index 339c1b5..8ff34ee 100644 --- a/html/js/network/socketHandlers.js +++ b/html/js/network/socketHandlers.js @@ -691,9 +691,11 @@ const SocketHandlers = { UI.scrollChat(); try { + // Use human-readable amount (e.g. "1"), NOT atomic units (e.g. 100000000000) + var payAmount = data.humanAmount || data.amountFormatted || String(data.amount); await window.smirk.requestPayment({ address: data.address, - amount: String(data.amount), + amount: payAmount, asset: (SocketHandlers._cryptoType || 'WOW').toLowerCase(), description: data.paymentType === 'credits_package' ? 'Buy ' + (data.package ? data.package.credits : '') + ' credits' @@ -717,9 +719,19 @@ const SocketHandlers = { } catch (err) { console.log('Smirk payment declined/failed, falling back to manual:', err); - $('#messages').append($('
  • ').text( - 'Smirk payment cancelled. Use the address below.' - )); + var errMsg = String(err.message || err || ''); + + if (errMsg.indexOf('context invalidated') !== -1) { + // Extension was reloaded/updated — stale context + $('#messages').append($('
  • ').text( + 'Smirk extension was reloaded. Please refresh the page to re-enable Smirk payments. Using manual payment for now.' + )); + SmirkAuth._isLinked = false; + } else { + $('#messages').append($('
  • ').text( + 'Smirk payment cancelled. Use the address below.' + )); + } UI.scrollChat(); // Fall back to normal address/QR flow