use krusty_kms::OpenZeppelinAccount;
use krusty_kms_common::address::Address;
use krusty_kms_common::chain::ChainId;
use krusty_kms_common::network::NetworkPreset;
use krusty_kms_common::{KmsError, Result};
use starknet_rust::accounts::AccountFactory;
use starknet_rust::accounts::OpenZeppelinAccountFactory;
use starknet_rust::core::types::FeeEstimate;
use starknet_rust::providers::jsonrpc::{HttpTransport, JsonRpcClient};
use starknet_rust::signers::{LocalWallet, SigningKey};
use std::sync::Arc;
use super::utils::{check_deployed, core_felt_to_rs};
use crate::tx::Tx;
pub struct DeployResult {
pub address: Address,
pub tx: Option<Tx>,
pub already_deployed: bool,
}
pub async fn deploy_oz_account(
provider: Arc<JsonRpcClient<HttpTransport>>,
signing_key: &SigningKey,
account_class: &OpenZeppelinAccount,
chain_id: ChainId,
network: NetworkPreset,
) -> Result<DeployResult> {
let verifying_key = signing_key.verifying_key();
let public_key_rs = verifying_key.scalar();
let public_key_core = super::utils::rs_felt_to_core(public_key_rs);
let descriptor = account_class.deployment_descriptor(&public_key_core)?;
let address = Address::from(descriptor.address);
let address_rs = core_felt_to_rs(descriptor.address);
let deployed = check_deployed(&provider, address_rs).await?;
if deployed {
return Ok(DeployResult {
address,
tx: None,
already_deployed: true,
});
}
let class_hash_rs = core_felt_to_rs(descriptor.class_hash);
let chain_id_rs = core_felt_to_rs(chain_id.as_felt());
let salt_rs = core_felt_to_rs(descriptor.salt);
let signer = LocalWallet::from(signing_key.clone());
let factory =
OpenZeppelinAccountFactory::new(class_hash_rs, chain_id_rs, signer, provider.clone())
.await
.map_err(|e| KmsError::CryptoError(e.to_string()))?;
let result = factory
.deploy_v3(salt_rs)
.send()
.await
.map_err(|e| classify_deploy_error(e.to_string()))?;
let tx = Tx::new(result.transaction_hash, provider, network);
Ok(DeployResult {
address,
tx: Some(tx),
already_deployed: false,
})
}
pub async fn estimate_deploy_fee(
provider: Arc<JsonRpcClient<HttpTransport>>,
signing_key: &SigningKey,
account_class: &OpenZeppelinAccount,
chain_id: ChainId,
) -> Result<FeeEstimate> {
let verifying_key = signing_key.verifying_key();
let public_key_rs = verifying_key.scalar();
let public_key_core = super::utils::rs_felt_to_core(public_key_rs);
let descriptor = account_class.deployment_descriptor(&public_key_core)?;
let class_hash_rs = core_felt_to_rs(descriptor.class_hash);
let chain_id_rs = core_felt_to_rs(chain_id.as_felt());
let salt_rs = core_felt_to_rs(descriptor.salt);
let signer = LocalWallet::from(signing_key.clone());
let factory =
OpenZeppelinAccountFactory::new(class_hash_rs, chain_id_rs, signer, provider.clone())
.await
.map_err(|e| KmsError::CryptoError(e.to_string()))?;
factory
.deploy_v3(salt_rs)
.estimate_fee()
.await
.map_err(|e| classify_deploy_error(e.to_string()))
}
fn classify_deploy_error(msg: String) -> KmsError {
let lower = msg.to_lowercase();
if lower.contains("already deployed")
|| lower.contains("already been deployed")
|| lower.contains("alreadydeployed")
{
KmsError::AlreadyDeployed(msg)
} else if lower.contains("insufficientaccountbalance")
|| (lower.contains("insufficient") && (lower.contains("balance") || lower.contains("fee")))
{
KmsError::InsufficientFeeBalance(msg)
} else if lower.contains("classhashnotfound")
|| (lower.contains("class hash") && lower.contains("not"))
{
KmsError::InvalidClassHash(msg)
} else if lower.contains("contractnotfound")
|| lower.contains("contract not found")
|| lower.contains("is not deployed")
{
KmsError::ContractNotFound(msg)
} else {
KmsError::TransactionError(msg)
}
}