Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safety Module Activation #166

Merged
merged 26 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
37b862b
mip-b16
ElliotFriedman Mar 31, 2024
be57de0
add assets
ElliotFriedman Mar 31, 2024
f19b095
add deploy impl
ElliotFriedman Mar 31, 2024
6d90898
Merge branch 'feat/mip-b26' of github.com:moonwell-fi/moonwell-contra…
ElliotFriedman Apr 1, 2024
3554007
Merge branch 'gauntlet-mips-march' of github.com:moonwell-fi/moonwell…
ElliotFriedman Apr 1, 2024
115fd0e
teardown before building and running
ElliotFriedman Apr 1, 2024
fbd4e89
updated proposal description
ElliotFriedman Apr 1, 2024
0963c00
teardown not pure
ElliotFriedman Apr 1, 2024
e65a783
add approval transferFrom action from msig to ecosystem reserve contr…
ElliotFriedman Apr 1, 2024
b6ebd1c
fix imports
ElliotFriedman Apr 1, 2024
0fcb7ce
remove unused import
ElliotFriedman Apr 2, 2024
a7f82ee
total supply change implies sender has non zero buffer cap
ElliotFriedman Apr 2, 2024
3414876
Merge pull request #168 from moonwell-fi/xwell-specification-improvement
ElliotFriedman Apr 3, 2024
450cb20
remove teardown, add moonbeam propose simulation
ElliotFriedman Apr 6, 2024
4c04710
use only moonbeam or moonbase chainid to fetch wormhole core address
ElliotFriedman Apr 6, 2024
105702c
index check gt
ElliotFriedman Apr 6, 2024
5583202
resubmission language
ElliotFriedman Apr 6, 2024
fa5ee03
WELL amount updated
ElliotFriedman Apr 6, 2024
eba1c1c
naming -> resubmission
ElliotFriedman Apr 6, 2024
5762eb1
run mip-b16
ElliotFriedman Apr 6, 2024
a569a07
estimated go live date in simple summary of proposal text
ElliotFriedman Apr 6, 2024
2b69387
fix merge conflicts
ElliotFriedman Apr 9, 2024
9506191
fix merge conflict
ElliotFriedman Apr 9, 2024
42faeae
_runBase function arguments
ElliotFriedman Apr 9, 2024
1a5bf53
WORMHOLE_CORE_BASE
ElliotFriedman Apr 9, 2024
fc93592
Update src/proposals/mips/mip-b16/mip-b16.sol
ElliotFriedman Apr 9, 2024
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
12 changes: 11 additions & 1 deletion certora/specs/ERC20.spec
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,18 @@ rule noChangeTotalSupply(env e) {
f(e, args);
uint256 totalSupplyAfter = totalSupply();

uint128 rateLimitPerSecond;
uint112 bufferCap;
uint32 lastBufferUsedTime;
uint112 bufferStored;
uint112 midpoint;

rateLimitPerSecond, bufferCap, lastBufferUsedTime, bufferStored, midpoint = rateLimits(e.msg.sender);

assert (totalSupplyAfter > totalSupplyBefore && bufferCap(e.msg.sender) > assert_uint256(midpoint)) =>
bufferCap(e.msg.sender) != 0;
assert totalSupplyAfter > totalSupplyBefore => f.selector == sig:mint(address,uint256).selector;
assert totalSupplyAfter < totalSupplyBefore => f.selector == sig:burn(address,uint256).selector;
assert totalSupplyAfter < totalSupplyBefore => f.selector == sig:burn(address,uint256).selector && bufferCap(e.msg.sender) != 0;
}

