Skip to content
Merged
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
19 changes: 8 additions & 11 deletions script/v2/DeployLevel.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -302,16 +302,6 @@ contract DeployLevel is Configurable, DeploymentUtils, Script {
address(config.levelContracts.vaultManager),
bytes4(abi.encodeWithSignature("withdrawDefault(address,uint256)"))
);
_setRoleCapabilityIfNotExists(
STRATEGIST_ROLE,
address(config.levelContracts.vaultManager),
bytes4(abi.encodeWithSignature("modifyAaveUmbrellaCooldownOperator(address,address,bool)"))
);
_setRoleCapabilityIfNotExists(
STRATEGIST_ROLE,
address(config.levelContracts.vaultManager),
bytes4(abi.encodeWithSignature("modifyAaveUmbrellaRewardsClaimer(address,address,bool)"))
);

_setRoleIfNotExists(address(config.levelContracts.levelMintingV2), STRATEGIST_ROLE);
_setRoleIfNotExists(address(config.users.operator), STRATEGIST_ROLE);
Expand Down Expand Up @@ -600,8 +590,15 @@ contract DeployLevel is Configurable, DeploymentUtils, Script {
revert("RolesAuthority must be deployed first");
}

if (address(config.levelContracts.pauserGuard) == address(0)) {
revert("PauserGuard must be deployed first");
}

bytes memory constructorArgs = abi.encodeWithSignature(
"initialize(address,address)", deployerWallet.addr, address(config.periphery.uniswapV3Router)
"initialize(address,address,address)",
deployerWallet.addr,
address(config.periphery.uniswapV3Router),
address(config.levelContracts.pauserGuard)
);

SwapManager _swapManager = new SwapManager{salt: convertNameToBytes32(LevelUsdSwapManagerName)}();
Expand Down
90 changes: 90 additions & 0 deletions script/v2/DeployOracles.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {CappedOneDollarOracle} from "@level/src/v2/oracles/CappedOneDollarOracle.sol";
import {IERC4626Oracle} from "@level/src/v2/interfaces/level/IERC4626Oracle.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";

import {DeploymentUtils} from "@level/script/v2/DeploymentUtils.s.sol";
import {Configurable} from "@level/config/Configurable.sol";

import {console2} from "forge-std/console2.sol";

/// @notice Script used to deploy new oracles required after v2 changes
/// @notice This script is meant to be used for mainnet deployments. Not a testing script.
contract DeployOracles is Configurable, DeploymentUtils, Script {
uint256 public chainId;

Vm.Wallet public deployerWallet;

error InvalidProxyAddress();
error UpgradeFailed();
error VerificationFailed();

function setUp() external {
uint256 _chainId = vm.envUint("CHAIN_ID");
setUp_(_chainId);
}

function setUp_(uint256 _chainId) public {
chainId = _chainId;
initConfig(_chainId);

vm.label(msg.sender, "Deployer EOA");
}

function setUp_(uint256 _chainId, uint256 _privateKey) public {
chainId = _chainId;
initConfig(_chainId);

if (msg.sender != vm.addr(_privateKey)) {
revert("Private key does not match sender");
}

deployerWallet.privateKey = _privateKey;
deployerWallet.addr = vm.addr(_privateKey);

vm.label(msg.sender, "Deployer EOA");
}

function run() external {
return upgrade();
}

function upgrade() public {
vm.startBroadcast(deployerWallet.privateKey);

// Deploy CappedMNavOracle
CappedOneDollarOracle mNavOracle = new CappedOneDollarOracle(address(config.oracles.mNav));
vm.label(address(mNavOracle), "CappedMNavOracle");
console2.log("CappedMNavOracle deployed to: %s", address(mNavOracle));

// Deploy sUsdcOracle
config.sparkVaults.sUsdc.oracle = deployERC4626Oracle(config.sparkVaults.sUsdc.vault);
console2.log("sUsdcOracle deployed to: %s", address(config.sparkVaults.sUsdc.oracle));

// Deploy waUsdcStakeTokenOracle
config.umbrellaVaults.waUsdcStakeToken.oracle =
deployERC4626Oracle(config.umbrellaVaults.waUsdcStakeToken.vault);
console2.log("waUsdcStakeTokenOracle deployed to: %s", address(config.umbrellaVaults.waUsdcStakeToken.oracle));

vm.stopBroadcast();
}

function verify() public view {
// TODO: Add verification logic here
}

function deployERC4626Oracle(IERC4626 vault) public returns (IERC4626Oracle) {
if (address(config.levelContracts.erc4626OracleFactory) == address(0)) {
revert("ERC4626OracleFactory must be deployed first");
}

IERC4626Oracle _erc4626Oracle = IERC4626Oracle(config.levelContracts.erc4626OracleFactory.create(vault));
vm.label(address(_erc4626Oracle), string.concat(vault.name(), " Oracle"));

return _erc4626Oracle;
}
}
55 changes: 35 additions & 20 deletions script/v2/lens/UpgradeLevelReserveLens.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,41 @@ contract UpgradeLevelReserveLens is Configurable, DeploymentUtils, Script {
"LevelReserveLens Implementation : https://etherscan.io/address/%s", address(impl)
);

