05-test-claiming.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import "dotenv/config"
  2. import { ethers } from "ethers"
  3. import * as fs from "fs"
  4. import * as path from "path"
  5. import { MockUSD1__factory, Launchpad__factory, BasicERC20__factory } from "../typechain-types/factories/contracts"
  6. import type { MockUSD1, Launchpad, BasicERC20 } from "../typechain-types/contracts"
  7. async function main() {
  8. // 获取环境配置
  9. const environment = process.env.ENVIRONMENT || "bsctest"
  10. const rpcUrl = process.env.RPC_URL || "https://data-seed-prebsc-1-s1.binance.org:8545/"
  11. const outputDir = process.env.OUTPUT_DIR || "./output/bsctest"
  12. console.log(`🚀 第5步:测试代币领取和提款...`)
  13. console.log(`🌍 环境: ${environment}`)
  14. console.log(`🔗 RPC: ${rpcUrl}`)
  15. console.log(`📁 输出目录: ${outputDir}`)
  16. // 检查环境变量
  17. if (!process.env.PRIVATE_KEY) {
  18. console.error("❌ 需要设置 PRIVATE_KEY 环境变量")
  19. process.exit(1)
  20. }
  21. // 从之前的步骤加载数据
  22. const step3DataPath = path.join(outputDir, "step3-data.json")
  23. if (!fs.existsSync(step3DataPath)) {
  24. console.error(`❌ 未找到 ${step3DataPath} 文件。请先运行第4步。`)
  25. process.exit(1)
  26. }
  27. const step3Data = JSON.parse(fs.readFileSync(step3DataPath, "utf8"))
  28. console.log("📋 已从之前的步骤加载数据")
  29. // 设置提供者
  30. const provider = new ethers.JsonRpcProvider(rpcUrl)
  31. const deployer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  32. // 连接到合约
  33. const mockUSD1 = MockUSD1__factory.connect(step3Data.mockUSD1, deployer)
  34. const launchpad = Launchpad__factory.connect(step3Data.launchpad, deployer)
  35. const saleToken = BasicERC20__factory.connect(step3Data.saleToken, deployer)
  36. // 从JSON文件加载测试账户
  37. const testAccountsPath = "./scripts/testAccount/BLaunchpadTest.json"
  38. const testAccounts = JSON.parse(fs.readFileSync(testAccountsPath, "utf8"))
  39. // 从加载的账户创建测试用户(保留用于兼容性)
  40. const user1 = new ethers.Wallet(testAccounts[0].privateKey, provider)
  41. const user2 = new ethers.Wallet(testAccounts[1].privateKey, provider)
  42. const user3 = new ethers.Wallet(testAccounts[2].privateKey, provider)
  43. // 获取当前时间和销售结束时间
  44. const currentTime = Math.floor(Date.now() / 1000)
  45. const saleEndTime = step3Data.saleParams.endTime
  46. console.log(`\n⏰ 当前时间: ${new Date(currentTime * 1000).toLocaleString()}`)
  47. console.log(`⏰ 销售结束时间: ${new Date(saleEndTime * 1000).toLocaleString()}`)
  48. // 检测是否为Hardhat环境
  49. const isHardhat = rpcUrl.includes("127.0.0.1") || rpcUrl.includes("localhost") || rpcUrl.includes("8545")
  50. if (isHardhat) {
  51. console.log("🔧 检测到Hardhat环境,使用时间快进功能...")
  52. // 使用Hardhat快进时间到销售结束后
  53. const timeToAdvance = saleEndTime - currentTime + 3600 // 快进到销售结束后1小时
  54. console.log(`⏰ 快进时间 ${timeToAdvance} 秒到销售结束后...`)
  55. await provider.send("evm_increaseTime", [timeToAdvance])
  56. await provider.send("evm_mine", [])
  57. // 获取区块链当前时间
  58. const blockNumber = await provider.getBlockNumber()
  59. const block = await provider.getBlock(blockNumber)
  60. const newCurrentTime = block?.timestamp || Math.floor(Date.now() / 1000)
  61. console.log("✅ 时间已快进到:", new Date(newCurrentTime * 1000).toLocaleString())
  62. console.log("\n🔓 销售已结束,启用领取...")
  63. // 启用领取
  64. const claimStartTime = newCurrentTime + 1 // 从现在起1秒后启用领取
  65. await launchpad.connect(deployer).enableClaimTokens(claimStartTime)
  66. console.log("✅ 领取已启用,时间:", new Date(claimStartTime * 1000).toLocaleString())
  67. // 快进时间到领取开始后
  68. if (newCurrentTime < claimStartTime) {
  69. const waitTime = claimStartTime - newCurrentTime + 1
  70. console.log(`⏰ 快进 ${waitTime} 秒到领取开始后...`)
  71. await provider.send("evm_increaseTime", [waitTime])
  72. await provider.send("evm_mine", [])
  73. const finalBlockNumber = await provider.getBlockNumber()
  74. const finalBlock = await provider.getBlock(finalBlockNumber)
  75. const finalTime = finalBlock?.timestamp || newCurrentTime
  76. console.log("✅ 时间已快进到:", new Date(finalTime * 1000).toLocaleString())
  77. }
  78. // 再次检查当前时间,确保销售已结束
  79. const finalCheckBlock = await provider.getBlock(await provider.getBlockNumber())
  80. const finalCheckTime = finalCheckBlock?.timestamp || Math.floor(Date.now() / 1000)
  81. console.log("🔍 最终时间检查:", new Date(finalCheckTime * 1000).toLocaleString())
  82. console.log("🔍 销售结束时间:", new Date(saleEndTime * 1000).toLocaleString())
  83. console.log("🔍 销售是否已结束:", finalCheckTime > saleEndTime)
  84. } else {
  85. console.log("🌐 检测到真实网络环境,检查销售是否已结束...")
  86. // 检查销售是否已经结束
  87. if (currentTime < saleEndTime) {
  88. console.log("❌ 销售尚未结束,无法进行领取测试")
  89. console.log("💡 提示:在真实网络中,需要等待销售自然结束才能进行领取测试")
  90. console.log("💡 或者可以修改合约的endTime参数来提前结束销售")
  91. return
  92. }
  93. console.log("✅ 销售已结束,检查是否已启用领取...")
  94. // 检查是否已经启用领取
  95. try {
  96. // 尝试启用领取(如果已经启用会失败,这是正常的)
  97. const claimStartTime = currentTime + 60 // 1分钟后启用
  98. await launchpad.connect(deployer).enableClaimTokens(claimStartTime)
  99. console.log("✅ 领取已启用,时间:", new Date(claimStartTime * 1000).toLocaleString())
  100. } catch (error) {
  101. console.log("✅ 领取功能已经启用或正在启用中...")
  102. }
  103. // 等待一段时间确保领取功能完全启用
  104. console.log("⏳ 等待领取功能完全启用...")
  105. await new Promise(resolve => setTimeout(resolve, 5000)) // 等待5秒
  106. }
  107. console.log("\n🎁 测试代币领取...")
  108. // 获取所有测试用户
  109. const allTestUsers = testAccounts.map((account: any) => new ethers.Wallet(account.privateKey, provider))
  110. // 记录所有用户的代币领取情况
  111. const userTokensReceived: { [key: string]: bigint } = {}
  112. let totalTokensClaimed = BigInt(0)
  113. // 检查是否需要快进时间(在Hardhat环境中)
  114. if (isHardhat) {
  115. // 获取当前区块链时间
  116. const currentBlockNumber = await provider.getBlockNumber()
  117. const currentBlock = await provider.getBlock(currentBlockNumber)
  118. const currentBlockTime = currentBlock?.timestamp || Math.floor(Date.now() / 1000)
  119. // 检查是否已经启用了领取功能
  120. try {
  121. const isClaimEnabled = await launchpad.isClaimEnabled()
  122. const claimStartTime = await launchpad.getClaimStartTime()
  123. console.log("🔍 检查领取功能状态...")
  124. console.log(`- 领取功能已启用: ${isClaimEnabled}`)
  125. console.log(`- 领取开始时间: ${new Date(Number(claimStartTime) * 1000).toLocaleString()}`)
  126. // 如果领取功能未启用,尝试启用
  127. if (!isClaimEnabled) {
  128. console.log("🔓 领取功能未启用,正在启用...")
  129. const newClaimStartTime = currentBlockTime + 1
  130. await launchpad.connect(deployer).enableClaimTokens(newClaimStartTime)
  131. console.log("✅ 领取功能已启用")
  132. // 快进时间到领取开始后
  133. const waitTime = 2
  134. console.log(`⏰ 快进 ${waitTime} 秒到领取开始后...`)
  135. await provider.send("evm_increaseTime", [waitTime])
  136. await provider.send("evm_mine", [])
  137. }
  138. } catch (error) {
  139. console.log("⚠️ 无法检测领取功能状态,继续执行...")
  140. }
  141. }
  142. // 让所有用户领取代币
  143. for (let i = 0; i < allTestUsers.length; i++) {
  144. const user = allTestUsers[i]
  145. console.log(`\n👤 用户${i + 1} (${user.address}) 领取代币...`)
  146. // 检查用户是否参与过贡献
  147. let userContributed = false
  148. let userContributionAmount = BigInt(0)
  149. try {
  150. // 从合约获取用户的贡献信息
  151. userContributionAmount = await launchpad.userContributionAmount(user.address)
  152. userContributed = userContributionAmount > 0
  153. console.log(`📊 用户${i + 1} 贡献金额: ${ethers.formatEther(userContributionAmount)} USD1`)
  154. } catch (error) {
  155. const errorMessage = error instanceof Error ? error.message : String(error)
  156. console.log(`⚠️ 无法检测用户${i + 1}的贡献状态: ${errorMessage}`)
  157. }
  158. if (!userContributed) {
  159. console.log(`❌ 用户${i + 1} 没有参与贡献,跳过领取`)
  160. userTokensReceived[user.address] = BigInt(0)
  161. continue
  162. }
  163. const userBalanceBefore = await saleToken.balanceOf(user.address)
  164. let userTokensReceivedAmount = BigInt(0)
  165. try {
  166. // 获取用户当前nonce
  167. const userNonce = await provider.getTransactionCount(user.address)
  168. await launchpad.connect(user).claimTokens({ nonce: userNonce })
  169. const userBalanceAfter = await saleToken.balanceOf(user.address)
  170. userTokensReceivedAmount = userBalanceAfter - userBalanceBefore
  171. totalTokensClaimed += userTokensReceivedAmount
  172. console.log(`✅ 用户${i + 1} 领取了 ${ethers.formatEther(userTokensReceivedAmount)} 个代币`)
  173. } catch (error) {
  174. const errorMessage = error instanceof Error ? error.message : String(error)
  175. if (errorMessage.includes("No tokens to claim")) {
  176. console.log(`✅ 用户${i + 1} 没有代币可领取(可能已经领取过了)`)
  177. } else if (errorMessage.includes("Claiming not enabled")) {
  178. console.log(`❌ 用户${i + 1} 领取功能尚未启用`)
  179. } else if (errorMessage.includes("Sale has not ended")) {
  180. console.log(`❌ 用户${i + 1} 销售尚未结束,无法领取`)
  181. } else {
  182. console.log(`❌ 用户${i + 1} 领取失败: ${errorMessage}`)
  183. }
  184. }
  185. userTokensReceived[user.address] = userTokensReceivedAmount
  186. }
  187. // 统计实际参与贡献的用户数量
  188. let participatingUsersCount = 0
  189. for (const user of allTestUsers) {
  190. const userContribution = await launchpad.userContributionAmount(user.address)
  191. if (userContribution > 0) {
  192. participatingUsersCount++
  193. }
  194. }
  195. console.log(`\n📊 代币领取总结:`)
  196. console.log(`- 总领取代币数量: ${totalTokensClaimed.toString()} tokens`)
  197. console.log(`- 参与用户数量: ${participatingUsersCount} 个用户`)
  198. // 所有者提款支付
  199. console.log("\n💸 所有者提款支付...")
  200. const ownerBalanceBefore = await mockUSD1.balanceOf(deployer.address)
  201. const ownerNonce = await provider.getTransactionCount(deployer.address)
  202. await launchpad.connect(deployer).withdrawPayments({ nonce: ownerNonce })
  203. const ownerBalanceAfter = await mockUSD1.balanceOf(deployer.address)
  204. const ownerReceived = ownerBalanceAfter - ownerBalanceBefore
  205. console.log("✅ 所有者收到了", ethers.formatEther(ownerReceived), "USD1")
  206. // 所有者提款剩余代币
  207. console.log("\n🏦 所有者提款剩余代币...")
  208. const remainingTokens = await saleToken.balanceOf(step3Data.launchpad)
  209. console.log("📊 合约中剩余代币:", ethers.formatEther(remainingTokens))
  210. if (remainingTokens > 0) {
  211. try {
  212. await launchpad.connect(deployer).withdrawRemainingTokens()
  213. console.log("✅ 所有者提款了", ethers.formatEther(remainingTokens), "个剩余代币")
  214. } catch (error) {
  215. console.log("⚠️ 无法提款剩余代币,可能合约逻辑认为所有代币已售出")
  216. console.log("💡 这通常发生在超额认购时,合约认为所有代币都已分配给用户")
  217. }
  218. } else {
  219. console.log("✅ 没有剩余代币可提款(所有代币已售出)")
  220. }
  221. // 最终总结
  222. console.log("\n🎉 领取和提款测试成功完成!")
  223. console.log("\n📋 最终总结:")
  224. console.log("- 总领取代币数量:", ethers.formatEther(totalTokensClaimed), "个代币")
  225. console.log("- 参与用户数量:", participatingUsersCount, "个用户")
  226. console.log("- 所有者收到了:", ethers.formatEther(ownerReceived), "USD1")
  227. console.log("- 所有者提款了:", ethers.formatEther(remainingTokens), "个剩余代币")
  228. // Save final data
  229. const finalData = {
  230. ...step3Data,
  231. claiming: {
  232. totalTokensClaimed: totalTokensClaimed.toString(),
  233. participatingUsersCount: participatingUsersCount,
  234. userTokensReceived: Object.fromEntries(
  235. Object.entries(userTokensReceived).map(([key, value]) => [key, value.toString()])
  236. ),
  237. ownerReceivedUSD1: ownerReceived.toString(),
  238. remainingTokens: remainingTokens.toString(),
  239. },
  240. }
  241. const finalDataPath = path.join(outputDir, "final-data.json")
  242. fs.writeFileSync(finalDataPath, JSON.stringify(finalData, null, 2))
  243. console.log(`\n📋 All data saved to ${finalDataPath}`)
  244. }
  245. // 导出main函数供多环境脚本调用
  246. export { main }
  247. // 如果直接运行此脚本
  248. if (require.main === module) {
  249. main()
  250. .then(() => process.exit(0))
  251. .catch((error) => {
  252. console.error("❌ Error:", error)
  253. process.exit(1)
  254. })
  255. }