d2a3f162d0
Marty, reading the feed on 25 September: "I see the level 1 payout, I see a level 2 payout, but I don't see who purchased something and what they bought." And in the main Crypto Team Build group the same lines carried no product name at all, so nobody knew what they were from. feedgroup.js composes one message from every event of a purchase transaction: the buyer and the package on top, the level payouts under it with their dollar equivalents, then who was passed over and why. It is triggered on AdminPaid, the last event the contract emits for a purchase, which is how the missed-payout notice already knows the whole transaction is indexed. Tier payouts and purchases are no longer posted one line at a time. In payouts mode a purchase that paid no member (root or unsponsored buyer) stays silent, as before. Every post now opens with the InstantAdPay header in the main group as well as the payments topic. Composed against three real transactions from the live index before shipping: three tiers, a double pass-up, and a root purchase. QA member walk: 0 bugs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
40 lines
2.3 KiB
JavaScript
40 lines
2.3 KiB
JavaScript
// One proof-feed message per purchase (Marty, 2026-09-25).
|
|
//
|
|
// The feed used to post each tier payout on its own line and, in payouts mode, never said who
|
|
// bought what. Marty: "I see the level 1 payout, I see a level 2 payout, but I don't see who
|
|
// purchased something and what they bought." So: the buyer and the package first, then the
|
|
// level payouts under it, then any pass-ups, as ONE message. It composes from every event of
|
|
// the transaction, which is why the caller triggers it on AdminPaid, the last event the contract
|
|
// emits for a purchase: by then Purchase, TierPaid and PassedUp of that tx are all indexed.
|
|
//
|
|
// Pure: events in, HTML string out. Tested against real index rows before it shipped.
|
|
'use strict';
|
|
|
|
const PCT = { 1: 50, 2: 20, 3: 10 };
|
|
|
|
function usd(cents) { return ('$' + (cents / 100).toFixed(2)).replace(/\.00$/, ''); }
|
|
|
|
// txEvents: every indexed event with this tx. who(id) -> "#12 @name". weiToPol(wei) -> "1.23".
|
|
// Returns null when there is no Purchase in the tx (not a package purchase) or when
|
|
// `requirePayout` is set and no member was paid (a root or unsponsored buyer: nothing to prove).
|
|
function compose(txEvents, who, weiToPol, opts) {
|
|
opts = opts || {};
|
|
const pur = txEvents.find(e => e.type === 'Purchase');
|
|
if (!pur) return null;
|
|
const tiers = txEvents.filter(e => e.type === 'TierPaid').sort((a, b) => (a.tier || 0) - (b.tier || 0) || (a.li || 0) - (b.li || 0));
|
|
if (opts.requirePayout && !tiers.length) return null;
|
|
const lines = ['\u{1F9FE} <b>' + who(pur.buyerId) + '</b> bought a <b>' + usd(pur.priceCents) + ' package</b>'];
|
|
for (const t of tiers) {
|
|
const pct = PCT[t.tier];
|
|
const about = pct ? ' (' + usd(Math.round(pur.priceCents * pct / 100)) + ')' : '';
|
|
lines.push('\u{1F4B8} Level ' + t.tier + ': <b>' + weiToPol(t.amountWei) + ' POL</b>' + about + ' → ' + who(t.recipientId)
|
|
+ (t.hops > 0 ? ' <i>(passed up ' + t.hops + ')</i>' : ''));
|
|
}
|
|
if (!tiers.length) lines.push('<i>No member payout on this one: the buyer has nobody above them to pay.</i>');
|
|
const passed = txEvents.filter(e => e.type === 'PassedUp');
|
|
for (const p of passed) if (p.skippedId) lines.push('⏭ Level ' + (p.tier || '?') + ' skipped ' + who(p.skippedId) + ' (not yet qualified)');
|
|
return lines.join('\n');
|
|
}
|
|
|
|
module.exports = { compose };
|