Skip to content

Commit

Permalink
feat: token changes
Browse files Browse the repository at this point in the history
  • Loading branch information
wadealexc committed Sep 9, 2024
1 parent c36027b commit 12917d9
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 24 deletions.
72 changes: 72 additions & 0 deletions script/deploy/mainnet/bEIGEN_timelock_reduction.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/governance/TimelockController.sol";

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

// # To load the variables in the .env file
// source .env

// # To deploy and verify our contract
// forge script script/deploy/mainnet/bEIGEN_timelock_reduction.s.sol:bEIGEN_timelock_reduction -vvvv --rpc-url $RPC_URL
contract bEIGEN_timelock_reduction is Script, Test {
Vm cheats = Vm(HEVM_ADDRESS);

TimelockController public bEIGEN_TimelockController = TimelockController(payable(0xd6EC41E453C5E7dA5494f4d51A053Ab571712E6f));
address public bEIGEN_TimelockAdmin = 0xbb00DDa2832850a43840A3A86515E3Fe226865F2;

uint256 public newDelay = 0;

function run() external {
// Read and log the chain ID
uint256 chainId = block.chainid;
emit log_named_uint("You are deploying on ChainID", chainId);

if (chainId == 1) {
// rpcUrl = "RPC_MAINNET";
} else {
revert("Chain not supported");
}

uint256 minDelayBefore = bEIGEN_TimelockController.getMinDelay();

require(minDelayBefore == 24 days,
"something horribly wrong");

bytes memory proposalData = abi.encodeWithSelector(
TimelockController.updateDelay.selector,
newDelay
);
emit log_named_bytes("proposalData", proposalData);

// propose change to zero delay
vm.startPrank(bEIGEN_TimelockAdmin);
bEIGEN_TimelockController.schedule({
target: address(bEIGEN_TimelockController),
value: 0,
data: proposalData,
predecessor: bytes32(0),
salt: bytes32(0),
delay: minDelayBefore
});

// fast-forward to after current delay and execute
vm.warp(block.timestamp + minDelayBefore);
bEIGEN_TimelockController.execute({
target: address(bEIGEN_TimelockController),
value: 0,
payload: proposalData,
predecessor: bytes32(0),
salt: bytes32(0)
});

cheats.stopPrank();

uint256 minDelayAfter = bEIGEN_TimelockController.getMinDelay();

require(minDelayAfter == 0,
"min delay not set to zero");
}
}
104 changes: 104 additions & 0 deletions script/deploy/mainnet/bEIGEN_upgrade.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/governance/TimelockController.sol";

import "../../../src/contracts/token/BackingEigen.sol";

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

// # To load the variables in the .env file
// source .env

