Skip to content

Commit

Permalink
feat: post-deploy v2 prep
Browse files Browse the repository at this point in the history
- solc 0.8.26
- latest common
- latest forge-std
- registrar as constructor arg
- excess destination as constructor arg
- constants made public
- token name changed
- `IsApprovedEarner` and `NotApprovedEarner` errors have account as parameter
- basic Migrator contract introduced
- version bump
- use more from common
- more test coverage
- fixed scripts to allow for generic deploy and mainnet upgrade
  • Loading branch information
deluca-mike committed Jan 16, 2025
1 parent 60b0d42 commit 3e9989e
Show file tree
Hide file tree
Showing 12 changed files with 454 additions and 196 deletions.
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ update:; forge update

# Deployment helpers
deploy:
FOUNDRY_PROFILE=production forge script script/DeployProduction.s.sol --skip src --skip test --rpc-url mainnet --slow --broadcast -vvv --verify
FOUNDRY_PROFILE=production MAINNET_RPC_URL=$(DEPLOY_RPC_URL) forge script script/Deploy.s.sol --skip src --skip test --slow --broadcast -vvv --verify

deploy-local:
FOUNDRY_PROFILE=production forge script script/DeployProduction.s.sol --skip src --skip test --rpc-url localhost --slow --broadcast -vvv
FOUNDRY_PROFILE=production forge script script/Deploy.s.sol --skip src --skip test --rpc-url localhost --slow --broadcast -vvv

deploy-upgrade:
FOUNDRY_PROFILE=production forge script script/DeployUpgradeMainnet.s.sol --skip src --skip test --rpc-url mainnet --slow --broadcast -vvv --verify

# Run slither
slither :
Expand Down
75 changes: 75 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.26;

import { Script, console2 } from "../lib/forge-std/src/Script.sol";

import { DeployBase } from "./DeployBase.sol";

contract DeployProduction is Script, DeployBase {
error DeployerMismatch(address expected, address actual);

error DeployerNonceTooHigh();

error UnexpectedDeployerNonce();

error CurrentNonceMismatch(uint64 expected, uint64 actual);

error ExpectedProxyMismatch(address expected, address actual);

error ResultingProxyMismatch(address expected, address actual);

function run() external {
address deployer_ = vm.rememberKey(vm.envUint("PRIVATE_KEY"));
address expectedDeployer_ = vm.envAddress("DEPLOYER");

uint64 deployerProxyNonce_ = uint64(vm.envUint("DEPLOYER_PROXY_NONCE"));

address registrar_ = vm.envAddress("REGISTRAR");
address excessDestination_ = vm.envAddress("EXCESS_DESTINATION");
address mToken_ = vm.envAddress("M_TOKEN");
address migrationAdmin_ = vm.envAddress("MIGRATION_ADMIN");
address expectedProxy_ = vm.envAddress("EXPECTED_PROXY");

console2.log("Deployer:", deployer_);

if (deployer_ != expectedDeployer_) revert DeployerMismatch(expectedDeployer_, deployer_);

uint64 currentNonce_ = vm.getNonce(deployer_);

uint64 startNonce_ = currentNonce_;
address implementation_;
address proxy_;

while (true) {
if (startNonce_ > deployerProxyNonce_) revert DeployerNonceTooHigh();

(implementation_, proxy_) = mockDeploy(deployer_, startNonce_);

if (proxy_ == expectedProxy_) break;

++startNonce_;
}

vm.startBroadcast(deployer_);

// Burn nonces until to `currentNonce_ == startNonce_`.
while (currentNonce_ < startNonce_) {
payable(deployer_).transfer(0);
++currentNonce_;
}

if (currentNonce_ != vm.getNonce(deployer_)) revert CurrentNonceMismatch(currentNonce_, vm.getNonce(deployer_));

if (currentNonce_ != startNonce_) revert UnexpectedDeployerNonce();

(implementation_, proxy_) = deployUpgrade(mToken_, registrar_, excessDestination_, migrationAdmin_);

vm.stopBroadcast();

console2.log("Wrapped M Implementation address:", implementation_);
console2.log("Migrator address:", proxy_);

if (proxy_ != expectedProxy_) revert ResultingProxyMismatch(expectedProxy_, proxy_);
}
}
72 changes: 51 additions & 21 deletions script/DeployBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ pragma solidity 0.8.26;
import { ContractHelper } from "../lib/common/src/libs/ContractHelper.sol";
import { Proxy } from "../lib/common/src/Proxy.sol";

import { MigratorV1 } from "../src/MigratorV1.sol";
import { WrappedMToken } from "../src/WrappedMToken.sol";

