use std::fmt::{Display, Formatter};
use std::str::FromStr;
use alloy_primitives::Address;
use alloy_provider::network::{AnyNetwork, EthereumWallet};
use alloy_provider::{Provider, ProviderBuilder};
use alloy_signer_local::PrivateKeySigner;
use tonic::transport::Endpoint;
use trident_sdk::proto::delivery_v1;
pub(crate) type ExampleResult<T = ()> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
#[derive(Debug)]
struct ExampleError(String);
impl Display for ExampleError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl std::error::Error for ExampleError {}
fn example_error(message: impl Into<String>) -> Box<dyn std::error::Error + Send + Sync> {
Box::new(ExampleError(message.into()))
}
pub(crate) fn env_var(name: &str) -> ExampleResult<String> {
std::env::var(name)
.map_err(|_| example_error(format!("missing required environment variable {name}")))
}
pub(crate) fn env_parse<T>(name: &str) -> ExampleResult<T>
where
T: FromStr,
T::Err: Display,
{
let raw = env_var(name)?;
raw.parse()
.map_err(|error| example_error(format!("failed to parse {name}: {error}")))
}
pub(crate) fn grpc_url() -> ExampleResult<String> {
env_var("TRIDENT_GRPC_URL")
}
pub(crate) fn grpc_endpoint() -> ExampleResult<Endpoint> {
Ok(Endpoint::from_shared(grpc_url()?)?)
}
pub(crate) fn signer_from_env() -> ExampleResult<PrivateKeySigner> {
env_parse("TRIDENT_PRIVATE_KEY")
}
pub(crate) async fn provider_from_env(
rpc_var: &str,
signer: &PrivateKeySigner,
) -> ExampleResult<impl Provider<AnyNetwork> + Clone + use<>> {
let rpc_url = env_var(rpc_var)?;
let wallet = EthereumWallet::new(signer.clone());
Ok(ProviderBuilder::default()
.with_recommended_fillers()
.wallet(wallet)
.connect(rpc_url.as_str())
.await?
.erased())
}
#[allow(dead_code)]
pub(crate) async fn deposit_contract_for_domain(domain: u32) -> ExampleResult<Address> {
let channel = grpc_endpoint()?.connect().await?;
let mut delivery = delivery_v1::delivery_service_client::DeliveryServiceClient::new(channel);
let deployments = delivery
.list_deployments(delivery_v1::ListDeploymentsRequest {})
.await?
.into_inner();
let deployment = deployments
.deployments
.into_iter()
.find(|deployment| deployment.domain == domain)
.ok_or_else(|| example_error(format!("no deployment returned for domain {domain}")))?;
let deposit_contract = deployment.deposit_contract.ok_or_else(|| {
example_error(format!(
"deployment for domain {domain} is missing deposit_contract"
))
})?;
Ok(Address::try_from(deposit_contract)?)
}