diff --git a/chain.js b/chain.js index 1981ec2..145ce80 100644 --- a/chain.js +++ b/chain.js @@ -200,6 +200,18 @@ function passedOver(fromId, toId) { return []; } +// Which generation caught a pass-up: matrix hops from the payer up to the +// recipient (1 = direct parent, 2 = grandparent, โ€ฆ). null if not on the chain. +function genBetween(fromId, toId) { + if (!state || !fromId || !toId) return null; + let cur = state.members[fromId] && state.members[fromId].uplineId; + for (let hops = 1; cur && hops <= 40; hops++) { + if (cur === toId) return hops; + cur = state.members[cur] && state.members[cur].uplineId; + } + return null; +} + async function processRange(fromBlock, toBlock) { const logs = await rpc('eth_getLogs', [{ address: CONTRACT, fromBlock: '0x' + fromBlock.toString(16), toBlock: '0x' + toBlock.toString(16), @@ -258,7 +270,7 @@ async function processRange(fromBlock, toBlock) { state.payouts.push(p); state.totals.count++; state.totals.pol = +(state.totals.pol + p.pol).toFixed(6); const rcpt = state.members[p.toId]; if (rcpt) rcpt.earnedPol = +((rcpt.earnedPol || 0) + p.pol).toFixed(6); - emit({ type: 'payout', kind: p.kind, toId: p.toId, fromId: p.fromId, pol: p.pol, levelName: levelName(p.level), upgrade: p.upgrade, tx, ts }); + emit({ type: 'payout', kind: p.kind, toId: p.toId, fromId: p.fromId, pol: p.pol, levelName: levelName(p.level), upgrade: p.upgrade, gen: p.kind === 'upline' ? genBetween(p.fromId, p.toId) : undefined, tx, ts }); } } } @@ -344,7 +356,7 @@ function getPayoutsPublic(offset = 0, limit = 40) { limit: lim, hasMore: off + lim < reversed.length, payouts: page.map(p => ({ - key: p.key, kind: p.kind, toId: p.toId, fromId: p.fromId, + key: p.key, kind: p.kind, toId: p.toId, fromId: p.fromId, gen: p.kind === 'upline' ? genBetween(p.fromId, p.toId) : undefined, level: p.level, levelName: levelName(p.level), pol: p.pol, tx: p.tx, ts: p.ts, desc: p.desc, toAccount: state.members[p.toId] ? state.members[p.toId].account : undefined, upgrade: p.upgrade ? { id: p.upgrade.id, newLevel: p.upgrade.newLevel, levelName: levelName(p.upgrade.newLevel), tier: tierName(p.upgrade.tier) } : undefined, diff --git a/public/payouts.js b/public/payouts.js index 7f01b7b..0834657 100644 --- a/public/payouts.js +++ b/public/payouts.js @@ -36,7 +36,7 @@ ?`๐Ÿš€ Member #${p.upgrade.id} upgraded to ${esc(p.upgrade.levelName)}` :`๐Ÿ’ธ Member #${p.toId} just got paid`; const sub=p.kind==='upline' - ?`${fmtPol(p.pol)} POL paid up to Member #${p.toId}` + ?`${fmtPol(p.pol)} POL paid up to Member #${p.toId}${p.gen?` ยท Gen ${p.gen} pass-up`:''}` :(p.kind==='referral'?`+${fmtPol(p.pol)} POL ยท direct referral reward`:`+${fmtPol(p.pol)} POL ยท ${p.desc||p.levelName||'payout'}`); el.innerHTML=`${head}${esc(sub)}${timeAgo(p.ts)} ยท Verify on Polygonscan โ†—`; getStack().appendChild(el); @@ -50,7 +50,7 @@ if(p.kind==='upline'){ const up=p.upgrade?`Member #${p.upgrade.id} upgraded to ${esc(p.upgrade.levelName)} โ€” `:''; const passed=p.passed&&p.passed.length?`
passed over ${p.passed.map(i=>'#'+i).join(', ')} (not yet eligible โ€” needs 2 directs and the level)
`:''; - return `
๐Ÿš€
${up}${fmtPol(p.pol)} POL paid up to Member #${p.toId}
Upgrade pass-up ยท ${esc(p.levelName)} ยท ${when}
${passed}
${verify}
`; + return `
๐Ÿš€
${up}${fmtPol(p.pol)} POL paid up to Member #${p.toId}
Upgrade pass-up${p.gen?` ยท Gen ${p.gen}`:''} ยท ${esc(p.levelName)} ยท ${when}
${passed}
${verify}
`; } const meta=p.kind==='referral'?`Direct referral reward from #${p.fromId}'s entry`:`${esc(p.desc||p.levelName)} โ€” from #${p.fromId}`; return `
๐Ÿ’ธ
Member #${p.toId} received ${fmtPol(p.pol)} POL
${meta} ยท ${when}
${verify}
`; diff --git a/public/styles.css b/public/styles.css index bfe9cac..fce2c4a 100644 --- a/public/styles.css +++ b/public/styles.css @@ -58,6 +58,7 @@ a{color:inherit}.wrap{width:min(1160px,calc(100% - 32px));margin:auto}.nav{heigh .pp-body{flex:1 1 auto;min-width:0} .pp-body strong{font-size:15px} .pp-meta{color:var(--muted);font-size:12.5px;margin-top:3px} +.pp-gen{color:var(--gold);font-weight:800;background:rgba(243,190,67,.12);border:1px solid rgba(243,190,67,.35);border-radius:6px;padding:1px 7px} .pp-passed{color:#f2c768;font-size:12px;margin-top:3px} .pp-verify{flex:0 0 auto;font-size:13px;color:var(--teal);text-decoration:none;border:1px solid rgba(78,214,203,.35);border-radius:9px;padding:7px 10px;white-space:nowrap} .pp-verify:hover{background:rgba(78,214,203,.1)} diff --git a/server.js b/server.js index 913d2dc..649dcf2 100644 --- a/server.js +++ b/server.js @@ -620,7 +620,7 @@ chain.startIndexer(evt=>{ let text; if(evt.type==='registered')text=`๐Ÿ“ˆ TEAM BUILD: new position!\n#${evt.id} registered under #${evt.referrerId} (${evt.tierName}).`; else if(evt.type==='upgraded')text=`๐Ÿš€ TEAM BUILD: #${evt.id} upgraded to ${evt.levelName}.`; - else text=`๐Ÿ’ธ TEAM BUILD: #${evt.toId} just got PAID ${evt.pol.toFixed(2)} POL${evt.kind==='upline'?` (upgrade pass-up from #${evt.fromId})`:` (referral reward from #${evt.fromId})`}.${contact(evt.toId)}`; + else text=`๐Ÿ’ธ TEAM BUILD: #${evt.toId} just got PAID ${evt.pol.toFixed(2)} POL${evt.kind==='upline'?` (${evt.gen?`Gen ${evt.gen} `:''}upgrade pass-up from #${evt.fromId})`:` (referral reward from #${evt.fromId})`}.${contact(evt.toId)}`; if(evt.tx)text+=`\nhttps://polygonscan.com/tx/${evt.tx}`; sendTelegram(text); // admin email alert โ€” same team-gated events, so deep-leg action still surfaces diff --git a/tweet.js b/tweet.js index 6bd2a71..b85c8f4 100644 --- a/tweet.js +++ b/tweet.js @@ -14,7 +14,7 @@ const BLOTATO_URL = 'https://backend.blotato.com/v2/posts'; const MIN_GAP_MS = 2600; // ~23/min ceiling, under Blotato's 30/min const DATA_DIR = process.env.DATA_DIR || '.'; const TWEETED_FILE = path.join(DATA_DIR, 'tweeted-payouts.json'); -const DEFAULT_CTA = 'https://rmcircle.saasy.top/?utm_source=x'; // short: Blotato counts raw URL length toward 280 +const DEFAULT_CTA = 'https://rmcircle.team/?utm_source=x'; // new primary domain; short (Blotato counts raw URL length toward 280) const DEFAULT_TAGS = '#CryptoTeamBuild #TheRMCircle #Polygon #Crypto #Web3'; const DEFAULT_TWITTER_ID = '7998'; // @cryptoteambuild in Blotato