Skip to content

Commit

Permalink
Merge branch 'master' into yearn-audit-variable-optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
aazhou1 authored Dec 23, 2024
2 parents 7f40555 + bfe30b8 commit 79941d6
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 78 deletions.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
16 changes: 7 additions & 9 deletions .github/workflows/deploy-strategy-hardhat-mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ on:
description: 'Asset address'
required: true
default: '0x'
strategyName:
description: 'Yearn strategy name'
strategyMeta:
description: 'Yearn strategy name and token symbol separated by a comma'
required: true
default: '0x'
symbol:
description: 'Yearn token symbol'
required: true
default: '0x'
default: 'SomeName,SOMESYMBOL'
strategyManagementAddress:
description: 'Strategy management address'
required: true
Expand Down Expand Up @@ -59,6 +55,7 @@ jobs:
fetch-depth: 0
- uses: foundry-rs/foundry-toolchain@v1
- run: forge install
- run: forge build
- run: forge remappings > remappings.txt
- id: nodeversion
run: echo "version=$(grep nodejs .tool-versions | sed -e 's/[^[:space:]]*[[:space:]]*//')" >> $GITHUB_OUTPUT
Expand All @@ -69,6 +66,8 @@ jobs:
cache: yarn
- run: yarn install
- run: rm -rf src/test/kontrol/
- run: yarn hardhat compile
- run: yarn hardhat typechain
- run: yarn mainnet:deploy-strategy
env:
ASSET_ADDRESS: ${{ github.event.inputs.asset }}
Expand All @@ -81,10 +80,9 @@ jobs:
NEW_REQUIRED_RESERVE_RATIO: ${{ github.event.inputs.requiredReserveRatio }}
ADMIN_ADDRESS: ${{ vars.ADMIN_ADDRESS }}
DEVOPS_ADDRESS: ${{ vars.DEVOPS_ADDRESS }}
STRATEGY_NAME: ${{ github.event.inputs.strategyName }}
STRATEGY_META: ${{ github.event.inputs.strategyMeta }}
PROFIT_MAX_UNLOCK_TIME: ${{ vars.PROFIT_MAX_UNLOCK_TIME }}
STRATEGY_MANAGEMENT_ADDRESS: ${{ github.event.inputs.strategyManagementAddress }}
SYMBOL: ${{ github.event.inputs.symbol }}
KEEPER_ADDRESS: ${{ vars.KEEPER }}
FEE_RECIPIENT: ${{ github.event.inputs.feeRecipient }}
COLLATERAL_TOKEN_ADDRESSES: ${{ github.event.inputs.collateralTokens }}
Expand Down
16 changes: 7 additions & 9 deletions .github/workflows/deploy-strategy-hardhat-sepolia.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ on:
description: 'Asset address'
required: true
default: '0x'
strategyName:
description: 'Yearn strategy name'
strategyMeta:
description: 'Yearn strategy name and token symbol separated by a comma'
required: true
default: '0x'
symbol:
description: 'Yearn token symbol'
required: true
default: '0x'
default: 'SomeName,SOMESYMBOL'
strategyManagementAddress:
description: 'Strategy management address'
required: true
Expand Down Expand Up @@ -55,6 +51,7 @@ jobs:
fetch-depth: 0
- uses: foundry-rs/foundry-toolchain@v1
- run: forge install
- run: forge build
- run: forge remappings > remappings.txt
- id: nodeversion
run: echo "version=$(grep nodejs .tool-versions | sed -e 's/[^[:space:]]*[[:space:]]*//')" >> $GITHUB_OUTPUT
Expand All @@ -65,6 +62,8 @@ jobs:
cache: yarn
- run: yarn install
- run: rm -rf src/test/kontrol/
- run: yarn hardhat compile
- run: yarn hardhat typechain
- run: yarn sepolia:deploy-strategy
env:
ASSET_ADDRESS: ${{ github.event.inputs.asset }}
Expand All @@ -77,8 +76,7 @@ jobs:
NEW_REQUIRED_RESERVE_RATIO: ${{ github.event.inputs.requiredReserveRatio }}
ADMIN_ADDRESS: ${{ vars.ADMIN_ADDRESS }}
DEVOPS_ADDRESS: ${{ vars.DEVOPS_ADDRESS }}
STRATEGY_NAME: ${{ github.event.inputs.strategyName }}
SYMBOL: ${{ github.event.inputs.symbol }}
STRATEGY_META: ${{ github.event.inputs.strategyMeta }}
PROFIT_MAX_UNLOCK_TIME: ${{ vars.PROFIT_MAX_UNLOCK_TIME }}
STRATEGY_MANAGEMENT_ADDRESS: ${{ github.event.inputs.strategyManagementAddress }}
KEEPER_ADDRESS: ${{ vars.KEEPER }}
Expand Down
130 changes: 80 additions & 50 deletions hardhat-scripts/deploy-strategy.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import hre from "hardhat";
import { ethers } from "hardhat"; // Use direct ethers import
import "@nomiclabs/hardhat-ethers";
import { NonceManager } from "@ethersproject/experimental";
import dotenv from "dotenv";
import { Signer } from "ethers";
import { promises as fs } from 'fs';
import path from 'path';
import { Strategy } from '../typechain-types/src/Strategy';
type StrategyParamsStruct = Strategy.StrategyParamsStruct;


