Skip to content

Commit

Permalink
chore: migrated fork tests to mainnet
Browse files Browse the repository at this point in the history
  • Loading branch information
cosminobol committed Mar 15, 2024
1 parent 06a9998 commit 90b85e6
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 205 deletions.
3 changes: 2 additions & 1 deletion src/eigenlayer/ObolEigenLayerPodController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ contract ObolEigenLayerPodController {
function initialize(address _owner, address _withdrawalAddress) external {
if (owner != address(0)) revert AlreadyInitialized();

eigenPod = eigenLayerPodManager.createPod();
eigenLayerPodManager.createPod();
eigenPod = eigenLayerPodManager.getPod(address(this));
owner = _owner;
withdrawalAddress = _withdrawalAddress;

Expand Down
253 changes: 234 additions & 19 deletions src/interfaces/IEigenLayer.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;


//TODO: update interfaces; check
import {ERC20} from "solmate/tokens/ERC20.sol";

interface IEigenLayerUtils {
Expand All @@ -25,25 +27,213 @@ interface IEigenLayerUtils {
}
}

interface IPauserRegistry {
function unpauser() external view returns (address);
}

interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);

/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);

/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);

/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);

/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);

/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);

/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);

/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}

/**
* @title Minimal interface for an `Strategy` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Custom `Strategy` implementations may expand extensively on this interface.
*/
interface IStrategy {
/**
* @notice Used to deposit tokens into this Strategy
* @param token is the ERC20 token being deposited
* @param amount is the amount of token being deposited
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
* @return newShares is the number of new shares issued at the current exchange ratio.
*/
function deposit(IERC20 token, uint256 amount) external returns (uint256);

/**
* @notice Used to withdraw tokens from this Strategy, to the `depositor`'s address
* @param depositor is the address to receive the withdrawn funds
* @param token is the ERC20 token being transferred out
* @param amountShares is the amount of shares being withdrawn
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* other functions, and individual share balances are recorded in the strategyManager as well.
*/
function withdraw(address depositor, IERC20 token, uint256 amountShares) external;

/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlying(uint256 amountShares) external returns (uint256);

/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToShares(uint256 amountUnderlying) external returns (uint256);

/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
*/
function userUnderlying(address user) external returns (uint256);

/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256);

/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256);

/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
*/
function userUnderlyingView(address user) external view returns (uint256);

/// @notice The underlying token for shares in this Strategy
function underlyingToken() external view returns (IERC20);

/// @notice The total number of extant shares in this Strategy
function totalShares() external view returns (uint256);

/// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
function explanation() external view returns (string memory);
}

/**
* @title Abstract interface for a contract that helps structure the delegation relationship.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice The gas budget provided to this contract in calls from EigenLayer contracts is limited.
*/
interface IDelegationTerms {
function payForService(IERC20 token, uint256 amount) external payable;

function onDelegationWithdrawn(
address delegator,
IStrategy[] memory stakerStrategyList,
uint256[] memory stakerShares
) external returns(bytes memory);

function onDelegationReceived(
address delegator,
IStrategy[] memory stakerStrategyList,
uint256[] memory stakerShares
) external returns(bytes memory);
}

interface IDelegationManager is IEigenLayerUtils {
/**
* @notice Caller delegates their stake to an operator.
* @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on
* EigenLayer.
* @param approverSignatureAndExpiry Verifies the operator approves of this delegation
* @param approverSalt A unique single use value tied to an individual signature.
* @dev The approverSignatureAndExpiry is used in the event that:
* 1) the operator's `delegationApprover` address is set to a non-zero value.
* AND
* 2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the
* operator
* or their delegationApprover is the `msg.sender`, then approval is assumed.
* @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's
* recommended to use an empty input
* in this case to save on complexity + gas costs
*/
function delegateTo(address operator, SignatureWithExpiry memory approverSignatureAndExpiry, bytes32 approverSalt)
external;
// /**
// * @notice Caller delegates their stake to an operator.
// * @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on
// * EigenLayer.
// * @param approverSignatureAndExpiry Verifies the operator approves of this delegation
// * @param approverSalt A unique single use value tied to an individual signature.
// * @dev The approverSignatureAndExpiry is used in the event that:
// * 1) the operator's `delegationApprover` address is set to a non-zero value.
// * AND
// * 2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the
// * operator
// * or their delegationApprover is the `msg.sender`, then approval is assumed.
// * @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's
// * recommended to use an empty input
// * in this case to save on complexity + gas costs
// */
// function delegateTo(address operator, SignatureWithExpiry memory approverSignatureAndExpiry, bytes32 approverSalt)
// external;
// TODO: above not available on mainnet deployments
function delegateTo(address operator) external;

function delegateToBySignature(address staker, address operator, uint256 expiry, bytes memory signature)
external;

/**
* @notice Undelegates the staker from the operator who they are delegated to. Puts the staker into the "undelegation
Expand All @@ -59,6 +249,23 @@ interface IDelegationManager is IEigenLayerUtils {
* @dev Reverts if the `staker` is already undelegated.
*/
function undelegate(address staker) external returns (bytes32 withdrawalRoot);

/**
* @notice This function is used to unpause an EigenLayer contract's functionality.
* It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
*/
function unpause(uint256 newPausedStatus) external;

/**
* @notice This will be called by an operator to register itself as an operator that stakers can choose to delegate to.
* @param dt is the `DelegationTerms` contract that the operator has for those who delegate to them.
* @dev An operator can set `dt` equal to their own address (or another EOA address), in the event that they want to split payments
* in a more 'trustful' manner.
* @dev In the present design, once set, there is no way for an operator to ever modify the address of their DelegationTerms contract.
*/
function registerAsOperator(IDelegationTerms dt) external;
}

