eas_sdk_rs/eas/
revoke.rs

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        // PendingTransaction is not copy and it is dropped there, but it is recreated from tx_hash and provider
85        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        // PendingTransaction is not copy and it is dropped there, but it is recreated from tx_hash and provider
115        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}