1use std::sync::Arc;
2
3use ethers::abi::{encode, Token};
4use ethers::contract::{EthLogDecode, Event};
5use ethers::providers::{Middleware, PendingTransaction, PubsubClient};
6
7use crate::contracts::eas::{
8 Attestation, AttestationRequest, AttestedFilter, MultiAttestationRequest,
9};
10use ethers::types::{BlockNumber, H256};
11
12use crate::contracts::AttestationData;
13
14use ::ethers::core::types::{Address, Bytes, U256};
15use futures::stream::BoxStream;
16use futures::{Stream, StreamExt};
17
18use tracing::debug;
19
20use crate::eas::{Error, EAS};
21use crate::transaction::{Error as TxError, PendingTx};
22
23pub struct AttestationDataBuilder {
24 pub recipient: Option<Address>,
25 pub expiration_time: Option<u64>,
26 pub revocable: bool,
27 pub ref_uid: Option<[u8; 32]>,
28 pub data: Option<Bytes>,
29 pub value: Option<U256>,
30}
31
32#[derive(Debug)]
33pub struct Attested {
34 pub recipient: Address,
35 pub attester: Address,
36 pub uid: H256,
37 pub schema: H256,
38}
39
40pub struct MultiAttestRequest {
41 pub schema: H256,
42 pub data: Vec<AttestationData>,
43}
44
45impl From<AttestedFilter> for Attested {
46 fn from(event: AttestedFilter) -> Self {
47 Self {
48 recipient: event.recipient,
49 attester: event.attester,
50 uid: H256::from_slice(&event.uid),
51 schema: H256::from_slice(&event.schema),
52 }
53 }
54}
55
56impl Default for AttestationDataBuilder {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl AttestationDataBuilder {
63 pub fn new() -> Self {
64 Self {
65 recipient: None,
66 expiration_time: None,
67 revocable: false,
68 ref_uid: None,
69 data: None,
70 value: None,
71 }
72 }
73
74 pub fn recipient(mut self, recipient: Address) -> Self {
75 self.recipient = Some(recipient);
76 self
77 }
78
79 pub fn expiration_time(mut self, expiration_time: u64) -> Self {
80 self.expiration_time = Some(expiration_time);
81 self
82 }
83
84 pub fn revocable(mut self, revocable: bool) -> Self {
85 self.revocable = revocable;
86 self
87 }
88
89 pub fn ref_uid(mut self, ref_uid: [u8; 32]) -> Self {
90 self.ref_uid = Some(ref_uid);
91 self
92 }
93
94 pub fn data(mut self, data: &[Token]) -> Self {
95 self.data = Some(encode(data).into());
96 self
97 }
98
99 pub fn value(mut self, value: U256) -> Self {
100 self.value = Some(value);
101 self
102 }
103
104 pub fn build(self) -> AttestationData {
105 AttestationData {
106 recipient: self.recipient.unwrap_or(Address::zero()),
107 expiration_time: self.expiration_time.unwrap_or(0),
108 revocable: self.revocable,
109 ref_uid: self.ref_uid.unwrap_or([0; 32]),
110 data: self.data.unwrap_or_default(),
111 value: self.value.unwrap_or(U256::zero()),
112 }
113 }
114}
115
116impl<M: Middleware + 'static> EAS<M> {
117 pub async fn attest(
118 &self,
119 schema: &H256,
120 data: AttestationData,
121 ) -> Result<PendingTx<Attested>, Error<M>> {
122 let attestation_request = AttestationRequest {
123 schema: schema.to_fixed_bytes(),
124 data,
125 };
126
127 let binding = self.contract.attest(attestation_request);
128 let tx = binding.send().await?;
129
130 debug!("Transaction sent: {:?}", tx.tx_hash());
131
132 let tx_hash = tx.tx_hash();
134 let provider = self.contract.client().clone();
135
136 let future = async move {
137 let tx = PendingTransaction::new(tx_hash, provider.provider());
138 let receipt = tx.await?;
139 let receipt = receipt.ok_or_else(|| TxError::TransactionDropped(tx_hash))?;
140
141 debug!("Receipt: {:?}", receipt);
142
143 let log = receipt.logs.first().ok_or_else(|| TxError::MissingLogs)?;
144
145 let attested = AttestedFilter::decode_log(&log.clone().into())?;
146
147 Ok(attested.into())
148 };
149
150 Ok(PendingTx::new(future))
151 }
152
153 pub async fn get_attestation(&self, attestation_id: &H256) -> Result<Attestation, Error<M>> {
154 let binding = self
155 .contract
156 .get_attestation(attestation_id.to_fixed_bytes());
157
158 let attestation_data = binding.call().await?;
159 Ok(attestation_data)
160 }
161
162 pub async fn is_attestation_valid(&self, attestation_id: &H256) -> Result<bool, Error<M>> {
163 let binding = self
164 .contract
165 .is_attestation_valid(attestation_id.to_fixed_bytes());
166
167 let is_valid = binding.call().await?;
168 Ok(is_valid)
169 }
170
171 pub async fn multi_attest(
172 &self,
173 request: Vec<MultiAttestRequest>,
174 ) -> Result<PendingTx<Vec<Result<Attested, TxError>>>, Error<M>> {
175 let attestation_requests = request
176 .iter()
177 .map(|req| MultiAttestationRequest {
178 schema: req.schema.to_fixed_bytes(),
179 data: req.data.clone(),
180 })
181 .collect();
182
183 let binding = self.contract.multi_attest(attestation_requests);
184 let tx = binding.send().await?;
185
186 debug!("Transaction sent: {:?}", tx.tx_hash());
187
188 let tx_hash = tx.tx_hash();
190 let provider = self.contract.client().clone();
191
192 let future = async move {
193 let tx = PendingTransaction::new(tx_hash, provider.provider());
194 let receipt = tx.await?;
195 let receipt = receipt.ok_or_else(|| TxError::TransactionDropped(tx_hash))?;
196
197 debug!("Receipt: {:?}", receipt);
198
199 let attested: Vec<Result<Attested, TxError>> = receipt
200 .logs
201 .iter()
202 .map(|log| {
203 AttestedFilter::decode_log(&log.clone().into())
204 .map(Into::into)
205 .map_err(TxError::from)
206 })
207 .collect();
208
209 Ok(attested)
210 };
211
212 Ok(PendingTx::new(future))
213 }
214
215 pub fn attested_event<T>(
216 &self,
217 start_block: T,
218 end_block: Option<T>,
219 uids: Option<Vec<H256>>,
220 ) -> AttestedEvent<M>
221 where
222 T: Into<BlockNumber>,
223 {
224 let mut event = self.contract.attested_filter().from_block(start_block);
225
226 if let Some(end_block) = end_block {
227 event = event.to_block(end_block);
228 }
229
230 if let Some(uids) = uids {
231 event = event.topic0(uids);
232 }
233
234 AttestedEvent::new(event)
235 }
236}
237
238pub struct AttestedEvent<M: Middleware + 'static> {
239 inner: Event<Arc<M>, M, AttestedFilter>,
240}
241
242impl<M: Middleware> AttestedEvent<M> {
243 pub fn new(filter: Event<Arc<M>, M, AttestedFilter>) -> Self {
244 Self { inner: filter }
245 }
246
247 pub async fn stream(&self) -> Result<BoxStream<Result<Attested, Error<M>>>, Error<M>> {
248 let stream = self
249 .inner
250 .stream()
251 .await
252 .map_err(Error::ContractError)?
253 .map(|e| Ok(Attested::from(e?)));
254 Ok(stream.boxed())
255 }
256
257 pub async fn query(&self) -> Result<Vec<Attested>, Error<M>> {
258 let logs = self
259 .inner
260 .query()
261 .await
262 .map_err(Error::ContractError)?
263 .iter()
264 .map(|e| Attested::from(e.clone()))
265 .collect();
266
267 Ok(logs)
268 }
269}
270
271impl<M: Middleware> AttestedEvent<M>
272where
273 M::Provider: PubsubClient,
274{
275 pub async fn subscribe(
276 &self,
277 ) -> Result<impl Stream<Item = Result<Attested, Error<M>>> + '_, Error<M>> {
278 let stream = self
279 .inner
280 .subscribe()
281 .await
282 .map_err(Error::ContractError)?
283 .map(|e| Ok(Attested::from(e?)));
284 Ok(stream)
285 }
286}