Fix credits showing 0 + purchase confirmation email

- chain.rpc(): retry the RPC pool 3 rounds with backoff. Public Amoy nodes
  routinely return transient "Temporary internal error. Please retry" on
  eth_call; a single miss was silently surfacing as 0 credits / chainReadError
  on the dashboard even when the buy succeeded on-chain.
- emailOnEvent: send a purchase confirmation on the Purchase event — credits
  added, new ad-credit balance, POL paid, and a link to view the tx on the
  explorer. Fires server-side for every wallet and the Mini App.
- Added a third Amoy RPC (tenderly) to the volume config for read redundancy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-08 10:26:53 -05:00
parent 09804cda22
commit 8958a9d145
2 changed files with 24 additions and 5 deletions
+11 -4
View File
@@ -89,10 +89,17 @@ function rpcOnce(url, method, params) {
async function rpc(method, params) {
const urls = getConfig().rpcs;
let last;
for (let i = 0; i < urls.length; i++) {
const url = urls[(rpcIdx + i) % urls.length];
try { const r = await rpcOnce(url, method, params); rpcIdx = (rpcIdx + i) % urls.length; return r; }
catch (e) { last = e; }
// 3 rounds over the RPC pool with backoff — the public Amoy nodes routinely
// return transient "Temporary internal error. Please retry" on eth_call, and a
// single miss was silently surfacing as 0 credits / chainReadError on the
// dashboard. Retry so a real read isn't lost to a momentary node hiccup.
for (let round = 0; round < 3; round++) {
for (let i = 0; i < urls.length; i++) {
const url = urls[(rpcIdx + i) % urls.length];
try { const r = await rpcOnce(url, method, params); rpcIdx = (rpcIdx + i) % urls.length; return r; }
catch (e) { last = e; }
}
if (round < 2) await new Promise(r => setTimeout(r, 400 * (round + 1)));
}
throw last || new Error('all RPCs failed');
}