use alloy::{
hex,
primitives::{Address, Bytes, TxKind, address},
providers::{DynProvider, Provider as _},
rpc::types::TransactionRequest,
sol,
sol_types::SolCall as _,
};
use eyre::{Context as _, ContextCompat as _};
pub const TACEO_ADMIN_PRIVATE_KEY: &str =
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
pub const TACEO_ADMIN_ADDRESS: Address = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
pub const OPRF_PEER_PRIVATE_KEY_0: &str =
"0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba";
pub const OPRF_PEER_ADDRESS_0: Address = address!("0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc");
pub const OPRF_PEER_PRIVATE_KEY_1: &str =
"0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e";
pub const OPRF_PEER_ADDRESS_1: Address = address!("0x976EA74026E726554dB657fA54763abd0C3a0aa9");
pub const OPRF_PEER_PRIVATE_KEY_2: &str =
"0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356";
pub const OPRF_PEER_ADDRESS_2: Address = address!("0x14dC79964da2C08b23698B3D3cc7Ca32193d9955");
pub const OPRF_PEER_PRIVATE_KEY_3: &str =
"0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97";
pub const OPRF_PEER_ADDRESS_3: Address = address!("0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f");
pub const OPRF_PEER_PRIVATE_KEY_4: &str =
"0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6";
pub const OPRF_PEER_ADDRESS_4: Address = address!("0xa0Ee7A142d267C1f36714E4a8F75612F20a79720");
pub const PEER_ADDRESSES: [Address; 5] = [
OPRF_PEER_ADDRESS_0,
OPRF_PEER_ADDRESS_1,
OPRF_PEER_ADDRESS_2,
OPRF_PEER_ADDRESS_3,
OPRF_PEER_ADDRESS_4,
];
pub const PEER_PRIVATE_KEYS: [&str; 5] = [
OPRF_PEER_PRIVATE_KEY_0,
OPRF_PEER_PRIVATE_KEY_1,
OPRF_PEER_PRIVATE_KEY_2,
OPRF_PEER_PRIVATE_KEY_3,
OPRF_PEER_PRIVATE_KEY_4,
];
sol!(
#[allow(clippy::too_many_arguments)]
#[sol(rpc, ignore_unlinked)]
VerifierKeyGen13,
concat!(env!("CARGO_MANIFEST_DIR"), "/contracts/Verifier.13.json")
);
sol!(
#[allow(clippy::too_many_arguments)]
#[sol(rpc, ignore_unlinked)]
VerifierKeyGen25,
concat!(env!("CARGO_MANIFEST_DIR"), "/contracts/Verifier.25.json")
);
sol!(
#[allow(clippy::too_many_arguments)]
#[sol(rpc, ignore_unlinked)]
TestOprfKeyRegistry,
concat!(
env!("CARGO_MANIFEST_DIR"),
"/contracts/TestOprfKeyRegistry.json"
)
);
sol!(
#[sol(rpc)]
ERC1967Proxy,
concat!(env!("CARGO_MANIFEST_DIR"), "/contracts/ERC1967Proxy.json")
);
async fn deploy_contract(
provider: DynProvider,
bytecode: Bytes,
constructor_args: Bytes,
) -> eyre::Result<Address> {
let mut deployment_bytecode = bytecode.to_vec();
deployment_bytecode.extend_from_slice(&constructor_args);
let tx = TransactionRequest {
to: Some(TxKind::Create),
input: deployment_bytecode.into(),
..Default::default()
};
let pending_tx = provider.send_transaction(tx).await?;
let receipt = pending_tx.get_receipt().await?;
receipt
.contract_address
.context("contract deployment failed - no address in receipt")
}
fn link_bytecode_hex(
json: &str,
bytecode_str: &str,
library_path: &str,
library_address: Address,
) -> eyre::Result<String> {
let json: serde_json::Value = serde_json::from_str(json)?;
let link_refs = &json["bytecode"]["linkReferences"];
let (file_path, library_name) = library_path
.split_once(':')
.context("library_path must be in format 'file:Library'")?;
let references = link_refs
.get(file_path)
.and_then(|v| v.get(library_name))
.and_then(|v| v.as_array())
.context("library reference not found")?;
let lib_addr_hex = format!("{library_address:040x}");
let mut linked_bytecode = bytecode_str.to_string();
let mut refs: Vec<_> = references
.iter()
.filter_map(|r| {
let start = r["start"].as_u64()? as usize * 2; Some(start)
})
.collect();
refs.sort_by(|a, b| b.cmp(a));
for start_pos in refs {
if start_pos + 40 <= linked_bytecode.len() {
linked_bytecode.replace_range(start_pos..start_pos + 40, &lib_addr_hex);
}
}
Ok(linked_bytecode)
}
async fn deploy_oprf_key_registry(
provider: DynProvider,
admin: Address,
key_gen_verifier: Address,
threshold: u16,
num_peers: u16,
) -> eyre::Result<Address> {
let baby_jub_jub_json = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/contracts/BabyJubJub.json"
));
let json_value: serde_json::Value = serde_json::from_str(baby_jub_jub_json)?;
let bytecode_str = json_value["bytecode"]["object"]
.as_str()
.context("bytecode not found in JSON")?
.strip_prefix("0x")
.unwrap_or_else(|| {
json_value["bytecode"]["object"]
.as_str()
.expect("bytecode should be a string")
})
.to_string();
let baby_jub_jub_bytecode = Bytes::from(hex::decode(bytecode_str)?);
let baby_jub_jub_address =
deploy_contract(provider.clone(), baby_jub_jub_bytecode, Bytes::new())
.await
.context("failed to deploy BabyJubJub library")?;
let oprf_key_registry_json = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/contracts/TestOprfKeyRegistry.json"
));
let json_value: serde_json::Value = serde_json::from_str(oprf_key_registry_json)?;
let mut bytecode_str = json_value["bytecode"]["object"]
.as_str()
.context("bytecode not found in JSON")?
.strip_prefix("0x")
.unwrap_or_else(|| {
json_value["bytecode"]["object"]
.as_str()
.expect("bytecode should be a string")
})
.to_string();
bytecode_str = link_bytecode_hex(
oprf_key_registry_json,
&bytecode_str,
"src/BabyJubJub.sol:BabyJubJub",
baby_jub_jub_address,
)?;
let oprf_key_registry_bytecode = Bytes::from(hex::decode(bytecode_str)?);
let implementation_address =
deploy_contract(provider.clone(), oprf_key_registry_bytecode, Bytes::new())
.await
.context("failed to deploy OprfKeyRegistry implementation")?;
let init_data = Bytes::from(
TestOprfKeyRegistry::initializeCall {
_keygenAdmin: admin,
_keyGenVerifierAddress: key_gen_verifier,
_threshold: threshold,
_numPeers: num_peers,
_owner: admin,
}
.abi_encode(),
);
let proxy = ERC1967Proxy::deploy(provider, implementation_address, init_data)
.await
.context("failed to deploy OprfKeyRegistry proxy")?;
Ok(*proxy.address())
}
pub async fn deploy_oprf_key_registry_13(
provider: DynProvider,
admin: Address,
) -> eyre::Result<Address> {
let key_gen_verifier = VerifierKeyGen13::deploy(provider.clone())
.await
.context("failed to deploy Groth16VerifierKeyGen13 contract")?;
deploy_oprf_key_registry(provider, admin, *key_gen_verifier.address(), 2, 3).await
}
pub async fn deploy_oprf_key_registry_25(
provider: DynProvider,
admin: Address,
) -> eyre::Result<Address> {
let key_gen_verifier = VerifierKeyGen25::deploy(provider.clone())
.await
.context("failed to deploy Groth16VerifierKeyGen25 contract")?;
deploy_oprf_key_registry(provider, admin, *key_gen_verifier.address(), 3, 5).await
}