use alloy::{
primitives::{
Address,
Bytes,
},
providers::Provider,
sol_types::SolCall,
};
use crate::{
artifacts::Artifacts,
bindings::transfer::{
BankInit,
IDiamondCut,
},
deploy::{
deploy_contract_from,
deploy_with_ctor,
},
error::{
Error,
Result,
},
};
pub const BANK_FACETS: &[&str] = &[
"DiamondLoupeFacet",
"OwnershipFacet",
"AdminFacet",
"VaultFacet",
"TransferFacet",
];
pub mod facet_cut_action {
pub const ADD: u8 = 0;
pub const REPLACE: u8 = 1;
pub const REMOVE: u8 = 2;
}
pub async fn deploy_bank_diamond<P: Provider>(
provider: &P,
artifacts: &Artifacts,
owner: Address,
notary_contract: Address,
backend: Address,
registry: Address,
) -> Result<Address> {
let cut_facet_addr = deploy_contract_from(
provider,
artifacts.bytecode("DiamondCutFacet")?,
"DiamondCutFacet",
None,
)
.await?;
let ctor_args =
alloy::sol_types::SolValue::abi_encode_params(&(owner, cut_facet_addr));
let diamond_addr = deploy_with_ctor(
provider,
&artifacts.bytecode("Diamond")?,
&ctor_args,
"Diamond",
None,
)
.await?;
let cut = deploy_facet_cut(provider, artifacts, facet_cut_action::ADD, None).await?;
let bank_init_addr =
deploy_contract_from(provider, artifacts.bytecode("BankInit")?, "BankInit", None)
.await?;
let init_calldata: Bytes = BankInit::initCall {
notary: notary_contract,
backend,
registry,
}
.abi_encode()
.into();
let diamond = IDiamondCut::new(diamond_addr, provider);
diamond
.diamondCut(cut, bank_init_addr, init_calldata)
.send()
.await
.map_err(|e| Error::Rpc {
detail: format!("Diamond.diamondCut send failed: {e}"),
})?
.get_receipt()
.await
.map_err(|e| Error::Rpc {
detail: format!("Diamond.diamondCut confirmation failed: {e}"),
})?;
Ok(diamond_addr)
}
pub async fn replace_bank_facets<P: Provider>(
provider: &P,
artifacts: &Artifacts,
diamond: Address,
sender: Option<Address>,
) -> Result<()> {
let cut =
deploy_facet_cut(provider, artifacts, facet_cut_action::REPLACE, sender).await?;
let diamond = IDiamondCut::new(diamond, provider);
let call = diamond.diamondCut(cut, Address::ZERO, Bytes::new());
let pending =
match sender {
Some(addr) => {
let nonce = provider.get_transaction_count(addr).await.map_err(|e| {
Error::Rpc {
detail: format!("Bank.diamondCut failed to fetch nonce: {e}"),
}
})?;
call.nonce(nonce).send().await
}
None => call.send().await,
}
.map_err(|e| Error::Rpc {
detail: format!("Bank.diamondCut send failed: {e}"),
})?;
pending.get_receipt().await.map_err(|e| Error::Rpc {
detail: format!("Bank.diamondCut confirmation failed: {e}"),
})?;
Ok(())
}
async fn deploy_facet_cut<P: Provider>(
provider: &P,
artifacts: &Artifacts,
action: u8,
sender: Option<Address>,
) -> Result<Vec<IDiamondCut::FacetCut>> {
let mut cut = Vec::with_capacity(BANK_FACETS.len());
for &name in BANK_FACETS {
let facet_addr =
deploy_contract_from(provider, artifacts.bytecode(name)?, name, sender)
.await?;
cut.push(IDiamondCut::FacetCut {
facetAddress: facet_addr,
action,
functionSelectors: artifacts.facet_selectors(name)?,
});
}
Ok(cut)
}