commit
This commit is contained in:
77
scripts/deploy/01-deployWUSD.ts
Normal file
77
scripts/deploy/01-deployWUSD.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { ethers, upgrades } from "hardhat";
|
||||
|
||||
/**
|
||||
* 部署WUSD代币
|
||||
*/
|
||||
async function main() {
|
||||
console.log("开始部署WUSD代币...\n");
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("部署账户:", deployer.address);
|
||||
console.log("账户余额:", ethers.formatEther(await ethers.provider.getBalance(deployer.address)), "ETH\n");
|
||||
|
||||
// ===== 部署WUSD (可升级) =====
|
||||
console.log("===== 部署WUSD (可升级) =====");
|
||||
const WUSD = await ethers.getContractFactory("WUSD");
|
||||
|
||||
console.log("部署WUSD代理...");
|
||||
const wusd = await upgrades.deployProxy(
|
||||
WUSD,
|
||||
["Wrapped USD", "WUSD"],
|
||||
{
|
||||
initializer: "initialize",
|
||||
kind: "uups",
|
||||
}
|
||||
);
|
||||
await wusd.waitForDeployment();
|
||||
const wusdAddress = await wusd.getAddress();
|
||||
console.log("✅ WUSD代理部署到:", wusdAddress);
|
||||
|
||||
const wusdImplAddress = await upgrades.erc1967.getImplementationAddress(wusdAddress);
|
||||
console.log("✅ WUSD实现地址:", wusdImplAddress);
|
||||
|
||||
// 验证部署
|
||||
const name = await wusd.name();
|
||||
const symbol = await wusd.symbol();
|
||||
const decimals = await wusd.decimals();
|
||||
console.log("\n代币信息:");
|
||||
console.log(" 名称:", name);
|
||||
console.log(" 符号:", symbol);
|
||||
console.log(" 精度:", decimals.toString());
|
||||
|
||||
// ===== 显示部署摘要 =====
|
||||
console.log("\n===== 部署摘要 =====");
|
||||
console.log("WUSD代理:", wusdAddress);
|
||||
console.log("WUSD实现:", wusdImplAddress);
|
||||
|
||||
// 保存到JSON文件
|
||||
const deploymentInfo = {
|
||||
network: (await ethers.provider.getNetwork()).name,
|
||||
chainId: (await ethers.provider.getNetwork()).chainId.toString(),
|
||||
deployer: deployer.address,
|
||||
timestamp: new Date().toISOString(),
|
||||
contracts: {
|
||||
WUSD: {
|
||||
proxy: wusdAddress,
|
||||
implementation: wusdImplAddress,
|
||||
name: name,
|
||||
symbol: symbol,
|
||||
decimals: Number(decimals)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const fs = require("fs");
|
||||
fs.writeFileSync(
|
||||
"./deployments-wusd.json",
|
||||
JSON.stringify(deploymentInfo, null, 2)
|
||||
);
|
||||
console.log("\n✅ 部署信息已保存到 deployments-wusd.json");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
184
scripts/deploy/02-deployYTLp.ts
Normal file
184
scripts/deploy/02-deployYTLp.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import { ethers, upgrades } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
|
||||
/**
|
||||
* 部署YTLp系统的所有合约(不包含配置)
|
||||
*/
|
||||
async function main() {
|
||||
console.log("开始部署YT协议可升级合约...\n");
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("部署账户:", deployer.address);
|
||||
console.log("账户余额:", ethers.formatEther(await ethers.provider.getBalance(deployer.address)), "ETH\n");
|
||||
|
||||
// ==================== 1. 部署代币合约 ====================
|
||||
console.log("===== 1. 部署代币合约 =====");
|
||||
|
||||
// 部署USDY (可升级)
|
||||
console.log("部署USDY...");
|
||||
const USDY = await ethers.getContractFactory("USDY");
|
||||
const usdy = await upgrades.deployProxy(USDY, [], {
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
});
|
||||
await usdy.waitForDeployment();
|
||||
const usdyAddress = await usdy.getAddress();
|
||||
console.log("✅ USDY deployed to:", usdyAddress);
|
||||
|
||||
// 部署YTLPToken (可升级)
|
||||
console.log("部署YTLPToken...");
|
||||
const YTLPToken = await ethers.getContractFactory("YTLPToken");
|
||||
const ytLP = await upgrades.deployProxy(YTLPToken, [], {
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
});
|
||||
await ytLP.waitForDeployment();
|
||||
const ytLPAddress = await ytLP.getAddress();
|
||||
console.log("✅ YTLPToken deployed to:", ytLPAddress);
|
||||
|
||||
// ==================== 2. 部署核心合约 ====================
|
||||
console.log("\n===== 2. 部署核心合约 =====");
|
||||
|
||||
if (!fs.existsSync("./deployments-wusd.json")) {
|
||||
throw new Error("未找到 deployments-wusd.json,请先运行 deployWUSD.ts");
|
||||
}
|
||||
|
||||
const wusdDeployment = JSON.parse(fs.readFileSync("./deployments-wusd.json", "utf8"));
|
||||
const wusdAddress = wusdDeployment.contracts.WUSD.proxy;
|
||||
|
||||
|
||||
// 部署YTPriceFeed (可升级)
|
||||
console.log("部署YTPriceFeed...");
|
||||
const YTPriceFeed = await ethers.getContractFactory("YTPriceFeed");
|
||||
const priceFeed = await upgrades.deployProxy(YTPriceFeed, [wusdAddress], {
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
});
|
||||
await priceFeed.waitForDeployment();
|
||||
const priceFeedAddress = await priceFeed.getAddress();
|
||||
console.log("✅ YTPriceFeed deployed to:", priceFeedAddress);
|
||||
|
||||
// 部署YTVault (可升级)
|
||||
console.log("部署YTVault...");
|
||||
const YTVault = await ethers.getContractFactory("YTVault");
|
||||
const vault = await upgrades.deployProxy(
|
||||
YTVault,
|
||||
[usdyAddress, priceFeedAddress],
|
||||
{
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
}
|
||||
);
|
||||
await vault.waitForDeployment();
|
||||
const vaultAddress = await vault.getAddress();
|
||||
console.log("✅ YTVault deployed to:", vaultAddress);
|
||||
|
||||
// 部署YTPoolManager (可升级)
|
||||
console.log("部署YTPoolManager...");
|
||||
const YTPoolManager = await ethers.getContractFactory("YTPoolManager");
|
||||
const cooldownDuration = 15 * 60; // 15分钟
|
||||
const poolManager = await upgrades.deployProxy(
|
||||
YTPoolManager,
|
||||
[vaultAddress, usdyAddress, ytLPAddress, cooldownDuration],
|
||||
{
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
}
|
||||
);
|
||||
await poolManager.waitForDeployment();
|
||||
const poolManagerAddress = await poolManager.getAddress();
|
||||
console.log("✅ YTPoolManager deployed to:", poolManagerAddress);
|
||||
|
||||
// 部署YTRewardRouter (可升级)
|
||||
console.log("部署YTRewardRouter...");
|
||||
const YTRewardRouter = await ethers.getContractFactory("YTRewardRouter");
|
||||
const router = await upgrades.deployProxy(
|
||||
YTRewardRouter,
|
||||
[usdyAddress, ytLPAddress, poolManagerAddress, vaultAddress],
|
||||
{
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
}
|
||||
);
|
||||
await router.waitForDeployment();
|
||||
const routerAddress = await router.getAddress();
|
||||
console.log("✅ YTRewardRouter deployed to:", routerAddress);
|
||||
|
||||
// ==================== 3. 输出部署信息 ====================
|
||||
console.log("\n===== 部署完成!=====");
|
||||
console.log("\n📋 合约地址:");
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
console.log("USDY: ", usdyAddress);
|
||||
console.log("YTLPToken: ", ytLPAddress);
|
||||
console.log("YTPriceFeed: ", priceFeedAddress);
|
||||
console.log("YTVault: ", vaultAddress);
|
||||
console.log("YTPoolManager: ", poolManagerAddress);
|
||||
console.log("YTRewardRouter: ", routerAddress);
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
|
||||
// 获取实现合约地址
|
||||
console.log("\n📋 实现合约地址 (用于验证和升级):");
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
const usdyImpl = await upgrades.erc1967.getImplementationAddress(usdyAddress);
|
||||
const ytLPImpl = await upgrades.erc1967.getImplementationAddress(ytLPAddress);
|
||||
const priceFeedImpl = await upgrades.erc1967.getImplementationAddress(priceFeedAddress);
|
||||
const vaultImpl = await upgrades.erc1967.getImplementationAddress(vaultAddress);
|
||||
const poolManagerImpl = await upgrades.erc1967.getImplementationAddress(poolManagerAddress);
|
||||
const routerImpl = await upgrades.erc1967.getImplementationAddress(routerAddress);
|
||||
|
||||
console.log("USDY Implementation: ", usdyImpl);
|
||||
console.log("YTLPToken Implementation: ", ytLPImpl);
|
||||
console.log("YTPriceFeed Implementation: ", priceFeedImpl);
|
||||
console.log("YTVault Implementation: ", vaultImpl);
|
||||
console.log("YTPoolManager Implementation: ", poolManagerImpl);
|
||||
console.log("YTRewardRouter Implementation: ", routerImpl);
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
|
||||
// 保存到JSON文件
|
||||
const deploymentInfo = {
|
||||
network: (await ethers.provider.getNetwork()).name,
|
||||
chainId: (await ethers.provider.getNetwork()).chainId.toString(),
|
||||
deployer: deployer.address,
|
||||
timestamp: new Date().toISOString(),
|
||||
contracts: {
|
||||
USDY: {
|
||||
proxy: usdyAddress,
|
||||
implementation: usdyImpl
|
||||
},
|
||||
YTLPToken: {
|
||||
proxy: ytLPAddress,
|
||||
implementation: ytLPImpl
|
||||
},
|
||||
YTPriceFeed: {
|
||||
proxy: priceFeedAddress,
|
||||
implementation: priceFeedImpl
|
||||
},
|
||||
YTVault: {
|
||||
proxy: vaultAddress,
|
||||
implementation: vaultImpl
|
||||
},
|
||||
YTPoolManager: {
|
||||
proxy: poolManagerAddress,
|
||||
implementation: poolManagerImpl
|
||||
},
|
||||
YTRewardRouter: {
|
||||
proxy: routerAddress,
|
||||
implementation: routerImpl
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
"./deployments-ytlp.json",
|
||||
JSON.stringify(deploymentInfo, null, 2)
|
||||
);
|
||||
console.log("\n✅ 部署信息已保存到 deployments-ytlp.json");
|
||||
console.log("\n⚠️ 注意: 合约已部署但未配置,请运行 configureYTLp.ts 进行配置");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
99
scripts/deploy/03-deployAsset.ts
Normal file
99
scripts/deploy/03-deployAsset.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { ethers, upgrades } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
/**
|
||||
* 部署YTAssetFactory和YTAssetVault系统
|
||||
*/
|
||||
async function main() {
|
||||
console.log("开始部署YT Asset Vault系统...\n");
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("部署账户:", deployer.address);
|
||||
console.log("账户余额:", ethers.formatEther(await ethers.provider.getBalance(deployer.address)), "ETH\n");
|
||||
|
||||
// WUSD地址(需要提前部署或使用已知地址)
|
||||
// const WUSD_ADDRESS = "0x7Cd017ca5ddb86861FA983a34b5F495C6F898c41";
|
||||
if (!fs.existsSync("./deployments-wusd.json")) {
|
||||
throw new Error("未找到 deployments-wusd.json,请先运行 deployWUSD.ts");
|
||||
}
|
||||
|
||||
const wusdDeployment = JSON.parse(fs.readFileSync("./deployments-wusd.json", "utf8"));
|
||||
const WUSD_ADDRESS = wusdDeployment.contracts.WUSD.proxy;
|
||||
|
||||
// ===== 1. 部署YTAssetVault实现合约 =====
|
||||
console.log("===== 1. 部署YTAssetVault实现合约 =====");
|
||||
const YTAssetVault = await ethers.getContractFactory("YTAssetVault");
|
||||
console.log("部署YTAssetVault实现...");
|
||||
const vaultImpl = await YTAssetVault.deploy();
|
||||
await vaultImpl.waitForDeployment();
|
||||
const vaultImplAddress = await vaultImpl.getAddress();
|
||||
console.log("✅ YTAssetVault实现部署到:", vaultImplAddress);
|
||||
|
||||
// ===== 2. 部署YTAssetFactory(可升级) =====
|
||||
console.log("\n===== 2. 部署YTAssetFactory(可升级) =====");
|
||||
const YTAssetFactory = await ethers.getContractFactory("YTAssetFactory");
|
||||
|
||||
// 默认硬顶: 1000万
|
||||
const defaultHardCap = ethers.parseEther("10000000");
|
||||
|
||||
console.log("部署YTAssetFactory代理...");
|
||||
const vaultFactory = await upgrades.deployProxy(
|
||||
YTAssetFactory,
|
||||
[vaultImplAddress, defaultHardCap],
|
||||
{
|
||||
initializer: "initialize",
|
||||
kind: "uups",
|
||||
}
|
||||
);
|
||||
await vaultFactory.waitForDeployment();
|
||||
const vaultFactoryAddress = await vaultFactory.getAddress();
|
||||
console.log("✅ YTAssetFactory部署到:", vaultFactoryAddress);
|
||||
|
||||
const vaultFactoryImplAddress = await upgrades.erc1967.getImplementationAddress(vaultFactoryAddress);
|
||||
console.log("✅ YTAssetFactory实现:", vaultFactoryImplAddress);
|
||||
|
||||
// ===== 3. 显示部署摘要 =====
|
||||
console.log("\n===== 部署摘要 =====");
|
||||
console.log("WUSD地址: ", WUSD_ADDRESS);
|
||||
console.log("YTAssetVault实现: ", vaultImplAddress);
|
||||
console.log("YTAssetFactory代理: ", vaultFactoryAddress);
|
||||
console.log("YTAssetFactory实现: ", vaultFactoryImplAddress);
|
||||
console.log("默认硬顶: ", ethers.formatEther(defaultHardCap), "tokens");
|
||||
|
||||
// 保存到JSON文件
|
||||
const deploymentInfo = {
|
||||
network: (await ethers.provider.getNetwork()).name,
|
||||
chainId: (await ethers.provider.getNetwork()).chainId.toString(),
|
||||
deployer: deployer.address,
|
||||
timestamp: new Date().toISOString(),
|
||||
wusdAddress: WUSD_ADDRESS,
|
||||
defaultHardCap: defaultHardCap.toString(),
|
||||
contracts: {
|
||||
YTAssetVault: {
|
||||
implementation: vaultImplAddress
|
||||
},
|
||||
YTAssetFactory: {
|
||||
proxy: vaultFactoryAddress,
|
||||
implementation: vaultFactoryImplAddress
|
||||
}
|
||||
},
|
||||
vaults: [] // 创建的vault将被添加到这里
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
"./deployments-vault-system.json",
|
||||
JSON.stringify(deploymentInfo, null, 2)
|
||||
);
|
||||
console.log("\n✅ 部署信息已保存到 deployments-vault-system.json");
|
||||
|
||||
console.log("\n💡 下一步:");
|
||||
console.log("1. 使用 createVault.ts 创建YTAssetVault代币");
|
||||
console.log("2. 在YTLp系统中将创建的vault添加到白名单");
|
||||
console.log("3. 为vault设置价格和其他参数");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
159
scripts/deploy/04-createVault.ts
Normal file
159
scripts/deploy/04-createVault.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { ethers } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
|
||||
/**
|
||||
* 通过YTAssetFactory创建YTAssetVault
|
||||
*/
|
||||
async function main() {
|
||||
console.log("开始创建YTAssetVault...\n");
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("操作账户:", deployer.address);
|
||||
|
||||
// ==================== 1. 读取Factory地址 ====================
|
||||
console.log("\n===== 1. 读取Factory地址 =====");
|
||||
|
||||
if (!fs.existsSync("./deployments-vault-system.json")) {
|
||||
throw new Error("未找到 deployments-vault-system.json,请先运行 deployAsset.ts");
|
||||
}
|
||||
|
||||
const vaultDeployment = JSON.parse(fs.readFileSync("./deployments-vault-system.json", "utf8"));
|
||||
const factoryAddress = vaultDeployment.contracts.YTAssetFactory.proxy;
|
||||
const wusdAddress = vaultDeployment.wusdAddress;
|
||||
|
||||
console.log("YTAssetFactory:", factoryAddress);
|
||||
console.log("WUSD地址:", wusdAddress);
|
||||
|
||||
const factory = await ethers.getContractAt("YTAssetFactory", factoryAddress);
|
||||
|
||||
// 注意:YTAssetVault的价格精度是1e30
|
||||
const PRICE_PRECISION = ethers.parseUnits("1", 30); // 1e30
|
||||
|
||||
// 可以在这里修改要创建的vault参数
|
||||
const vaultParams = [
|
||||
{
|
||||
name: "YT Token A",
|
||||
symbol: "YT-A",
|
||||
manager: deployer.address,
|
||||
hardCap: ethers.parseEther("10000000"), // 1000万
|
||||
redemptionTime: Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60, // 1年后
|
||||
initialWusdPrice: PRICE_PRECISION, // $1.00 (精度1e30)
|
||||
initialYtPrice: PRICE_PRECISION // $1.00 (精度1e30)
|
||||
},
|
||||
{
|
||||
name: "YT Token B",
|
||||
symbol: "YT-B",
|
||||
manager: deployer.address,
|
||||
hardCap: ethers.parseEther("10000000"),
|
||||
redemptionTime: Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60,
|
||||
initialWusdPrice: PRICE_PRECISION, // $1.00 (精度1e30)
|
||||
initialYtPrice: PRICE_PRECISION // $1.00 (精度1e30)
|
||||
},
|
||||
{
|
||||
name: "YT Token C",
|
||||
symbol: "YT-C",
|
||||
manager: deployer.address,
|
||||
hardCap: ethers.parseEther("10000000"),
|
||||
redemptionTime: Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60,
|
||||
initialWusdPrice: PRICE_PRECISION, // $1.00 (精度1e30)
|
||||
initialYtPrice: PRICE_PRECISION // $1.00 (精度1e30)
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== 2. 创建Vaults ====================
|
||||
console.log("\n===== 2. 创建Vaults =====");
|
||||
|
||||
const createdVaults: any[] = [];
|
||||
|
||||
for (const params of vaultParams) {
|
||||
console.log(`\n创建 ${params.name} (${params.symbol})...`);
|
||||
|
||||
// 价格已经是1e30精度,直接使用
|
||||
const wusdPrice = params.initialWusdPrice;
|
||||
const ytPrice = params.initialYtPrice;
|
||||
|
||||
const tx = await factory.createVault(
|
||||
params.name,
|
||||
params.symbol,
|
||||
params.manager,
|
||||
params.hardCap,
|
||||
wusdAddress,
|
||||
params.redemptionTime,
|
||||
wusdPrice,
|
||||
ytPrice
|
||||
);
|
||||
|
||||
const receipt = await tx.wait();
|
||||
|
||||
// 从事件中获取vault地址
|
||||
const event = receipt?.logs.find((log: any) => {
|
||||
try {
|
||||
const parsed = factory.interface.parseLog({
|
||||
topics: log.topics as string[],
|
||||
data: log.data
|
||||
});
|
||||
return parsed?.name === "VaultCreated";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (event) {
|
||||
const parsed = factory.interface.parseLog({
|
||||
topics: event.topics as string[],
|
||||
data: event.data
|
||||
});
|
||||
const vaultAddress = parsed?.args[0];
|
||||
const index = parsed?.args[5];
|
||||
|
||||
console.log(" ✅ Vault地址:", vaultAddress);
|
||||
console.log(" ✅ Vault索引:", index.toString());
|
||||
|
||||
createdVaults.push({
|
||||
name: params.name,
|
||||
symbol: params.symbol,
|
||||
address: vaultAddress,
|
||||
index: index.toString(),
|
||||
manager: params.manager,
|
||||
hardCap: params.hardCap.toString(),
|
||||
redemptionTime: params.redemptionTime,
|
||||
wusdPrice: wusdPrice.toString(),
|
||||
ytPrice: ytPrice.toString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 3. 输出摘要 ====================
|
||||
console.log("\n===== 创建完成!=====");
|
||||
console.log("\n📋 创建的Vaults:");
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
createdVaults.forEach((vault, i) => {
|
||||
console.log(`${i + 1}. ${vault.name} (${vault.symbol})`);
|
||||
console.log(` 地址: ${vault.address}`);
|
||||
console.log(` 索引: ${vault.index}`);
|
||||
});
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
|
||||
// 更新部署文件,添加创建的vaults
|
||||
vaultDeployment.vaults = createdVaults;
|
||||
vaultDeployment.lastUpdate = new Date().toISOString();
|
||||
|
||||
fs.writeFileSync(
|
||||
"./deployments-vault-system.json",
|
||||
JSON.stringify(vaultDeployment, null, 2)
|
||||
);
|
||||
console.log("\n✅ Vault信息已保存到 deployments-vault-system.json");
|
||||
|
||||
console.log("\n💡 下一步:");
|
||||
console.log("1. 在YTLp系统中将这些vault添加到白名单");
|
||||
console.log("2. 为YTPriceFeed设置价格来源(使用第一个vault)");
|
||||
console.log("3. 为每个vault设置初始价格");
|
||||
console.log("4. 开始使用!");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
189
scripts/deploy/05-configureYTLp.ts
Normal file
189
scripts/deploy/05-configureYTLp.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import { ethers } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
|
||||
/**
|
||||
* 配置YTLp系统的权限和参数
|
||||
* 需要先运行 deployYTLp.ts 和 deployAsset.ts
|
||||
*/
|
||||
async function main() {
|
||||
console.log("开始配置YT协议...\n");
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("配置账户:", deployer.address);
|
||||
console.log("账户余额:", ethers.formatEther(await ethers.provider.getBalance(deployer.address)), "ETH\n");
|
||||
|
||||
// ==================== 1. 读取部署地址 ====================
|
||||
console.log("===== 1. 读取部署地址 =====");
|
||||
|
||||
// 读取YTLp系统部署信息
|
||||
const ytlpDeployment = JSON.parse(fs.readFileSync("./deployments-ytlp.json", "utf8"));
|
||||
const usdyAddress = ytlpDeployment.contracts.USDY.proxy;
|
||||
const ytLPAddress = ytlpDeployment.contracts.YTLPToken.proxy;
|
||||
const priceFeedAddress = ytlpDeployment.contracts.YTPriceFeed.proxy;
|
||||
const vaultAddress = ytlpDeployment.contracts.YTVault.proxy;
|
||||
const poolManagerAddress = ytlpDeployment.contracts.YTPoolManager.proxy;
|
||||
const routerAddress = ytlpDeployment.contracts.YTRewardRouter.proxy;
|
||||
|
||||
console.log("USDY: ", usdyAddress);
|
||||
console.log("YTLPToken: ", ytLPAddress);
|
||||
console.log("YTPriceFeed: ", priceFeedAddress);
|
||||
console.log("YTVault: ", vaultAddress);
|
||||
console.log("YTPoolManager: ", poolManagerAddress);
|
||||
console.log("YTRewardRouter: ", routerAddress);
|
||||
|
||||
// 读取YTAssetFactory部署信息(可选)
|
||||
let factoryAddress: string | undefined;
|
||||
let firstVaultAddress: string | undefined;
|
||||
|
||||
if (fs.existsSync("./deployments-vault-system.json")) {
|
||||
const vaultDeployment = JSON.parse(fs.readFileSync("./deployments-vault-system.json", "utf8"));
|
||||
factoryAddress = vaultDeployment.contracts.YTAssetFactory.proxy;
|
||||
console.log("YTAssetFactory: ", factoryAddress);
|
||||
|
||||
// 如果有创建的vault,读取第一个作为wusdPriceSource
|
||||
if (vaultDeployment.vaults && vaultDeployment.vaults.length > 0) {
|
||||
firstVaultAddress = vaultDeployment.vaults[0].address;
|
||||
console.log("第一个Vault: ", firstVaultAddress);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取合约实例
|
||||
const usdy = await ethers.getContractAt("USDY", usdyAddress);
|
||||
const ytLP = await ethers.getContractAt("YTLPToken", ytLPAddress);
|
||||
const priceFeed = await ethers.getContractAt("YTPriceFeed", priceFeedAddress);
|
||||
const vault = await ethers.getContractAt("YTVault", vaultAddress);
|
||||
const poolManager = await ethers.getContractAt("YTPoolManager", poolManagerAddress);
|
||||
|
||||
// ==================== 2. 配置权限 ====================
|
||||
console.log("\n===== 2. 配置权限 =====");
|
||||
|
||||
// 配置USDY权限
|
||||
console.log("配置USDY vault权限...");
|
||||
await usdy.addVault(vaultAddress);
|
||||
console.log(" ✅ 添加YTVault");
|
||||
await usdy.addVault(poolManagerAddress);
|
||||
console.log(" ✅ 添加YTPoolManager");
|
||||
|
||||
// 配置YTLPToken权限
|
||||
console.log("配置YTLPToken minter权限...");
|
||||
await ytLP.setMinter(poolManagerAddress, true);
|
||||
console.log(" ✅ 设置YTPoolManager为minter");
|
||||
|
||||
// 配置Vault权限
|
||||
console.log("配置YTVault权限...");
|
||||
await vault.setPoolManager(poolManagerAddress);
|
||||
console.log(" ✅ 设置PoolManager");
|
||||
await vault.setSwapper(routerAddress, true);
|
||||
console.log(" ✅ 添加Router为swapper");
|
||||
|
||||
// 配置PoolManager权限
|
||||
console.log("配置YTPoolManager handler权限...");
|
||||
await poolManager.setHandler(routerAddress, true);
|
||||
console.log(" ✅ 添加Router为handler");
|
||||
|
||||
// ==================== 3. 配置YTPriceFeed ====================
|
||||
console.log("\n===== 3. 配置YTPriceFeed =====");
|
||||
|
||||
// 设置WUSD价格来源(如果有YTAssetVault)
|
||||
if (firstVaultAddress) {
|
||||
console.log("设置WUSD价格来源...");
|
||||
await priceFeed.setWusdPriceSource(firstVaultAddress);
|
||||
console.log(" ✅ WUSD价格来源:", firstVaultAddress);
|
||||
} else {
|
||||
console.log(" ⚠️ 未找到YTAssetVault,跳过WUSD价格来源设置");
|
||||
console.log(" 💡 提示: 请在创建YTAssetVault后,手动调用 priceFeed.setWusdPriceSource()");
|
||||
}
|
||||
|
||||
// 设置keeper权限(默认设置deployer为keeper)
|
||||
console.log("设置Keeper权限...");
|
||||
await priceFeed.setKeeper(deployer.address, true);
|
||||
console.log(" ✅ 添加Keeper:", deployer.address);
|
||||
|
||||
// 设置价格保护参数
|
||||
console.log("设置价格保护参数...");
|
||||
const maxPriceChangeBps = 500; // 5%
|
||||
await priceFeed.setMaxPriceChangeBps(maxPriceChangeBps);
|
||||
console.log(" ✅ 最大价格变动:", maxPriceChangeBps / 100, "%");
|
||||
|
||||
// ==================== 4. 配置YTVault参数 ====================
|
||||
console.log("\n===== 4. 配置YTVault参数 =====");
|
||||
|
||||
// 设置动态费率(初始关闭)
|
||||
console.log("设置动态费率...");
|
||||
await vault.setDynamicFees(true);
|
||||
console.log(" ✅ 动态费率: 开启");
|
||||
|
||||
// 设置最大滑点
|
||||
console.log("设置最大滑点...");
|
||||
const maxSwapSlippageBps = 1000; // 10%
|
||||
await vault.setMaxSwapSlippageBps(maxSwapSlippageBps);
|
||||
console.log(" ✅ 最大滑点:", maxSwapSlippageBps / 100, "%");
|
||||
|
||||
// ==================== 5. 配置YTPoolManager参数 ====================
|
||||
console.log("\n===== 5. 配置YTPoolManager参数 =====");
|
||||
|
||||
// ==================== 6. 输出配置摘要 ====================
|
||||
console.log("\n===== 配置完成!=====");
|
||||
console.log("\n📋 权限配置:");
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
console.log("✅ USDY vaults: YTVault, YTPoolManager");
|
||||
console.log("✅ YTLPToken minter: YTPoolManager");
|
||||
console.log("✅ YTVault poolManager: YTPoolManager");
|
||||
console.log("✅ YTVault swapper: YTRewardRouter");
|
||||
console.log("✅ YTPoolManager handler: YTRewardRouter");
|
||||
console.log("✅ YTPriceFeed keeper:", deployer.address);
|
||||
if (firstVaultAddress) {
|
||||
console.log("✅ YTPriceFeed wusdPriceSource:", firstVaultAddress);
|
||||
}
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
|
||||
console.log("\n📋 参数配置:");
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
console.log("✅ 动态费率: 开启");
|
||||
console.log("✅ 最大滑点:", maxSwapSlippageBps / 100, "%");
|
||||
console.log("✅ 最大价格变动:", maxPriceChangeBps / 100, "%");
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
|
||||
// 保存配置信息
|
||||
const configInfo = {
|
||||
network: (await ethers.provider.getNetwork()).name,
|
||||
chainId: (await ethers.provider.getNetwork()).chainId.toString(),
|
||||
configurer: deployer.address,
|
||||
timestamp: new Date().toISOString(),
|
||||
configuration: {
|
||||
permissions: {
|
||||
usdyVaults: [vaultAddress, poolManagerAddress],
|
||||
ytlpMinters: [poolManagerAddress],
|
||||
vaultPoolManager: poolManagerAddress,
|
||||
vaultSwappers: [routerAddress],
|
||||
poolManagerHandlers: [routerAddress],
|
||||
priceFeedKeepers: [deployer.address],
|
||||
priceFeedWusdSource: firstVaultAddress || "未设置"
|
||||
},
|
||||
parameters: {
|
||||
dynamicFees: true,
|
||||
maxSwapSlippageBps,
|
||||
maxPriceChangeBps
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
"./deployments-ytlp-config.json",
|
||||
JSON.stringify(configInfo, null, 2)
|
||||
);
|
||||
console.log("\n✅ 配置信息已保存到 deployments-ytlp-config.json");
|
||||
|
||||
console.log("\n💡 下一步:");
|
||||
console.log("1. 通过YTAssetFactory创建YTAssetVault代币");
|
||||
console.log("2. 将YTAssetVault添加到YTVault的白名单");
|
||||
console.log("3. 为YTAssetVault设置价格");
|
||||
console.log("4. 开始使用协议!");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
169
scripts/deploy/06-addVaultToWhitelist.ts
Normal file
169
scripts/deploy/06-addVaultToWhitelist.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import { ethers } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
|
||||
/**
|
||||
* 将YTAssetVault添加到YTVault白名单并设置价格
|
||||
*/
|
||||
async function main() {
|
||||
console.log("开始添加Vault到白名单...\n");
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("操作账户:", deployer.address);
|
||||
|
||||
// ==================== 1. 读取部署地址 ====================
|
||||
console.log("\n===== 1. 读取部署地址 =====");
|
||||
|
||||
// 读取YTLp系统部署信息
|
||||
const ytlpDeployment = JSON.parse(fs.readFileSync("./deployments-ytlp.json", "utf8"));
|
||||
const priceFeedAddress = ytlpDeployment.contracts.YTPriceFeed.proxy;
|
||||
const vaultAddress = ytlpDeployment.contracts.YTVault.proxy;
|
||||
|
||||
console.log("YTPriceFeed:", priceFeedAddress);
|
||||
console.log("YTVault: ", vaultAddress);
|
||||
|
||||
// 读取YTAssetFactory部署信息
|
||||
const vaultSystemDeployment = JSON.parse(fs.readFileSync("./deployments-vault-system.json", "utf8"));
|
||||
const vaults = vaultSystemDeployment.vaults;
|
||||
|
||||
if (!vaults || vaults.length === 0) {
|
||||
throw new Error("未找到YTAssetVault,请先运行 createVault.ts");
|
||||
}
|
||||
|
||||
console.log("\n找到", vaults.length, "个YTAssetVault:");
|
||||
vaults.forEach((v: any, i: number) => {
|
||||
console.log(` ${i + 1}. ${v.name} (${v.symbol}): ${v.address}`);
|
||||
});
|
||||
|
||||
// 获取合约实例
|
||||
const priceFeed = await ethers.getContractAt("YTPriceFeed", priceFeedAddress);
|
||||
const vault = await ethers.getContractAt("YTVault", vaultAddress);
|
||||
|
||||
// ==================== 2. 添加到白名单 ====================
|
||||
console.log("\n===== 2. 添加到白名单 =====");
|
||||
|
||||
// 配置参数(可根据需要调整)
|
||||
// 注意:总权重 = 4000 + 3000 + 2000 = 9000
|
||||
const whitelistParams = [
|
||||
{
|
||||
weight: 4000, // 4000/9000 = 44.44%
|
||||
maxUsdyAmount: ethers.parseEther("45000000"), // 4500万
|
||||
isStable: false
|
||||
},
|
||||
{
|
||||
weight: 3000, // 3000/9000 = 33.33%
|
||||
maxUsdyAmount: ethers.parseEther("35000000"), // 3500万
|
||||
isStable: false
|
||||
},
|
||||
{
|
||||
weight: 2000, // 2000/9000 = 22.22%
|
||||
maxUsdyAmount: ethers.parseEther("25000000"), // 2500万
|
||||
isStable: false
|
||||
}
|
||||
];
|
||||
|
||||
for (let i = 0; i < vaults.length && i < whitelistParams.length; i++) {
|
||||
const v = vaults[i];
|
||||
const params = whitelistParams[i];
|
||||
|
||||
console.log(`\n添加 ${v.name} (${v.symbol}) 到白名单...`);
|
||||
|
||||
const tx = await vault.setWhitelistedToken(
|
||||
v.address,
|
||||
18, // decimals
|
||||
params.weight,
|
||||
params.maxUsdyAmount,
|
||||
params.isStable
|
||||
);
|
||||
await tx.wait();
|
||||
|
||||
console.log(" ✅ 权重:", params.weight);
|
||||
console.log(" ✅ 最大USDY:", ethers.formatEther(params.maxUsdyAmount));
|
||||
console.log(" ✅ 是否稳定币:", params.isStable);
|
||||
}
|
||||
|
||||
// ==================== 3. 设置价格 ====================
|
||||
console.log("\n===== 3. 设置价格 =====");
|
||||
|
||||
for (const v of vaults) {
|
||||
console.log(`\n设置 ${v.name} (${v.symbol}) 价格...`);
|
||||
|
||||
// 使用vault中保存的初始价格(已经是1e30精度,直接使用)
|
||||
const price = v.ytPrice;
|
||||
|
||||
const tx = await priceFeed.forceUpdatePrice(
|
||||
v.address,
|
||||
price
|
||||
);
|
||||
await tx.wait();
|
||||
|
||||
console.log(" ✅ 价格已设置:", ethers.formatUnits(price, 30), "(精度1e30)");
|
||||
}
|
||||
|
||||
// ==================== 4. 设置WUSD价格来源 ====================
|
||||
console.log("\n===== 4. 设置WUSD价格来源 =====");
|
||||
|
||||
// 使用第一个vault作为WUSD价格来源
|
||||
const firstVault = vaults[0];
|
||||
console.log("设置WUSD价格来源为:", firstVault.name, firstVault.address);
|
||||
|
||||
const tx = await priceFeed.setWusdPriceSource(firstVault.address);
|
||||
await tx.wait();
|
||||
|
||||
console.log(" ✅ WUSD价格来源已设置");
|
||||
|
||||
// ==================== 5. 验证配置 ====================
|
||||
console.log("\n===== 5. 验证配置 =====");
|
||||
|
||||
for (const v of vaults) {
|
||||
const isWhitelisted = await vault.whitelistedTokens(v.address);
|
||||
const weight = await vault.tokenWeights(v.address);
|
||||
const price = await priceFeed.getPrice(v.address, true);
|
||||
|
||||
console.log(`\n${v.name} (${v.symbol}):`);
|
||||
console.log(" 白名单:", isWhitelisted ? "✅" : "❌");
|
||||
console.log(" 权重:", weight.toString());
|
||||
console.log(" 价格:", ethers.formatUnits(price, 30));
|
||||
}
|
||||
|
||||
const totalWeight = await vault.totalTokenWeights();
|
||||
console.log("\n总权重:", totalWeight.toString());
|
||||
|
||||
const wusdPriceSource = await priceFeed.wusdPriceSource();
|
||||
console.log("WUSD价格来源:", wusdPriceSource);
|
||||
|
||||
// ==================== 6. 输出摘要 ====================
|
||||
console.log("\n===== 配置完成!=====");
|
||||
console.log("\n✅ 已添加", vaults.length, "个vault到白名单");
|
||||
console.log("✅ 已为所有vault设置初始价格");
|
||||
console.log("✅ 已设置WUSD价格来源");
|
||||
console.log("\n💡 系统已就绪,可以开始使用!");
|
||||
|
||||
// 保存配置信息
|
||||
const configInfo = {
|
||||
timestamp: new Date().toISOString(),
|
||||
operator: deployer.address,
|
||||
whitelistedVaults: vaults.map((v: any, i: number) => ({
|
||||
name: v.name,
|
||||
symbol: v.symbol,
|
||||
address: v.address,
|
||||
weight: whitelistParams[i]?.weight || 0,
|
||||
maxUsdyAmount: whitelistParams[i]?.maxUsdyAmount.toString() || "0",
|
||||
price: v.ytPrice
|
||||
})),
|
||||
totalWeight: totalWeight.toString(),
|
||||
wusdPriceSource: wusdPriceSource
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
"./deployments-whitelist-config.json",
|
||||
JSON.stringify(configInfo, null, 2)
|
||||
);
|
||||
console.log("\n✅ 白名单配置信息已保存到 deployments-whitelist-config.json");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
118
scripts/deploy/07-deployLending.ts
Normal file
118
scripts/deploy/07-deployLending.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { ethers, upgrades } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
/**
|
||||
* 部署 Lending 借贷池系统
|
||||
* 包含:LendingFactory, Configurator, Lending 实现和代理
|
||||
*/
|
||||
async function main() {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("\n==========================================");
|
||||
console.log("📦 部署 Lending 借贷池系统");
|
||||
console.log("==========================================");
|
||||
console.log("部署账户:", deployer.address);
|
||||
console.log("账户余额:", ethers.formatEther(await ethers.provider.getBalance(deployer.address)), "ETH\n");
|
||||
|
||||
const deployments: any = {};
|
||||
|
||||
// ========== 第一阶段:部署工厂合约 ==========
|
||||
console.log("📦 Phase 1: 部署 LendingFactory...");
|
||||
const LendingFactory = await ethers.getContractFactory("LendingFactory");
|
||||
const lendingFactory = await LendingFactory.deploy();
|
||||
await lendingFactory.waitForDeployment();
|
||||
const lendingFactoryAddress = await lendingFactory.getAddress();
|
||||
console.log("✅ LendingFactory 已部署:", lendingFactoryAddress);
|
||||
deployments.lendingFactory = lendingFactoryAddress;
|
||||
|
||||
// ========== 第二阶段:部署 Configurator ==========
|
||||
console.log("\n📦 Phase 2: 部署 Configurator (UUPS 代理)...");
|
||||
const Configurator = await ethers.getContractFactory("Configurator");
|
||||
|
||||
// 使用 upgrades 插件部署 UUPS 代理
|
||||
const configurator = await upgrades.deployProxy(
|
||||
Configurator,
|
||||
[],
|
||||
{
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
}
|
||||
);
|
||||
await configurator.waitForDeployment();
|
||||
|
||||
const configuratorProxyAddress = await configurator.getAddress();
|
||||
console.log("✅ Configurator Proxy:", configuratorProxyAddress);
|
||||
deployments.configuratorProxy = configuratorProxyAddress;
|
||||
|
||||
// 获取实现合约地址
|
||||
const configuratorImplAddress = await upgrades.erc1967.getImplementationAddress(configuratorProxyAddress);
|
||||
console.log("✅ Configurator Implementation:", configuratorImplAddress);
|
||||
deployments.configuratorImpl = configuratorImplAddress;
|
||||
|
||||
console.log("✅ Configurator Owner:", await configurator.owner());
|
||||
|
||||
// ========== 第三阶段:部署 Lending 实现合约 ==========
|
||||
console.log("\n📦 Phase 3: 通过工厂部署 Lending 实现合约...");
|
||||
const deployTx = await lendingFactory.deploy();
|
||||
const deployReceipt = await deployTx.wait();
|
||||
|
||||
// 使用 logs 和 interface.parseLog 解析事件
|
||||
let lendingImplAddress;
|
||||
for (const log of deployReceipt.logs) {
|
||||
try {
|
||||
const parsedLog = lendingFactory.interface.parseLog({
|
||||
topics: [...log.topics],
|
||||
data: log.data
|
||||
});
|
||||
if (parsedLog && parsedLog.name === 'LendingDeployed') {
|
||||
lendingImplAddress = parsedLog.args.lending;
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略无法解析的日志
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("✅ Lending Implementation:", lendingImplAddress);
|
||||
deployments.lendingImpl = lendingImplAddress;
|
||||
|
||||
// ========== 第四阶段:准备部署 Lending 代理 ==========
|
||||
console.log("\n📦 Phase 4: 准备部署 Lending 代理(需要先配置参数)");
|
||||
console.log("⚠️ 请运行配置脚本 08-configureLending.ts 来完成配置和代理部署");
|
||||
|
||||
// ========== 保存部署信息 ==========
|
||||
const deploymentsPath = path.join(__dirname, "../../deployments-lending.json");
|
||||
const existingDeployments = fs.existsSync(deploymentsPath)
|
||||
? JSON.parse(fs.readFileSync(deploymentsPath, "utf-8"))
|
||||
: {};
|
||||
|
||||
const network = await ethers.provider.getNetwork();
|
||||
const chainId = network.chainId.toString();
|
||||
existingDeployments[chainId] = {
|
||||
...existingDeployments[chainId],
|
||||
...deployments,
|
||||
timestamp: new Date().toISOString(),
|
||||
deployer: deployer.address
|
||||
};
|
||||
|
||||
fs.writeFileSync(deploymentsPath, JSON.stringify(existingDeployments, null, 2));
|
||||
console.log("\n💾 部署信息已保存到:", deploymentsPath);
|
||||
|
||||
// ========== 部署总结 ==========
|
||||
console.log("\n🎉 部署总结:");
|
||||
console.log("=====================================");
|
||||
console.log("LendingFactory: ", deployments.lendingFactory);
|
||||
console.log("Configurator (Proxy): ", deployments.configuratorProxy);
|
||||
console.log("Configurator (Impl): ", deployments.configuratorImpl);
|
||||
console.log("Lending (Impl): ", deployments.lendingImpl);
|
||||
console.log("=====================================\n");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
197
scripts/deploy/08-configureLending.ts
Normal file
197
scripts/deploy/08-configureLending.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
import { ethers, upgrades } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
/**
|
||||
* 配置 Lending 借贷池参数并部署代理
|
||||
* 包含:设置工厂、配置市场参数、添加抵押资产、部署 Lending 代理
|
||||
*/
|
||||
async function main() {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("\n==========================================");
|
||||
console.log("⚙️ 配置 Lending 借贷池");
|
||||
console.log("==========================================");
|
||||
console.log("配置账户:", deployer.address, "\n");
|
||||
|
||||
// ========== 读取部署信息 ==========
|
||||
const deploymentsPath = path.join(__dirname, "../../deployments-lending.json");
|
||||
if (!fs.existsSync(deploymentsPath)) {
|
||||
throw new Error("未找到部署信息文件,请先运行 07-deployLending.ts");
|
||||
}
|
||||
|
||||
const network = await ethers.provider.getNetwork();
|
||||
const chainId = network.chainId.toString();
|
||||
const deployments = JSON.parse(fs.readFileSync(deploymentsPath, "utf-8"))[chainId];
|
||||
|
||||
if (!deployments) {
|
||||
throw new Error(`未找到网络 ${chainId} 的部署信息`);
|
||||
}
|
||||
|
||||
console.log("📋 使用已部署的合约:");
|
||||
console.log(" LendingFactory:", deployments.lendingFactory);
|
||||
console.log(" Configurator:", deployments.configuratorProxy);
|
||||
console.log(" Lending Impl:", deployments.lendingImpl, "\n");
|
||||
|
||||
const configurator = await ethers.getContractAt("Configurator", deployments.configuratorProxy);
|
||||
const lendingFactory = await ethers.getContractAt("LendingFactory", deployments.lendingFactory);
|
||||
|
||||
// ========== 第一阶段:配置外部代币和价格源 ==========
|
||||
console.log("⚙️ Phase 1: 配置外部代币和价格源");
|
||||
|
||||
// 这里使用示例地址,实际部署时需要替换为真实地址
|
||||
// 如果你已有 WUSD 等合约,请从部署文件中读取
|
||||
const USDC = {
|
||||
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // Mainnet USDC (示例)
|
||||
decimals: 6
|
||||
};
|
||||
|
||||
const WETH = {
|
||||
address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // Mainnet WETH (示例)
|
||||
decimals: 18
|
||||
};
|
||||
|
||||
// 价格预言机地址(需要部署或使用 Chainlink)
|
||||
const usdcPriceFeed = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"; // Chainlink USDC/USD (示例)
|
||||
const ethPriceFeed = "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"; // Chainlink ETH/USD (示例)
|
||||
|
||||
console.log(" 基础资产 (USDC):", USDC.address);
|
||||
console.log(" 抵押资产 (WETH):", WETH.address);
|
||||
console.log(" USDC 价格源:", usdcPriceFeed);
|
||||
console.log(" ETH 价格源:", ethPriceFeed, "\n");
|
||||
|
||||
// ========== 第二阶段:准备配置参数 ==========
|
||||
console.log("⚙️ Phase 2: 准备市场配置参数");
|
||||
|
||||
// 使用占位符地址作为 Lending 代理地址
|
||||
const LENDING_PROXY_PLACEHOLDER = ethers.ZeroAddress;
|
||||
|
||||
const configuration = {
|
||||
baseToken: USDC.address,
|
||||
baseTokenPriceFeed: usdcPriceFeed,
|
||||
|
||||
// 利率模型参数(年化利率,18位精度)
|
||||
// 注意:这些年化利率会在 initialize 时自动转换为每秒利率
|
||||
// 转换公式:perSecondRate = perYearRate / 31,536,000
|
||||
supplyKink: ethers.parseUnits("0.8", 18), // 80% 利用率拐点
|
||||
supplyPerYearInterestRateSlopeLow: ethers.parseUnits("0.03", 18), // 3% APY
|
||||
supplyPerYearInterestRateSlopeHigh: ethers.parseUnits("0.4", 18), // 40% APY
|
||||
supplyPerYearInterestRateBase: ethers.parseUnits("0", 18), // 0% 基础
|
||||
|
||||
borrowKink: ethers.parseUnits("0.8", 18), // 80% 利用率拐点
|
||||
borrowPerYearInterestRateSlopeLow: ethers.parseUnits("0.05", 18), // 5% APY
|
||||
borrowPerYearInterestRateSlopeHigh: ethers.parseUnits("1.5", 18), // 150% APY
|
||||
borrowPerYearInterestRateBase: ethers.parseUnits("0.015", 18), // 1.5% 基础
|
||||
|
||||
storeFrontPriceFactor: ethers.parseUnits("0.5", 18), // 50% 清算折扣
|
||||
trackingIndexScale: ethers.parseUnits("1", 15), // 10^15 比例
|
||||
baseBorrowMin: ethers.parseUnits("100", USDC.decimals), // 最小借 100 USDC
|
||||
targetReserves: ethers.parseUnits("5000000", USDC.decimals), // 目标储备 500 万
|
||||
|
||||
assetConfigs: [
|
||||
{
|
||||
asset: WETH.address,
|
||||
priceFeed: ethPriceFeed,
|
||||
decimals: WETH.decimals,
|
||||
borrowCollateralFactor: ethers.parseUnits("0.80", 18), // 80% LTV
|
||||
liquidateCollateralFactor: ethers.parseUnits("0.85", 18), // 85% 清算线
|
||||
liquidationFactor: ethers.parseUnits("0.95", 18), // 95% (配合 storeFrontPriceFactor 产生折扣)
|
||||
supplyCap: ethers.parseUnits("100000", WETH.decimals) // 最多 10 万 ETH
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
console.log("✅ 配置参数已准备\n");
|
||||
|
||||
// ========== 第三阶段:设置工厂和配置 ==========
|
||||
console.log("⚙️ Phase 3: 设置工厂和配置参数");
|
||||
|
||||
console.log(" 设置工厂合约...");
|
||||
const setFactoryTx = await configurator.setFactory(LENDING_PROXY_PLACEHOLDER, deployments.lendingFactory);
|
||||
await setFactoryTx.wait();
|
||||
console.log(" ✅ 工厂已设置");
|
||||
|
||||
console.log(" 设置市场配置...");
|
||||
const setConfigTx = await configurator.setConfiguration(LENDING_PROXY_PLACEHOLDER, configuration);
|
||||
await setConfigTx.wait();
|
||||
console.log(" ✅ 配置已设置\n");
|
||||
|
||||
// ========== 第四阶段:部署 Lending 代理 ==========
|
||||
console.log("⚙️ Phase 4: 部署 Lending 代理");
|
||||
|
||||
console.log(" 获取配置信息...");
|
||||
const config = await configurator.getConfiguration(LENDING_PROXY_PLACEHOLDER);
|
||||
|
||||
console.log(" 部署 Lending 代理...");
|
||||
const Lending = await ethers.getContractFactory("Lending");
|
||||
|
||||
// 使用 upgrades 插件部署 UUPS 代理
|
||||
const lending = await upgrades.deployProxy(
|
||||
Lending,
|
||||
[config],
|
||||
{
|
||||
kind: "uups",
|
||||
initializer: "initialize"
|
||||
}
|
||||
);
|
||||
await lending.waitForDeployment();
|
||||
const lendingProxyAddress = await lending.getAddress();
|
||||
console.log(" ✅ Lending Proxy 已部署:", lendingProxyAddress);
|
||||
|
||||
// 获取实现合约地址(验证)
|
||||
const lendingImplAddress = await upgrades.erc1967.getImplementationAddress(lendingProxyAddress);
|
||||
console.log(" ✅ Lending Implementation (验证):", lendingImplAddress, "\n");
|
||||
|
||||
// ========== 第五阶段:验证部署 ==========
|
||||
console.log("✨ Phase 5: 验证部署");
|
||||
console.log(" Lending Owner:", await lending.owner());
|
||||
console.log(" Lending Paused:", await lending.paused());
|
||||
console.log(" Base Token:", await lending.baseToken());
|
||||
console.log(" Total Supply:", ethers.formatUnits(await lending.totalSupply(), USDC.decimals));
|
||||
console.log(" Total Borrow:", ethers.formatUnits(await lending.totalBorrow(), USDC.decimals));
|
||||
|
||||
const supplyRate = await lending.getSupplyRate();
|
||||
const borrowRate = await lending.getBorrowRate();
|
||||
// 注意:返回的是每秒利率,需要乘以一年的秒数得到 APY
|
||||
const SECONDS_PER_YEAR = 365 * 24 * 60 * 60;
|
||||
console.log(" Supply Rate (per second):", ethers.formatUnits(supplyRate, 18));
|
||||
console.log(" Supply APY:", ethers.formatUnits(BigInt(supplyRate) * BigInt(SECONDS_PER_YEAR), 18));
|
||||
console.log(" Borrow Rate (per second):", ethers.formatUnits(borrowRate, 18));
|
||||
console.log(" Borrow APY:", ethers.formatUnits(BigInt(borrowRate) * BigInt(SECONDS_PER_YEAR), 18), "\n");
|
||||
|
||||
// ========== 保存部署信息 ==========
|
||||
deployments.lendingProxy = lendingProxyAddress;
|
||||
deployments.configTimestamp = new Date().toISOString();
|
||||
|
||||
const allDeployments = JSON.parse(fs.readFileSync(deploymentsPath, "utf-8"));
|
||||
allDeployments[chainId] = deployments;
|
||||
fs.writeFileSync(deploymentsPath, JSON.stringify(allDeployments, null, 2));
|
||||
|
||||
console.log("💾 配置信息已保存到:", deploymentsPath);
|
||||
|
||||
// ========== 配置总结 ==========
|
||||
console.log("\n🎉 配置总结:");
|
||||
console.log("=====================================");
|
||||
console.log("Lending Proxy: ", lendingProxyAddress);
|
||||
console.log("Base Token: ", USDC.address);
|
||||
console.log("Collateral Assets: ", configuration.assetConfigs.length);
|
||||
console.log("Supply Kink: ", "80%");
|
||||
console.log("Borrow Kink: ", "80%");
|
||||
console.log("Min Borrow: ", "100 USDC");
|
||||
console.log("=====================================\n");
|
||||
|
||||
console.log("✅ Lending 借贷池已完全配置完成!");
|
||||
console.log("📝 后续步骤:");
|
||||
console.log(" 1. 用户可以调用 supply() 存入 USDC");
|
||||
console.log(" 2. 用户可以调用 supplyCollateral() 存入 WETH");
|
||||
console.log(" 3. 用户可以调用 borrow() 借出 USDC");
|
||||
console.log(" 4. 清算人可以调用 absorb() 清算不良贷款");
|
||||
console.log(" 5. 清算人可以调用 buyCollateral() 购买清算抵押品\n");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
156
scripts/deploy/09-upgradeLending.ts
Normal file
156
scripts/deploy/09-upgradeLending.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { ethers, upgrades } from "hardhat";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
/**
|
||||
* 升级 Lending 或 Configurator 合约
|
||||
* 使用 upgrades.upgradeProxy() 进行 UUPS 升级
|
||||
*/
|
||||
async function main() {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log("\n==========================================");
|
||||
console.log("🔄 升级 Lending 借贷池系统");
|
||||
console.log("==========================================");
|
||||
console.log("升级账户:", deployer.address);
|
||||
console.log("账户余额:", ethers.formatEther(await ethers.provider.getBalance(deployer.address)), "ETH\n");
|
||||
|
||||
// ========== 读取部署信息 ==========
|
||||
const deploymentsPath = path.join(__dirname, "../../deployments-lending.json");
|
||||
if (!fs.existsSync(deploymentsPath)) {
|
||||
throw new Error("未找到部署信息文件,请先运行部署脚本");
|
||||
}
|
||||
|
||||
const network = await ethers.provider.getNetwork();
|
||||
const chainId = network.chainId.toString();
|
||||
const deployments = JSON.parse(fs.readFileSync(deploymentsPath, "utf-8"))[chainId];
|
||||
|
||||
if (!deployments) {
|
||||
throw new Error(`未找到网络 ${chainId} 的部署信息`);
|
||||
}
|
||||
|
||||
console.log("📋 当前部署的合约:");
|
||||
console.log(" Configurator Proxy:", deployments.configuratorProxy);
|
||||
console.log(" Configurator Impl:", deployments.configuratorImpl);
|
||||
console.log(" Lending Proxy:", deployments.lendingProxy);
|
||||
console.log(" Lending Impl:", deployments.lendingImpl, "\n");
|
||||
|
||||
// ========== 选择要升级的合约 ==========
|
||||
// 修改这里来选择升级 Lending 或 Configurator
|
||||
const UPGRADE_LENDING = true; // true = 升级 Lending, false = 升级 Configurator
|
||||
|
||||
if (UPGRADE_LENDING) {
|
||||
// ========== 升级 Lending ==========
|
||||
console.log("🔄 Phase 1: 升级 Lending 合约");
|
||||
|
||||
if (!deployments.lendingProxy) {
|
||||
throw new Error("未找到 Lending Proxy 地址,请先运行配置脚本");
|
||||
}
|
||||
|
||||
console.log(" 当前 Lending Proxy:", deployments.lendingProxy);
|
||||
console.log(" 当前 Lending Implementation:", deployments.lendingImpl);
|
||||
|
||||
// 获取新的 Lending 合约工厂
|
||||
// 注意:如果你有 LendingV2,请替换为 "LendingV2"
|
||||
const LendingV2 = await ethers.getContractFactory("Lending");
|
||||
|
||||
console.log("\n 正在验证新实现合约...");
|
||||
// upgrades.upgradeProxy 会自动验证存储布局兼容性
|
||||
const upgradedLending = await upgrades.upgradeProxy(
|
||||
deployments.lendingProxy,
|
||||
LendingV2,
|
||||
{
|
||||
kind: "uups"
|
||||
}
|
||||
);
|
||||
await upgradedLending.waitForDeployment();
|
||||
|
||||
console.log(" ✅ Lending 已升级!");
|
||||
|
||||
// 获取新的实现合约地址
|
||||
const upgradedLendingAddress = await upgradedLending.getAddress();
|
||||
const newLendingImplAddress = await upgrades.erc1967.getImplementationAddress(upgradedLendingAddress);
|
||||
console.log(" 新 Lending Implementation:", newLendingImplAddress);
|
||||
|
||||
// 验证升级
|
||||
console.log("\n 验证升级结果:");
|
||||
console.log(" Lending Proxy (不变):", upgradedLendingAddress);
|
||||
console.log(" Owner:", await upgradedLending.owner());
|
||||
console.log(" Base Token:", await upgradedLending.baseToken());
|
||||
|
||||
// 保存新的实现地址
|
||||
deployments.lendingImpl = newLendingImplAddress;
|
||||
deployments.lendingUpgradeTimestamp = new Date().toISOString();
|
||||
|
||||
} else {
|
||||
// ========== 升级 Configurator ==========
|
||||
console.log("🔄 Phase 1: 升级 Configurator 合约");
|
||||
|
||||
console.log(" 当前 Configurator Proxy:", deployments.configuratorProxy);
|
||||
console.log(" 当前 Configurator Implementation:", deployments.configuratorImpl);
|
||||
|
||||
// 获取新的 Configurator 合约工厂
|
||||
// 注意:如果你有 ConfiguratorV2,请替换为 "ConfiguratorV2"
|
||||
const ConfiguratorV2 = await ethers.getContractFactory("Configurator");
|
||||
|
||||
console.log("\n 正在验证新实现合约...");
|
||||
const upgradedConfigurator = await upgrades.upgradeProxy(
|
||||
deployments.configuratorProxy,
|
||||
ConfiguratorV2,
|
||||
{
|
||||
kind: "uups"
|
||||
}
|
||||
);
|
||||
await upgradedConfigurator.waitForDeployment();
|
||||
|
||||
console.log(" ✅ Configurator 已升级!");
|
||||
|
||||
// 获取新的实现合约地址
|
||||
const upgradedConfiguratorAddress = await upgradedConfigurator.getAddress();
|
||||
const newConfiguratorImplAddress = await upgrades.erc1967.getImplementationAddress(upgradedConfiguratorAddress);
|
||||
console.log(" 新 Configurator Implementation:", newConfiguratorImplAddress);
|
||||
|
||||
// 验证升级
|
||||
console.log("\n 验证升级结果:");
|
||||
console.log(" Configurator Proxy (不变):", upgradedConfiguratorAddress);
|
||||
console.log(" Owner:", await upgradedConfigurator.owner());
|
||||
|
||||
// 保存新的实现地址
|
||||
deployments.configuratorImpl = newConfiguratorImplAddress;
|
||||
deployments.configuratorUpgradeTimestamp = new Date().toISOString();
|
||||
}
|
||||
|
||||
// ========== 保存部署信息 ==========
|
||||
const allDeployments = JSON.parse(fs.readFileSync(deploymentsPath, "utf-8"));
|
||||
allDeployments[chainId] = deployments;
|
||||
fs.writeFileSync(deploymentsPath, JSON.stringify(allDeployments, null, 2));
|
||||
|
||||
console.log("\n💾 升级信息已保存到:", deploymentsPath);
|
||||
|
||||
// ========== 升级总结 ==========
|
||||
console.log("\n🎉 升级总结:");
|
||||
console.log("=====================================");
|
||||
if (UPGRADE_LENDING) {
|
||||
console.log("升级合约: Lending");
|
||||
console.log("Lending Proxy: ", deployments.lendingProxy);
|
||||
console.log("新 Lending Implementation:", deployments.lendingImpl);
|
||||
} else {
|
||||
console.log("升级合约: Configurator");
|
||||
console.log("Configurator Proxy: ", deployments.configuratorProxy);
|
||||
console.log("新 Configurator Impl: ", deployments.configuratorImpl);
|
||||
}
|
||||
console.log("=====================================\n");
|
||||
|
||||
console.log("✅ 升级完成!");
|
||||
console.log("⚠️ 重要提示:");
|
||||
console.log(" 1. 代理地址保持不变,用户无需更改合约地址");
|
||||
console.log(" 2. 所有状态数据已保留");
|
||||
console.log(" 3. 建议在测试网充分测试后再升级主网\n");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
25
scripts/test.s.sol
Normal file
25
scripts/test.s.sol
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "forge-std/console.sol";
|
||||
|
||||
contract TestFun is Script {
|
||||
function run() external {
|
||||
|
||||
address from = 0xa013422A5918CD099C63c8CC35283EACa99a705d;
|
||||
address to = 0x51eEF57eC57c867AC23945f0ce21aA5A9a2C246c;
|
||||
|
||||
bytes memory data = hex"925a9aef0000000000000000000000005d91fd16fa85547b0784c377a47bf7706d7875d3000000000000000000000000333805c9ee75f59aa2cc79dfde2499f920c7b408000000000000000000000000000000000000000000000001c9f78d2893e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a013422a5918cd099c63c8cc35283eaca99a705d";
|
||||
|
||||
vm.startPrank(from);
|
||||
|
||||
(bool ok, bytes memory ret) = to.call(data);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
console.log("Call success:", ok);
|
||||
console.logBytes(ret);
|
||||
|
||||
}
|
||||
}
|
||||
46
scripts/utils/generateCalldata.ts
Normal file
46
scripts/utils/generateCalldata.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
async function generateSetAllowedBrokerCalldata() {
|
||||
// 合约地址
|
||||
const vaultAddress = "0x82b6b970711C07FE98Fa60C9d80f1be5B9fa32FF";
|
||||
|
||||
// 参数
|
||||
const brokerHash = "0xad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5";
|
||||
const allowed = true; // 添加 broker
|
||||
|
||||
// 定义函数的 ABI
|
||||
const functionAbi = [
|
||||
"function setAllowedBroker(bytes32 _brokerHash, bool _allowed)"
|
||||
];
|
||||
|
||||
// 创建 Interface 实例
|
||||
const iface = new ethers.Interface(functionAbi);
|
||||
|
||||
// 编码函数调用数据
|
||||
const calldata = iface.encodeFunctionData("setAllowedBroker", [
|
||||
brokerHash,
|
||||
allowed
|
||||
]);
|
||||
|
||||
console.log("=".repeat(80));
|
||||
console.log("Vault 合约地址:", vaultAddress);
|
||||
console.log("函数名称: setAllowedBroker");
|
||||
console.log("参数:");
|
||||
console.log(" - brokerHash:", brokerHash);
|
||||
console.log(" - allowed:", allowed);
|
||||
console.log("=".repeat(80));
|
||||
console.log("生成的 Calldata:");
|
||||
console.log(calldata);
|
||||
console.log("=".repeat(80));
|
||||
|
||||
return calldata;
|
||||
}
|
||||
|
||||
// 执行函数
|
||||
generateSetAllowedBrokerCalldata()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user