Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
497 changes: 497 additions & 0 deletions broadcast/DeployStrategy.s.sol/1/run-1787527737485.json

Large diffs are not rendered by default.

508 changes: 508 additions & 0 deletions broadcast/DeployStrategy.s.sol/1/run-1789572435382.json

Large diffs are not rendered by default.

387 changes: 199 additions & 188 deletions broadcast/DeployStrategy.s.sol/1/run-latest.json

Large diffs are not rendered by default.

473 changes: 473 additions & 0 deletions broadcast/DeployVault.s.sol/1/run-1789572134483.json

Large diffs are not rendered by default.

473 changes: 473 additions & 0 deletions broadcast/DeployVault.s.sol/1/run-latest.json

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions script/DeployAvantStrategy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

import {IStrategy} from "../src/interfaces/IStrategy.sol";
import {ICentralAPROracle} from "./interfaces/ICentralAPROracle.sol";
import {ICommonReportTrigger} from "./interfaces/ICommonReportTrigger.sol";

import {AvantFlexLenderStrategy} from "../src/integrations/AvantStrategy.sol";

import "forge-std/Script.sol";

// ---- Usage ----

// deploy:
// forge script script/DeployAvantStrategy.s.sol:DeployAvantStrategy --verify --slow --etherscan-api-key $KEY --rpc-url $RPC_URL --broadcast

contract DeployAvantStrategy is Script {

// Market params
string public constant NAME = "Flex savETH/WETH Lender";
address public constant LENDER = address(0); // TODO: Flex v2 savETH/WETH Lender

// Yearn addresses
address public constant SMS = 0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7; // sms mainnet
address public constant VAULT = 0xfaC55fAFD0b55BFb8dD41F735EfCc195adA9891F; // yvFlexWETH mainnet
address public constant KEEPER = 0x604e586F17cE106B64185A7a0d2c1Da5bAce711E; // yHaaS mainnet
address public constant ACCOUNTANT = 0x5A74Cb32D36f2f517DB6f7b0A0591e09b22cDE69; // accountant mainnet

// Deployed contracts
address public constant EXIT_ROUTER = 0xe8a511403B0C83e7b85513e00Ed39996B48c2aeD;
address public constant FIXED_REPORT_TRIGGER = 0xb9F57B62Cbe9463da16E5b75e3B809321a0eA871;
address public constant STRATEGY_APR_ORACLE = 0xcB5A60AB76F3741204C87744ECFe0445C74Eb171;
ICentralAPROracle public constant CENTRAL_APR_ORACLE = ICentralAPROracle(0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92);
ICommonReportTrigger public constant COMMON_REPORT_TRIGGER = ICommonReportTrigger(0xf8dF17a35c88AbB25e83C92f9D293B4368b9D52D);

function run() public {
uint256 _pk = vm.envUint("DEPLOYER_PRIVATE_KEY");

// Derive deployer address from private key
address _deployerAddress = vm.addr(_pk);

require(_deployerAddress == address(0x000005281a2b04A182085D37cC9E6dD552795caa), "!johnny.flexmeow.eth");
require(LENDER != address(0), "!lender");
console.log("Deployer address: %s", _deployerAddress);

vm.startBroadcast(_pk);

// Deploy the Strategy. The deployer is management, keeper, and fee recipient until set below
IStrategy _strategy = IStrategy(address(new AvantFlexLenderStrategy(LENDER, EXIT_ROUTER, NAME)));

// Set up the Strategy
_strategy.setKeeper(KEEPER);
_strategy.setPerformanceFeeRecipient(ACCOUNTANT);
_strategy.setProfitMaxUnlockTime(0 days);
_strategy.setAllowed(VAULT, true);
_strategy.setPerformanceFee(0);
_strategy.setPendingManagement(SMS);

// Set APR oracle for the strategy
CENTRAL_APR_ORACLE.setOracle(address(_strategy), STRATEGY_APR_ORACLE);

// Set report trigger for the strategy
COMMON_REPORT_TRIGGER.setCustomStrategyTrigger(address(_strategy), FIXED_REPORT_TRIGGER);

console2.log("---------------------------------");
console2.log("Strategy: ", address(_strategy));
console2.log("---------------------------------");

vm.stopBroadcast();
}

}
72 changes: 72 additions & 0 deletions script/DeployLockedYvusdStrategy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

import {IStrategy} from "../src/interfaces/IStrategy.sol";
import {ICentralAPROracle} from "./interfaces/ICentralAPROracle.sol";
import {ICommonReportTrigger} from "./interfaces/ICommonReportTrigger.sol";