/*
Expand Down
1 change: 1 addition & 0 deletions certora/specs/IERC20.spec
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ methods {
function rateLimitPerSecond(address) external returns (uint256) envfree;
function minBufferCap() external returns (uint112) envfree;
function maxRateLimitPerSecond() external returns (uint128) envfree;
function rateLimits(address) external returns (uint128, uint112, uint32, uint112, uint112) envfree;
}
12 changes: 12 additions & 0 deletions src/IStakedWell.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ interface IStakedWell {
uint256 blockNumber
) external view returns (uint256);

/// @notice view the reward speed for stkWELL
function assets(
address
)
external
view
returns (
uint128 emissionsPerSecond,
uint128 lastUpdateTimestamp,
uint256 index
);

function redeem(address to, uint256 amount) external;

function mint(address to, uint256 amount) external;
Expand Down
4 changes: 4 additions & 0 deletions src/governance/multichain/MultichainGovernorDeploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ contract MultichainGovernorDeploy is Test {
);
}

function deployStkWellImpl() public returns (address) {
return deployCode("StakedWell.sol:StakedWell");
}

function deployStakedWell(
address stakedToken,
address rewardToken,
Expand Down
2 changes: 1 addition & 1 deletion src/proposals/MIPProposal.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ abstract contract MIPProposal is Script {
if (DO_AFTER_DEPLOY_SETUP) afterDeploySetup(addresses);
vm.stopBroadcast();

if (DO_TEARDOWN) teardown(addresses, deployerAddress);
if (DO_BUILD) build(addresses);
if (DO_RUN) run(addresses, deployerAddress);
if (DO_TEARDOWN) teardown(addresses, deployerAddress);
if (DO_VALIDATE) validate(addresses, deployerAddress);
/// todo print out actual proposal calldata
if (DO_PRINT) {
Expand Down
49 changes: 49 additions & 0 deletions src/proposals/mips/mip-b16/MIP-B16.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# MIP-B16 Base Safety Module Activation Resubmission

**Authors**: Elliot, Ana

## Simple Summary

The original proposal was approved but contained an error that prevented
successful execution on Moonbeam. This issue has been corrected in this
resubmission. If this proposal passes, the community can expect to have rewards
enabled for the Safety Module on Base on Thursday.

## Summary

This proposal aims to activate reward emissions for the new Safety Module on
Base, incentivizing users to help secure the Moonwell protocol through staking
and participate in onchain governance.

## Overview

The Moonwell community has recently approved the implementation of a new
multichain governor contract to govern the Moonwell protocol. Additionally, a
new Base native WELL token utilizing the xERC20 token standard has been approved
for usage, which is a significant milestone for the community. By adopting this
new Base native WELL token, tokenholders will soon be able to stake their WELL
directly on Base and vote in onchain governance. A new Safety Module has already
been deployed on Base and is registered in the Multichain Vote Collection
contract as a source of voting power, allowing users securing the protocol to
participate in governance. Initially, rewards were set to 0 on the new Safety
Module on Base. This proposal aims to enable rewards for users in the Safety
Module with the new Base native WELL token.

## Implementation

This proposal will set and fund rewards that will be distributed to all Safety
Module stakers on Base. Initial reward speeds will be set to the value
recommended by emissions admin Warden Finance of 0.8962755116489610000 WELL per
second. **Voting**

A "Yay" vote indicates your support for enabling reward emissions for the Safety
Module on Base, as outlined in this proposal. A "Nay" vote indicates your
opposition to enabling reward emissions for the Safety Module on Base.

## Conclusion

Adding rewards to the Safety Module on Base creates incentives for users to
backstop the protocol with the new Base native WELL token. Staking WELL in the
Safety Module not only gives community members the ability to earn native yield
on their holdings, but also presents an easy way to get involved in governance
as WELL is automatically self delegated.
123 changes: 123 additions & 0 deletions src/proposals/mips/mip-b16/mip-b16.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;

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

import "@forge-std/Test.sol";

import {Addresses} from "@proposals/Addresses.sol";
import {IStakedWell} from "@protocol/IStakedWell.sol";
import {HybridProposal} from "@proposals/proposalTypes/HybridProposal.sol";
import {ParameterValidation} from "@proposals/utils/ParameterValidation.sol";
import {MultichainGovernorDeploy} from "@protocol/governance/multichain/MultichainGovernorDeploy.sol";

/// DO_VALIDATE=true DO_PRINT=true DO_BUILD=true DO_RUN=true forge script
/// src/proposals/mips/mip-b16/mip-b16.sol:mipb16
contract mipb16 is
HybridProposal,
MultichainGovernorDeploy,
ParameterValidation
{
string public constant name = "MIP-B16 Resubmission";

/// @notice this is based on Warden Finance's recommendation for reward speeds
uint256 public constant REWARD_SPEED = 896275511648961000;

/// @notice the amount of WELL to be sent to the Safety Module for funding 38 days of rewards
/// 36*86400*.896275511648961000 = 2,787,775.3514329283 WELL, round up to 2,787,776
uint256 public constant WELL_AMOUNT = 2_787_776 * 1e18;

constructor() {
bytes memory proposalDescription = abi.encodePacked(
vm.readFile("./src/proposals/mips/mip-b16/MIP-B16.md")
);

_setProposalDescription(proposalDescription);
}

/// @notice proposal's actions happen only on base
function primaryForkId() public view override returns (uint256) {
return baseForkId;
}

function teardown(Addresses addresses, address) public override {}

/// run this action through the Multichain Governor
function build(Addresses addresses) public override {
/// Base actions

_pushHybridAction(
addresses.getAddress("xWELL_PROXY"),
abi.encodeWithSignature(
"transferFrom(address,address,uint256)",
addresses.getAddress("FOUNDATION_MULTISIG"),
addresses.getAddress("ECOSYSTEM_RESERVE_PROXY"),
WELL_AMOUNT
),
"Transfer xWELL rewards to Ecosystem Reserve Proxy on Base",
false
);

_pushHybridAction(
addresses.getAddress("stkWELL_PROXY"),
abi.encodeWithSignature(
"configureAsset(uint128,address)",
REWARD_SPEED,
addresses.getAddress("stkWELL_PROXY")
),
"Set reward speed for the Safety Module on Base",
false
);
}

function run(Addresses addresses, address) public override {
/// safety check to ensure no moonbeam actions are run
require(
baseActions.length == 2,
"MIP-B16: should have two base actions"
);

require(
moonbeamActions.length == 0,
"MIP-B16: should have no moonbeam actions"
);
vm.selectFork(moonbeamForkId);

_runMoonbeamMultichainGovernor(addresses, address(1000000000));

vm.selectFork(baseForkId);

_runBase(addresses, addresses.getAddress("TEMPORAL_GOVERNOR"));
}

/// @notice validations on Base
function validate(Addresses addresses, address) public override {
vm.selectFork(baseForkId);

address stkWellProxy = addresses.getAddress("stkWELL_PROXY");
(
uint128 emissionsPerSecond,
uint128 lastUpdateTimestamp,

) = IStakedWell(stkWellProxy).assets(stkWellProxy);

assertEq(
emissionsPerSecond,
REWARD_SPEED,
"MIP-B16: emissionsPerSecond incorrect"
);

assertGt(
lastUpdateTimestamp,
0,
"MIP-B16: lastUpdateTimestamp not set"
);
assertEq(
ERC20(addresses.getAddress("xWELL_PROXY")).balanceOf(
addresses.getAddress("ECOSYSTEM_RESERVE_PROXY")
),
WELL_AMOUNT,
"MIP-B16: ecosystem reserve not funded"
);
}
}
2 changes: 1 addition & 1 deletion src/proposals/proposalTypes/HybridProposal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ abstract contract HybridProposal is

function build(Addresses) public virtual override {}

function teardown(Addresses, address) public pure virtual override {}
function teardown(Addresses, address) public virtual override {}

function run(Addresses, address) public virtual override {}

Expand Down
31 changes: 27 additions & 4 deletions test/integration/MultichainProposal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ import {IEcosystemReserveUplift, IEcosystemReserveControllerUplift} from "@proto
import {TokenSaleDistributorInterfaceV1} from "@protocol/views/TokenSaleDistributorInterfaceV1.sol";

import {mipm23c} from "@proposals/mips/mip-m23/mip-m23c.sol";
import {mipm25} from "@proposals/mips/mip-m25/mip-m25.sol";

import {validateProxy} from "@proposals/utils/ProxyUtils.sol";
import {ITimelock as Timelock} from "@protocol/interfaces/ITimelock.sol";

/// @notice run this on a chainforked moonbeam node.
Expand Down Expand Up @@ -269,6 +267,31 @@ contract MultichainProposalTest is
);
}

function testNoBaseWormholeCoreAddressInProposal() public {
address wormholeBase = addresses.getAddress(
"WORMHOLE_CORE_BASE",
baseChainId
);
vm.selectFork(moonbeamForkId);
uint256[] memory proposals = governor.liveProposals();
for (uint256 i = 0; i < proposals.length; i++) {
if (proposals[i] == 4) {
continue;
}

(address[] memory targets, , ) = governor.getProposalData(
proposals[i]
);

for (uint256 j = 0; j < targets.length; j++) {
require(
targets[j] != wormholeBase,
"targeted wormhole core base address on moonbeam"
);
}
}
}

function testGetAllMarketConfigs() public {
MultiRewardDistributor mrd = MultiRewardDistributor(
addresses.getAddress("MRD_PROXY")
Expand Down Expand Up @@ -2405,7 +2428,7 @@ contract MultichainProposalTest is
) = stkwell.assets(address(stkwell));

assertEq(1e18, emissionsPerSecond, "emissions per second");
assertGt(index, 0, "index incorrect");
assertGt(index, 1, "rewards per second");
assertEq(
block.timestamp,
lastUpdateTimestamp,
Expand Down Expand Up @@ -2587,7 +2610,7 @@ contract MultichainProposalTest is
) = stkwell.assets(address(stkwell));

assertEq(1e18, emissionsPerSecond, "emissions per second");
assertGt(index, 0, "index incorrect");
assertGt(index, 1, "rewards per second");
assertEq(
block.timestamp,
lastUpdateTimestamp,
Expand Down
Loading