// Call timelock to upgrade the proxy
vm.startBroadcast(config.users.admin);
console2.log("Scheduling upgrade of LevelReserveLens from proxy %s", address(proxy));
TimelockController timelock = TimelockController(payable(config.levelContracts.adminTimelock));
timelock.schedule(
address(proxy),
0,
abi.encodeWithSelector(proxy.upgradeToAndCall.selector, address(impl), ""),
bytes32(0),
0,
5 days
);

vm.warp(block.timestamp + 5 days);

timelock.execute(
address(proxy), 0, abi.encodeWithSelector(proxy.upgradeToAndCall.selector, address(impl), ""), bytes32(0), 0
);

vm.stopBroadcast();
bool isTesting = vm.activeFork() != uint256(0);

// Only execute timelock operations in test environment
if (isTesting) {
// Call timelock to upgrade the proxy
vm.startBroadcast(config.users.admin);
console2.log("Scheduling upgrade of LevelReserveLens from proxy %s", address(proxy));

TimelockController timelock = TimelockController(payable(config.levelContracts.adminTimelock));
timelock.schedule(
address(proxy),
0,
abi.encodeWithSelector(proxy.upgradeToAndCall.selector, address(impl), ""),
bytes32(0),
0,
5 days
);

vm.warp(block.timestamp + 5 days);

timelock.execute(
address(proxy),
0,
abi.encodeWithSelector(proxy.upgradeToAndCall.selector, address(impl), ""),
bytes32(0),
0
);

console2.log("=====> LevelReserveLens upgraded ....");
console2.log(
"LevelReserveLens Proxy address : https://etherscan.io/address/%s", address(proxy)
);

vm.stopBroadcast();
}