// # To deploy and verify our contract
// forge script script/deploy/mainnet/bEIGEN_upgrade.s.sol:bEIGEN_upgrade -vvvv --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast
contract bEIGEN_upgrade is Script, Test {
Vm cheats = Vm(HEVM_ADDRESS);

BackingEigen public bEIGEN_proxy = BackingEigen(0x83E9115d334D248Ce39a6f36144aEaB5b3456e75);
BackingEigen public bEIGEN_implementation;
ProxyAdmin public bEIGEN_ProxyAdmin = ProxyAdmin(0x3f5Ab2D4418d38568705bFd6672630fCC3435CC9);
TimelockController public bEIGEN_TimelockController = TimelockController(payable(0xd6EC41E453C5E7dA5494f4d51A053Ab571712E6f));
address public bEIGEN_TimelockAdmin = 0xbb00DDa2832850a43840A3A86515E3Fe226865F2;

// // RPC url to fork from for pre-upgrade state change tests
// string public rpcUrl;

IERC20 public EIGEN_addressBefore;

function run() external {
// Read and log the chain ID
uint256 chainId = block.chainid;
emit log_named_uint("You are deploying on ChainID", chainId);

if (chainId == 1) {
// rpcUrl = "RPC_MAINNET";
} else {
revert("Chain not supported");
}

EIGEN_addressBefore = bEIGEN_proxy.EIGEN();

require(EIGEN_addressBefore == IERC20(0xec53bF9167f50cDEB3Ae105f56099aaaB9061F83),
"something horribly wrong");

// Begin deployment
vm.startBroadcast();

// Deploy new implmementation contract
bEIGEN_implementation = new BackingEigen({
_EIGEN: EIGEN_addressBefore
});

vm.stopBroadcast();

emit log_named_address("bEIGEN_implementation", address(bEIGEN_implementation));

// Perform post-upgrade tests
simulatePerformingUpgrade();
checkUpgradeCorrectness();
}

function simulatePerformingUpgrade() public {
// Upgrade beacon
uint256 delay = bEIGEN_TimelockController.getMinDelay();
bytes memory data = abi.encodeWithSelector(
ProxyAdmin.upgrade.selector,
TransparentUpgradeableProxy(payable(address(bEIGEN_proxy))),
bEIGEN_implementation
);
emit log_named_bytes("data", data);

vm.startPrank(bEIGEN_TimelockAdmin);
bEIGEN_TimelockController.schedule({
target: address(bEIGEN_ProxyAdmin),
value: 0,
data: data,
predecessor: bytes32(0),
salt: bytes32(0),
delay: delay
});

vm.warp(block.timestamp + delay);
bEIGEN_TimelockController.execute({
target: address(bEIGEN_ProxyAdmin),
value: 0,
payload: data,
predecessor: bytes32(0),
salt: bytes32(0)
});

cheats.stopPrank();
}

function checkUpgradeCorrectness() public {
vm.prank(address(bEIGEN_TimelockController));
require(bEIGEN_ProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(bEIGEN_proxy)))) == address(bEIGEN_implementation),
"implementation set incorrectly");
require(bEIGEN_proxy.EIGEN() == EIGEN_addressBefore,
"EIGEN address changed unexpectedly");
}
}
27 changes: 27 additions & 0 deletions src/contracts/interfaces/IBackingEigen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,33 @@ interface IBackingEigen is IERC20 {
*/
function disableTransferRestrictions() external;

/**
* @notice An initializer function that sets initial values for the contract's state variables.
*/
function initialize(address initialOwner) external;

// @notice Allows the contract owner to modify an entry in the `isMinter` mapping.
function setIsMinter(address minterAddress, bool newStatus) external;

/**
* @notice Allows any privileged address to mint `amount` new tokens to the address `to`.
* @dev Callable only by an address that has `isMinter` set to true.
*/
function mint(address to, uint256 amount) external;

/**
* @dev Destroys `amount` tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 amount) external;

/// @notice the address of the wrapped Eigen token EIGEN
function EIGEN() external view returns (IERC20);

/// @notice the timestamp after which transfer restrictions are disabled
function transferRestrictionsDisabledAfter() external view returns (uint256);

/**
* @dev Clock used for flagging checkpoints. Has been overridden to implement timestamp based
* checkpoints (and voting).
Expand Down
6 changes: 6 additions & 0 deletions src/contracts/interfaces/IEigen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ interface IEigen is IERC20 {
*/
function unwrap(uint256 amount) external;

// @notice Burns EIGEN tokens held by the EIGEN token address itself
function burnExtraTokens() external;

/// @notice the address of the backing Eigen token bEIGEN
function bEIGEN() external view returns (IERC20);

/**
* @dev Clock used for flagging checkpoints. Has been overridden to implement timestamp based
* checkpoints (and voting).
Expand Down
30 changes: 29 additions & 1 deletion src/contracts/token/BackingEigen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ contract BackingEigen is OwnableUpgradeable, ERC20VotesUpgradeable {
mapping(address => bool) public allowedFrom;
/// @notice mapping of addresses that are allowed to receive tokens from any address
mapping(address => bool) public allowedTo;
// @notice whether or not an address is allowed to mint new bEIGEN tokens
mapping(address => bool) public isMinter;

/// @notice event emitted when the allowedFrom status of an address is set
event SetAllowedFrom(address indexed from, bool isAllowedFrom);
Expand All @@ -26,12 +28,38 @@ contract BackingEigen is OwnableUpgradeable, ERC20VotesUpgradeable {
event TransferRestrictionsDisabled();
/// @notice event emitted when the EIGEN token is backed
event Backed();
// @notice event emitted when the `isMinter` mapping is modified
event IsMinterModified(address indexed minterAddress, bool newStatus);

constructor(IERC20 _EIGEN) {
EIGEN = _EIGEN;
_disableInitializers();
}

// @notice Allows the contract owner to modify an entry in the `isMinter` mapping.
function setIsMinter(address minterAddress, bool newStatus) external onlyOwner {
emit IsMinterModified(minterAddress, newStatus);
isMinter[minterAddress] = newStatus;
}

/**
* @notice Allows any privileged address to mint `amount` new tokens to the address `to`.
* @dev Callable only by an address that has `isMinter` set to true.
*/
function mint(address to, uint256 amount) external {
require(isMinter[msg.sender], "BackingEigen.mint: caller is not a minter");
_mint(to, amount);
}

/**
* @dev Destroys `amount` tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}

/**
* @notice An initializer function that sets initial values for the contract's state variables.
*/
Expand All @@ -51,7 +79,7 @@ contract BackingEigen is OwnableUpgradeable, ERC20VotesUpgradeable {

// Mint the entire supply of EIGEN - this is a one-time event that
// ensures bEIGEN fully backs EIGEN.
_mint(address(EIGEN), EIGEN.totalSupply());
_mint(address(EIGEN), 1673646668284660000000000000);
emit Backed();
}

Expand Down
13 changes: 11 additions & 2 deletions src/contracts/token/Eigen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,14 @@ contract Eigen is OwnableUpgradeable, ERC20VotesUpgradeable {
*/
function wrap(uint256 amount) external {
require(bEIGEN.transferFrom(msg.sender, address(this), amount), "Eigen.wrap: bEIGEN transfer failed");
_transfer(address(this), msg.sender, amount);
_mint(msg.sender, amount);
}

/**
* @notice This function allows Eigen holders to unwrap their tokens into bEIGEN
*/
function unwrap(uint256 amount) external {
_transfer(msg.sender, address(this), amount);
_burn(msg.sender, amount);
require(bEIGEN.transfer(msg.sender, amount), "Eigen.unwrap: bEIGEN transfer failed");
}

Expand Down Expand Up @@ -162,6 +162,15 @@ contract Eigen is OwnableUpgradeable, ERC20VotesUpgradeable {
super._beforeTokenTransfer(from, to, amount);
}

/**
* @notice Overridden to return the total bEIGEN supply instead.
* @dev The issued supply of EIGEN should match the bEIGEN balance of this contract,
* less any bEIGEN tokens that were sent directly to the contract (rather than being wrapped)
*/
function totalSupply() public view override returns (uint256) {
return bEIGEN.totalSupply();
}

/**
* @dev Clock used for flagging checkpoints. Has been overridden to implement timestamp based
* checkpoints (and voting).
Expand Down
14 changes: 11 additions & 3 deletions src/test/token/EigenTransferRestrictions.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ pragma solidity ^0.8.12;

import "forge-std/Test.sol";

import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin-v4.9.0/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin-v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin-v4.9.0/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol";
import "../harnesses/EigenHarness.sol";

contract EigenTransferRestrictionsTest is Test {
Expand Down Expand Up @@ -38,8 +39,15 @@ contract EigenTransferRestrictionsTest is Test {
vm.startPrank(minter1);
proxyAdmin = new ProxyAdmin();
// initialize with dummy BackingEigen address
eigenImpl = new EigenHarness(IERC20(address(0)));

eigenImpl = new EigenHarness(new ERC20PresetFixedSupply({
name: "bEIGEN",
symbol: "bEIGEN",
initialSupply: totalSupply,
owner: minter1
}));
eigen = Eigen(address(new TransparentUpgradeableProxy(address(eigenImpl), address(proxyAdmin), "")));
eigen.bEIGEN().transfer(address(eigen), totalSupply);
vm.stopPrank();

fuzzedOutAddresses[minter1] = true;
Expand Down
Loading

0 comments on commit 12917d9

Please sign in to comment.