Skip to content

Commit

Permalink
Use anyhow for error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
cchudant committed Sep 5, 2024
1 parent 883622c commit 3371d0a
Show file tree
Hide file tree
Showing 20 changed files with 787 additions and 493 deletions.
13 changes: 7 additions & 6 deletions src/contract_clients/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use anyhow::Context;
use ethereum_instance::EthereumClient;
use starknet_providers::jsonrpc::HttpTransport;
use starknet_providers::JsonRpcClient;
Expand All @@ -20,18 +21,18 @@ impl Config {
}

/// To deploy the instance of ethereum and starknet and returning the struct.
pub async fn init(config: &CliArgs) -> Self {
pub async fn init(config: &CliArgs) -> anyhow::Result<Self> {
let client_instance = EthereumClient::attach(
Option::from(config.eth_rpc.clone()),
Option::from(config.eth_priv_key.clone()),
Option::from(config.eth_chain_id),
Some(config.eth_rpc.clone()),
Some(config.eth_priv_key.clone()),
Some(config.eth_chain_id),
)
.unwrap();
.context("Creating the Ethereum RPC client")?;

let provider_l2 = JsonRpcClient::new(HttpTransport::new(
Url::parse(&config.rollup_seq_url).expect("Failed to declare provider for app chain"),
));

Self { eth_client: client_instance, provider_l2 }
Ok(Self { eth_client: client_instance, provider_l2 })
}
}
18 changes: 9 additions & 9 deletions src/contract_clients/core_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub trait CoreContract {

fn client(&self) -> Arc<LocalWalletSignerMiddleware>;

async fn initialize_with(&self, init_data: CoreContractInitData);
async fn initialize_with(&self, init_data: CoreContractInitData) -> anyhow::Result<()>;

#[allow(clippy::too_many_arguments)]
async fn add_implementation_core_contract(
Expand All @@ -33,7 +33,7 @@ pub trait CoreContract {
implementation_address: Address,
verifier_address: Address,
finalized: bool,
);
) -> anyhow::Result<()>;

#[allow(clippy::too_many_arguments)]
async fn upgrade_to_core_contract(
Expand All @@ -45,15 +45,15 @@ pub trait CoreContract {
implementation_address: Address,
verifier_address: Address,
finalized: bool,
);
) -> anyhow::Result<()>;

async fn register_operator_core_contract(&self, operator_address: Address);
async fn register_operator_core_contract(&self, operator_address: Address) -> anyhow::Result<()>;

async fn nominate_governor_core_contract(&self, l1_governor_address: Address);
async fn nominate_governor_core_contract(&self, l1_governor_address: Address) -> anyhow::Result<()>;

async fn nominate_governor_core_contract_proxy(&self, l1_governor_address: Address);
async fn nominate_governor_core_contract_proxy(&self, l1_governor_address: Address) -> anyhow::Result<()>;

async fn initialize(&self, program_hash: StarkFelt, config_hash: StarkFelt);
async fn initialize(&self, program_hash: StarkFelt, config_hash: StarkFelt) -> anyhow::Result<()>;

async fn initialize_core_contract(
&self,
Expand All @@ -62,11 +62,11 @@ pub trait CoreContract {
program_hash: FieldElement,
config_hash: StarkHash,
verifer_address: Address,
);
) -> anyhow::Result<()>;
}

pub trait CoreContractDeploy<T> {
fn deploy(config: &Config) -> impl Future<Output = T> + Send;
fn deploy(config: &Config) -> impl Future<Output = anyhow::Result<T>> + Send;
}

