Skip to content

Commit

Permalink
feat: introduce deployment script for RewardsStreamerMP
Browse files Browse the repository at this point in the history
This commit introduces a deployment script for the stake manager which
can later be extended to work with other networks.

The deployment script is also used inside our testsuite, ensuring it's
working as intended.

Closes #88
  • Loading branch information
0x-r4bbit committed Dec 9, 2024
1 parent 106ec98 commit a565dbb
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 53 deletions.
61 changes: 51 additions & 10 deletions .gas-report
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
| script/DeployRewardsStreamerMP.s.sol:DeployRewardsStreamerMPScript contract | | | | | |
|-----------------------------------------------------------------------------|-----------------|---------|---------|---------|---------|
| Deployment Cost | Deployment Size | | | | |
| 6200681 | 29704 | | | | |
| Function Name | min | avg | median | max | # calls |
| run | 5302574 | 5302574 | 5302574 | 5302574 | 57 |


| script/DeploymentConfig.s.sol:DeploymentConfig contract | | | | | |
|---------------------------------------------------------|-----------------|-----|--------|-----|---------|
| Deployment Cost | Deployment Size | | | | |
| 0 | 0 | | | | |
| Function Name | min | avg | median | max | # calls |
| activeNetworkConfig | 454 | 454 | 454 | 454 | 114 |


| src/RewardsStreamer.sol:RewardsStreamer contract | | | | | |
|--------------------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
Expand All @@ -21,7 +37,7 @@
| MAX_MULTIPLIER | 251 | 251 | 251 | 251 | 11 |
| MIN_LOCKUP_PERIOD | 297 | 297 | 297 | 297 | 11 |
| MP_RATE_PER_YEAR | 253 | 253 | 253 | 253 | 3 |
| STAKING_TOKEN | 2428 | 2428 | 2428 | 2428 | 292 |
| STAKING_TOKEN | 428 | 2037 | 2428 | 2428 | 292 |
| emergencyModeEnabled | 2420 | 2420 | 2420 | 2420 | 7 |
| enableEmergencyMode | 2485 | 19392 | 24677 | 24677 | 8 |
| getAccount | 1661 | 1661 | 1661 | 1661 | 72 |
Expand All @@ -31,7 +47,6 @@
| getUserTotalStakedBalance | 15118 | 15118 | 15118 | 15118 | 1 |
| getUserVaults | 5201 | 5201 | 5201 | 5201 | 4 |
| initialize | 115611 | 115611 | 115611 | 115611 | 59 |
| isTrustedCodehash | 519 | 519 | 519 | 519 | 231 |
| lastRewardTime | 395 | 1395 | 1395 | 2395 | 2 |
| leave | 56244 | 56244 | 56244 | 56244 | 1 |
| lock | 12063 | 34172 | 16480 | 73975 | 3 |
Expand All @@ -41,7 +56,7 @@
| rewardStartTime | 352 | 1352 | 1352 | 2352 | 2 |
| rewardsBalanceOf | 1317 | 1317 | 1317 | 1317 | 4 |
| setReward | 2583 | 50892 | 60278 | 102595 | 7 |
| setTrustedCodehash | 26243 | 26243 | 26243 | 26243 | 59 |
| setTrustedCodehash | 24243 | 24310 | 24243 | 26243 | 59 |
| stake | 131082 | 170202 | 177899 | 198232 | 66 |
| totalMP | 373 | 373 | 373 | 373 | 81 |
| totalMaxMP | 350 | 350 | 350 | 350 | 81 |
Expand All @@ -54,13 +69,39 @@
| upgradeToAndCall | 3225 | 9387 | 10926 | 10936 | 5 |


