Skip to content

Commit

Permalink
add ezeth
Browse files Browse the repository at this point in the history
  • Loading branch information
sentilesdal committed May 1, 2024
1 parent a28cbe9 commit e599acd
Show file tree
Hide file tree
Showing 10 changed files with 542 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ broadcast
node_modules/
yarn-error.log

# Hardhat
artifacts/

# random files on MacOs
.DS_Store

Expand Down
2 changes: 1 addition & 1 deletion contracts/src/interfaces/IRenzo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ interface IRenzoOracle {
uint256 _ezETHBeingBurned,
uint256 _existingEzETHSupply,
uint256 _currentValueInProtocol
) external pure returns (uint256);
) external view returns (uint256);
}

interface IDepositQueue {
Expand Down
247 changes: 247 additions & 0 deletions contracts/test/MockEzEthPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.20;

import { MultiRolesAuthority } from "solmate/auth/authorities/MultiRolesAuthority.sol";
import { FixedPointMath } from "../src/libraries/FixedPointMath.sol";
import { ERC20Mintable } from "./ERC20Mintable.sol";
import { IERC20 } from "../src/interfaces/IERC20.sol";
import { IRestakeManager, IRenzoOracle } from "../src/interfaces/IRenzo.sol";

/// @author DELV
/// @title MockLido
/// @notice This mock yield source will accrue interest at a specified rate
/// Every stateful interaction will accrue interest, so the interest
/// accrual will approximate continuous compounding as the contract
/// is called more frequently.
/// @custom:disclaimer The language used in this code is for coding convenience
/// only, and is not intended to, and does not, have any
/// particular legal or regulatory significance.
contract MockEzEthPool is
IRestakeManager,
IRenzoOracle,
MultiRolesAuthority,
ERC20Mintable
{
using FixedPointMath for uint256;

// Interest State
uint256 internal _rate;
uint256 internal _lastUpdated;

// Lido State
uint256 totalPooledEther;
uint256 totalShares;

constructor(
uint256 _initialRate,
address _admin,
bool _isCompetitionMode,
uint256 _maxMintAmount
)
ERC20Mintable(
"Renzo ezETH",
"ezETH",
18,
_admin,
_isCompetitionMode,
_maxMintAmount
)
{
_rate = _initialRate;
_lastUpdated = block.timestamp;
}

/// Overrides ///

function submit(address) external payable returns (uint256) {
// Accrue interest.
_accrue();

// If this is the first deposit, mint shares 1:1.
if (getTotalShares() == 0) {
totalShares = msg.value;
totalPooledEther = msg.value;
_mint(msg.sender, msg.value);
return msg.value;
}

// Calculate the amount of stETH shares that should be minted.
uint256 shares = msg.value.mulDivDown(
getTotalShares(),
getTotalPooledEther()
);

// Update the Lido state.
totalPooledEther += msg.value;
totalShares += shares;

// Mint the stETH tokens to the user.
_mint(msg.sender, msg.value);

return shares;
}

function transferShares(
address _recipient,
uint256 _sharesAmount
) external returns (uint256) {
// Accrue interest.
_accrue();

// Calculate the amount of tokens that should be transferred.
uint256 tokenAmount = _sharesAmount.mulDivDown(
getTotalPooledEther(),
getTotalShares()
);

// Transfer the tokens to the user.
transfer(_recipient, tokenAmount);

return tokenAmount;
}

function transferSharesFrom(
address _sender,
address _recipient,
uint256 _sharesAmount
) external returns (uint256) {
// Accrue interest.
_accrue();

// Calculate the amount of tokens that should be transferred.
uint256 tokenAmount = _sharesAmount.mulDivDown(
getTotalPooledEther(),
getTotalShares()
);

// Transfer the tokens to the user.
transferFrom(_sender, _recipient, tokenAmount);

return tokenAmount;
}

function getSharesByPooledEth(
uint256 _ethAmount
) external view returns (uint256) {
return _ethAmount.mulDivDown(getTotalShares(), getTotalPooledEther());
}

function getPooledEthByShares(
uint256 _sharesAmount
) public view returns (uint256) {
return
_sharesAmount.mulDivDown(getTotalPooledEther(), getTotalShares());
}

function getBufferedEther() external pure returns (uint256) {
return 0;
}

function getTotalPooledEther() public view returns (uint256) {
return totalPooledEther + _getAccruedInterest();
}

function getTotalShares() public view returns (uint256) {
return totalShares;
}

function sharesOf(address _account) external view returns (uint256) {
uint256 tokenBalance = balanceOf[_account];
return tokenBalance.mulDivDown(getTotalShares(), getTotalPooledEther());
}

/// Mock ///

function setRate(uint256 _rate_) external requiresAuthDuringCompetition {
_accrue();
_rate = _rate_;
}

function getRate() external view returns (uint256) {
return _rate;
}

function _accrue() internal {
uint256 interest = _getAccruedInterest();
if (interest > 0) {
totalPooledEther += interest;
}
_lastUpdated = block.timestamp;
}

function _getAccruedInterest() internal view returns (uint256) {
if (_rate == 0) {
return 0;
}

// base_balance = base_balance * (1 + r * t)
uint256 timeElapsed = (block.timestamp - _lastUpdated).divDown(
365 days
);
uint256 accrued = totalPooledEther.mulDown(_rate.mulDown(timeElapsed));
return accrued;
}

function calculateTVLs()
public
view
override
returns (uint256[][] memory, uint256[] memory, uint256)
{
uint256[][] memory operator_tokens_tvls;
uint256[] memory operator_tvls;
uint256 tvl = getTotalPooledEther();
return (operator_tokens_tvls, operator_tvls, tvl);
}

function depositETH() external payable {
revert("depositETH: Not Implemented");
}

function ezETH() external view returns (address) {
return address(this);
}

function renzoOracle() external view returns (address) {
return address(this);
}

// Renzo Oracle Functions //

function lookupTokenValue(
IERC20, //_token,
uint256 //_balance
) external pure returns (uint256) {
revert("lookupTokenValue: Not Implemented");
}

function lookupTokenAmountFromValue(
IERC20, // _token,
uint256 // _value
) external pure returns (uint256) {
revert("lookupTokenValue: Not Implemented");
}

function lookupTokenValues(
IERC20[] memory, // _tokens,
uint256[] memory // _balances
) external pure returns (uint256) {
revert("lookupTokenValue: Not Implemented");
}

function calculateMintAmount(
uint256, // _currentValueInProtocol,
uint256, // _newValueAdded,
uint256 // _existingEzETHSupply
) external pure returns (uint256) {
revert("lookupTokenValue: Not Implemented");
}

function calculateRedeemAmount(
uint256 _ezETHBeingBurned,
uint256, // _existingEzETHSupply,
uint256 // _currentValueInProtocol
) public view returns (uint256) {
return getPooledEthByShares(_ezETHBeingBurned);
}
}
33 changes: 33 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
StETHInstanceDeployConfigInput,
} from "./tasks";
import { RETHInstanceDeployConfigInput } from "./tasks/deploy/instances/reth";
import { EzETHInstanceDeployConfigInput } from "./tasks/deploy/instances/ezeth";

