diff --git a/server.js b/server.js index 52dc320..28c80a2 100644 --- a/server.js +++ b/server.js @@ -653,6 +653,21 @@ async function walkUpActivatedSponsor(tok) { } return { id: 0, name: null, skipped, reason: 'none' }; } +// The feed line for a walk-up: who had not switched on payouts, whose referral (and purchase, when the +// activation and the buy share a tx) routed past them, and who it belongs to now. +async function postWalkUp(buyerId, oldRef, toId, pur) { + const sc = siteConfig(); if (!sc.telegramBotToken || (!sc.telegramChatId && !sc.telegramEchoChatId)) return; + const lostAcct = await refAccount(oldRef); if (!lostAcct) return; + const lostName = lostAcct.username ? '@' + lostAcct.username : lostAcct.email.replace(/@.*/, '') + '@'; + const nm = await accounts.namesForMembers([buyerId, toId]).catch(() => ({})); + const who = id => '#' + id + (nm[id] ? ' @' + nm[id] : ''); + const site = 'https://instantadpay.com/my'; + const what = pur ? who(buyerId) + "'s $" + Math.round(pur.priceCents / 100) + ' purchase routed past them' : who(buyerId) + ' switched on payouts and their position routed past them'; + const missed = '\u{1F62C} Missed sale: ' + lostName + ' had not switched on payouts, so ' + what + '. That member, and every payout from them, now belongs to ' + who(toId) + '.' + + '\nTwo minutes on the Wallet tab prevents this: ' + site.replace(/^https:\/\//, '') + ''; + if (sc.telegramChatId && String(sc.telegramEvents || 'payouts') !== 'none') await telegramSend(sc.telegramChatId, missed, sc.telegramTopicId).catch(() => {}); + if (sc.telegramEchoChatId && String(sc.telegramEchoEvents || 'payouts') !== 'none') await telegramSend(sc.telegramEchoChatId, '\u{1F7E0} InstantAdPay \u00b7 ' + missed, sc.telegramEchoTopicId).catch(() => {}); +} // The referral follows the money (Marty, 2026-09-16): when a position is created on-chain under a // different sponsor than the account's stored referrer (walk-up past an unactivated sponsor, or the // catch-position fallback), move the account to the sponsor that actually got paid, #1 included. @@ -668,7 +683,10 @@ async function sponsorSyncOnEvent(ev) { const ref = spAcct && spAcct.code ? spAcct.code : String(onchain); const old = acct.sponsorRef || ''; await accounts.setSponsorRef(acct.email, ref); - movedByTx.set(ev.tx, { buyerId: Number(ev.id) || 0, toId: onchain, oldRef: old, at: Date.now() }); // read by telegramOnEvent on the Purchase in the same tx + movedByTx.set(ev.tx, { buyerId: Number(ev.id) || 0, toId: onchain, oldRef: old, at: Date.now(), posted: true }); // posted below, at activation; the Purchase branch stays quiet + // Post it now (Marty, 2026-09-21): the post used to wait for a Purchase in the same tx, so an activation that + // came first (switch on payouts, buy later) was never posted. The activation is the fact; it goes out here. + try { const pur = chain.recentEvents(1e9).find(x => x.tx === ev.tx && x.type === 'Purchase') || null; await postWalkUp(Number(ev.id) || 0, old, onchain, pur); } catch (e) { console.error('walk-up post', e.message); } if (movedByTx.size > 200) { const k = movedByTx.keys().next().value; movedByTx.delete(k); } console.log('referral moved to where the pay landed:', acct.email, JSON.stringify(old), '->', ref, '(#' + onchain + ')'); // Notices, now that it is a fact on the chain (Marty, 2026-09-16): everyone between the stored @@ -978,7 +996,7 @@ async function telegramOnEvent(ev) { missed = missedNotice.composeMissed(txEvents, who2, had, site); } } - if (ev.type === 'Purchase' && movedByTx.has(ev.tx)) { + if (ev.type === 'Purchase' && movedByTx.has(ev.tx) && !movedByTx.get(ev.tx).posted) { // legacy path; walk-ups now post at activation const mv = movedByTx.get(ev.tx); movedByTx.delete(ev.tx); const lostAcct = await refAccount(mv.oldRef); if (lostAcct) {