01-deploy-contracts.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import "dotenv/config"
  2. import { ethers } from "ethers"
  3. import * as fs from "fs"
  4. import * as path from "path"
  5. import { execSync } from "child_process"
  6. import { BasicERC20__factory, Launchpad__factory, MockUSD1__factory } from "../typechain-types"
  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. const chainId = process.env.CHAIN_ID || "97"
  13. console.log(`🚀 第1步:部署合约到${environment === "hardhat" ? "Hardhat本地环境" : "BSC测试网"}...`)
  14. console.log(`🌍 环境: ${environment}`)
  15. console.log(`🔗 RPC: ${rpcUrl}`)
  16. console.log(`📁 输出目录: ${outputDir}`)
  17. // 确保合约已编译
  18. console.log("\n🔨 编译合约...")
  19. try {
  20. execSync("npx hardhat compile", { stdio: "inherit" })
  21. console.log("✅ 合约编译完成")
  22. } catch (error) {
  23. console.error("❌ 合约编译失败:", error)
  24. process.exit(1)
  25. }
  26. // 检查环境变量
  27. if (!process.env.PRIVATE_KEY) {
  28. console.error("❌ 需要设置 PRIVATE_KEY 环境变量")
  29. process.exit(1)
  30. }
  31. // 设置提供者和部署者
  32. const provider = new ethers.JsonRpcProvider(rpcUrl)
  33. const deployer = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
  34. // 获取当前nonce
  35. const currentNonce = await provider.getTransactionCount(deployer.address)
  36. console.log("📋 当前nonce:", currentNonce)
  37. console.log("📋 部署者地址:", deployer.address)
  38. // 检查部署者余额
  39. const balance = await provider.getBalance(deployer.address)
  40. console.log("💰 部署者余额:", ethers.formatEther(balance), "BNB")
  41. if (balance < ethers.parseEther("0.01")) {
  42. console.error("❌ 余额不足。部署需要至少0.01 BNB")
  43. process.exit(1)
  44. }
  45. // 检查是否已有合约地址文件
  46. let existingAddresses: any = {}
  47. let mockUSD1Address: string
  48. let saleTokenAddress: string
  49. const contractAddressesPath = path.join(outputDir, "contract-addresses.json")
  50. if (fs.existsSync(contractAddressesPath)) {
  51. console.log("\n📋 检测到现有合约地址文件,检查合约状态...")
  52. existingAddresses = JSON.parse(fs.readFileSync(contractAddressesPath, "utf8"))
  53. // 检查MockUSD1合约是否存在
  54. try {
  55. const mockUSD1 = MockUSD1__factory.connect(existingAddresses.mockUSD1, provider)
  56. await mockUSD1.name() // 尝试调用合约方法验证合约存在
  57. mockUSD1Address = existingAddresses.mockUSD1
  58. console.log("✅ MockUSD1合约已存在:", mockUSD1Address)
  59. } catch (error) {
  60. console.log("❌ MockUSD1合约不存在或无效,需要重新部署")
  61. mockUSD1Address = ""
  62. }
  63. // 检查BasicERC20合约是否存在
  64. try {
  65. const saleToken = BasicERC20__factory.connect(existingAddresses.saleToken, provider)
  66. await saleToken.name() // 尝试调用合约方法验证合约存在
  67. saleTokenAddress = existingAddresses.saleToken
  68. console.log("✅ 销售代币合约已存在:", saleTokenAddress)
  69. } catch (error) {
  70. console.log("❌ 销售代币合约不存在或无效,需要重新部署")
  71. saleTokenAddress = ""
  72. }
  73. } else {
  74. console.log("\n📋 未检测到现有合约地址文件,将部署所有合约")
  75. mockUSD1Address = ""
  76. saleTokenAddress = ""
  77. }
  78. // 部署MockUSD1代币(如果需要)
  79. let mockUSD1: any
  80. let nonce = currentNonce
  81. if (!mockUSD1Address) {
  82. console.log("\n📦 部署MockUSD1代币...")
  83. mockUSD1 = await new MockUSD1__factory(deployer).deploy({ nonce: nonce++ })
  84. await mockUSD1.waitForDeployment()
  85. mockUSD1Address = await mockUSD1.getAddress()
  86. console.log("✅ MockUSD1已部署到:", mockUSD1Address)
  87. } else {
  88. mockUSD1 = MockUSD1__factory.connect(mockUSD1Address, deployer)
  89. }
  90. // 部署BasicERC20代币(如果需要)
  91. let saleToken: any
  92. if (!saleTokenAddress) {
  93. console.log("\n📦 部署BasicERC20代币...")
  94. saleToken = await new BasicERC20__factory(deployer).deploy("Test Token", "TEST", deployer.address, { nonce: nonce++ })
  95. await saleToken.waitForDeployment()
  96. saleTokenAddress = await saleToken.getAddress()
  97. console.log("✅ 销售代币已部署到:", saleTokenAddress)
  98. } else {
  99. saleToken = BasicERC20__factory.connect(saleTokenAddress, deployer)
  100. }
  101. // 总是部署新的启动板合约
  102. console.log("\n📦 部署新的启动板合约...")
  103. const launchpad = await new Launchpad__factory(deployer).deploy({ nonce: nonce++ })
  104. await launchpad.waitForDeployment()
  105. const launchpadAddress = await launchpad.getAddress()
  106. console.log("✅ 启动板已部署到:", launchpadAddress)
  107. // 保存合约地址到文件供后续步骤使用
  108. const contractAddresses = {
  109. mockUSD1: mockUSD1Address,
  110. saleToken: saleTokenAddress,
  111. launchpad: launchpadAddress,
  112. deployer: deployer.address,
  113. }
  114. fs.writeFileSync(contractAddressesPath, JSON.stringify(contractAddresses, null, 2))
  115. console.log("\n🎉 合约部署成功完成!")
  116. console.log(`\n📋 合约地址已保存到 ${contractAddressesPath}:`)
  117. console.log("- MockUSD1:", contractAddresses.mockUSD1)
  118. console.log("- 销售代币:", contractAddresses.saleToken)
  119. console.log("- 启动板:", contractAddresses.launchpad)
  120. console.log("- 部署者:", contractAddresses.deployer)
  121. console.log("\n📋 下一步:运行 'npm run 02:distribute' 来分发测试代币")
  122. }
  123. // 导出main函数供多环境脚本调用
  124. export { main }
  125. // 如果直接运行此脚本
  126. if (require.main === module) {
  127. main()
  128. .then(() => process.exit(0))
  129. .catch((error) => {
  130. console.error("❌ Error:", error)
  131. process.exit(1)
  132. })
  133. }