const TEST_FACTORY: FactoryDeployConfigInput = {
governance: "0xd94a3A0BfC798b98a700a785D5C610E8a2d5DBD8",
Expand Down Expand Up @@ -103,6 +104,37 @@ const TEST_STETH: StETHInstanceDeployConfigInput = {
},
};

const TEST_EZETH: EzETHInstanceDeployConfigInput = {
name: "TEST_EZETH",
deploymentId: "0xabbabac",
salt: "0x69420",
contribution: "0.1",
fixedAPR: "0.5",
timestretchAPR: "0.5",
options: {
// destination: "0xsomeone",
asBase: false,
// extraData: "0x",
},
poolDeployConfig: {
// vaultSharesToken: "0x...",
minimumShareReserves: "0.001",
minimumTransactionAmount: "0.001",
positionDuration: "30 days",
checkpointDuration: "1 day",
timeStretch: "0",
governance: "0xd94a3A0BfC798b98a700a785D5C610E8a2d5DBD8",
feeCollector: "0xd94a3A0BfC798b98a700a785D5C610E8a2d5DBD8",
sweepCollector: "0xd94a3A0BfC798b98a700a785D5C610E8a2d5DBD8",
fees: {
curve: "0.001",
flat: "0.0001",
governanceLP: "0.15",
governanceZombie: "0.03",
},
},
};

const TEST_RETH: RETHInstanceDeployConfigInput = {
name: "TEST_RETH",
deploymentId: "0x666666666",
Expand Down Expand Up @@ -165,6 +197,7 @@ const config: HardhatUserConfig = {
erc4626: [TEST_ERC4626],
steth: [TEST_STETH],
reth: [TEST_RETH],
ezeth: [TEST_EZETH],
},
},
sepolia: {
Expand Down
1 change: 1 addition & 0 deletions tasks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The complete list of tasks can be seen by running `npx hardhat --help` in your t
deploy:coordinators:erc4626 deploys the ERC4626 deployment coordinator
deploy:coordinators:reth deploys the RETH deployment coordinator
deploy:coordinators:steth deploys the STETH deployment coordinator
deploy:coordinators:ezeth deploys the EzETH deployment coordinator
deploy:factory deploys the hyperdrive factory to the configured chain
deploy:forwarder deploys the ERC20ForwarderFactory to the configured chain
deploy:instances:all deploys the ERC4626 deployment coordinator
Expand Down
Loading

0 comments on commit e599acd

Please sign in to comment.