import {LockedYvusdFlexLenderStrategy} from "../src/integrations/LockedYvusdStrategy.sol";

import "forge-std/Script.sol";

// ---- Usage ----

// deploy:
// forge script script/DeployLockedYvusdStrategy.s.sol:DeployLockedYvusdStrategy --verify --slow --etherscan-api-key $KEY --rpc-url $RPC_URL --broadcast

contract DeployLockedYvusdStrategy is Script {

// Market params
string public constant NAME = "Flex Locked yvUSD/USDC Lender";
address public constant LENDER = address(0); // TODO: Flex v2 Locked yvUSD/USDC Lender

// Yearn addresses
address public constant SMS = 0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7; // sms mainnet
address public constant VAULT = 0x863687e4E9751b57F38b4B0ebA04744C72d0f7B8; // yvFlexUSDC mainnet
address public constant KEEPER = 0x604e586F17cE106B64185A7a0d2c1Da5bAce711E; // yHaaS mainnet
address public constant ACCOUNTANT = 0x5A74Cb32D36f2f517DB6f7b0A0591e09b22cDE69; // accountant mainnet

// Deployed contracts
address public constant EXIT_ROUTER = 0xe8a511403B0C83e7b85513e00Ed39996B48c2aeD;
address public constant FIXED_REPORT_TRIGGER = 0xb9F57B62Cbe9463da16E5b75e3B809321a0eA871;
address public constant STRATEGY_APR_ORACLE = 0xcB5A60AB76F3741204C87744ECFe0445C74Eb171;
ICentralAPROracle public constant CENTRAL_APR_ORACLE = ICentralAPROracle(0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92);
ICommonReportTrigger public constant COMMON_REPORT_TRIGGER = ICommonReportTrigger(0xf8dF17a35c88AbB25e83C92f9D293B4368b9D52D);

function run() public {
uint256 _pk = vm.envUint("DEPLOYER_PRIVATE_KEY");

// Derive deployer address from private key
address _deployerAddress = vm.addr(_pk);

require(_deployerAddress == address(0x000005281a2b04A182085D37cC9E6dD552795caa), "!johnny.flexmeow.eth");
require(LENDER != address(0), "!lender");
console.log("Deployer address: %s", _deployerAddress);

vm.startBroadcast(_pk);

// Deploy the Strategy. The deployer is management, keeper, and fee recipient until set below
IStrategy _strategy = IStrategy(address(new LockedYvusdFlexLenderStrategy(LENDER, EXIT_ROUTER, NAME)));

// Set up the Strategy
_strategy.setKeeper(KEEPER);
_strategy.setPerformanceFeeRecipient(ACCOUNTANT);
_strategy.setProfitMaxUnlockTime(0 days);
_strategy.setAllowed(VAULT, true);
_strategy.setPerformanceFee(0);
_strategy.setPendingManagement(SMS);

// Set APR oracle for the strategy
CENTRAL_APR_ORACLE.setOracle(address(_strategy), STRATEGY_APR_ORACLE);

// Set report trigger for the strategy
COMMON_REPORT_TRIGGER.setCustomStrategyTrigger(address(_strategy), FIXED_REPORT_TRIGGER);

console2.log("---------------------------------");
console2.log("Strategy: ", address(_strategy));
console2.log("---------------------------------");

vm.stopBroadcast();
}

}
8 changes: 4 additions & 4 deletions script/DeployStrategy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import "forge-std/Script.sol";
contract DeployStrategy is Script {

// Market params
string public constant NAME = "Flex ysyBOLD/USDC Lender";
address public constant ASSET = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC
address public constant LENDER = 0xf4996Ca4190A1a3e7CF19AbE2F6eb712abd4a03C; // Flex v2 ysyBOLD/USDC Lender
string public constant NAME = "Flex yvWETH-2/WETH Lender";
address public constant ASSET = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH
address public constant LENDER = 0x0d57098e501D68905fC4B0A3397f7D4Aa4889E36; // Flex v2 yvWETH-2/WETH Lender

// Yearn addresses
address public constant SMS = 0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7; // sms mainnet
address public constant VAULT = 0x863687e4E9751b57F38b4B0ebA04744C72d0f7B8; // yvFlexUSDC mainnet
address public constant VAULT = 0xfaC55fAFD0b55BFb8dD41F735EfCc195adA9891F; // yvFlexWETH mainnet
address public constant KEEPER = 0x604e586F17cE106B64185A7a0d2c1Da5bAce711E; // yHaaS mainnet
address public constant ACCOUNTANT = 0x5A74Cb32D36f2f517DB6f7b0A0591e09b22cDE69; // accountant mainnet

Expand Down
12 changes: 6 additions & 6 deletions script/DeployVault.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import "forge-std/Script.sol";

contract DeployVault is Script {

string private constant NAME = "Flex USDC yVault";
string private constant SYMBOL = "yvFlexUSDC";
address private constant ASSET = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
string private constant NAME = "Flex WETH yVault";
string private constant SYMBOL = "yvFlexWETH";
address private constant ASSET = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH
address private constant SMS = 0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7; // sms mainnet
address private constant KEEPER = 0x604e586F17cE106B64185A7a0d2c1Da5bAce711E; // yHaaS mainnet
address private constant ROLE_MANAGER = 0xb3bd6B2E61753C311EFbCF0111f75D29706D9a41;

// 3.0.4 Vault Factory
IVaultFactory private constant VAULT_FACTORY = IVaultFactory(0x770D0d1Fb036483Ed4AbB6d53c1C88fb277D812F);
// 3.1.0 Vault Factory
IVaultFactory private constant VAULT_FACTORY = IVaultFactory(0x310aC28ACF5E514abDbFF9Ab25e21f1bfe22bcAC);

function run() public {
uint256 _pk = vm.envUint("DEPLOYER_PRIVATE_KEY");
Expand All @@ -34,7 +34,7 @@ contract DeployVault is Script {

vm.startBroadcast(_pk);

IVault _vault = IVault(VAULT_FACTORY.deploy_new_vault(ASSET, NAME, SYMBOL, _deployerAddress, 7 days));
IVault _vault = IVault(VAULT_FACTORY.deploy_new_vault(ASSET, NAME, SYMBOL, _deployerAddress, 4 days));
_vault.set_role(_deployerAddress, 16383); // ADD_STRATEGY_MANAGER/DEPOSIT_LIMIT_MANAGER/MAX_DEBT_MANAGER/DEBT_MANAGER
_vault.set_role(SMS, 16383); // ADD_STRATEGY_MANAGER/DEPOSIT_LIMIT_MANAGER/MAX_DEBT_MANAGER/DEBT_MANAGER
_vault.set_role(KEEPER, 32); // REPORTING_MANAGER
Expand Down
11 changes: 7 additions & 4 deletions script/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

- Allocator Strategy APR Oracle (v1): 0x84D1AeC938D4b9F492c50A1b5218E77195899471
- Allocator Strategy Factory (v1): 0x7A3B96E84156d22Cdb53CbfC0B035Ddd61805266
- Allocator Strategy APR Oracle (v2): 0xcB5A60AB76F3741204C87744ECFe0445C74Eb171
- Allocator Strategy Factory (v2): 0x1792348Fe3ebDdc0C6bB123aC24c094ac9D78252
- Allocator Strategy APR Oracle: 0xcB5A60AB76F3741204C87744ECFe0445C74Eb171
- Allocator Strategy Factory: 0x1792348Fe3ebDdc0C6bB123aC24c094ac9D78252
- Exit Router: 0xe8a511403B0C83e7b85513e00Ed39996B48c2aeD

** Yearn Allocator **

- yvFlexUSDC: 0x863687e4E9751b57F38b4B0ebA04744C72d0f7B8
- yvFlexWETH: 0xfaC55fAFD0b55BFb8dD41F735EfCc195adA9891F
- yvUSD/USDC Strategy (v1): 0x467Ce10870747372968ba98463A1d9af9Fb27751
- siUSD/USDC Strategy (v1): 0x1231310e5F68398dfE929Cc43ce65c1B871eb2C8
- yvUSD/USDC Strategy (v2): 0x7501EAE6b5C2Cb0A6EDAC908E3A679B20eDd737b
- ysyBOLD/USDC Strategy (v2): 0xDd58AeFE74585DA2C7Ad3D3dF0F3aeEAb05b5176
- yvUSD/USDC Strategy: 0x7501EAE6b5C2Cb0A6EDAC908E3A679B20eDd737b
- ysyBOLD/USDC Strategy: 0xDd58AeFE74585DA2C7Ad3D3dF0F3aeEAb05b5176
- yvcrvUSD-2/USDC Strategy: 0xC818A0Be1BB2cE820CfdefAD5f890667e885f39d
- yvWETH-2/WETH Strategy: 0x7E4a6A89583e117C641aB3ce8897209800A3F2E3
120 changes: 120 additions & 0 deletions src/integrations/AvantStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.30;

import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import {IAvantMinting} from "../interfaces/IAvantMinting.sol";
import {IStakedAvant} from "../interfaces/IStakedAvant.sol";

import {CooldownFlexLenderStrategy, ERC20, Math} from "./CooldownStrategy.sol";

/// @title Avant Flex Lender Strategy
/// @author Flex
/// @notice Flex Lender Strategy for savETH collateral markets. Collateral taken in kind from redemption
/// auctions is unstaked to avETH through savETH's cooldown, then redeemed for the asset by Avant
/// off-chain, against orders signed on this strategy's behalf by a delegated signer
contract AvantFlexLenderStrategy is CooldownFlexLenderStrategy {

using SafeERC20 for ERC20;

// ============================================================================================
// Constants
// ============================================================================================

/// @notice WETH token
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

/// @notice avETH token, 1:1 with the asset
ERC20 public constant AVETH = ERC20(0x9469470C9878bf3d6d0604831d9A3A366156f7EE);

/// @notice Avant minting contract, redeems avETH for the asset
IAvantMinting public constant AVANT_MINTING = IAvantMinting(0x09becF6E5e297825D19aA14eD6081A03524532D7);

// ============================================================================================
// Constructor
// ============================================================================================

/// @notice Constructor
/// @param _lender The address of the Lender contract
/// @param _exitRouter The address of the exit router
/// @param _name The name of the strategy
constructor(
address _lender,
address _exitRouter,
string memory _name
) CooldownFlexLenderStrategy(WETH, _lender, _exitRouter, _name) {
// Make sure the collateral (savETH) unstakes to avETH
require(COLLATERAL.asset() == address(AVETH), "!aveth");

// Max approve the minting contract to pull the avETH being redeemed
AVETH.forceApprove(address(AVANT_MINTING), type(uint256).max);
}

// ============================================================================================
// Public view functions
// ============================================================================================

/// @inheritdoc CooldownFlexLenderStrategy
function pendingRedemptions() public view override returns (uint256 _pending) {
// savETH taken in kind, and what is cooling in the silo. savETH --> avETH
(, uint152 _cooling) = IStakedAvant(address(COLLATERAL)).cooldowns(address(this));
_pending = COLLATERAL.convertToAssets(takenInKind) + _cooling;

// Loose avETH, waiting to be redeemed
_pending += AVETH.balanceOf(address(this));
}

// ============================================================================================
// Management functions
// ============================================================================================

/// @notice Delegate the signing of Avant redemption orders on this strategy's behalf
/// @dev Only callable by management
/// @dev The signer must confirm the delegation on the minting contract. Orders must have this
/// strategy as both benefactor and beneficiary
/// @param _signer The address to delegate to
function setDelegatedSigner(
address _signer
) external onlyManagement {
AVANT_MINTING.setDelegatedSigner(_signer);
}

// ============================================================================================
// Cooldown
// ============================================================================================

/// @notice Start the cooldown on loose savETH
/// @dev Only callable by management
/// @dev Calling while a cooldown is in progress adds to it and restarts its timer
/// @param _shares The amount of savETH to unwind, capped by the loose balance
/// @return The amount of avETH cooling
function initiateCooldown(
uint256 _shares
) external onlyManagement returns (uint256) {
// Cap the shares by the loose collateral balance
_shares = _capToBalance(COLLATERAL, _shares);

// Consume the collateral taken in kind variable
takenInKind -= Math.min(_shares, takenInKind);

// savETH --> avETH, into the silo
return IStakedAvant(address(COLLATERAL)).cooldownShares(_shares);
}

/// @notice Unstake the cooled avETH from the silo once the cooldown passed
/// @dev Only callable by management
/// @dev The avETH is then redeemed for the asset by Avant, see `setDelegatedSigner`
/// @return _avethOut The amount of avETH received
function claimCooldown() external onlyManagement returns (uint256 _avethOut) {
// Make sure there is something cooled
IStakedAvant _savETH = IStakedAvant(address(COLLATERAL));
(uint104 _cooldownEnd, uint152 _cooling) = _savETH.cooldowns(address(this));
require(_cooling > 0 && block.timestamp >= _cooldownEnd, "!claim");

// Silo --> avETH
uint256 _preBalance = AVETH.balanceOf(address(this));
_savETH.unstake(address(this));
_avethOut = AVETH.balanceOf(address(this)) - _preBalance;
}

}
Loading
Loading