| src/StakeManagerProxy.sol:StakeManagerProxy contract | | | | | |
|------------------------------------------------------|-----------------|------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 256079 | 1231 | | | | |
| Function Name | min | avg | median | max | # calls |
| fallback | 678 | 8892 | 2115 | 136272 | 1047 |
| implementation | 343 | 808 | 343 | 2343 | 382 |
| src/StakeManagerProxy.sol:StakeManagerProxy contract | | | | | |
|------------------------------------------------------|-----------------|-------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 256467 | 1263 | | | | |
| Function Name | min | avg | median | max | # calls |
| MAX_LOCKUP_PERIOD | 5276 | 5276 | 5276 | 5276 | 4 |
| MAX_MULTIPLIER | 678 | 3132 | 5178 | 5178 | 11 |
| MIN_LOCKUP_PERIOD | 724 | 3996 | 5224 | 5224 | 11 |
| MP_RATE_PER_YEAR | 680 | 680 | 680 | 680 | 3 |
| STAKING_TOKEN | 855 | 6086 | 7355 | 7355 | 292 |
| emergencyModeEnabled | 7347 | 7347 | 7347 | 7347 | 7 |
| enableEmergencyMode | 28480 | 45381 | 50665 | 50665 | 8 |
| getAccount | 2115 | 2115 | 2115 | 2115 | 72 |
| getStakedBalance | 7559 | 7559 | 7559 | 7559 | 1 |
| getUserTotalMP | 9660 | 9660 | 9660 | 9660 | 1 |
| getUserTotalMaxMP | 3553 | 3553 | 3553 | 3553 | 1 |
| getUserTotalStakedBalance | 15548 | 15548 | 15548 | 15548 | 1 |
| getUserVaults | 5637 | 6762 | 5637 | 10137 | 4 |
| implementation | 343 | 808 | 343 | 2343 | 382 |
| lastRewardTime | 822 | 1822 | 1822 | 2822 | 2 |
| rewardEndTime | 800 | 1800 | 1800 | 2800 | 2 |
| rewardStartTime | 779 | 4029 | 4029 | 7279 | 2 |
| rewardsBalanceOf | 1747 | 1747 | 1747 | 1747 | 4 |
| setReward | 28863 | 77206 | 86636 | 128881 | 7 |
| setTrustedCodehash | 52889 | 52889 | 52889 | 52889 | 2 |
| totalMP | 800 | 800 | 800 | 800 | 81 |
| totalMaxMP | 777 | 777 | 777 | 777 | 81 |
| totalRewardsAccrued | 800 | 800 | 800 | 800 | 3 |
| totalRewardsSupply | 1387 | 2498 | 2151 | 11627 | 30 |
| totalStaked | 823 | 823 | 823 | 823 | 82 |
| updateAccountMP | 41755 | 44833 | 44257 | 61357 | 21 |
| updateGlobalState | 37076 | 54033 | 51237 | 136272 | 21 |
| upgradeToAndCall | 29868 | 36025 | 37562 | 37572 | 5 |


| src/StakeVault.sol:StakeVault contract | | | | | |
Expand Down
14 changes: 7 additions & 7 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ EmergencyExitTest:test_OnlyOwnerCanEnableEmergencyMode() (gas: 39430)
IntegrationTest:testStakeFoo() (gas: 1178499)
LeaveTest:test_LeaveShouldProperlyUpdateAccounting() (gas: 2960876)
LeaveTest:test_RevertWhenStakeManagerIsTrusted() (gas: 294826)
LeaveTest:test_TrustNewStakeManager() (gas: 3036018)
LeaveTest:test_TrustNewStakeManager() (gas: 3038518)
LockTest:test_LockFailsWithInvalidPeriod() (gas: 309911)
LockTest:test_LockFailsWithNoStake() (gas: 63708)
LockTest:test_LockWithoutPriorLock() (gas: 385937)
Expand All @@ -21,12 +21,12 @@ NFTMetadataGeneratorSVGTest:testSetImageStringsRevert() (gas: 35804)
NFTMetadataGeneratorURLTest:testGenerateMetadata() (gas: 102512)
NFTMetadataGeneratorURLTest:testSetBaseURL() (gas: 49555)
NFTMetadataGeneratorURLTest:testSetBaseURLRevert() (gas: 35979)
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 670682)
RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 160280)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 39345)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 39368)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39381)
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 610702)
RewardsStreamerMP_RewardsTest:testRewardsBalanceOf() (gas: 670670)
RewardsStreamerMP_RewardsTest:testSetRewards() (gas: 160274)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadAmount() (gas: 39339)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsBadDuration() (gas: 39362)
RewardsStreamerMP_RewardsTest:testSetRewards_RevertsNotAuthorized() (gas: 39375)
RewardsStreamerMP_RewardsTest:testTotalRewardsSupply() (gas: 610684)
RewardsStreamerTest:testStake() (gas: 869181)
StakeTest:test_StakeMultipleAccounts() (gas: 494442)
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 500380)
Expand Down
41 changes: 41 additions & 0 deletions script/Base.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.26 <=0.9.0;

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

abstract contract BaseScript is Script {
/// @dev Included to enable compilation of the script without a $MNEMONIC environment variable.
string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk";

/// @dev Needed for the deterministic deployments.
bytes32 internal constant ZERO_SALT = bytes32(0);

/// @dev The address of the transaction broadcaster.
address internal broadcaster;

/// @dev Used to derive the broadcaster's address if $ETH_FROM is not defined.
string internal mnemonic;

/// @dev Initializes the transaction broadcaster like this:
///
/// - If $ETH_FROM is defined, use it.
/// - Otherwise, derive the broadcaster address from $MNEMONIC.
/// - If $MNEMONIC is not defined, default to a test mnemonic.
///
/// The use case for $ETH_FROM is to specify the broadcaster key and its address via the command line.
constructor() {
address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) });
if (from != address(0)) {
broadcaster = from;
} else {
mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC });
(broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 });
}
}

modifier broadcast() {
vm.startBroadcast(broadcaster);
_;
vm.stopBroadcast();
}
}
33 changes: 33 additions & 0 deletions script/DeployRewardsStreamerMP.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import { BaseScript } from "./Base.s.sol";
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
import { StakeManagerProxy } from "../src/StakeManagerProxy.sol";
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
import { StakeVault } from "../src/StakeVault.sol";

