| 71 | } |
| 72 | |
| 73 | function humanizeError(msg: string, t: (key: string, vars?: Record<string, string | number>) => string): string { |
| 74 | const m = msg.toLowerCase(); |
| 75 | if (m.includes("user rejected") || m.includes("user denied") || m.includes("rejected by user")) return t("trade.userCancelled"); |
| 76 | if (m.includes("insufficient funds") || m.includes("insufficient balance")) return t("trade.insufficientUsdc"); |
| 77 | if (m.includes("not enough balance") || m.includes("allowance")) return t("trade.tokenApprovalMissing"); |
| 78 | if (m.includes("execution reverted")) return t("trade.orderRejected"); |
| 79 | if (m.includes("nonce") || m.includes("already known")) return t("trade.duplicateOrder"); |
| 80 | if (m.includes("geo") || m.includes("restricted") || m.includes("unavailable in your region")) return t("trade.regionRestricted"); |
| 81 | if (m.includes("network") || m.includes("fetch") || m.includes("failed to fetch")) return t("trade.networkError"); |
| 82 | if (m.includes("401") || m.includes("unauthorized") || m.includes("session")) return t("trade.sessionExpired"); |
| 83 | if (m.includes("min order") || m.includes("minimum")) return t("trade.orderTooSmall"); |
| 84 | if (m.includes("timeout")) return t("trade.requestTimeout"); |
| 85 | // Keep message but strip long hex strings |
| 86 | return msg.replace(/0x[0-9a-f]{20,}/gi, "…").slice(0, 80); |
| 87 | } |
| 88 | |
| 89 | /** Check Polymarket geo-restriction directly from the browser. |
| 90 | * Must be called from client so Polymarket sees the user's real IP. |