前言
文章主要介绍了收益聚合器Beefy协议在币安智能链测试网网上的编译测试部署流程,以Pancake上的USDC-BUSD最新Curve版流动池的农场质押为例,详细介绍了完整的操作流程。
准备工作
Node.js环境
WebStorm IDE
beefy源码
💡准备工作不做任何科普,关键链接已经写明,请自行折腾。
Beefy工程简介
本教程用到的目录有如下几个
- contracts
- scripts
- test
contracts
这个目录下是所有的Beefy合约,当前还在使用的是BIFI目录下的合约,下面简要介绍一下子目录。
infra
这个目录下的合约为基础合约,提供一些基础功能,比如手续费控制等.
文章用到的有
BeefyFeeConfigurator.sol手续费设置合约
strategies
策略合约目录
文章用到的有
Curve/StrategyChefCurveLP.sol 使用Curve实现的流动性池策略合约
utils
工具合约目录
文章用到的有
GasFeeThrottler.sol Gas费限制器合约
GasPrice.sol Gas费限制配置合约
vaults
金库合约目录
文章用到的有
BeefyVaultV6.sol V6版的金库合约
scripts
infra
基础合约的部署脚本
文章用到的有
deploy-gasPrice.js 部署手续费限制器合约
deployFeeConfigurator.ts 部署手续费设置合约的可升级合约(ERC967)
vault
金库合约的部署脚本
此处没有我们需要的最新的基于Curve的StableLP的金库合约部署模板,需要自行编写,下文会有详细的代码。
Hardhat配置
作者是区块链的小白,hardhat也是这几天才接触,有说的不对的请大家指正。
Hardhat安装
自行搜索
Hardhat配置
hardhat.config.ts
这个配置文件中我们需要关注的部分,一个是bsc测试网的支持,一个是用到的账户的配置
bsc测试网是在config对象的networks属性下添加,例如:
const config: DeploymentConfig = {
defaultNetwork: "bsctest",
networks: {
bsctest: {
url: "https://data-seed-prebsc-1-s3.binance.org:8545",
chainId: 97,
gasLimit: 20000000,
gas: 3000000000000000,
gasPrice: 10000000000,
accounts,
},
}
}
💡其中gasPrice是因为GasPrice.sol中的限制而取的最大值。
RPC的列表可以在这个链接检索
选Latency最小的即可
dafaultNetwork设置为bsctest可以让你在后续执行命令式无需手动指定bsctest
此时我们把目光移到
const accounts = getPKs();
这一行,这行是获取到项目用到的账号,打开getPKs()的方法体我们看到系统是读取了四个环境变量,因此我们需要在项目的根目录新增一个 .env文件,用以保存我们用到的账号,格式如下:
DEPLOYER_PK="Your Private Key Without 0x Prefix"
KEEPER_PK="Your Private Key Without 0x Prefix"
UPGRADER_PK="Your Private Key Without 0x Prefix"
REWARDER_PK="Your Private Key Without 0x Prefix"
部署顺序
GasPrice配置合约
hardhat run scripts/infra/deploy-gasPrice.js --network bsctest
部署完毕后得到GasPrice合约的地址A1.
BeefyFeeConfigurator手续费配置合约
hardhat run scripts/infra/deployFeeConfigurator.ts --network bsctest
金库策略合约部署
部署之前要修改合约及关联合约中的几处变量
GasFeeThrottler.sol
address public gasprice = address(0x4548b3B8257E634Dd6cc91D1e94d29838Baf37ef);
修改为
address public gasprice = address(A1);//GasPrice合约部署后的地址
下面是deploy-chef-curve-strat.ts的源码
import hardhat, { ethers, web3 } from "hardhat";
import { addressBook } from "blockchain-addressbook";
import { predictAddresses } from "../../utils/predictAddresses";
import { setPendingRewardsFunctionName } from "../../utils/setPendingRewardsFunctionName";
import { verifyContract } from "../../utils/verifyContract";
const registerSubsidy = require("../../utils/registerSubsidy");
const CAKE = '0xFa60D973F7642B748046464e165A65B7323b0DEE'.toLowerCase();
const WBNB = '0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd'.toLowerCase();
const BUSD = '0x8516Fc284AEEaa0374E66037BD2309349FF728eA'.toLowerCase();
const shouldVerifyOnEtherscan = false;
const shouldTransferVaultOwnership = false;
const want = web3.utils.toChecksumAddress("0x1a77c359d0019cd8f4d36b7cdf5a88043d801072");
const vaultParams = {
mooName: "Moo CakeV2 USDC-BUSD",
mooSymbol: "mooCakeV2USDC-BUSD",
delay: 21600,
};
const strategyParamsTestnet = {
want: "0xb98C30fA9f5e9cf6749B7021b4DDc0DBFe73b73e",
poolId: 3,
chef: "0xB4A466911556e39210a6bB2FaECBB59E4eB7E43d",
pool: "0xb98C30fA9f5e9cf6749B7021b4DDc0DBFe73b73e",
poolSize: 2,
depositIndex: 1,
useMetapool: false,
unirouter: "0xD99D1c33F9fC3444f8101754aBC46c52416550D1",
strategist: process.env.STRATEGIST_ADDRESS,
keeper: process.env.KEEPER_ADDRESS,
beefyFeeRecipient: process.env.FEE_RECIPIENT_ADDRESS,
beefyFeeConfig: process.env.FEE_CONFIG_ADDRESS,
outputToNativeRoute: [CAKE, WBNB],
outputToDepositRoute: [CAKE, BUSD],
shouldSetPendingRewardsFunctionName: false,
pendingRewardsFunctionName: "pendingCake",
};
const contractNames = {
vault: "BeefyVaultV6",
strategy: "StrategyChefCurveLP",
};
async function main() {
if (
Object.values(vaultParams).some(v => v === undefined) ||
Object.values(strategyParams).some(v => v === undefined) ||
Object.values(contractNames).some(v => v === undefined)
) {
console.error("one of config values undefined");
return;
}
await hardhat.run("compile");
const Vault = await ethers.getContractFactory(contractNames.vault);
const Strategy = await ethers.getContractFactory(contractNames.strategy);
const [deployer] = await ethers.getSigners();
console.log("deployer:", deployer.address);
console.log("Deploying:", vaultParams.mooName);
const predictedAddresses = await predictAddresses({ creator: deployer.address });
console.log("predictedAddresses :", predictedAddresses);
const vaultConstructorArguments = [
predictedAddresses.strategy,
vaultParams.mooName,
vaultParams.mooSymbol,
vaultParams.delay,
];
console.log("Deploying Vault :");
const vault = await Vault.deploy(...vaultConstructorArguments);
await vault.deployed();
console.log("Deployed Vault!", vault.address);
const strategyConstructorArguments = [
strategyParamsTestnet.want,
strategyParamsTestnet.poolId,
strategyParamsTestnet.chef,
strategyParamsTestnet.pool,
strategyParamsTestnet.poolSize,
strategyParamsTestnet.depositIndex,
strategyParamsTestnet.useMetapool,
strategyParamsTestnet.outputToNativeRoute,
strategyParamsTestnet.outputToDepositRoute,
[
vault.address,
strategyParamsTestnet.unirouter,
strategyParamsTestnet.keeper,
strategyParamsTestnet.strategist,
strategyParamsTestnet.beefyFeeRecipient,
strategyParamsTestnet.beefyFeeConfig,
],
];
console.log("Deploying Strategy :");
const override = { gasLimit: 20000000 };
const strategy = await Strategy.deploy(...strategyConstructorArguments, override);
await strategy.deployed();
console.log("Deployed Strategy!", strategy.address);
// add this info to PR
console.log();
console.log("Vault:", vault.address);
console.log("Strategy:", strategy.address);
console.log("Want:", strategyParams.want);
console.log("PoolId:", strategyParams.poolId);
console.log();
console.log("Running post deployment");
const verifyContractsPromises: Promise<any>[] = [];
if (shouldVerifyOnEtherscan) {
// skip await as this is a long running operation, and you can do other stuff to prepare vault while this finishes
verifyContractsPromises.push(
verifyContract(vault.address, vaultConstructorArguments),
verifyContract(strategy.address, strategyConstructorArguments)
);
}
if (strategyParams.shouldSetPendingRewardsFunctionName) {
console.log("Set PendingRewards Function Name...");
await setPendingRewardsFunctionName(strategy, strategyParams.pendingRewardsFunctionName);
console.log("Set done!");
console.log();
}
if (shouldTransferVaultOwnership) {
console.log(`Transfering Vault Owner to ${process.env.VAULT_OWNER_ADDRESS}`)
await vault.transferOwnership(beefyfinance.vaultOwner);
console.log();
}
await Promise.all(verifyContractsPromises);
if (hardhat.network.name === "bsc") {
await registerSubsidy(vault.address, deployer);
await registerSubsidy(strategy.address, deployer);
}
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
执行脚本部署合约
hardhat run scripts/vault/deploy-chef-curve-strat.ts --network bsctest
❗此处有很多坑等我慢慢补充
TBD