contract DeployRewardsStreamerMPScript is BaseScript {
function run() public returns (RewardsStreamerMP, DeploymentConfig) {
DeploymentConfig deploymentConfig = new DeploymentConfig(broadcaster);
(address deployer, address stakingToken) = deploymentConfig.activeNetworkConfig();

bytes memory initializeData = abi.encodeCall(RewardsStreamerMP.initialize, (deployer, stakingToken));

vm.startBroadcast(deployer);
address impl = address(new RewardsStreamerMP());
address proxy = address(new StakeManagerProxy(impl, initializeData));
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);
}
}
42 changes: 42 additions & 0 deletions script/DeploymentConfig.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//// SPDX-License-Identifier: UNLICENSED

pragma solidity >=0.8.26 <=0.9.0;

import { Script } from "forge-std/Script.sol";
import { MockToken } from "../test/mocks/MockToken.sol";

contract DeploymentConfig is Script {
error DeploymentConfig_InvalidDeployerAddress();
error DeploymentConfig_NoConfigForChain(uint256);

struct NetworkConfig {
address deployer;
address stakingToken;
}

NetworkConfig public activeNetworkConfig;

address private deployer;

constructor(address _broadcaster) {
if (_broadcaster == address(0)) revert DeploymentConfig_InvalidDeployerAddress();
deployer = _broadcaster;
if (block.chainid == 31_337) {
activeNetworkConfig = getOrCreateAnvilEthConfig();
} else {
revert DeploymentConfig_NoConfigForChain(block.chainid);
}
}

function getOrCreateAnvilEthConfig() public returns (NetworkConfig memory) {
MockToken stakingToken = new MockToken("Staking Token", "ST");
return NetworkConfig({ deployer: deployer, stakingToken: address(stakingToken) });
}

// This function is a hack to have it excluded by `forge coverage` until
// https://github.com/foundry-rs/foundry/issues/2988 is fixed.
// See: https://github.com/foundry-rs/foundry/issues/2988#issuecomment-1437784542
// for more info.
// solhint-disable-next-line
function test() public { }
}
17 changes: 0 additions & 17 deletions script/RewardsStreamer.s.sol

This file was deleted.

28 changes: 9 additions & 19 deletions test/RewardsStreamerMP.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ pragma solidity ^0.8.26;

import { Test } from "forge-std/Test.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { DeployRewardsStreamerMPScript } from "../script/DeployRewardsStreamerMP.s.sol";
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { RewardsStreamerMP } from "../src/RewardsStreamerMP.sol";
import { StakeVault } from "../src/StakeVault.sol";
import { IStakeManagerProxy } from "../src/interfaces/IStakeManagerProxy.sol";
Expand All @@ -17,7 +18,7 @@ contract RewardsStreamerMPTest is Test {
MockToken stakingToken;
RewardsStreamerMP public streamer;

address admin = makeAddr("admin");
address admin;
address alice = makeAddr("alice");
address bob = makeAddr("bob");
address charlie = makeAddr("charlie");
Expand All @@ -26,20 +27,14 @@ contract RewardsStreamerMPTest is Test {
mapping(address owner => address vault) public vaults;

function setUp() public virtual {
stakingToken = new MockToken("Staking Token", "ST");
DeployRewardsStreamerMPScript deployment = new DeployRewardsStreamerMPScript();
(RewardsStreamerMP stakeManager, DeploymentConfig deploymentConfig) = deployment.run();

bytes memory initializeData = abi.encodeCall(RewardsStreamerMP.initialize, (admin, address(stakingToken)));
address impl = address(new RewardsStreamerMP());
address proxy = address(new StakeManagerProxy(impl, initializeData));
streamer = RewardsStreamerMP(proxy);
(address _deployer, address _stakingToken) = deploymentConfig.activeNetworkConfig();

// Create a temporary vault just to get the codehash
StakeVault tempVault = new StakeVault(address(this), IStakeManagerProxy(address(streamer)));
bytes32 vaultCodeHash = address(tempVault).codehash;

// Register the codehash before creating any user vaults
vm.prank(admin);
streamer.setTrustedCodehash(vaultCodeHash, true);
streamer = stakeManager;
stakingToken = MockToken(_stakingToken);
admin = _deployer;

address[4] memory accounts = [alice, bob, charlie, dave];
for (uint256 i = 0; i < accounts.length; i++) {
Expand Down Expand Up @@ -111,11 +106,6 @@ contract RewardsStreamerMPTest is Test {
vm.prank(owner);
vault = new StakeVault(owner, IStakeManagerProxy(address(streamer)));
vault.register();

if (!streamer.isTrustedCodehash(address(vault).codehash)) {
vm.prank(admin);
streamer.setTrustedCodehash(address(vault).codehash, true);
}
}

function _stake(address account, uint256 amount, uint256 lockupTime) public {
Expand Down

0 comments on commit a565dbb

Please sign in to comment.