Skip to content

Commit

Permalink
add anvil utilities from go sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
supernovahs committed Jun 19, 2024
1 parent 9cb8f08 commit c67ddd0
Show file tree
Hide file tree
Showing 25 changed files with 1,217 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
path = crates/contracts/bindings/utils/middleware
url = [email protected]:Layr-Labs/eigenlayer-middleware.git
branch = m2-mainnet
[submodule "crates/contracts/lib/forge-std"]
path = crates/contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "crates/contracts/lib/eigenlayer-middleware"]
path = crates/contracts/lib/eigenlayer-middleware
url = https://github.com/Layr-labs/eigenlayer-middleware
14 changes: 14 additions & 0 deletions crates/contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Compiler files
cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/

# Docs
docs/

# Dotenv file
.env
1 change: 1 addition & 0 deletions crates/contracts/anvil/contracts_deployed_anvil_state.json

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions crates/contracts/anvil/deploy_contracts_save_anvil_state.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/bash

# Enable the script to exit immediately if a command exits with a non-zero status
set -o errexit -o nounset -o pipefail

# Define your cleanup function
clean_up() {
echo "Executing cleanup function..."
set +e
pkill -f anvil

# Check if the exit status is non-zero
exit_status=$?
if [ $exit_status -ne 0 ]; then
echo "Script exited due to set -e on line $1 with command '$2'. Exit status: $exit_status"
fi
}
# Use trap to call the clean_up function when the script exits
trap 'clean_up $LINENO "$BASH_COMMAND"' EXIT

# cd to the directory of this script so that this can be run from anywhere
anvil_dir=$(
cd "$(dirname "${BASH_SOURCE[0]}")"
pwd -P
)
root_dir=$(realpath $anvil_dir/../..)

set -a
source $anvil_dir/utils.sh
# we overwrite some variables here because should always deploy to anvil (localhost)
ETH_HTTP_URL=http://localhost:8545
DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
set +a

# start an empty anvil chain in the background and dump its state to a json file upon exit
start_anvil_docker "" $anvil_dir/contracts-deployed-anvil-state.json
sleep 1

CHAIN_ID=$(cast chain-id)

# DEPLOY CONTRACT REGISTRY
cd $root_dir/contracts
forge create src/ContractsRegistry.sol:ContractsRegistry --rpc-url $ETH_HTTP_URL --private-key $DEPLOYER_PRIVATE_KEY

# DEPLOY EIGENLAYER
EIGEN_CONTRACTS_DIR=$root_dir/contracts/lib/eigenlayer-middleware/lib/eigenlayer-contracts
DEVNET_OUTPUT_DIR=$EIGEN_CONTRACTS_DIR/script/output/devnet
# deployment overwrites this file, so we save it as backup, because we want that output in our local files, and not in the eigenlayer-contracts submodule files
mv $DEVNET_OUTPUT_DIR/M2_from_scratch_deployment_data.json $DEVNET_OUTPUT_DIR/M2_from_scratch_deployment_data.json.bak
cd $EIGEN_CONTRACTS_DIR
forge script script/deploy/devnet/M2_Deploy_From_Scratch.s.sol --rpc-url $ETH_HTTP_URL \
--private-key $DEPLOYER_PRIVATE_KEY --broadcast \
--sig "run(string memory configFileName)" -- M2_deploy_from_scratch.anvil.config.json
mv $DEVNET_OUTPUT_DIR/M2_from_scratch_deployment_data.json $root_dir/contracts/script/output/${CHAIN_ID:?}/eigenlayer_deployment_output.json
mv $DEVNET_OUTPUT_DIR/M2_from_scratch_deployment_data.json.bak $DEVNET_OUTPUT_DIR/M2_from_scratch_deployment_data.json

# DEPLOY MOCKAVS
cd $root_dir/contracts
forge script script/DeployMockAvs.s.sol --rpc-url $ETH_HTTP_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast

