Checkpoint: 修复预售网站三个关键问题:1) 购买按钮永远禁用(maxPurchaseUSDT=0导致),2) 新增Add XIC to Wallet按钮,3) 完整重写useWallet.ts支持TokenPocket/OKX/Bitget等中国钱包
This commit is contained in:
parent
ca5883ace8
commit
dd24e6ba13
|
|
@ -1,6 +1,6 @@
|
||||||
// NAC XIC Presale — Wallet Connection Hook
|
// NAC XIC Presale — Wallet Connection Hook
|
||||||
// Supports MetaMask, Trust Wallet, OKX Wallet, Coinbase Wallet, and all EVM-compatible wallets
|
// Supports MetaMask, TokenPocket, OKX, Bitget, Trust Wallet, imToken, SafePal, and all EVM wallets
|
||||||
// v3: improved error handling, MetaMask initialization detection, toast notifications
|
// v4: improved Chinese wallet support (TokenPocket, OKX, Bitget first priority)
|
||||||
|
|
||||||
import { useState, useEffect, useCallback, useRef } from "react";
|
import { useState, useEffect, useCallback, useRef } from "react";
|
||||||
import { BrowserProvider, JsonRpcSigner, Eip1193Provider } from "ethers";
|
import { BrowserProvider, JsonRpcSigner, Eip1193Provider } from "ethers";
|
||||||
|
|
@ -30,53 +30,60 @@ const INITIAL_STATE: WalletState = {
|
||||||
error: null,
|
error: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type EthProvider = Eip1193Provider & {
|
||||||
|
isMetaMask?: boolean;
|
||||||
|
isTrust?: boolean;
|
||||||
|
isTrustWallet?: boolean;
|
||||||
|
isOKExWallet?: boolean;
|
||||||
|
isOkxWallet?: boolean;
|
||||||
|
isCoinbaseWallet?: boolean;
|
||||||
|
isTokenPocket?: boolean;
|
||||||
|
isBitkeep?: boolean;
|
||||||
|
isBitgetWallet?: boolean;
|
||||||
|
providers?: EthProvider[];
|
||||||
|
};
|
||||||
|
|
||||||
// Detect the best available EVM provider across all major wallets
|
// Detect the best available EVM provider across all major wallets
|
||||||
|
// Priority: TokenPocket > OKX > Bitget > Trust Wallet > MetaMask > others
|
||||||
export function detectProvider(): Eip1193Provider | null {
|
export function detectProvider(): Eip1193Provider | null {
|
||||||
if (typeof window === "undefined") return null;
|
if (typeof window === "undefined") return null;
|
||||||
|
|
||||||
const w = window as unknown as Record<string, unknown>;
|
const w = window as unknown as Record<string, unknown>;
|
||||||
const eth = w.ethereum as (Eip1193Provider & {
|
|
||||||
providers?: Eip1193Provider[];
|
|
||||||
isMetaMask?: boolean;
|
|
||||||
isTrust?: boolean;
|
|
||||||
isOKExWallet?: boolean;
|
|
||||||
isCoinbaseWallet?: boolean;
|
|
||||||
}) | undefined;
|
|
||||||
|
|
||||||
if (!eth) {
|
// 1. TokenPocket — injects window.ethereum with isTokenPocket flag
|
||||||
// Fallback: check wallet-specific globals
|
const eth = w.ethereum as EthProvider | undefined;
|
||||||
if (w.okxwallet) return w.okxwallet as Eip1193Provider;
|
if (eth) {
|
||||||
if (w.coinbaseWalletExtension) return w.coinbaseWalletExtension as Eip1193Provider;
|
// Check providers array first (multiple extensions installed)
|
||||||
return null;
|
if (eth.providers && Array.isArray(eth.providers) && eth.providers.length > 0) {
|
||||||
}
|
// Priority order for Chinese users
|
||||||
|
const tp = eth.providers.find((p: EthProvider) => p.isTokenPocket);
|
||||||
// If multiple providers are injected (common when multiple extensions installed)
|
if (tp) return tp;
|
||||||
if (eth.providers && Array.isArray(eth.providers) && eth.providers.length > 0) {
|
const okx = eth.providers.find((p: EthProvider) => p.isOKExWallet || p.isOkxWallet);
|
||||||
const metamask = eth.providers.find((p: Eip1193Provider & { isMetaMask?: boolean }) => p.isMetaMask);
|
if (okx) return okx;
|
||||||
return metamask ?? eth.providers[0];
|
const bitget = eth.providers.find((p: EthProvider) => p.isBitkeep || p.isBitgetWallet);
|
||||||
}
|
if (bitget) return bitget;
|
||||||
|
const trust = eth.providers.find((p: EthProvider) => p.isTrust || p.isTrustWallet);
|
||||||
return eth;
|
if (trust) return trust;
|
||||||
}
|
const metamask = eth.providers.find((p: EthProvider) => p.isMetaMask);
|
||||||
|
if (metamask) return metamask;
|
||||||
// Check if MetaMask is installed but not yet initialized (no wallet created/imported)
|
return eth.providers[0];
|
||||||
export async function checkWalletReady(rawProvider: Eip1193Provider): Promise<{ ready: boolean; reason?: string }> {
|
|
||||||
try {
|
|
||||||
// eth_accounts is silent — if it returns empty array, wallet is installed but locked or not initialized
|
|
||||||
const accounts = await (rawProvider as { request: (args: { method: string }) => Promise<string[]> }).request({
|
|
||||||
method: "eth_accounts",
|
|
||||||
});
|
|
||||||
// If we get here, the wallet is at least initialized (even if locked / no accounts)
|
|
||||||
return { ready: true };
|
|
||||||
} catch (err: unknown) {
|
|
||||||
const error = err as { code?: number; message?: string };
|
|
||||||
// -32002: Request already pending (MetaMask not initialized or another request pending)
|
|
||||||
if (error?.code === -32002) {
|
|
||||||
return { ready: false, reason: "pending" };
|
|
||||||
}
|
}
|
||||||
// Any other error — treat as not ready
|
|
||||||
return { ready: false, reason: error?.message || "unknown" };
|
// Single provider — return it directly
|
||||||
|
return eth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. OKX Wallet — sometimes injects window.okxwallet separately
|
||||||
|
if (w.okxwallet) return w.okxwallet as Eip1193Provider;
|
||||||
|
|
||||||
|
// 3. Bitget Wallet — sometimes injects window.bitkeep.ethereum
|
||||||
|
const bitkeep = w.bitkeep as { ethereum?: Eip1193Provider } | undefined;
|
||||||
|
if (bitkeep?.ethereum) return bitkeep.ethereum;
|
||||||
|
|
||||||
|
// 4. Coinbase Wallet
|
||||||
|
if (w.coinbaseWalletExtension) return w.coinbaseWalletExtension as Eip1193Provider;
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build wallet state from a provider and accounts
|
// Build wallet state from a provider and accounts
|
||||||
|
|
@ -136,7 +143,7 @@ export function useWallet() {
|
||||||
const rawProvider = detectProvider();
|
const rawProvider = detectProvider();
|
||||||
|
|
||||||
if (!rawProvider) {
|
if (!rawProvider) {
|
||||||
const msg = "未检测到钱包插件。请安装 MetaMask 或其他 EVM 兼容钱包后刷新页面。";
|
const msg = "未检测到钱包插件。请安装 TokenPocket、MetaMask 或其他 EVM 兼容钱包后刷新页面。";
|
||||||
if (mountedRef.current) setState(s => ({ ...s, error: msg }));
|
if (mountedRef.current) setState(s => ({ ...s, error: msg }));
|
||||||
return { success: false, error: msg };
|
return { success: false, error: msg };
|
||||||
}
|
}
|
||||||
|
|
@ -168,16 +175,10 @@ export function useWallet() {
|
||||||
// User rejected
|
// User rejected
|
||||||
msg = "已取消连接 / Connection cancelled";
|
msg = "已取消连接 / Connection cancelled";
|
||||||
} else if (error?.code === -32002) {
|
} else if (error?.code === -32002) {
|
||||||
// MetaMask has a pending request — usually means it's not initialized or popup is already open
|
// Wallet has a pending request
|
||||||
msg = "钱包请求处理中,请检查 MetaMask 弹窗。如未弹出,请先完成 MetaMask 初始化设置(创建或导入钱包),然后刷新页面重试。";
|
msg = "钱包请求处理中,请检查钱包弹窗。如未弹出,请先完成钱包初始化设置,然后刷新页面重试。";
|
||||||
} else if (error?.message === "no_accounts") {
|
} else if (error?.message === "no_accounts") {
|
||||||
msg = "未获取到账户,请确认钱包已解锁并授权此网站。";
|
msg = "未获取到账户,请确认钱包已解锁并授权此网站。";
|
||||||
} else if (
|
|
||||||
error?.message?.toLowerCase().includes("not initialized") ||
|
|
||||||
error?.message?.toLowerCase().includes("setup") ||
|
|
||||||
error?.message?.toLowerCase().includes("onboarding")
|
|
||||||
) {
|
|
||||||
msg = "MetaMask 尚未完成初始化。请先打开 MetaMask 扩展,创建或导入钱包,然后刷新页面重试。";
|
|
||||||
} else {
|
} else {
|
||||||
msg = `连接失败: ${error?.message || "未知错误"}。请刷新页面重试。`;
|
msg = `连接失败: ${error?.message || "未知错误"}。请刷新页面重试。`;
|
||||||
}
|
}
|
||||||
|
|
@ -226,8 +227,9 @@ export function useWallet() {
|
||||||
|
|
||||||
const rawProvider = detectProvider();
|
const rawProvider = detectProvider();
|
||||||
if (!rawProvider) {
|
if (!rawProvider) {
|
||||||
if (attempt < 3) {
|
if (attempt < 5) {
|
||||||
retryRef.current = setTimeout(() => tryAutoDetect(attempt + 1), 800 * attempt);
|
// Retry more times — some wallets inject later (especially mobile in-app browsers)
|
||||||
|
retryRef.current = setTimeout(() => tryAutoDetect(attempt + 1), 600 * attempt);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -242,11 +244,14 @@ export function useWallet() {
|
||||||
if (!cancelled && mountedRef.current) {
|
if (!cancelled && mountedRef.current) {
|
||||||
setState({ ...INITIAL_STATE, ...partial });
|
setState({ ...INITIAL_STATE, ...partial });
|
||||||
}
|
}
|
||||||
} else if (attempt < 3) {
|
} else if (attempt < 5) {
|
||||||
retryRef.current = setTimeout(() => tryAutoDetect(attempt + 1), 1000 * attempt);
|
retryRef.current = setTimeout(() => tryAutoDetect(attempt + 1), 800 * attempt);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Silently ignore — user hasn't connected yet
|
// Silently ignore — user hasn't connected yet
|
||||||
|
if (attempt < 3) {
|
||||||
|
retryRef.current = setTimeout(() => tryAutoDetect(attempt + 1), 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const CONTRACTS = {
|
||||||
rpcUrl: "https://bsc-dataseed1.binance.org/",
|
rpcUrl: "https://bsc-dataseed1.binance.org/",
|
||||||
explorerUrl: "https://bscscan.com",
|
explorerUrl: "https://bscscan.com",
|
||||||
nativeCurrency: { name: "BNB", symbol: "BNB", decimals: 18 },
|
nativeCurrency: { name: "BNB", symbol: "BNB", decimals: 18 },
|
||||||
presale: "0xc65e7a2738ed884db8d26a6eb2fecf7daca2e90c",
|
presale: "0x5953c025dA734e710886916F2d739A3A78f8bbc4", // XICPresale v2 — 购买即时发放
|
||||||
token: "0x59FF34dD59680a7125782b1f6df2A86ed46F5A24",
|
token: "0x59FF34dD59680a7125782b1f6df2A86ed46F5A24",
|
||||||
usdt: "0x55d398326f99059fF775485246999027B3197955",
|
usdt: "0x55d398326f99059fF775485246999027B3197955",
|
||||||
},
|
},
|
||||||
|
|
@ -50,9 +50,9 @@ export const PRESALE_CONFIG = {
|
||||||
tokenName: "New AssetChain Token",
|
tokenName: "New AssetChain Token",
|
||||||
tokenDecimals: 18,
|
tokenDecimals: 18,
|
||||||
minPurchaseUSDT: 0, // No minimum purchase limit
|
minPurchaseUSDT: 0, // No minimum purchase limit
|
||||||
maxPurchaseUSDT: 50000, // Maximum $50,000 USDT
|
maxPurchaseUSDT: 50000, // Max $50,000 USDT per purchase
|
||||||
totalSupply: 100_000_000_000, // 100 billion XIC
|
totalSupply: 100_000_000_000, // 100 billion XIC
|
||||||
presaleAllocation: 30_000_000_000, // 30 billion for presale
|
presaleAllocation: 2_500_000_000, // 2.5 billion for presale (25亿)
|
||||||
// TRC20 memo format
|
// TRC20 memo format
|
||||||
trc20Memo: "XIC_PRESALE",
|
trc20Memo: "XIC_PRESALE",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,8 @@ function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; l
|
||||||
|
|
||||||
const usdtAmount = parseFloat(usdtInput) || 0;
|
const usdtAmount = parseFloat(usdtInput) || 0;
|
||||||
const tokenAmount = calcTokens(usdtAmount);
|
const tokenAmount = calcTokens(usdtAmount);
|
||||||
const isValidAmount = usdtAmount > 0 && usdtAmount <= PRESALE_CONFIG.maxPurchaseUSDT;
|
// maxPurchaseUSDT=0 means no limit; otherwise check against the limit
|
||||||
|
const isValidAmount = usdtAmount > 0 && (PRESALE_CONFIG.maxPurchaseUSDT === 0 || usdtAmount <= PRESALE_CONFIG.maxPurchaseUSDT);
|
||||||
|
|
||||||
const handleBuy = async () => {
|
const handleBuy = async () => {
|
||||||
if (!isValidAmount) {
|
if (!isValidAmount) {
|
||||||
|
|
@ -516,8 +517,59 @@ function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; l
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<p className="text-xs text-center text-white/30">
|
<p className="text-xs text-center text-white/30">
|
||||||
{t("buy_no_min_max")} ${PRESALE_CONFIG.maxPurchaseUSDT.toLocaleString()} USDT
|
{PRESALE_CONFIG.maxPurchaseUSDT > 0
|
||||||
|
? `${t("buy_no_min_max")} $${PRESALE_CONFIG.maxPurchaseUSDT.toLocaleString()} USDT`
|
||||||
|
: (lang === "zh" ? "无最低/最高购买限制" : "No minimum or maximum purchase limit")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{/* Add XIC to Wallet button — only show on BSC where token address is known */}
|
||||||
|
{network === "BSC" && CONTRACTS.BSC.token && (
|
||||||
|
<button
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
// Use the raw provider to call wallet_watchAsset
|
||||||
|
const rawProvider = (window as unknown as { ethereum?: { request: (args: { method: string; params?: unknown }) => Promise<unknown> } }).ethereum;
|
||||||
|
if (!rawProvider) {
|
||||||
|
toast.error(lang === "zh" ? "未检测到钱包,请先安装 MetaMask 或其他 EVM 钱包" : "No wallet detected. Please install MetaMask or another EVM wallet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await rawProvider.request({
|
||||||
|
method: "wallet_watchAsset",
|
||||||
|
params: {
|
||||||
|
type: "ERC20",
|
||||||
|
options: {
|
||||||
|
address: CONTRACTS.BSC.token,
|
||||||
|
symbol: PRESALE_CONFIG.tokenSymbol,
|
||||||
|
decimals: PRESALE_CONFIG.tokenDecimals,
|
||||||
|
image: "https://d2xsxph8kpxj0f.cloudfront.net/310519663287655625/Ngki3MumDNGduV3xJt3mga/nac-token-icon_382e5c30.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
toast.success(lang === "zh" ? "XIC 代币已添加到钱包!" : "XIC token added to wallet!");
|
||||||
|
} catch (err: unknown) {
|
||||||
|
const error = err as { code?: number; message?: string };
|
||||||
|
if (error?.code === 4001) {
|
||||||
|
// User rejected — not an error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toast.error(lang === "zh" ? "添加失败,请手动添加代币" : "Failed to add token. Please add manually.");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="w-full py-2.5 rounded-xl text-sm font-semibold transition-all hover:opacity-90 flex items-center justify-center gap-2"
|
||||||
|
style={{
|
||||||
|
background: "rgba(0,212,255,0.08)",
|
||||||
|
border: "1px solid rgba(0,212,255,0.25)",
|
||||||
|
color: "rgba(0,212,255,0.9)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||||
|
<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/>
|
||||||
|
<path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/>
|
||||||
|
<path d="M18 12a2 2 0 0 0 0 4h4v-4z"/>
|
||||||
|
</svg>
|
||||||
|
{lang === "zh" ? "添加 XIC 到钱包" : "Add XIC to Wallet"}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ const RPC_POOLS = {
|
||||||
// ─── Contract Addresses ────────────────────────────────────────────────────────
|
// ─── Contract Addresses ────────────────────────────────────────────────────────
|
||||||
export const CONTRACTS = {
|
export const CONTRACTS = {
|
||||||
BSC: {
|
BSC: {
|
||||||
presale: "0xc65e7a2738ed884db8d26a6eb2fecf7daca2e90c",
|
presale: "0x5953c025dA734e710886916F2d739A3A78f8bbc4", // XICPresale v2
|
||||||
token: "0x59ff34dd59680a7125782b1f6df2a86ed46f5a24",
|
token: "0x59ff34dd59680a7125782b1f6df2a86ed46f5a24",
|
||||||
rpc: RPC_POOLS.BSC[0],
|
rpc: RPC_POOLS.BSC[0],
|
||||||
chainId: 56,
|
chainId: 56,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
/**
|
||||||
|
* 测试链上数据读取
|
||||||
|
* 直接调用BSC和ETH合约,查看能读到哪些数据
|
||||||
|
*/
|
||||||
|
import { ethers } from "ethers";
|
||||||
|
|
||||||
|
const BSC_PRESALE = "0xc65e7a2738ed884db8d26a6eb2fecf7daca2e90c";
|
||||||
|
const ETH_PRESALE = "0x85AB2F2d9f7ca7ecB272b5E8726c70f3fd45D1E3";
|
||||||
|
|
||||||
|
// 尝试多种可能的函数名
|
||||||
|
const TEST_ABI = [
|
||||||
|
"function totalUSDTRaised() view returns (uint256)",
|
||||||
|
"function totalTokensSold() view returns (uint256)",
|
||||||
|
"function weiRaised() view returns (uint256)",
|
||||||
|
"function tokensSold() view returns (uint256)",
|
||||||
|
"function usdtRaised() view returns (uint256)",
|
||||||
|
"function totalRaised() view returns (uint256)",
|
||||||
|
"function amountRaised() view returns (uint256)",
|
||||||
|
"function hardCap() view returns (uint256)",
|
||||||
|
"function cap() view returns (uint256)",
|
||||||
|
"function owner() view returns (address)",
|
||||||
|
"function paused() view returns (bool)",
|
||||||
|
];
|
||||||
|
|
||||||
|
async function testContract(name, address, rpcUrl) {
|
||||||
|
console.log(`\n=== 测试 ${name} 合约 ===`);
|
||||||
|
console.log(`地址: ${address}`);
|
||||||
|
console.log(`RPC: ${rpcUrl}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const provider = new ethers.JsonRpcProvider(rpcUrl, undefined, {
|
||||||
|
staticNetwork: true,
|
||||||
|
polling: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 先检查合约是否存在
|
||||||
|
const code = await provider.getCode(address);
|
||||||
|
if (code === "0x") {
|
||||||
|
console.log("❌ 该地址没有合约代码!合约地址可能错误。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(`✅ 合约存在,字节码长度: ${code.length} 字符`);
|
||||||
|
|
||||||
|
const contract = new ethers.Contract(address, TEST_ABI, provider);
|
||||||
|
|
||||||
|
// 逐个测试函数
|
||||||
|
const functions = [
|
||||||
|
"totalUSDTRaised",
|
||||||
|
"totalTokensSold",
|
||||||
|
"weiRaised",
|
||||||
|
"tokensSold",
|
||||||
|
"usdtRaised",
|
||||||
|
"totalRaised",
|
||||||
|
"amountRaised",
|
||||||
|
"hardCap",
|
||||||
|
"cap",
|
||||||
|
"owner",
|
||||||
|
"paused",
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const fn of functions) {
|
||||||
|
try {
|
||||||
|
const result = await contract[fn]();
|
||||||
|
console.log(` ✅ ${fn}() = ${result}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(` ❌ ${fn}() 不存在或调用失败`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取合约事件日志(最近100个块)
|
||||||
|
const latestBlock = await provider.getBlockNumber();
|
||||||
|
console.log(`\n当前区块高度: ${latestBlock}`);
|
||||||
|
|
||||||
|
// 查找Transfer事件(USDT转入)
|
||||||
|
const usdtAddress = name === "BSC"
|
||||||
|
? "0x55d398326f99059fF775485246999027B3197955"
|
||||||
|
: "0xdAC17F958D2ee523a2206206994597C13D831ec7";
|
||||||
|
|
||||||
|
const usdtAbi = ["event Transfer(address indexed from, address indexed to, uint256 value)"];
|
||||||
|
const usdtContract = new ethers.Contract(usdtAddress, usdtAbi, provider);
|
||||||
|
|
||||||
|
console.log(`\n查询最近1000个块内转入预售合约的USDT...`);
|
||||||
|
const fromBlock = latestBlock - 1000;
|
||||||
|
const filter = usdtContract.filters.Transfer(null, address);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const events = await usdtContract.queryFilter(filter, fromBlock, latestBlock);
|
||||||
|
console.log(`找到 ${events.length} 笔USDT转入记录`);
|
||||||
|
|
||||||
|
let totalUsdt = 0n;
|
||||||
|
for (const event of events.slice(-5)) {
|
||||||
|
const args = event.args;
|
||||||
|
const amount = args[2];
|
||||||
|
totalUsdt += amount;
|
||||||
|
const decimals = name === "BSC" ? 18 : 6;
|
||||||
|
console.log(` ${args[0]} → ${ethers.formatUnits(amount, decimals)} USDT`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`查询事件失败: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`测试失败: ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试BSC
|
||||||
|
await testContract("BSC", BSC_PRESALE, "https://bsc-dataseed1.binance.org/");
|
||||||
|
|
||||||
|
// 测试ETH
|
||||||
|
await testContract("ETH", ETH_PRESALE, "https://eth.llamarpc.com");
|
||||||
|
|
||||||
|
console.log("\n=== 测试完成 ===");
|
||||||
Loading…
Reference in New Issue