|
|
|
|
@ -568,22 +568,48 @@ Reference: ${invoiceRef}`;
|
|
|
|
|
|
|
|
|
|
if (statusEl) statusEl.textContent = "Submitting transaction hash to portal…"; |
|
|
|
|
|
|
|
|
|
const resp = await fetch(`/portal/invoice/${invoiceId}/submit-crypto-tx`, { |
|
|
|
|
method: "POST", |
|
|
|
|
headers: { "Content-Type": "application/json" }, |
|
|
|
|
body: JSON.stringify({ |
|
|
|
|
payment_id: paymentId, |
|
|
|
|
asset: asset, |
|
|
|
|
tx_hash: txHash |
|
|
|
|
}) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const data = await resp.json(); |
|
|
|
|
if (!resp.ok || !data.ok) { |
|
|
|
|
throw new Error((data && (data.detail || data.error)) || "Portal rejected tx hash"); |
|
|
|
|
async function submitTxHashWithRetry() { |
|
|
|
|
const maxAttempts = 12; // about 60 seconds total |
|
|
|
|
const waitMs = 5000; |
|
|
|
|
|
|
|
|
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) { |
|
|
|
|
if (statusEl) { |
|
|
|
|
statusEl.textContent = `Checking RPC for transaction… attempt ${attempt}/${maxAttempts}`; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const resp = await fetch(`/portal/invoice/${invoiceId}/submit-crypto-tx`, { |
|
|
|
|
method: "POST", |
|
|
|
|
headers: { "Content-Type": "application/json" }, |
|
|
|
|
body: JSON.stringify({ |
|
|
|
|
payment_id: paymentId, |
|
|
|
|
asset: asset, |
|
|
|
|
tx_hash: txHash |
|
|
|
|
}) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const data = await resp.json(); |
|
|
|
|
|
|
|
|
|
if (resp.ok && data.ok) { |
|
|
|
|
window.location.href = data.redirect_url; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const detail = String((data && (data.detail || data.error)) || ""); |
|
|
|
|
const retryable = detail.toLowerCase().includes("not found on rpc"); |
|
|
|
|
|
|
|
|
|
if (!retryable || attempt === maxAttempts) { |
|
|
|
|
throw new Error(detail || "Portal rejected tx hash"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (statusEl) { |
|
|
|
|
statusEl.textContent = `Transaction sent. Waiting for RPC to see it… retrying in ${Math.floor(waitMs / 1000)}s`; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, waitMs)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
window.location.href = data.redirect_url; |
|
|
|
|
await submitTxHashWithRetry(); |
|
|
|
|
} catch (err) { |
|
|
|
|
if (statusEl) statusEl.textContent = String(err.message || err); |
|
|
|
|
walletButton.disabled = false; |
|
|
|
|
|