pub fn get_init_data_core_contract(
Expand Down
148 changes: 98 additions & 50 deletions src/contract_clients/eth_bridge.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::sync::Arc;

use anyhow::Context;
use async_trait::async_trait;
use ethers::addressbook::Address;
use ethers::providers::Middleware;
Expand All @@ -21,8 +22,8 @@ use crate::helpers::account_actions::{get_contract_address_from_deploy_tx, Accou
use crate::utils::{invoke_contract, wait_for_transaction};

#[async_trait]
pub trait BridgeDeployable {
async fn deploy(client: Arc<LocalWalletSignerMiddleware>, is_dev: bool) -> Self;
pub trait BridgeDeployable: Sized {
async fn deploy(client: Arc<LocalWalletSignerMiddleware>, is_dev: bool) -> anyhow::Result<Self>;
}

pub struct StarknetLegacyEthBridge {
Expand All @@ -31,17 +32,17 @@ pub struct StarknetLegacyEthBridge {

#[async_trait]
impl BridgeDeployable for StarknetLegacyEthBridge {
async fn deploy(client: Arc<LocalWalletSignerMiddleware>, is_dev: bool) -> Self {
async fn deploy(client: Arc<LocalWalletSignerMiddleware>, is_dev: bool) -> anyhow::Result<Self> {
let eth_bridge = match is_dev {
true => deploy_starknet_eth_bridge_behind_unsafe_proxy(client.clone())
.await
.expect("Failed to deploy starknet contract"),
.context("Failed to deploy starknet contract")?,
false => deploy_starknet_eth_bridge_behind_safe_proxy(client.clone())
.await
.expect("Failed to deploy starknet contract"),
.context("Failed to deploy starknet contract")?,
};

Self { eth_bridge }
Ok(Self { eth_bridge })
}
}

Expand All @@ -63,25 +64,28 @@ impl StarknetLegacyEthBridge {
legacy_eth_bridge_class_hash: FieldElement,
legacy_eth_bridge_proxy_address: FieldElement,
account: &RpcAccount<'_>,
) -> FieldElement {
) -> anyhow::Result<FieldElement> {
let deploy_tx = account
.invoke_contract(
account.address(),
"deploy_contract",
vec![legacy_eth_bridge_class_hash, FieldElement::ZERO, FieldElement::ZERO, FieldElement::ZERO],
None,
)
.context("Creating the invoke transaction for contract proxy deployment")?
.send()
.await
.expect("Error deploying the contract proxy.");
.context("Error deploying the contract proxy")?;
wait_for_transaction(
rpc_provider_l2,
deploy_tx.transaction_hash,
"deploy_l2_contracts : deploy_contract : eth bridge",
)
.await
.unwrap();
let contract_address = get_contract_address_from_deploy_tx(account.provider(), &deploy_tx).await.unwrap();
.context("Waiting for contract proxy deployment")?;
let contract_address = get_contract_address_from_deploy_tx(account.provider(), &deploy_tx)
.await
.context("Getting contract address from deploy transaction")?;

log::debug!("🎡 contract address (eth bridge) : {:?}", contract_address);

Expand All @@ -91,38 +95,40 @@ impl StarknetLegacyEthBridge {
vec![contract_address, FieldElement::ZERO, FieldElement::ONE, account.address(), FieldElement::ZERO],
account,
)
.await;
.await
.context("Creating the add_implementation transaction")?;

wait_for_transaction(
rpc_provider_l2,
add_implementation_txn.transaction_hash,
"deploy_l2_contracts : add_implementation : eth bridge",
)
.await
.unwrap();
.context("Waiting for the add_implementation transaction to settle")?;

let upgrade_to_txn = invoke_contract(
legacy_eth_bridge_proxy_address,
"upgrade_to",
vec![contract_address, FieldElement::ZERO, FieldElement::ONE, account.address(), FieldElement::ZERO],
account,
)
.await;
.await
.context("Creating the upgrade_to transaction")?;

wait_for_transaction(
rpc_provider_l2,
upgrade_to_txn.transaction_hash,
"deploy_l2_contracts : upgrade_to : eth bridge",
)
.await
.unwrap();
.context("Waiting for the upgrade_to transaction to settle")?;

legacy_eth_bridge_proxy_address
Ok(legacy_eth_bridge_proxy_address)
}

/// Initialize Starknet Legacy Eth Bridge
/// IMP : only need to be called when using unsafe proxy
pub async fn initialize(&self, messaging_contract: Address) {
pub async fn initialize(&self, messaging_contract: Address) -> anyhow::Result<()> {
let empty_bytes = [0u8; 32];

let messaging_bytes = messaging_contract.as_bytes();
Expand All @@ -136,11 +142,12 @@ impl StarknetLegacyEthBridge {
calldata.extend(empty_bytes);
calldata.extend(padded_messaging_bytes);

self.eth_bridge.initialize(Bytes::from(calldata)).await.expect("Failed to initialize eth bridge");
self.eth_bridge.initialize(Bytes::from(calldata)).await.context("Failed to initialize eth bridge")?;
Ok(())
}

/// Add Implementation Starknet Legacy Eth Bridge
pub async fn add_implementation_eth_bridge(&self, messaging_contract: Address) {
pub async fn add_implementation_eth_bridge(&self, messaging_contract: Address) -> anyhow::Result<()> {
let empty_bytes = [0u8; 32];

let messaging_bytes = messaging_contract.as_bytes();
Expand All @@ -163,11 +170,12 @@ impl StarknetLegacyEthBridge {
self.eth_bridge
.add_implementation(Bytes::from(calldata), self.implementation_address(), false)
.await
.expect("Failed to initialize eth bridge");
.context("Failed to initialize eth bridge")?;
Ok(())
}

/// Upgrade To Starknet Legacy Eth Bridge
pub async fn upgrade_to_eth_bridge(&self, messaging_contract: Address) {
pub async fn upgrade_to_eth_bridge(&self, messaging_contract: Address) -> anyhow::Result<()> {
let empty_bytes = [0u8; 32];

let messaging_bytes = messaging_contract.as_bytes();
Expand All @@ -190,7 +198,9 @@ impl StarknetLegacyEthBridge {
self.eth_bridge
.upgrade_to(Bytes::from(calldata), self.implementation_address(), false)
.await
.expect("Failed to initialize eth bridge");
.context("Failed to upgrade the eth bridge")?;

Ok(())
}

/// Sets up the Eth bridge with the specified data
Expand All @@ -201,15 +211,30 @@ impl StarknetLegacyEthBridge {
l2_bridge: FieldElement,
l1_multisig_address: Address,
is_dev: bool,
) {
self.eth_bridge.set_max_total_balance(U256::from_dec_str(max_total_balance).unwrap()).await.unwrap();
self.eth_bridge.set_max_deposit(U256::from_dec_str(max_deposit).unwrap()).await.unwrap();
self.eth_bridge.set_l2_token_bridge(field_element_to_u256(l2_bridge)).await.unwrap();
) -> anyhow::Result<()> {
self.eth_bridge
.set_max_total_balance(
U256::from_dec_str(max_total_balance).context("Converting max total balance to U256")?,
)
.await
.context("Setting max total balance")?;
self.eth_bridge
.set_max_deposit(U256::from_dec_str(max_deposit).context("Converting max deposit to U256")?)
.await
.context("Setting the max deposit")?;
self.eth_bridge
.set_l2_token_bridge(field_element_to_u256(l2_bridge))
.await
.context("Setting the L2 token bridge")?;

if !is_dev {
// Nominating a new governor as l1 multi sig address
self.eth_bridge.proxy_nominate_new_governor(l1_multisig_address).await.unwrap();
self.eth_bridge
.proxy_nominate_new_governor(l1_multisig_address)
.await
.context("Nominating the proxy governor")?;
}
Ok(())
}

pub async fn setup_l2_bridge(
Expand All @@ -219,61 +244,84 @@ impl StarknetLegacyEthBridge {
erc20_address: FieldElement,
l2_deployer_address: &str,
account: &RpcAccount<'_>,
) {
) -> anyhow::Result<()> {
let tx = invoke_contract(
l2_bridge_address,
"initialize",
vec![FieldElement::from_dec_str("1").unwrap(), FieldElement::from_hex_be(l2_deployer_address).unwrap()],
vec![
FieldElement::from_dec_str("1").expect("Converting a constant"),
FieldElement::from_hex_be(l2_deployer_address).context("Parsing the L2 deployer address")?,
],
account,
)
.await;
.await
.context("Creating the initialize transaction")?;

log::debug!("🎡 setup_l2_bridge : l2 bridge initialized //");
wait_for_transaction(rpc_provider, tx.transaction_hash, "setup_l2_bridge : initialize").await.unwrap();
wait_for_transaction(rpc_provider, tx.transaction_hash, "setup_l2_bridge : initialize")
.await
.context("Waiting for the initialize transaction to settle")?;

let tx = invoke_contract(l2_bridge_address, "set_l2_token", vec![erc20_address], account).await;
let tx = invoke_contract(l2_bridge_address, "set_l2_token", vec![erc20_address], account)
.await
.context("Creating the set_l2_token transaction")?;

log::debug!("🎡 setup_l2_bridge : l2 token set //");
wait_for_transaction(rpc_provider, tx.transaction_hash, "setup_l2_bridge : set_l2_token").await.unwrap();
wait_for_transaction(rpc_provider, tx.transaction_hash, "setup_l2_bridge : set_l2_token")
.await
.context("Waiting for the set_l2_token transaction to settle")?;

let tx = invoke_contract(
l2_bridge_address,
"set_l1_bridge",
vec![FieldElement::from_byte_slice_be(self.eth_bridge.address().as_bytes()).unwrap()],
vec![
FieldElement::from_byte_slice_be(self.eth_bridge.address().as_bytes())
.context("Parsing the eth_bridge address")?,
],
account,
)
.await;
.await
.context("Creating the set_l1_bridge transaction")?;

log::debug!("🎡 setup_l2_bridge : l1 bridge set //");
wait_for_transaction(rpc_provider, tx.transaction_hash, "setup_l2_bridge : set_l1_bridge").await.unwrap();
wait_for_transaction(rpc_provider, tx.transaction_hash, "setup_l2_bridge : set_l1_bridge")
.await
.context("Waiting for the set_l1_bridge transaction to settle")?;

Ok(())
}

pub async fn set_max_total_balance(&self, amount: U256) {
self.eth_bridge
.set_max_total_balance(amount)
.await
.expect("Failed to set max total balance value in Eth bridge");
pub async fn set_max_total_balance(&self, amount: U256) -> anyhow::Result<()> {
self.eth_bridge.set_max_total_balance(amount).await.context("Setting the max total balance")?;
Ok(())
}

pub async fn set_max_deposit(&self, amount: U256) {
self.eth_bridge.set_max_deposit(amount).await.expect("Failed to set max deposit value in eth bridge");
pub async fn set_max_deposit(&self, amount: U256) -> anyhow::Result<()> {
self.eth_bridge.set_max_deposit(amount).await.context("Failed to set max deposit value in eth bridge")?;
Ok(())
}

pub async fn set_l2_token_bridge(&self, l2_bridge: U256) {
self.eth_bridge.set_l2_token_bridge(l2_bridge).await.expect("Failed to set l2 bridge in eth bridge");
pub async fn set_l2_token_bridge(&self, l2_bridge: U256) -> anyhow::Result<()> {
self.eth_bridge.set_l2_token_bridge(l2_bridge).await.context("Failed to set l2 bridge in eth bridge")?;
Ok(())
}

pub async fn deposit(&self, amount: U256, l2_address: U256, fee: U256) {
self.eth_bridge.deposit(amount, l2_address, fee).await.expect("Failed to deposit in eth bridge");
pub async fn deposit(&self, amount: U256, l2_address: U256, fee: U256) -> anyhow::Result<()> {
self.eth_bridge.deposit(amount, l2_address, fee).await.context("Failed to deposit in eth bridge")?;
Ok(())
}

pub async fn withdraw(&self, amount: U256, l1_recipient: Address) {
self.eth_bridge.withdraw(amount, l1_recipient).await.expect("Failed to withdraw from eth bridge");
pub async fn withdraw(&self, amount: U256, l1_recipient: Address) -> anyhow::Result<()> {
self.eth_bridge.withdraw(amount, l1_recipient).await.context("Failed to withdraw from eth bridge")?;
Ok(())
}

pub async fn eth_balance(&self, l1_recipient: Address) -> U256 {
pub async fn eth_balance(&self, l1_recipient: Address) -> anyhow::Result<U256> {
let provider = self.eth_bridge.client().provider().clone();

provider.get_balance(l1_recipient, None).await.unwrap()
provider
.get_balance(l1_recipient, None)
.await
.with_context(|| format!("Getting the eth balance for {}", l1_recipient))
}
}
Loading

0 comments on commit 3371d0a

Please sign in to comment.