import "dotenv/config" import { ethers } from "ethers" import * as fs from "fs" import * as path from "path" import { MockUSD1__factory, Launchpad__factory, BasicERC20__factory } from "../typechain-types/factories/contracts" import type { MockUSD1, Launchpad, BasicERC20 } from "../typechain-types/contracts" async function main() { // 获取环境配置 const environment = process.env.ENVIRONMENT || "bsctest" const rpcUrl = process.env.RPC_URL || "https://data-seed-prebsc-1-s1.binance.org:8545/" const outputDir = process.env.OUTPUT_DIR || "./output/bsctest" console.log(`🚀 第5步:测试代币领取和提款...`) console.log(`🌍 环境: ${environment}`) console.log(`🔗 RPC: ${rpcUrl}`) console.log(`📁 输出目录: ${outputDir}`) // 检查环境变量 if (!process.env.PRIVATE_KEY) { console.error("❌ 需要设置 PRIVATE_KEY 环境变量") process.exit(1) } // 从之前的步骤加载数据 const step3DataPath = path.join(outputDir, "step3-data.json") if (!fs.existsSync(step3DataPath)) { console.error(`❌ 未找到 ${step3DataPath} 文件。请先运行第4步。`) process.exit(1) } const step3Data = JSON.parse(fs.readFileSync(step3DataPath, "utf8")) console.log("📋 已从之前的步骤加载数据") // 设置提供者 const provider = new ethers.JsonRpcProvider(rpcUrl) const deployer = new ethers.Wallet(process.env.PRIVATE_KEY, provider) // 连接到合约 const mockUSD1 = MockUSD1__factory.connect(step3Data.mockUSD1, deployer) const launchpad = Launchpad__factory.connect(step3Data.launchpad, deployer) const saleToken = BasicERC20__factory.connect(step3Data.saleToken, deployer) // 从JSON文件加载测试账户 const testAccountsPath = "./scripts/testAccount/BLaunchpadTest.json" const testAccounts = JSON.parse(fs.readFileSync(testAccountsPath, "utf8")) // 从加载的账户创建测试用户(保留用于兼容性) const user1 = new ethers.Wallet(testAccounts[0].privateKey, provider) const user2 = new ethers.Wallet(testAccounts[1].privateKey, provider) const user3 = new ethers.Wallet(testAccounts[2].privateKey, provider) // 获取当前时间和销售结束时间 const currentTime = Math.floor(Date.now() / 1000) const saleEndTime = step3Data.saleParams.endTime console.log(`\n⏰ 当前时间: ${new Date(currentTime * 1000).toLocaleString()}`) console.log(`⏰ 销售结束时间: ${new Date(saleEndTime * 1000).toLocaleString()}`) // 检测是否为Hardhat环境 const isHardhat = rpcUrl.includes("127.0.0.1") || rpcUrl.includes("localhost") || rpcUrl.includes("8545") if (isHardhat) { console.log("🔧 检测到Hardhat环境,使用时间快进功能...") // 使用Hardhat快进时间到销售结束后 const timeToAdvance = saleEndTime - currentTime + 3600 // 快进到销售结束后1小时 console.log(`⏰ 快进时间 ${timeToAdvance} 秒到销售结束后...`) await provider.send("evm_increaseTime", [timeToAdvance]) await provider.send("evm_mine", []) // 获取区块链当前时间 const blockNumber = await provider.getBlockNumber() const block = await provider.getBlock(blockNumber) const newCurrentTime = block?.timestamp || Math.floor(Date.now() / 1000) console.log("✅ 时间已快进到:", new Date(newCurrentTime * 1000).toLocaleString()) console.log("\n🔓 销售已结束,启用领取...") // 启用领取 const claimStartTime = newCurrentTime + 1 // 从现在起1秒后启用领取 await launchpad.connect(deployer).enableClaimTokens(claimStartTime) console.log("✅ 领取已启用,时间:", new Date(claimStartTime * 1000).toLocaleString()) // 快进时间到领取开始后 if (newCurrentTime < claimStartTime) { const waitTime = claimStartTime - newCurrentTime + 1 console.log(`⏰ 快进 ${waitTime} 秒到领取开始后...`) await provider.send("evm_increaseTime", [waitTime]) await provider.send("evm_mine", []) const finalBlockNumber = await provider.getBlockNumber() const finalBlock = await provider.getBlock(finalBlockNumber) const finalTime = finalBlock?.timestamp || newCurrentTime console.log("✅ 时间已快进到:", new Date(finalTime * 1000).toLocaleString()) } // 再次检查当前时间,确保销售已结束 const finalCheckBlock = await provider.getBlock(await provider.getBlockNumber()) const finalCheckTime = finalCheckBlock?.timestamp || Math.floor(Date.now() / 1000) console.log("🔍 最终时间检查:", new Date(finalCheckTime * 1000).toLocaleString()) console.log("🔍 销售结束时间:", new Date(saleEndTime * 1000).toLocaleString()) console.log("🔍 销售是否已结束:", finalCheckTime > saleEndTime) } else { console.log("🌐 检测到真实网络环境,检查销售是否已结束...") // 检查销售是否已经结束 if (currentTime < saleEndTime) { console.log("❌ 销售尚未结束,无法进行领取测试") console.log("💡 提示:在真实网络中,需要等待销售自然结束才能进行领取测试") console.log("💡 或者可以修改合约的endTime参数来提前结束销售") return } console.log("✅ 销售已结束,检查是否已启用领取...") // 检查是否已经启用领取 try { // 尝试启用领取(如果已经启用会失败,这是正常的) const claimStartTime = currentTime + 60 // 1分钟后启用 await launchpad.connect(deployer).enableClaimTokens(claimStartTime) console.log("✅ 领取已启用,时间:", new Date(claimStartTime * 1000).toLocaleString()) } catch (error) { console.log("✅ 领取功能已经启用或正在启用中...") } // 等待一段时间确保领取功能完全启用 console.log("⏳ 等待领取功能完全启用...") await new Promise(resolve => setTimeout(resolve, 5000)) // 等待5秒 } console.log("\n🎁 测试代币领取...") // 获取所有测试用户 const allTestUsers = testAccounts.map((account: any) => new ethers.Wallet(account.privateKey, provider)) // 记录所有用户的代币领取情况 const userTokensReceived: { [key: string]: bigint } = {} let totalTokensClaimed = BigInt(0) // 检查是否需要快进时间(在Hardhat环境中) if (isHardhat) { // 获取当前区块链时间 const currentBlockNumber = await provider.getBlockNumber() const currentBlock = await provider.getBlock(currentBlockNumber) const currentBlockTime = currentBlock?.timestamp || Math.floor(Date.now() / 1000) // 检查是否已经启用了领取功能 try { const isClaimEnabled = await launchpad.isClaimEnabled() const claimStartTime = await launchpad.getClaimStartTime() console.log("🔍 检查领取功能状态...") console.log(`- 领取功能已启用: ${isClaimEnabled}`) console.log(`- 领取开始时间: ${new Date(Number(claimStartTime) * 1000).toLocaleString()}`) // 如果领取功能未启用,尝试启用 if (!isClaimEnabled) { console.log("🔓 领取功能未启用,正在启用...") const newClaimStartTime = currentBlockTime + 1 await launchpad.connect(deployer).enableClaimTokens(newClaimStartTime) console.log("✅ 领取功能已启用") // 快进时间到领取开始后 const waitTime = 2 console.log(`⏰ 快进 ${waitTime} 秒到领取开始后...`) await provider.send("evm_increaseTime", [waitTime]) await provider.send("evm_mine", []) } } catch (error) { console.log("⚠️ 无法检测领取功能状态,继续执行...") } } // 让所有用户领取代币 for (let i = 0; i < allTestUsers.length; i++) { const user = allTestUsers[i] console.log(`\n👤 用户${i + 1} (${user.address}) 领取代币...`) // 检查用户是否参与过贡献 let userContributed = false let userContributionAmount = BigInt(0) try { // 从合约获取用户的贡献信息 userContributionAmount = await launchpad.userContributionAmount(user.address) userContributed = userContributionAmount > 0 console.log(`📊 用户${i + 1} 贡献金额: ${ethers.formatEther(userContributionAmount)} USD1`) } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error) console.log(`⚠️ 无法检测用户${i + 1}的贡献状态: ${errorMessage}`) } if (!userContributed) { console.log(`❌ 用户${i + 1} 没有参与贡献,跳过领取`) userTokensReceived[user.address] = BigInt(0) continue } const userBalanceBefore = await saleToken.balanceOf(user.address) let userTokensReceivedAmount = BigInt(0) try { // 获取用户当前nonce const userNonce = await provider.getTransactionCount(user.address) await launchpad.connect(user).claimTokens({ nonce: userNonce }) const userBalanceAfter = await saleToken.balanceOf(user.address) userTokensReceivedAmount = userBalanceAfter - userBalanceBefore totalTokensClaimed += userTokensReceivedAmount console.log(`✅ 用户${i + 1} 领取了 ${ethers.formatEther(userTokensReceivedAmount)} 个代币`) } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error) if (errorMessage.includes("No tokens to claim")) { console.log(`✅ 用户${i + 1} 没有代币可领取(可能已经领取过了)`) } else if (errorMessage.includes("Claiming not enabled")) { console.log(`❌ 用户${i + 1} 领取功能尚未启用`) } else if (errorMessage.includes("Sale has not ended")) { console.log(`❌ 用户${i + 1} 销售尚未结束,无法领取`) } else { console.log(`❌ 用户${i + 1} 领取失败: ${errorMessage}`) } } userTokensReceived[user.address] = userTokensReceivedAmount } // 统计实际参与贡献的用户数量 let participatingUsersCount = 0 for (const user of allTestUsers) { const userContribution = await launchpad.userContributionAmount(user.address) if (userContribution > 0) { participatingUsersCount++ } } console.log(`\n📊 代币领取总结:`) console.log(`- 总领取代币数量: ${totalTokensClaimed.toString()} tokens`) console.log(`- 参与用户数量: ${participatingUsersCount} 个用户`) // 所有者提款支付 console.log("\n💸 所有者提款支付...") const ownerBalanceBefore = await mockUSD1.balanceOf(deployer.address) const ownerNonce = await provider.getTransactionCount(deployer.address) await launchpad.connect(deployer).withdrawPayments({ nonce: ownerNonce }) const ownerBalanceAfter = await mockUSD1.balanceOf(deployer.address) const ownerReceived = ownerBalanceAfter - ownerBalanceBefore console.log("✅ 所有者收到了", ethers.formatEther(ownerReceived), "USD1") // 所有者提款剩余代币 console.log("\n🏦 所有者提款剩余代币...") const remainingTokens = await saleToken.balanceOf(step3Data.launchpad) console.log("📊 合约中剩余代币:", ethers.formatEther(remainingTokens)) if (remainingTokens > 0) { try { await launchpad.connect(deployer).withdrawRemainingTokens() console.log("✅ 所有者提款了", ethers.formatEther(remainingTokens), "个剩余代币") } catch (error) { console.log("⚠️ 无法提款剩余代币,可能合约逻辑认为所有代币已售出") console.log("💡 这通常发生在超额认购时,合约认为所有代币都已分配给用户") } } else { console.log("✅ 没有剩余代币可提款(所有代币已售出)") } // 最终总结 console.log("\n🎉 领取和提款测试成功完成!") console.log("\n📋 最终总结:") console.log("- 总领取代币数量:", ethers.formatEther(totalTokensClaimed), "个代币") console.log("- 参与用户数量:", participatingUsersCount, "个用户") console.log("- 所有者收到了:", ethers.formatEther(ownerReceived), "USD1") console.log("- 所有者提款了:", ethers.formatEther(remainingTokens), "个剩余代币") // Save final data const finalData = { ...step3Data, claiming: { totalTokensClaimed: totalTokensClaimed.toString(), participatingUsersCount: participatingUsersCount, userTokensReceived: Object.fromEntries( Object.entries(userTokensReceived).map(([key, value]) => [key, value.toString()]) ), ownerReceivedUSD1: ownerReceived.toString(), remainingTokens: remainingTokens.toString(), }, } const finalDataPath = path.join(outputDir, "final-data.json") fs.writeFileSync(finalDataPath, JSON.stringify(finalData, null, 2)) console.log(`\n📋 All data saved to ${finalDataPath}`) } // 导出main函数供多环境脚本调用 export { main } // 如果直接运行此脚本 if (require.main === module) { main() .then(() => process.exit(0)) .catch((error) => { console.error("❌ Error:", error) process.exit(1) }) }