# DEPLOY TOKENS AND STRATEGIES
cd $root_dir/contracts
# DO NOT REMOVE THE SLOW DIRECTIVE FROM THIS SCRIPT INVOCATION
# slow ensures that the transaction reciept is successful and recieved before sending the next transaction
# this should prevent the strategies deploying/registering in a flakey manner,
forge script script/DeployTokensStrategiesCreateQuorums.s.sol --rpc-url $ETH_HTTP_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow

# REGISTER OPERATORS WITH EIGENLAYER
cd $root_dir/contracts
# DO NOT REMOVE THE SLOW DIRECTIVE FROM THIS SCRIPT INVOCATION
# slow ensures that the transaction receipt is successful and recieved before sending the next transaction
# this should prevent the operators registering in a flakey manner, the operators registered will change from run to run without this
forge script script/RegisterOperatorsWithEigenlayer.s.sol --rpc-url $ETH_HTTP_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

set -o errexit -o nounset -o pipefail

# cd to the directory of this script so that this can be run from anywhere
anvil_dir=$(
cd "$(dirname "${BASH_SOURCE[0]}")"
pwd -P
)
root_dir=$(realpath $anvil_dir/../..)

set -a
source $anvil_dir/utils.sh
set +a

# start an anvil instance in the background that has eigenlayer contracts deployed
# we start anvil in the background so that we can run the below script
start_anvil_docker $anvil_dir/contracts-deployed-anvil-state.json ""

cd $root_dir/contracts
# we need to restart the anvil chain at the correct block, otherwise the indexRegistry has a quorumUpdate at the block number
# at which it was deployed (aka quorum was created/updated), but when we start anvil by loading state file it starts at block number 0
# so calling getOperatorListAtBlockNumber reverts because it thinks there are no quorums registered at block 0
# advancing chain manually like this is a current hack until https://github.com/foundry-rs/foundry/issues/6679 is merged
cast rpc anvil_mine 200 --rpc-url http://localhost:8545 > /dev/null
echo "Anvil is ready. Advanced chain to block-number:" $(cast block-number)


docker attach anvil
39 changes: 39 additions & 0 deletions crates/contracts/anvil/utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash

set -e -o nounset

parent_path=$(
cd "$(dirname "${BASH_SOURCE[0]}")"
pwd -P
)

FOUNDRY_IMAGE=ghcr.io/foundry-rs/foundry:nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a

clean_up() {
# Check if the exit status is non-zero
exit_status=$?
if [ $exit_status -ne 0 ]; then
echo "Script exited due to set -e on line $1 with command '$2'. Exit status: $exit_status"
fi
}
# Use trap to call the clean_up function when the script exits
trap 'clean_up $LINENO "$BASH_COMMAND"' ERR