dotenv.config();

function stringToAddressArray(input: string): string[] {
if (!input) return [];
return input.split(",").map((addr) => {
const trimmed = addr.trim();
if (!hre.ethers.utils.isAddress(trimmed)) {
if (!ethers.utils.isAddress(trimmed)) {
throw new Error(`Invalid address: ${trimmed}`);
}
return trimmed;
});
}

function stringToUintArray(input: string): number[] {
function stringToUintArray(input: string): string[] { // Changed return type to string[]
if (!input) return [];
return input.split(",").map((num) => {
const trimmed = num.trim();
const parsed = parseInt(trimmed);
if (isNaN(parsed) || parsed.toString() !== trimmed) {
// Just validate that it's a valid number string but return the string
if (isNaN(Number(trimmed))) {
throw new Error(`Invalid number: ${trimmed}`);
}
return parsed;
return trimmed; // Return the string instead of parsing to number
});
}

Expand All @@ -34,61 +39,60 @@ async function checkUnderlyingVaultAsset(
underlyingVault: string,
managedSigner: Signer
) {
const vault = await hre.ethers.getContractAt(
const vault = await ethers.getContractAt(
"IERC4626",
underlyingVault,
managedSigner
);
const underlyingAsset = await vault.asset();
if (underlyingAsset.toLowerCase() !== asset.toLowerCase()) {
throw new Error("Underlying asset does not match asset");
throw new Error(`Underlying asset (${underlyingAsset}) does not match asset (${asset})`);
}
}

async function buildStrategyParams(
eventEmitter: string,
_eventEmitter: string,
deployer: string,
managedSigner: Signer
) {
const asset = process.env.ASSET_ADDRESS!;
const yearnVaultAddress = process.env.YEARN_VAULT_ADDRESS!;
const discountRateAdapterAddress = process.env.DISCOUNT_RATE_ADAPTER_ADDRESS!;
const termController = process.env.TERM_CONTROLLER_ADDRESS!;
const discountRateMarkup = process.env.DISCOUNT_RATE_MARKUP!;
const timeToMaturityThreshold = process.env.TIME_TO_MATURITY_THRESHOLD!;
const repoTokenConcentrationLimit =
process.env.REPOTOKEN_CONCENTRATION_LIMIT!;
const newRequiredReserveRatio = process.env.NEW_REQUIRED_RESERVE_RATIO!;

await checkUnderlyingVaultAsset(asset, yearnVaultAddress, managedSigner);
const _asset = process.env.ASSET_ADDRESS!;
const _yearnVault = process.env.YEARN_VAULT_ADDRESS!;
const _discountRateAdapter = process.env.DISCOUNT_RATE_ADAPTER_ADDRESS!;
const _termController = process.env.TERM_CONTROLLER_ADDRESS!;
const _discountRateMarkup = process.env.DISCOUNT_RATE_MARKUP!;
const _timeToMaturityThreshold = process.env.TIME_TO_MATURITY_THRESHOLD!;
const _repoTokenConcentrationLimit = process.env.REPOTOKEN_CONCENTRATION_LIMIT!;
const _requiredReserveRatio = process.env.NEW_REQUIRED_RESERVE_RATIO!;

await checkUnderlyingVaultAsset(_asset, _yearnVault, managedSigner);

return {
asset,
yearnVaultAddress,
discountRateAdapterAddress,
eventEmitter,
deployer,
termController,
repoTokenConcentrationLimit,
timeToMaturityThreshold,
newRequiredReserveRatio,
discountRateMarkup,
};
_asset,
_yearnVault,
_discountRateAdapter,
_eventEmitter,
_governorAddress: deployer,
_termController,
_repoTokenConcentrationLimit,
_timeToMaturityThreshold,
_requiredReserveRatio,
_discountRateMarkup,
} as StrategyParamsStruct;
}

async function deployEventEmitter(managedSigner: Signer) {
const admin = process.env.ADMIN_ADDRESS!;
const devops = process.env.DEVOPS_ADDRESS!;

const EventEmitter = (
await hre.ethers.getContractFactory("TermVaultEventEmitter")
await ethers.getContractFactory("TermVaultEventEmitter")
).connect(managedSigner);
const eventEmitterImpl = await EventEmitter.deploy();
await eventEmitterImpl.deployed();

console.log("Deployed event emitter impl to:", eventEmitterImpl.address);

const Proxy = (await hre.ethers.getContractFactory("ERC1967Proxy")).connect(
const Proxy = (await ethers.getContractFactory("ERC1967Proxy")).connect(
managedSigner
);
const initData = EventEmitter.interface.encodeFunctionData("initialize", [
Expand All @@ -104,7 +108,7 @@ async function deployEventEmitter(managedSigner: Signer) {

console.log("Deployed event emitter proxy to:", eventEmitterProxy.address);

return hre.ethers.getContractAt(
return ethers.getContractAt(
"TermVaultEventEmitter",
eventEmitterProxy.address,
managedSigner
Expand All @@ -113,7 +117,7 @@ async function deployEventEmitter(managedSigner: Signer) {

async function main() {
// Get the deployer's address and setup managed signer
const [deployer] = await hre.ethers.getSigners();
const [deployer] = await ethers.getSigners();
const managedSigner = new NonceManager(deployer as any) as unknown as Signer;

// Deploy EventEmitter first
Expand All @@ -125,18 +129,34 @@ async function main() {
deployer.address,
managedSigner
);
console.log(JSON.stringify(params));

// Deploy Strategy
const Strategy = (await hre.ethers.getContractFactory("Strategy")).connect(
managedSigner ?? null
// Match your working pattern exactly
const Strategy = await ethers.getContractFactory(
"Strategy",
{
signer: managedSigner,
}
);

const strategyMeta = process.env.STRATEGY_META!;
const [strategyName, strategySymbol] = strategyMeta.trim().split(",").map(x => x.trim())
console.log(`Deploying strategy with (${strategyName}, ${strategySymbol})`);


// Create a struct that exactly matches the constructor's tuple type
const strategy = await Strategy.deploy(
strategyName,
strategySymbol,
params
);
const strategy = await Strategy.deploy(process.env.STRATEGY_NAME!, process.env.SYMBOL!, params);
await strategy.deployed();

await strategy.deployed();

console.log("Deployed strategy to:", strategy.address);

// Post-deployment setup
const strategyContract = await hre.ethers.getContractAt(
const strategyContract = await ethers.getContractAt(
"ITokenizedStrategy",
strategy.address,
managedSigner
Expand All @@ -145,19 +165,29 @@ async function main() {
await strategyContract.setProfitMaxUnlockTime(
process.env.PROFIT_MAX_UNLOCK_TIME!
);
await strategyContract.setPendingManagement(
process.env.STRATEGY_MANAGEMENT_ADDRESS!
const tx1 = await strategyContract.setProfitMaxUnlockTime(
process.env.PROFIT_MAX_UNLOCK_TIME!
);
await strategyContract.setKeeper(process.env.KEEPER_ADDRESS!);
await strategyContract.setPerformanceFeeRecipient(process.env.FEE_RECIPIENT!);
await tx1.wait();
console.log("Set profit max unlock time to:", process.env.PROFIT_MAX_UNLOCK_TIME, "Transaction hash:", tx1.hash);

console.log(
"Set pending management to:",
process.env.STRATEGY_MANAGEMENT_ADDRESS
const tx2 = await strategyContract.setPendingManagement(
process.env.STRATEGY_MANAGEMENT_ADDRESS!
);
await tx2.wait();
console.log("Set pending management to:", process.env.STRATEGY_MANAGEMENT_ADDRESS, "Transaction hash:", tx2.hash);

const tx3 = await strategyContract.setKeeper(process.env.KEEPER_ADDRESS!);
await tx3.wait();
console.log("Set keeper to:", process.env.KEEPER_ADDRESS, "Transaction hash:", tx3.hash);

const tx4 = await strategyContract.setPerformanceFeeRecipient(process.env.FEE_RECIPIENT!);
await tx4.wait();
console.log("Set performance fee recipient to:", process.env.FEE_RECIPIENT, "Transaction hash:", tx4.hash);

await eventEmitter.pairVaultContract(strategy.address);
console.log("Paired strategy with event emitter");
const tx5 = await eventEmitter.pairVaultContract(strategy.address);
await tx5.wait();
console.log("Paired strategy with event emitter. Transaction hash:", tx5.hash);

// Set collateral token parameters
const collateralTokens = stringToAddressArray(
Expand Down
19 changes: 17 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { task } from "hardhat/config";
import path from "path";
import glob from "glob";
import fs from "fs";
import "hardhat-abi-exporter";
import "@typechain/hardhat";



const remappings = fs
.readFileSync("remappings.txt", "utf-8")
Expand Down Expand Up @@ -46,10 +50,21 @@ const config: HardhatUserConfig = {
},
},
},
abiExporter: {
runOnCompile: true,
clear: true,
flat: false,
format: "json",
},
typechain: {
outDir: "typechain-types",
target: "ethers-v5",
},
paths: {
sources: "./src", // Specify the main directory for source files
sources: "./src", // Where your contracts are
artifacts: "./artifacts", // Where compiled artifacts go
cache: "./cache" // Cache directory
},

networks: {
sepolia: {
url: process.env.SEPOLIA_RPC_URL || "",
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
"@ethersproject/experimental": "^5.7.0",
"@nomicfoundation/hardhat-foundry": "^1.1.3",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@typechain/ethers-v5": "^11.1.2",
"@typechain/hardhat": "^6.1.2",
"dotenv": "^16.4.7",
"env-cmd": "^10.1.0",
"ethers": "^5.4.7",
"hardhat": "^2.22.17",
"hardhat-abi-exporter": "^2.10.1",
"path": "^0.12.7",
"prettier": "^2.5.1",
"prettier-plugin-solidity": "^1.0.0-beta.19",
Expand All @@ -16,6 +19,7 @@
"solhint": "^3.3.7",
"solhint-plugin-prettier": "^0.0.5",
"ts-node": "^10.9.2",
"typechain": "^8.3.2",
"typescript": "^5.7.2"
},
"scripts": {
Expand Down
Loading

0 comments on commit 79941d6

Please sign in to comment.