use async_trait::async_trait;
use auto_impl::auto_impl;
use serde::Serialize;
use starknet_core::types::{
requests::*, BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction,
BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction,
ConfirmedBlockId, ContractClass, ContractStorageKeys, DeclareTransactionResult,
DeployAccountTransactionResult, EventFilter, EventsPage, FeeEstimate, Felt, FunctionCall,
Hash256, InvokeTransactionResult, MaybePreConfirmedBlockWithReceipts,
MaybePreConfirmedBlockWithTxHashes, MaybePreConfirmedBlockWithTxs,
MaybePreConfirmedStateUpdate, MessageFeeEstimate, MessageStatus, MsgFromL1,
SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, StarknetError,
StorageProof, SubscriptionId, SyncStatusType, Transaction, TransactionReceiptWithBlockInfo,
TransactionStatus, TransactionTrace, TransactionTraceWithHash,
};
use std::{any::Any, error::Error, fmt::Debug};
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[auto_impl(&, Box, Arc)]
pub trait Provider {
async fn spec_version(&self) -> Result<String, ProviderError>;
async fn get_block_with_tx_hashes<B>(
&self,
block_id: B,
) -> Result<MaybePreConfirmedBlockWithTxHashes, ProviderError>
where
B: AsRef<BlockId> + Send + Sync;
async fn get_block_with_txs<B>(
&self,
block_id: B,
) -> Result<MaybePreConfirmedBlockWithTxs, ProviderError>
where
B: AsRef<BlockId> + Send + Sync;
async fn get_block_with_receipts<B>(
&self,
block_id: B,
) -> Result<MaybePreConfirmedBlockWithReceipts, ProviderError>
where
B: AsRef<BlockId> + Send + Sync;
async fn get_state_update<B>(
&self,
block_id: B,
) -> Result<MaybePreConfirmedStateUpdate, ProviderError>
where
B: AsRef<BlockId> + Send + Sync;
async fn get_storage_at<A, K, B>(
&self,
contract_address: A,
key: K,
block_id: B,
) -> Result<Felt, ProviderError>
where
A: AsRef<Felt> + Send + Sync,
K: AsRef<Felt> + Send + Sync,
B: AsRef<BlockId> + Send + Sync;
async fn get_messages_status(
&self,
transaction_hash: Hash256,
) -> Result<Vec<MessageStatus>, ProviderError>;
async fn get_transaction_status<H>(
&self,
transaction_hash: H,
) -> Result<TransactionStatus, ProviderError>
where
H: AsRef<Felt> + Send + Sync;
async fn get_transaction_by_hash<H>(
&self,
transaction_hash: H,
) -> Result<Transaction, ProviderError>
where
H: AsRef<Felt> + Send + Sync;
async fn get_transaction_by_block_id_and_index<B>(
&self,
block_id: B,
index: u64,
) -> Result<Transaction, ProviderError>
where
B: AsRef<BlockId> + Send + Sync;
async fn get_transaction_receipt<H>(
&self,
transaction_hash: H,
) -> Result<TransactionReceiptWithBlockInfo, ProviderError>
where
H: AsRef<Felt> + Send + Sync;
async fn get_class<B, H>(
&self,
block_id: B,
class_hash: H,
) -> Result<ContractClass, ProviderError>
where
B: AsRef<BlockId> + Send + Sync,
H: AsRef<Felt> + Send + Sync;
async fn get_class_hash_at<B, A>(
&self,
block_id: B,
contract_address: A,
) -> Result<Felt, ProviderError>
where
B: AsRef<BlockId> + Send + Sync,
A: AsRef<Felt> + Send + Sync;
async fn get_class_at<B, A>(
&self,
block_id: B,
contract_address: A,
) -> Result<ContractClass, ProviderError>
where
B: AsRef<BlockId> + Send + Sync,
A: AsRef<Felt> + Send + Sync;
async fn get_block_transaction_count<B>(&self, block_id: B) -> Result<u64, ProviderError>
where
B: AsRef<BlockId> + Send + Sync;
async fn call<R, B>(&self, request: R, block_id: B) -> Result<Vec<Felt>, ProviderError>
where
R: AsRef<FunctionCall> + Send + Sync,
B: AsRef<BlockId> + Send + Sync;
async fn estimate_fee<R, S, B>(
&self,
request: R,
simulation_flags: S,
block_id: B,
) -> Result<Vec<FeeEstimate>, ProviderError>
where
R: AsRef<[BroadcastedTransaction]> + Send + Sync,
S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
B: AsRef<BlockId> + Send + Sync;
async fn estimate_message_fee<M, B>(
&self,
message: M,
block_id: B,
) -> Result<MessageFeeEstimate, ProviderError>
where
M: AsRef<MsgFromL1> + Send + Sync,
B: AsRef<BlockId> + Send + Sync;
async fn block_number(&self) -> Result<u64, ProviderError>;
async fn block_hash_and_number(&self) -> Result<BlockHashAndNumber, ProviderError>;
async fn chain_id(&self) -> Result<Felt, ProviderError>;
async fn syncing(&self) -> Result<SyncStatusType, ProviderError>;
async fn get_events(
&self,
filter: EventFilter,
continuation_token: Option<String>,
chunk_size: u64,
) -> Result<EventsPage, ProviderError>;
async fn get_nonce<B, A>(
&self,
block_id: B,
contract_address: A,
) -> Result<Felt, ProviderError>
where
B: AsRef<BlockId> + Send + Sync,
A: AsRef<Felt> + Send + Sync;
async fn get_storage_proof<B, H, A, K>(
&self,
block_id: B,
class_hashes: H,
contract_addresses: A,
contracts_storage_keys: K,
) -> Result<StorageProof, ProviderError>
where
B: AsRef<ConfirmedBlockId> + Send + Sync,
H: AsRef<[Felt]> + Send + Sync,
A: AsRef<[Felt]> + Send + Sync,
K: AsRef<[ContractStorageKeys]> + Send + Sync;
async fn add_invoke_transaction<I>(
&self,
invoke_transaction: I,
) -> Result<InvokeTransactionResult, ProviderError>
where
I: AsRef<BroadcastedInvokeTransaction> + Send + Sync;
async fn add_declare_transaction<D>(
&self,
declare_transaction: D,
) -> Result<DeclareTransactionResult, ProviderError>
where
D: AsRef<BroadcastedDeclareTransaction> + Send + Sync;
async fn add_deploy_account_transaction<D>(
&self,
deploy_account_transaction: D,
) -> Result<DeployAccountTransactionResult, ProviderError>
where
D: AsRef<BroadcastedDeployAccountTransaction> + Send + Sync;
async fn trace_transaction<H>(
&self,
transaction_hash: H,
) -> Result<TransactionTrace, ProviderError>
where
H: AsRef<Felt> + Send + Sync;
async fn simulate_transactions<B, T, S>(
&self,
block_id: B,
transactions: T,
simulation_flags: S,
) -> Result<Vec<SimulatedTransaction>, ProviderError>
where
B: AsRef<BlockId> + Send + Sync,
T: AsRef<[BroadcastedTransaction]> + Send + Sync,
S: AsRef<[SimulationFlag]> + Send + Sync;
async fn trace_block_transactions<B>(
&self,
block_id: B,
) -> Result<Vec<TransactionTraceWithHash>, ProviderError>
where
B: AsRef<ConfirmedBlockId> + Send + Sync;
async fn batch_requests<R>(
&self,
requests: R,
) -> Result<Vec<ProviderResponseData>, ProviderError>
where
R: AsRef<[ProviderRequestData]> + Send + Sync;
async fn estimate_fee_single<R, S, B>(
&self,
request: R,
simulation_flags: S,
block_id: B,
) -> Result<FeeEstimate, ProviderError>
where
R: AsRef<BroadcastedTransaction> + Send + Sync,
S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
B: AsRef<BlockId> + Send + Sync,
{
let mut result = self
.estimate_fee([request.as_ref().to_owned()], simulation_flags, block_id)
.await?;
if result.len() == 1 {
Ok(result.pop().unwrap())
} else {
Err(ProviderError::ArrayLengthMismatch)
}
}
async fn simulate_transaction<B, T, S>(
&self,
block_id: B,
transaction: T,
simulation_flags: S,
) -> Result<SimulatedTransaction, ProviderError>
where
B: AsRef<BlockId> + Send + Sync,
T: AsRef<BroadcastedTransaction> + Send + Sync,
S: AsRef<[SimulationFlag]> + Send + Sync,
{
let mut result = self
.simulate_transactions(
block_id,
[transaction.as_ref().to_owned()],
simulation_flags,
)
.await?;
if result.len() == 1 {
Ok(result.pop().unwrap())
} else {
Err(ProviderError::ArrayLengthMismatch)
}
}
}
pub trait ProviderImplError: Error + Debug + Send + Sync {
fn as_any(&self) -> &dyn Any;
}
#[derive(Debug, thiserror::Error)]
pub enum ProviderError {
#[error(transparent)]
StarknetError(StarknetError),
#[error("Request rate limited")]
RateLimited,
#[error("Array length mismatch")]
ArrayLengthMismatch,
#[error("{0}")]
Other(Box<dyn ProviderImplError>),
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum ProviderRequestData {
SpecVersion(SpecVersionRequest),
GetBlockWithTxHashes(GetBlockWithTxHashesRequest),
GetBlockWithTxs(GetBlockWithTxsRequest),
GetBlockWithReceipts(GetBlockWithReceiptsRequest),
GetStateUpdate(GetStateUpdateRequest),
GetStorageAt(GetStorageAtRequest),
GetMessagesStatus(GetMessagesStatusRequest),
GetTransactionStatus(GetTransactionStatusRequest),
GetTransactionByHash(GetTransactionByHashRequest),
GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest),
GetTransactionReceipt(GetTransactionReceiptRequest),
GetClass(GetClassRequest),
GetClassHashAt(GetClassHashAtRequest),
GetClassAt(GetClassAtRequest),
GetBlockTransactionCount(GetBlockTransactionCountRequest),
Call(CallRequest),
EstimateFee(EstimateFeeRequest),
EstimateMessageFee(EstimateMessageFeeRequest),
BlockNumber(BlockNumberRequest),
BlockHashAndNumber(BlockHashAndNumberRequest),
ChainId(ChainIdRequest),
Syncing(SyncingRequest),
GetEvents(GetEventsRequest),
GetNonce(GetNonceRequest),
GetStorageProof(GetStorageProofRequest),
AddInvokeTransaction(AddInvokeTransactionRequest),
AddDeclareTransaction(AddDeclareTransactionRequest),
AddDeployAccountTransaction(AddDeployAccountTransactionRequest),
TraceTransaction(TraceTransactionRequest),
SimulateTransactions(SimulateTransactionsRequest),
TraceBlockTransactions(TraceBlockTransactionsRequest),
SubscribeNewHeads(SubscribeNewHeadsRequest),
SubscribeEvents(SubscribeEventsRequest),
SubscribeTransactionStatus(SubscribeTransactionStatusRequest),
SubscribeNewTransactionReceipts(SubscribeNewTransactionReceiptsRequest),
SubscribeNewTransactions(SubscribeNewTransactionsRequest),
Unsubscribe(UnsubscribeRequest),
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
pub enum ProviderResponseData {
SpecVersion(String),
GetBlockWithTxHashes(MaybePreConfirmedBlockWithTxHashes),
GetBlockWithTxs(MaybePreConfirmedBlockWithTxs),
GetBlockWithReceipts(MaybePreConfirmedBlockWithReceipts),
GetStateUpdate(MaybePreConfirmedStateUpdate),
GetStorageAt(Felt),
GetMessagesStatus(Vec<MessageStatus>),
GetTransactionStatus(TransactionStatus),
GetTransactionByHash(Transaction),
GetTransactionByBlockIdAndIndex(Transaction),
GetTransactionReceipt(TransactionReceiptWithBlockInfo),
GetClass(ContractClass),
GetClassHashAt(Felt),
GetClassAt(ContractClass),
GetBlockTransactionCount(u64),
Call(Vec<Felt>),
EstimateFee(Vec<FeeEstimate>),
EstimateMessageFee(FeeEstimate),
BlockNumber(u64),
BlockHashAndNumber(BlockHashAndNumber),
ChainId(Felt),
Syncing(SyncStatusType),
GetEvents(EventsPage),
GetNonce(Felt),
GetStorageProof(StorageProof),
AddInvokeTransaction(InvokeTransactionResult),
AddDeclareTransaction(DeclareTransactionResult),
AddDeployAccountTransaction(DeployAccountTransactionResult),
TraceTransaction(TransactionTrace),
SimulateTransactions(Vec<SimulatedTransaction>),
TraceBlockTransactions(Vec<TransactionTraceWithHash>),
SubscribeNewHeads(SubscriptionId),
SubscribeEvents(SubscriptionId),
SubscribeTransactionStatus(SubscriptionId),
SubscribeNewTransactionReceipts(SubscriptionId),
SubscribeNewTransactions(SubscriptionId),
Unsubscribe(bool),
}
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum StreamUpdateData {
SubscriptionNewHeads(SubscriptionNewHeadsRequest),
SubscriptionEvents(SubscriptionEventsRequest),
SubscriptionTransactionStatus(SubscriptionTransactionStatusRequest),
SubscriptionNewTransactionReceipts(SubscriptionNewTransactionReceiptsRequest),
SubscriptionNewTransaction(SubscriptionNewTransactionRequest),
SubscriptionReorg(SubscriptionReorgRequest),
}
impl StreamUpdateData {
pub fn subscription_id(&self) -> &SubscriptionId {
match self {
Self::SubscriptionNewHeads(update) => &update.subscription_id,
Self::SubscriptionEvents(update) => &update.subscription_id,
Self::SubscriptionTransactionStatus(update) => &update.subscription_id,
Self::SubscriptionNewTransactionReceipts(update) => &update.subscription_id,
Self::SubscriptionNewTransaction(update) => &update.subscription_id,
Self::SubscriptionReorg(update) => &update.subscription_id,
}
}
}