fix(token-aggregation): enforce wallet-safe Chain 138 RPC URLs

Ensure MetaMask add-chain payloads never inherit LAN HTTP RPCs by routing Chain 138 wallet payloads through a public HTTPS-only resolver.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-07-07 09:58:44 -07:00
parent 8abbdf997d
commit 869d61bcc7
2 changed files with 31 additions and 2 deletions

View File

@@ -6,8 +6,25 @@ export const CHAIN138_PUBLIC_RPC_URLS = [
] as const;
const DEFAULT_CHAIN138_PUBLIC_RPC_URL = CHAIN138_PUBLIC_RPC_URLS[0];
const DEFAULT_CHAIN138_WALLET_RPC_URL = CHAIN138_PUBLIC_RPC_URLS[1];
const DEFAULT_CHAIN138_SERVER_RPC_URL = 'http://192.168.11.235:8545';
export function isWalletSafeRpcUrl(url: string | undefined): boolean {
if (!url) return false;
try {
const parsed = new URL(url);
if (parsed.protocol !== 'https:') return false;
const host = parsed.hostname.toLowerCase();
if (host === 'localhost' || host === '127.0.0.1' || host.endsWith('.local')) return false;
if (/^10\./.test(host) || /^192\.168\./.test(host) || /^172\.(1[6-9]|2\d|3[0-1])\./.test(host)) {
return false;
}
return true;
} catch {
return false;
}
}
/** HTTPS FQDN for wallets, MetaMask, and browser JSON-RPC (same on LAN and external). */
export function resolveChain138PublicRpcUrl(): string {
return String(
@@ -19,6 +36,18 @@ export function resolveChain138PublicRpcUrl(): string {
).trim();
}
export function resolveChain138WalletRpcUrl(): string {
const candidates = [
process.env.CHAIN138_WALLET_RPC_URL,
process.env.CHAIN138_RPC_HTTP_PUBLIC_FQDN,
process.env.RPC_URL_138_PUBLIC,
process.env.CHAIN138_RPC_URL_PUBLIC,
process.env.CHAIN_138_RPC_URL,
DEFAULT_CHAIN138_WALLET_RPC_URL,
];
return candidates.map((url) => String(url || '').trim()).find(isWalletSafeRpcUrl) || DEFAULT_CHAIN138_WALLET_RPC_URL;
}
export function resolveChain138PublicRpcUrls(): string[] {
const fromEnv = process.env.CHAIN138_PUBLIC_RPC_URLS?.trim();
if (fromEnv) {

View File

@@ -1,5 +1,5 @@
import type { NetworkEntry } from '../config/networks';
import { resolveChain138PublicRpcUrl } from '../config/chain138-rpc';
import { resolveChain138WalletRpcUrl } from '../config/chain138-rpc';
import { filterMetamaskSafeIconUrls } from '../config/metamask-wallet-images';
/** EIP-3085 fields accepted by MetaMask `wallet_addEthereumChain` (strict subset). */
@@ -28,7 +28,7 @@ export function toWalletAddEthereumChainParams(
const httpsList = httpsOnly(network.rpcUrls) ?? ['https://rpc-http-pub.d-bis.org'];
// MetaMask rejects some multi-rpc addEthereumChain payloads; ship one canonical HTTPS URL.
const primaryRpc =
network.chainId === '0x8a' ? resolveChain138PublicRpcUrl() : httpsList[0];
network.chainId === '0x8a' ? resolveChain138WalletRpcUrl() : httpsList[0];
const rpcUrls = primaryRpc ? [primaryRpc] : httpsList.slice(0, 1);
const out: WalletAddEthereumChainParams = {
chainId: network.chainId,