# start_anvil_docker $LOAD_STATE_FILE $DUMP_STATE_FILE
start_anvil_docker() {
LOAD_STATE_FILE=$1
DUMP_STATE_FILE=$2
LOAD_STATE_VOLUME_DOCKER_ARG=$([[ -z $LOAD_STATE_FILE ]] && echo "" || echo "-v $LOAD_STATE_FILE:/load-state.json")
DUMP_STATE_VOLUME_DOCKER_ARG=$([[ -z $DUMP_STATE_FILE ]] && echo "" || echo "-v $DUMP_STATE_FILE:/dump-state.json")
LOAD_STATE_ANVIL_ARG=$([[ -z $LOAD_STATE_FILE ]] && echo "" || echo "--load-state /load-state.json")
DUMP_STATE_ANVIL_ARG=$([[ -z $DUMP_STATE_FILE ]] && echo "" || echo "--dump-state /dump-state.json")

trap 'docker stop anvil 2>/dev/null || true' EXIT
set -o xtrace
docker run --rm -d --name anvil -p 8545:8545 $LOAD_STATE_VOLUME_DOCKER_ARG $DUMP_STATE_VOLUME_DOCKER_ARG \
--entrypoint anvil \
$FOUNDRY_IMAGE \
$LOAD_STATE_ANVIL_ARG $DUMP_STATE_ANVIL_ARG --host 0.0.0.0
set +o xtrace
sleep 2
}
7 changes: 7 additions & 0 deletions crates/contracts/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
fs_permissions = [{ access = "read-write", path = "./" }]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
1 change: 1 addition & 0 deletions crates/contracts/lib/eigenlayer-middleware
Submodule eigenlayer-middleware added at 89cbd3
1 change: 1 addition & 0 deletions crates/contracts/lib/forge-std
Submodule forge-std added at 19891e
14 changes: 14 additions & 0 deletions crates/contracts/remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@openzeppelin-upgrades-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/
@openzeppelin-upgrades/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/
@openzeppelin-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/
@openzeppelin/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/
ds-test/=lib/eigenlayer-middleware/lib/ds-test/src/
eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/
eigenlayer-middleware/=lib/eigenlayer-middleware/
forge-std/=lib/forge-std/src/
openzeppelin-contracts-upgradeable/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/
openzeppelin-contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/
erc4626-tests/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/lib/erc4626-tests/
openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/
openzeppelin-contracts-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/
openzeppelin/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/
77 changes: 77 additions & 0 deletions crates/contracts/script/DeployMockAvs.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "./DeployMockAvsRegistries.s.sol";
import "forge-std/console.sol";

// forge script script/DeployMockAvs.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --etherscan-api-key $ETHERSCAN_API_KEY --broadcast --verify
contract DeployMockAvs is DeployMockAvsRegistries {
MockAvsServiceManager public mockAvsServiceManager;
MockAvsServiceManager public mockAvsServiceManagerImplementation;

function run() public virtual {
// The ContractsRegistry contract should always be deployed at this address on anvil
// it's the address of the contract created at nonce 0 by the first anvil account (0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)
ContractsRegistry contractsRegistry = ContractsRegistry(
0x5FbDB2315678afecb367f032d93F642f64180aa3
);
EigenlayerContracts
memory eigenlayerContracts = _loadEigenlayerDeployedContracts();
MockAvsOpsAddresses memory addressConfig = _loadAvsOpsAddresses(
"ops_addresses"
);

vm.startBroadcast();

// Deploy proxy admin for ability to upgrade proxy contracts
// Note: can't deploy ProxyAdmin in setUp function, b/c its owner is not set correctly if so.
// not sure why...
emptyContract = new EmptyContract();
mockAvsProxyAdmin = new ProxyAdmin();
mockAvsServiceManager = MockAvsServiceManager(
address(
new TransparentUpgradeableProxy(
address(emptyContract),
address(mockAvsProxyAdmin),
""
)
)
);
MockAvsContracts
memory mockAvsContracts = _deploymockAvsRegistryContracts(
eigenlayerContracts,
addressConfig,
mockAvsServiceManager,
mockAvsServiceManagerImplementation
);
mockAvsServiceManagerImplementation = new MockAvsServiceManager(
registryCoordinator,
eigenlayerContracts.avsDirectory,
eigenlayerContracts.rewardsCoordinator
);

mockAvsProxyAdmin.upgradeAndCall(
TransparentUpgradeableProxy(
payable(address(mockAvsServiceManager))
),
address(mockAvsServiceManagerImplementation),
abi.encodeWithSelector(
mockAvsServiceManager.initialize.selector,
addressConfig.communityMultisig
)
);
require(
Ownable(address(mockAvsServiceManager)).owner() != address(0),
"Owner uninitialized"
);

if (block.chainid == 31337 || block.chainid == 1337) {
_writeContractsToRegistry(
contractsRegistry,
eigenlayerContracts,
mockAvsContracts
);
}
vm.stopBroadcast();
}
}
Loading

0 comments on commit c67ddd0

Please sign in to comment.