// verify(impl);
}
Expand Down
13 changes: 12 additions & 1 deletion script/v2/usd/DeploySwapManager.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,19 @@ contract DeploySwapManager is Configurable, DeploymentUtils, Script {

console2.log("Deploying SwapManager from address %s", deployerWallet.addr);

if (address(config.levelContracts.pauserGuard) == address(0)) {
revert("PauserGuard must be deployed first");
}

if (address(config.levelContracts.rolesAuthority) == address(0)) {
revert("RolesAuthority must be deployed first");
}

bytes memory constructorArgs = abi.encodeWithSignature(
"initialize(address,address)", deployerWallet.addr, address(config.periphery.uniswapV3Router)
"initialize(address,address,address)",
deployerWallet.addr,
address(config.periphery.uniswapV3Router),
address(config.levelContracts.pauserGuard)
);

SwapManager _swapManager = new SwapManager{salt: convertNameToBytes32(LevelUsdSwapManagerName)}();
Expand Down
29 changes: 3 additions & 26 deletions script/v2/usd/UpgradeRewardsManager.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,32 +68,9 @@ contract UpgradeRewardsManager is Configurable, DeploymentUtils, Script {
console2.log("=====> RewardsManager deployed ....");
console2.log("RewardsManager Implementation : https://etherscan.io/address/%s", address(impl));

vm.startBroadcast(config.users.admin);

console2.log("Upgrading RewardsManager from proxy %s", address(proxy));
console2.log("New implementation: %s", address(impl));

try proxy.upgradeToAndCall(address(impl), "") {
console2.log("Upgrade successful!");
} catch {
revert UpgradeFailed();
}

vm.stopBroadcast();

// verify(impl);

/* STEPS AFTER UPGRADE

- Add all strategies

StrategyConfig[] memory usdcConfigs = new StrategyConfig[](3);
usdcConfigs[0] = aUsdcConfig;
usdcConfigs[1] = steakhouseUsdcConfig;
usdcConfigs[2] = sUsdcConfig;

config.levelContracts.rewardsManager.setAllStrategies(address(config.tokens.usdc), usdcConfigs);
*/
// Since RewardsManager is owned by timelock, we cannot directly upgrade the proxy
// For a real deployment, use the above implementation address to externally schedule a proxy upgrade
// through the timelock.
}

function verify(RewardsManager manager) public view {
Expand Down
113 changes: 3 additions & 110 deletions script/v2/usd/UpgradeVaultManager.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,6 @@ contract UpgradeVaultManager is Configurable, DeploymentUtils, Script {
vm.label(msg.sender, "Deployer EOA");
}

function setUp_(uint256 _chainId, uint256 _privateKey, BaseConfig.Config memory _config) public {
chainId = _chainId;
config = _config;

if (msg.sender != vm.addr(_privateKey)) {
revert("Private key does not match sender");
}

deployerWallet.privateKey = _privateKey;
deployerWallet.addr = vm.addr(_privateKey);

vm.label(msg.sender, "Deployer EOA");
}

function run() external returns (BaseConfig.Config memory) {
return upgrade();
}
Expand All @@ -86,106 +72,13 @@ contract UpgradeVaultManager is Configurable, DeploymentUtils, Script {
console2.log("=====> VaultManager deployed ....");
console2.log("VaultManager Implementation : https://etherscan.io/address/%s", address(impl));

// Setup update

CappedOneDollarOracle mNavOracle = new CappedOneDollarOracle(address(config.oracles.mNav));
vm.label(address(mNavOracle), "CappedMNavOracle");

StrategyConfig memory ustbConfig = StrategyConfig({
category: StrategyCategory.SUPERSTATE,
baseCollateral: config.tokens.usdc,
receiptToken: config.tokens.ustb,
oracle: config.oracles.ustb,
depositContract: address(config.tokens.ustb),
withdrawContract: address(config.periphery.ustbRedemptionIdle),
heartbeat: 1 days
});

StrategyConfig memory mConfig = StrategyConfig({
category: StrategyCategory.M0,
baseCollateral: config.tokens.usdc,
receiptToken: config.tokens.wrappedM,
oracle: AggregatorV3Interface(address(mNavOracle)),
depositContract: address(config.levelContracts.swapManager),
withdrawContract: address(config.levelContracts.swapManager),
heartbeat: 26 hours
});

address[] memory targets = new address[](5);
targets[0] = address(config.levelContracts.vaultManager);
targets[1] = address(config.levelContracts.vaultManager);
targets[2] = address(config.levelContracts.vaultManager);
targets[3] = address(config.levelContracts.rolesAuthority);
targets[4] = address(config.levelContracts.rolesAuthority);

bytes[] memory payloads = new bytes[](5);
// Upgrade to new implementation
payloads[0] = abi.encodeWithSelector(proxy.upgradeToAndCall.selector, address(impl), "");
// Add ustb as a strategy
payloads[1] = abi.encodeWithSelector(
config.levelContracts.vaultManager.addAssetStrategy.selector,
address(config.tokens.usdc),
address(config.tokens.ustb),
ustbConfig
);
// Add m as a strategy
payloads[2] = abi.encodeWithSelector(
config.levelContracts.vaultManager.addAssetStrategy.selector,
address(config.tokens.usdc),
address(config.tokens.wrappedM),
mConfig
);
// Add cooldown operator capability to strategist role
payloads[3] = abi.encodeWithSelector(
config.levelContracts.rolesAuthority.setRoleCapability.selector,
STRATEGIST_ROLE,
address(config.levelContracts.vaultManager),
bytes4(abi.encodeWithSignature("modifyAaveUmbrellaCooldownOperator(address,address,bool)")),
true
);
// Add rewards claimer capability to strategist role
payloads[4] = abi.encodeWithSelector(
config.levelContracts.rolesAuthority.setRoleCapability.selector,
STRATEGIST_ROLE,
address(config.levelContracts.vaultManager),
bytes4(abi.encodeWithSignature("modifyAaveUmbrellaRewardsClaimer(address,address,bool)")),
true
);

vm.startBroadcast(config.users.admin);

TimelockController timelock = TimelockController(payable(config.levelContracts.adminTimelock));
timelock.scheduleBatch(targets, new uint256[](5), payloads, bytes32(0), bytes32(0), 5 days);

vm.warp(block.timestamp + 5 days);

timelock.executeBatch(targets, new uint256[](5), payloads, bytes32(0), bytes32(0));

vm.stopBroadcast();
// As the deployed vaultManager is owned by timelock, we cannot directly upgrade the proxy
// For a real deployment, use the above implementation address to externally schedule a proxy upgrade
// through the timelock.

return config;

// verify(impl);

/* STEPS AFTER UPGRADE

- Add asset strategy for sUsdc
if (address(config.sparkVaults.sUsdc.vault) == address(0)) {
revert("Spark USDC vaults not deployed");
} else {
config.levelContracts.vaultManager.addAssetStrategy(
address(config.tokens.usdc), address(config.sparkVaults.sUsdc.vault), sUsdcConfig
);
}

- Add default strategy for USDC
address[] memory usdcDefaultStrategies = new address[](3);
usdcDefaultStrategies[0] = address(config.periphery.aaveV3);
usdcDefaultStrategies[1] = address(config.morphoVaults.steakhouseUsdc.vault);
usdcDefaultStrategies[2] = address(config.sparkVaults.sUsdc.vault);

config.levelContracts.vaultManager.setDefaultStrategies(address(config.tokens.usdc), usdcDefaultStrategies);
*/
}

function verify(VaultManager manager) public view {
Expand Down
Loading