contract DeployBase {
/**
* @dev Deploys Wrapped M Token.
* @param mToken_ The address the M Token contract.
* @param registrar_ The address the Registrar contract.
* @param mToken_ The address of the M Token contract.
* @param registrar_ The address of the Registrar contract.
* @param excessDestination_ The address of the excess destination.
* @param migrationAdmin_ The address the Migration Admin.
* @param migrationAdmin_ The address of the Migration Admin.
* @return implementation_ The address of the deployed Wrapped M Token implementation.
* @return proxy_ The address of the deployed Wrapped M Token proxy.
*/
Expand All @@ -23,39 +24,68 @@ contract DeployBase {
address excessDestination_,
address migrationAdmin_
) public virtual returns (address implementation_, address proxy_) {
// Wrapped M token needs `mToken_`, `registrar_`, and `migrationAdmin_` addresses.
// Wrapped M token needs `mToken_`, `registrar_`, `excessDestination_`, and `migrationAdmin_` addresses.
// Proxy needs `implementation_` addresses.

implementation_ = address(new WrappedMToken(mToken_, registrar_, excessDestination_, migrationAdmin_));
proxy_ = address(new Proxy(implementation_));
}

function _getExpectedWrappedMTokenImplementation(
address deployer_,
uint256 deployerNonce_
) internal pure returns (address) {
return ContractHelper.getContractFrom(deployer_, deployerNonce_);
/**
* @dev Deploys Wrapped M Token components needed to upgrade an existing Wrapped M proxy.
* @param mToken_ The address of the M Token contract.
* @param registrar_ The address of the Registrar contract.
* @param excessDestination_ The address of the excess destination.
* @param migrationAdmin_ The address of the Migration Admin.
* @return implementation_ The address of the deployed Wrapped M Token implementation.
* @return migrator_ The address of the deployed Migrator.
*/
function deployUpgrade(
address mToken_,
address registrar_,
address excessDestination_,
address migrationAdmin_
) public virtual returns (address implementation_, address migrator_) {
// Wrapped M token needs `mToken_`, `registrar_`, `excessDestination_`, and `migrationAdmin_` addresses.
// Migrator needs `implementation_` addresses.

implementation_ = address(new WrappedMToken(mToken_, registrar_, excessDestination_, migrationAdmin_));
migrator_ = address(new MigratorV1(implementation_));
}

function getExpectedWrappedMTokenImplementation(
/**
* @dev Mock deploys Wrapped M Token, returning the would-be addresses.
* @param deployer_ The address of the deployer.
* @param deployerNonce_ The nonce of the deployer.
* @return implementation_ The address of the would-be Wrapped M Token implementation.
* @return proxy_ The address of the would-be Wrapped M Token proxy.
*/
function mockDeploy(
address deployer_,
uint256 deployerNonce_
) public pure virtual returns (address) {
return _getExpectedWrappedMTokenImplementation(deployer_, deployerNonce_);
}
) public view virtual returns (address implementation_, address proxy_) {
// Wrapped M token needs `mToken_`, `registrar_`, `excessDestination_`, and `migrationAdmin_` addresses.
// Proxy needs `implementation_` addresses.

function _getExpectedWrappedMTokenProxy(address deployer_, uint256 deployerNonce_) internal pure returns (address) {
return ContractHelper.getContractFrom(deployer_, deployerNonce_ + 1);
implementation_ = ContractHelper.getContractFrom(deployer_, deployerNonce_);
proxy_ = ContractHelper.getContractFrom(deployer_, deployerNonce_ + 1);
}

function getExpectedWrappedMTokenProxy(
/**
* @dev Mock deploys Wrapped M Token, returning the would-be addresses.
* @param deployer_ The address of the deployer.
* @param deployerNonce_ The nonce of the deployer.
* @return implementation_ The address of the would-be Wrapped M Token implementation.
* @return migrator_ The address of the would-be Migrator.
*/
function mockDeployUpgrade(
address deployer_,
uint256 deployerNonce_
) public pure virtual returns (address) {
return _getExpectedWrappedMTokenProxy(deployer_, deployerNonce_);
}
) public view virtual returns (address implementation_, address migrator_) {
// Wrapped M token needs `mToken_`, `registrar_`, `excessDestination_`, and `migrationAdmin_` addresses.
// Migrator needs `implementation_` addresses.

function getDeployerNonceAfterProtocolDeployment(uint256 deployerNonce_) public pure virtual returns (uint256) {
return deployerNonce_ + 2;
implementation_ = ContractHelper.getContractFrom(deployer_, deployerNonce_);
migrator_ = ContractHelper.getContractFrom(deployer_, deployerNonce_ + 1);
}
}
47 changes: 26 additions & 21 deletions script/DeployProduction.s.sol → script/DeployUpgradeMainnet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Script, console2 } from "../lib/forge-std/src/Script.sol";

import { DeployBase } from "./DeployBase.sol";

contract DeployProduction is Script, DeployBase {
contract DeployUpgradeMainnet is Script, DeployBase {
error DeployerMismatch(address expected, address actual);

error DeployerNonceTooHigh();
Expand All @@ -15,30 +15,28 @@ contract DeployProduction is Script, DeployBase {

error CurrentNonceMismatch(uint64 expected, uint64 actual);

error ExpectedProxyMismatch(address expected, address actual);
error ResultingMigratorMismatch(address expected, address actual);

error ResultingProxyMismatch(address expected, address actual);

// NOTE: Ensure this is the correct Registrar testnet/mainnet address.
address internal constant _REGISTRAR = 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c;

// NOTE: Ensure this is the correct Excess Destination testnet/mainnet address.
// NOTE: Ensure this is the correct Excess Destination mainnet address.
address internal constant _EXCESS_DESTINATION = 0xd7298f620B0F752Cf41BD818a16C756d9dCAA34f; // Vault

// NOTE: Ensure this is the correct M Token testnet/mainnet address.
address internal constant _M_TOKEN = 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b;

// NOTE: Ensure this is the correct Migration Admin testnet/mainnet address.
// NOTE: Ensure this is the correct Migration Admin mainnet address.
address internal constant _MIGRATION_ADMIN = 0x431169728D75bd02f4053435b87D15c8d1FB2C72;

// NOTE: Ensure this is the correct deployer testnet/mainnet to use.
address internal constant _PROXY = 0x437cc33344a0B27A429f795ff6B469C72698B291; // Mainnet address for the Proxy.

// NOTE: Ensure this is the correct mainnet deployer to use.
address internal constant _EXPECTED_DEPLOYER = 0xF2f1ACbe0BA726fEE8d75f3E32900526874740BB;

// NOTE: Ensure this is the correct nonce to use to deploy the Proxy on testnet/mainnet.
uint64 internal constant _DEPLOYER_PROXY_NONCE = 40;
// NOTE: Ensure this is the correct nonce to use to deploy the Migrator on mainnet.
uint64 internal constant _DEPLOYER_MIGRATOR_NONCE = 40;

// NOTE: Ensure this is the correct expected testnet/mainnet address for the Proxy.
address internal constant _EXPECTED_PROXY = 0x437cc33344a0B27A429f795ff6B469C72698B291;
// NOTE: Ensure this is the correct expected mainnet address for the Migrator.
address internal constant _EXPECTED_MIGRATOR = address(0);

function run() external {
address deployer_ = vm.rememberKey(vm.envUint("PRIVATE_KEY"));
Expand All @@ -48,17 +46,24 @@ contract DeployProduction is Script, DeployBase {
if (deployer_ != _EXPECTED_DEPLOYER) revert DeployerMismatch(_EXPECTED_DEPLOYER, deployer_);

uint64 currentNonce_ = vm.getNonce(deployer_);
uint64 startNonce_ = _DEPLOYER_PROXY_NONCE - 1;

if (currentNonce_ >= startNonce_) revert DeployerNonceTooHigh();
uint64 startNonce_ = currentNonce_;
address implementation_;
address migrator_;

while (true) {
if (startNonce_ > _DEPLOYER_MIGRATOR_NONCE) revert DeployerNonceTooHigh();

address expectedProxy_ = getExpectedWrappedMTokenProxy(deployer_, startNonce_);
(implementation_, migrator_) = mockDeployUpgrade(deployer_, startNonce_);

if (expectedProxy_ != _EXPECTED_PROXY) revert ExpectedProxyMismatch(_EXPECTED_PROXY, expectedProxy_);
if (migrator_ == _EXPECTED_MIGRATOR) break;

++startNonce_;
}

vm.startBroadcast(deployer_);

// Burn nonces until to 1 before `_DEPLOYER_PROXY_NONCE` since implementation is deployed before proxy.
// Burn nonces until to `currentNonce_ == startNonce_`.
while (currentNonce_ < startNonce_) {
payable(deployer_).transfer(0);
++currentNonce_;
Expand All @@ -68,13 +73,13 @@ contract DeployProduction is Script, DeployBase {

if (currentNonce_ != startNonce_) revert UnexpectedDeployerNonce();

(address implementation_, address proxy_) = deploy(_M_TOKEN, _REGISTRAR, _EXCESS_DESTINATION, _MIGRATION_ADMIN);
(implementation_, migrator_) = deployUpgrade(_M_TOKEN, _REGISTRAR, _EXCESS_DESTINATION, _MIGRATION_ADMIN);

vm.stopBroadcast();

console2.log("Wrapped M Implementation address:", implementation_);
console2.log("Wrapped M Proxy address:", proxy_);
console2.log("Migrator address:", migrator_);

if (proxy_ != _EXPECTED_PROXY) revert ResultingProxyMismatch(_EXPECTED_PROXY, proxy_);
if (migrator_ != _EXPECTED_MIGRATOR) revert ResultingMigratorMismatch(_EXPECTED_MIGRATOR, migrator_);
}
}
10 changes: 5 additions & 5 deletions src/MigratorV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ contract MigratorV1 {
/// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.implementation') - 1`.
uint256 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

address public immutable implementationV2;
address public immutable newImplementation;

constructor(address implementationV2_) {
implementationV2 = implementationV2_;
constructor(address newImplementation_) {
newImplementation = newImplementation_;
}

fallback() external virtual {
address implementationV2_ = implementationV2;
address newImplementation_ = newImplementation;

assembly {
sstore(_IMPLEMENTATION_SLOT, implementationV2_)
sstore(_IMPLEMENTATION_SLOT, newImplementation_)
}
}
}
Loading

0 comments on commit 3e9989e

Please sign in to comment.