feat: introduce proxy clones

This commit introduces proxy clones to make create `StakeVault`s as
cheap as possible.

Major changes here are:

- Introduce `VaultFactory` which takes care of creating clones and
  registering them with the stake manager
- Make `StakeVault` and `Initializable` so it can be used as a
  "template" contract to later have proxies point to it
- Adjust the deployment script to also deploy `VaultFactory` and ensure
  The proxy is whitelisted in the stake manager
- Make use of the new proxy clones in tests
- Add a test for `TrustedCodehashAccess` that ensures the proxy
  whitelisting works and setting up a (malicious) proxy is not going to
  work

Closes #101
This commit is contained in:
r4bbit
2025-02-03 14:02:51 +01:00
parent 177aba24d6
commit 70a7f30d2a
7 changed files with 267 additions and 133 deletions

View File

@@ -1,15 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
import { BaseScript } from "./Base.s.sol";
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
import { TransparentProxy } from "../src/TransparentProxy.sol";
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
import { StakeVault } from "../src/StakeVault.sol";
import { VaultFactory } from "../src/VaultFactory.sol";
contract DeployRewardsStreamerMPScript is BaseScript {
function run() public returns (RewardsStreamerMP, DeploymentConfig) {
function run() public returns (RewardsStreamerMP, VaultFactory, DeploymentConfig) {
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
(address deployer, address stakingToken) = deploymentConfig.activeNetworkConfig();
@@ -21,16 +25,19 @@ contract DeployRewardsStreamerMPScript is BaseScript {
address impl = address(new RewardsStreamerMP());
// Create upgradeable proxy
address proxy = address(new TransparentProxy(impl, initializeData));
// Create vault implementation for proxy clones
address vaultImplementation = address(new StakeVault(IERC20(stakingToken)));
address proxyClone = Clones.clone(vaultImplementation);
// Whitelist vault implementation codehash
RewardsStreamerMP(proxy).setTrustedCodehash(proxyClone.codehash, true);
// Create vault factory
VaultFactory vaultFactory = new VaultFactory(deployer, proxy, vaultImplementation);
vm.stopBroadcast();
RewardsStreamerMP stakeManager = RewardsStreamerMP(proxy);
StakeVault tempVault = new StakeVault(address(this), IStakeManagerProxy(proxy));
bytes32 vaultCodeHash = address(tempVault).codehash;
vm.startBroadcast(deployer);
stakeManager.setTrustedCodehash(vaultCodeHash, true);
vm.stopBroadcast();
return (stakeManager, deploymentConfig);
return (RewardsStreamerMP(proxy), vaultFactory, deploymentConfig);
}
}