1use std::sync::Arc;
2
3use crate::contracts::eas::{
4 MultiRevocationRequest, RevocationRequest, RevocationRequestData, RevokedFilter,
5};
6use crate::transaction::{Error as TxError, PendingTx};
7use ethers::{
8 contract::{EthLogDecode, Event},
9 providers::{Middleware, PendingTransaction, PubsubClient},
10 types::{Address, BlockNumber, H256, U256},
11};
12use futures::{stream::BoxStream, Stream, StreamExt};
13use tracing::debug;
14
15use super::{Error, EAS};
16
17#[derive(Debug)]
18pub struct Revoked {
19 pub recipient: Address,
20 pub attester: Address,
21 pub uid: H256,
22 pub schema: H256,
23}
24
25pub struct MultiRevokeRequest {
26 pub schema_id: H256,
27 pub data: Vec<RevokeRequestData>,
28}
29
30pub struct RevokeRequestData {
31 pub attestation_id: H256,
32 pub value: U256,
33}
34
35impl From<MultiRevokeRequest> for MultiRevocationRequest {
36 fn from(req: MultiRevokeRequest) -> Self {
37 Self {
38 schema: req.schema_id.into(),
39 data: req.data.into_iter().map(|data| data.into()).collect(),
40 }
41 }
42}
43
44impl From<RevokeRequestData> for RevocationRequestData {
45 fn from(data: RevokeRequestData) -> Self {
46 Self {
47 uid: data.attestation_id.into(),
48 value: data.value,
49 }
50 }
51}
52
53impl From<RevokedFilter> for Revoked {
54 fn from(event: RevokedFilter) -> Self {
55 Self {
56 recipient: event.recipient,
57 attester: event.attester,
58 uid: H256::from_slice(&event.uid),
59 schema: H256::from_slice(&event.schema),
60 }
61 }
62}
63
64impl<M: Middleware + 'static> EAS<M> {
65 pub async fn revoke(
66 &self,
67 schema_id: H256,
68 attestation_id: H256,
69 value: U256,
70 ) -> Result<PendingTx<Revoked>, Error<M>> {
71 let req = RevocationRequest {
72 schema: schema_id.into(),
73 data: RevocationRequestData {
74 uid: attestation_id.into(),
75 value,
76 },
77 };
78
79 let binding = self.contract.revoke(req);
80 let tx = binding.send().await?;
81
82 debug!("Transaction sent: {:?}", tx.tx_hash());
83
84 let tx_hash = tx.tx_hash();
86 let provider = self.contract.client().clone();
87
88 let future = async move {
89 let tx = PendingTransaction::new(tx_hash, provider.provider());
90 let receipt = tx.await?;
91 let receipt = receipt.ok_or_else(|| TxError::TransactionDropped(tx_hash))?;
92
93 let log = receipt.logs.first().ok_or_else(|| TxError::MissingLogs)?;
94
95 let revoked = RevokedFilter::decode_log(&log.clone().into())?;
96 Ok(revoked.into())
97 };
98
99 Ok(PendingTx::new(future))
100 }
101
102 pub async fn multi_revoke(
103 &self,
104 revokes: Vec<MultiRevokeRequest>,
105 ) -> Result<PendingTx<Vec<Result<Revoked, TxError>>>, Error<M>> {
106 let requests: Vec<MultiRevocationRequest> =
107 revokes.into_iter().map(|req| req.into()).collect();
108
109 let binding = self.contract.multi_revoke(requests);
110 let tx = binding.send().await?;
111
112 debug!("Transaction sent: {:?}", tx.tx_hash());
113
114 let tx_hash = tx.tx_hash();
116 let provider = self.contract.client().clone();
117
118 let future = async move {
119 let tx = PendingTransaction::new(tx_hash, provider.provider());
120 let receipt = tx.await?;
121 let receipt = receipt.ok_or_else(|| TxError::TransactionDropped(tx_hash))?;
122
123 let revoked: Vec<Result<Revoked, TxError>> = receipt
124 .logs
125 .iter()
126 .map(|log| {
127 RevokedFilter::decode_log(&log.clone().into())
128 .map(Into::into)
129 .map_err(TxError::from)
130 })
131 .collect();
132
133 Ok(revoked)
134 };
135
136 Ok(PendingTx::new(future))
137 }
138
139 pub fn revoked_event<T>(
140 &self,
141 start_block: T,
142 end_block: Option<T>,
143 uids: Option<Vec<H256>>,
144 ) -> RevokedEvent<M>
145 where
146 T: Into<BlockNumber>,
147 {
148 let mut event = self.contract.revoked_filter().from_block(start_block);
149
150 if let Some(end_block) = end_block {
151 event = event.to_block(end_block);
152 }
153
154 if let Some(uids) = uids {
155 event = event.topic0(uids);
156 }
157
158 RevokedEvent::new(event)
159 }
160}
161
162pub struct RevokedEvent<M: Middleware + 'static> {
163 inner: Event<Arc<M>, M, RevokedFilter>,
164}
165
166impl<M: Middleware> RevokedEvent<M> {
167 pub fn new(filter: Event<Arc<M>, M, RevokedFilter>) -> Self {
168 Self { inner: filter }
169 }
170
171 pub async fn stream(&self) -> Result<BoxStream<Result<Revoked, Error<M>>>, Error<M>> {
172 let stream = self
173 .inner
174 .stream()
175 .await
176 .map_err(Error::ContractError)?
177 .map(|e| Ok(Revoked::from(e?)));
178 Ok(stream.boxed())
179 }
180
181 pub async fn query(&self) -> Result<Vec<Revoked>, Error<M>> {
182 let logs = self
183 .inner
184 .query()
185 .await
186 .map_err(Error::ContractError)?
187 .iter()
188 .map(|e| Revoked::from(e.clone()))
189 .collect();
190
191 Ok(logs)
192 }
193}
194
195impl<M: Middleware> RevokedEvent<M>
196where
197 M::Provider: PubsubClient,
198{
199 pub async fn subscribe(
200 &self,
201 ) -> Result<impl Stream<Item = Result<Revoked, Error<M>>> + '_, Error<M>> {
202 let stream = self
203 .inner
204 .subscribe()
205 .await
206 .map_err(Error::ContractError)?
207 .map(|e| Ok(Revoked::from(e?)));
208 Ok(stream)
209 }
210}