interface IEigenPodManager {
Expand All @@ -67,7 +274,7 @@ interface IEigenPodManager {
* @dev Function will revert if the `msg.sender` already has an EigenPod.
* @dev Returns EigenPod address
*/
function createPod() external returns (address);
function createPod() external;

/**
* @notice Stakes for a new beacon chain validator on the sender's EigenPod.
Expand Down Expand Up @@ -144,4 +351,12 @@ interface IEigenPod {

/// @notice Called by EigenPodManager when the owner wants to create another ETH validator.
function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;

/**
* @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address
* @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain.
* @dev Called during withdrawal or slashing.
* @dev Note that this function is marked as non-reentrant to prevent the recipient calling back into it
*/
function withdrawRestakedBeaconChainETH(address recipient, uint256 amount) external;
}
19 changes: 9 additions & 10 deletions src/test/controllers/IMSC.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ contract IMSC is Test {
error Unauthorized();
error Invalid_SplitBalance();

address internal SPLIT_MAIN_GOERLI = 0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE;
address internal SPLIT_MAIN_MAINNET = 0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE;
uint256 public constant PERCENTAGE_SCALE = 1e6;

ImmutableSplitControllerFactory public factory;
Expand All @@ -31,10 +31,9 @@ contract IMSC is Test {
address owner;

function setUp() public {
uint256 goerliBlock = 8_529_931;
vm.createSelectFork(getChain("goerli").rpcUrl);
vm.createSelectFork(getChain("mainnet").rpcUrl);

factory = new ImmutableSplitControllerFactory(SPLIT_MAIN_GOERLI);
factory = new ImmutableSplitControllerFactory(SPLIT_MAIN_MAINNET);
cntrlImpl = factory.controller();

accounts = new address[](2);
Expand Down Expand Up @@ -63,7 +62,7 @@ contract IMSC is Test {
address predictedControllerAddress =
factory.predictSplitControllerAddress(owner, controllerAccounts, controllerPercentAllocations, 0, deploymentSalt);

split = ISplitMain(SPLIT_MAIN_GOERLI).createSplit(accounts, percentAllocations, 0, predictedControllerAddress);
split = ISplitMain(SPLIT_MAIN_MAINNET).createSplit(accounts, percentAllocations, 0, predictedControllerAddress);

// deploy controller
controller =
Expand All @@ -77,7 +76,7 @@ contract IMSC is Test {
}

function testCan_getSplitMain() public {
assertEq(controller.splitMain(), SPLIT_MAIN_GOERLI, "valid splitMain address");
assertEq(controller.splitMain(), SPLIT_MAIN_MAINNET, "valid splitMain address");
}

function testCan_getOwner() public {
Expand Down Expand Up @@ -136,7 +135,7 @@ contract IMSC is Test {
controller.updateSplit();

assertEq(
ISplitMain(SPLIT_MAIN_GOERLI).getHash(split),
ISplitMain(SPLIT_MAIN_MAINNET).getHash(split),
_hashSplit(controllerAccounts, controllerPercentAllocations, 0),
"invalid split hash"
);
Expand Down Expand Up @@ -168,7 +167,7 @@ contract IMSC is Test {

// create split
address fuzzSplit =
ISplitMain(SPLIT_MAIN_GOERLI).createSplit(splitterAccts, splitterPercentAlloc, 0, predictedControllerAddress);
ISplitMain(SPLIT_MAIN_MAINNET).createSplit(splitterAccts, splitterPercentAlloc, 0, predictedControllerAddress);

// create controller
controller =
Expand All @@ -177,12 +176,12 @@ contract IMSC is Test {
assertEq(controller.owner(), ownerAddress, "invalid owner address");

// get current split hash
bytes32 currentSplitHash = ISplitMain(SPLIT_MAIN_GOERLI).getHash(fuzzSplit);
bytes32 currentSplitHash = ISplitMain(SPLIT_MAIN_MAINNET).getHash(fuzzSplit);
// update split
vm.prank(ownerAddress);
controller.updateSplit();

bytes32 newSplitHash = ISplitMain(SPLIT_MAIN_GOERLI).getHash(fuzzSplit);
bytes32 newSplitHash = ISplitMain(SPLIT_MAIN_MAINNET).getHash(fuzzSplit);

bytes32 calculatedSplitHash = _hashSplit(ctrllerAccounts, ctrllerPercentAlloc, 0);

Expand Down
Loading

0 comments on commit 90b85e6

Please sign in to comment.