Skip to main content

pod_sdk/auctions/
client.rs

1use std::time::SystemTime;
2
3use crate::{network::PodNetwork, provider::PodProvider, Address, U256};
4use alloy_eips::BlockNumberOrTag;
5use anyhow::Context;
6
7use pod_contracts::i_auction::IAuction::IAuctionInstance;
8use pod_types::{rpc::receipt::PodReceiptResponse, Timestamp};
9
10pub struct AuctionClient {
11    pub auction: IAuctionInstance<PodProvider, PodNetwork>,
12}
13
14pub struct Bid {
15    pub amount: U256,
16    pub bidder: Address,
17    pub data: Vec<u8>,
18}
19
20impl AuctionClient {
21    // Convert SystemTime -> microseconds as `u128`.
22    fn micros_from_system_time(deadline: SystemTime) -> u128 {
23        Timestamp::from(deadline).as_micros()
24    }
25
26    // Convert SystemTime -> microseconds as `u64`, failing with a clear message on overflow.
27    fn micros_u64_from_system_time(deadline: SystemTime) -> anyhow::Result<u64> {
28        let micros = Self::micros_from_system_time(deadline);
29        micros
30            .try_into()
31            .context("deadline microseconds must fit in u64")
32    }
33
34    // Convert SystemTime -> microseconds as `U256` for contract topics.
35    fn micros_u256_from_system_time(deadline: SystemTime) -> U256 {
36        U256::from(Self::micros_from_system_time(deadline))
37    }
38
39    pub fn new(provider: PodProvider, contract: Address) -> Self {
40        AuctionClient {
41            auction: IAuctionInstance::new(contract, provider),
42        }
43    }
44
45    #[tracing::instrument(skip(self))]
46    pub async fn wait_for_auction_end(&self, deadline: SystemTime) -> anyhow::Result<()> {
47        Ok(self
48            .auction
49            .provider()
50            .wait_past_perfect_time(deadline.into())
51            .await?)
52    }
53
54    #[tracing::instrument(skip(self))]
55    pub async fn fetch_bids(&self, auction_id: U256) -> anyhow::Result<Vec<Bid>> {
56        let logs = self
57            .auction
58            .BidSubmitted_filter()
59            .topic1(auction_id)
60            .to_block(BlockNumberOrTag::Latest)
61            .query()
62            .await
63            .context("fetching bid logs")?;
64
65        logs.into_iter()
66            .map(|(event, _)| {
67                Ok(Bid {
68                    amount: event.value,
69                    bidder: event.bidder,
70                    data: event.data.to_vec(),
71                })
72            })
73            .collect()
74    }
75
76    #[tracing::instrument(skip(self))]
77    pub async fn fetch_bids_for_deadline(&self, deadline: SystemTime) -> anyhow::Result<Vec<Bid>> {
78        let deadline_us = Self::micros_u256_from_system_time(deadline);
79
80        let logs = self
81            .auction
82            .BidSubmitted_filter()
83            .topic3(deadline_us)
84            .to_block(BlockNumberOrTag::Latest)
85            .query()
86            .await
87            .context("fetching bid logs")?;
88
89        logs.into_iter()
90            .map(|(event, _)| {
91                Ok(Bid {
92                    amount: event.value,
93                    bidder: event.bidder,
94                    data: event.data.to_vec(),
95                })
96            })
97            .collect()
98    }
99
100    pub async fn submit_bid(
101        &self,
102        auction_id: U256,
103        deadline: SystemTime,
104        bid: U256,
105        data: Vec<u8>,
106    ) -> anyhow::Result<PodReceiptResponse> {
107        let deadline = Self::micros_u64_from_system_time(deadline)?;
108
109        let pending_tx = self
110            .auction
111            .submitBid(auction_id, deadline, bid, data.into())
112            .max_priority_fee_per_gas(0)
113            .send()
114            .await
115            .context("sending bid TX")?;
116
117        let receipt = pending_tx
118            .get_receipt()
119            .await
120            .context("awaiting for bid TX confirmation")?;
121
122        anyhow::ensure!(receipt.status(), "failed to submit bid TX");
123        Ok(receipt)
124    }
125}