use alloy_provider::RootProvider;
use blueprint_chain_setup::anvil::start_default_anvil_testnet;
use blueprint_evm_extra::util::get_provider_http;
use blueprint_runner::config::SupportedChains;
use blueprint_std::collections::HashMap;
use blueprint_std::fs;
use blueprint_std::process::Command;
use blueprint_testing_utils::setup_log;
use color_eyre::eyre::Result;
use serde_json::Value;
use tempfile::TempDir;
use crate::command::deploy::eigenlayer::{EigenlayerDeployOpts, deploy_avs_contracts};
#[tokio::test]
async fn test_deploy_local_on_anvil() -> Result<()> {
setup_log();
let temp_dir = TempDir::new()?;
let contract_src_dir = temp_dir.path().join("src");
let contract_out_dir = temp_dir.path().join("out");
let contract_dir = temp_dir.path();
fs::create_dir_all(&contract_src_dir)?;
fs::create_dir_all(&contract_out_dir)?;
let keystore_path = temp_dir.path().join("./keystore");
let contract_content = r"// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
contract TestContract {
uint256 private value;
event ValueSet(uint256 newValue);
constructor(uint256 a, uint256 b) {
value = a * b;
}
function setValue(uint256 _value) public {
value = _value;
emit ValueSet(_value);
}
function getValue() public view returns (uint256) {
return value;
}
}
";
fs::write(contract_src_dir.join("TestContract.sol"), contract_content)?;
let second_contract_content = r"// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
contract SimpleStorage {
string private storedData;
event DataStored(string newData);
constructor(string memory initialData) {
storedData = initialData;
}
function set(string memory newData) public {
storedData = newData;
emit DataStored(newData);
}
function get() public view returns (string memory) {
return storedData;
}
}
";
fs::write(
contract_src_dir.join("SimpleStorage.sol"),
second_contract_content,
)?;
let foundry_content = format!(
r"[profile.default]
src = 'src'
out = '{}'
libs = ['lib']
evm_version = 'shanghai'",
contract_out_dir
.strip_prefix(temp_dir.path())
.unwrap()
.display()
);
fs::write(temp_dir.path().join("foundry.toml"), foundry_content)?;
let testnet = start_default_anvil_testnet(false).await;
let mut constructor_args = HashMap::new();
let init_a_value = 2;
let init_b_value = 3;
let init_get_value = init_a_value * init_b_value;
constructor_args.insert(
"TestContract".to_string(),
vec![init_a_value.to_string(), init_b_value.to_string()],
);
constructor_args.insert(
"SimpleStorage".to_string(),
vec!["Initial Data".to_string()],
);
let opts = EigenlayerDeployOpts {
rpc_url: testnet.http_endpoint.clone(),
contracts_path: contract_dir.to_string_lossy().to_string(),
constructor_args: Some(constructor_args),
ordered_deployment: false,
chain: SupportedChains::LocalTestnet,
keystore_path: keystore_path.to_string_lossy().to_string(),
};
let _build_output = Command::new("forge")
.arg("build")
.arg("--evm-version")
.arg("shanghai")
.arg("--out")
.arg(&contract_out_dir)
.current_dir(temp_dir.path())
.output()
.expect("Failed to build contracts");
let test_contract_json = contract_out_dir.join("TestContract.sol/TestContract.json");
let simple_storage_json = contract_out_dir.join("SimpleStorage.sol/SimpleStorage.json");
assert!(test_contract_json.exists());
assert!(simple_storage_json.exists());
let contract_addresses = deploy_avs_contracts(&opts)?;
let &test_contract_address = contract_addresses
.iter()
.find(|(key, _value)| key.contains("TestContract"))
.map(|(_key, value)| value)
.expect("Could not find TestContract in deployed contracts");
let &simple_storage_address = contract_addresses
.iter()
.find(|(key, _value)| key.contains("SimpleStorage"))
.map(|(_key, value)| value)
.expect("Could not find SimpleStorage in deployed contracts");
let json_path = temp_dir
.path()
.join("out/TestContract.sol/TestContract.json");
let json_content = fs::read_to_string(json_path)?;
let json: Value = serde_json::from_str(&json_content)?;
let abi = json["abi"].to_string();
let abi = alloy_json_abi::JsonAbi::from_json_str(&abi)?;
let provider = get_provider_http(testnet.http_endpoint.clone());
let test_contract =
alloy_contract::ContractInstance::<RootProvider, alloy_network::Ethereum>::new(
test_contract_address,
provider.clone(),
alloy_contract::Interface::new(abi),
);
let value = alloy_dyn_abi::DynSolValue::from(alloy_primitives::U256::from(123));
let get_result = test_contract.function("getValue", &[])?.call().await?;
let get_result_value: alloy_primitives::U256 =
if let alloy_dyn_abi::DynSolValue::Uint(val, 256) = get_result[0] {
val
} else {
panic!("Expected Uint256, but did not receive correct type")
};
assert_eq!(
get_result_value,
alloy_primitives::U256::from(init_get_value)
);
let set_result = test_contract
.function("setValue", &[value])
.unwrap()
.send()
.await?
.get_receipt()
.await?;
assert!(set_result.status());
let get_result = test_contract.function("getValue", &[])?.call().await?;
let get_result_value: alloy_primitives::U256 =
if let alloy_dyn_abi::DynSolValue::Uint(val, 256) = get_result[0] {
val
} else {
panic!("Expected Uint256, but did not receive correct type")
};
assert_eq!(get_result_value, alloy_primitives::U256::from(123));
let json_path = temp_dir
.path()
.join("out/SimpleStorage.sol/SimpleStorage.json");
let json_content = fs::read_to_string(json_path)?;
let json: Value = serde_json::from_str(&json_content)?;
let abi = json["abi"].to_string();
let abi = alloy_json_abi::JsonAbi::from_json_str(&abi)?;
let provider = get_provider_http(testnet.http_endpoint);
let simple_storage_contract =
alloy_contract::ContractInstance::<RootProvider, alloy_network::Ethereum>::new(
simple_storage_address,
provider.clone(),
alloy_contract::Interface::new(abi),
);
let get_result = simple_storage_contract.function("get", &[])?.call().await?;
let get_result_value: String =
if let alloy_dyn_abi::DynSolValue::String(val) = get_result[0].clone() {
val
} else {
panic!("Expected String, but did not receive correct type")
};
assert_eq!(get_result_value, "Initial Data".to_string());
Ok(())
}