Phone-run fixes: hash tokens, embed wakes on tab focus, dry faucet leaves drips due (+admin retry), short drip status, claim box wraps; one drip per wallet per mission
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+11
-2
@@ -30,16 +30,25 @@ async function tick(notify) {
|
||||
let paid = 0;
|
||||
try {
|
||||
const due = rewards.payable();
|
||||
// a dry faucet is not a failed drip: check the balance first, leave the drips due, alert once
|
||||
let bal0 = null; try { bal0 = await balance(); } catch (e) {}
|
||||
if (bal0 != null && due.length) {
|
||||
const need = due.reduce((n, p) => n + p.pol, 0) + 0.01;
|
||||
if (bal0 < due[0].pol + 0.005) { if (notify) { const st = store.read('faucet-state', {}); const day = new Date().toLocaleDateString('en-CA', { timeZone: 'America/Chicago' }); if (st.dryAlertDay !== day) { st.dryAlertDay = day; store.write('faucet-state', st); await notify('low', { balance: bal0, threshold: need, address: wallet.address }); } } ticking = false; return { paid: 0, waiting: due.length, balance: bal0 }; }
|
||||
}
|
||||
for (const p of due) {
|
||||
if (bal0 != null && bal0 < p.pol + 0.005) break; // pay what the balance covers, leave the rest due
|
||||
if (!p.wallet || !/^0x[a-f0-9]{40}$/i.test(p.wallet)) { rewards.mark(p.id, { status: 'failed', error: 'no wallet on the account' }); continue; }
|
||||
try {
|
||||
const tx = await wallet.sendTransaction({ to: p.wallet, value: ethers.parseEther(String(p.pol)) });
|
||||
rewards.mark(p.id, { status: 'sent', tx: tx.hash });
|
||||
const rc = await tx.wait(1);
|
||||
rewards.mark(p.id, { status: rc && rc.status === 1 ? 'paid' : 'failed', paidAt: Date.now(), error: rc && rc.status === 1 ? null : 'reverted' });
|
||||
if (rc && rc.status === 1) { paid++; if (notify) await notify('paid', Object.assign({}, p, { tx: tx.hash })); }
|
||||
if (rc && rc.status === 1) { paid++; if (bal0 != null) bal0 -= p.pol; if (notify) await notify('paid', Object.assign({}, p, { tx: tx.hash })); }
|
||||
} catch (e) {
|
||||
rewards.mark(p.id, { status: 'failed', error: String(e.message || e).slice(0, 200) });
|
||||
const msg = String(e.message || e);
|
||||
if (/insufficient funds/i.test(msg)) { rewards.mark(p.id, { status: 'due', error: null }); break; } // dry: leave it due, stop this pass
|
||||
rewards.mark(p.id, { status: 'failed', error: msg.slice(0, 200) });
|
||||
if (notify) await notify('failed', Object.assign({}, p, { error: String(e.message || e).slice(0, 200) }));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -30,8 +30,10 @@ function paidToday(day) {
|
||||
}
|
||||
|
||||
// has this member completed this mission already?
|
||||
function completed(memberId, missionId) {
|
||||
return store.read('payouts', []).some(p => p.memberId === Number(memberId) && p.missionId === missionId && p.status !== 'failed');
|
||||
// by member id, and also by wallet: two accounts sharing a wallet get one drip per mission between them
|
||||
function completed(memberId, missionId, wallet) {
|
||||
const w = wallet ? String(wallet).toLowerCase() : null;
|
||||
return store.read('payouts', []).some(p => p.missionId === missionId && p.status !== 'failed' && (p.memberId === Number(memberId) || (w && p.wallet && String(p.wallet).toLowerCase() === w)));
|
||||
}
|
||||
|
||||
// record a completion; decide paid-today vs queued
|
||||
|
||||
Reference in New Issue
Block a user