mirror of
https://github.com/vacp2p/staking-reward-streamer.git
synced 2026-01-07 22:43:53 -05:00
feat: introduce deployment script for RewardsStreamerMP
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
This commit is contained in:
61
.gas-report
61
.gas-report
@@ -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 | | | | |
|
||||
@@ -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 |
|
||||
@@ -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 |
|
||||
@@ -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 |
|
||||
@@ -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 | | | | | |
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
41
script/Base.s.sol
Normal file
41
script/Base.s.sol
Normal file
@@ -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
script/DeployRewardsStreamerMP.s.sol
Normal file
33
script/DeployRewardsStreamerMP.s.sol
Normal file
@@ -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
script/DeploymentConfig.s.sol
Normal file
42
script/DeploymentConfig.s.sol
Normal file
@@ -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 { }
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import { Script } from "forge-std/Script.sol";
|
||||
import { RewardsStreamer } from "../src/RewardsStreamer.sol";
|
||||
|
||||
contract RewardsStreamerScript is Script {
|
||||
RewardsStreamer public rewardsStreamer;
|
||||
|
||||
function run() public {
|
||||
vm.startBroadcast();
|
||||
|
||||
// stakeManager = new StakeManager();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
@@ -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");
|
||||
@@ -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++) {
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user