drive_proof_verifier/proof/
token_perpetual_distribution_last_claim.rs

1use dapi_grpc::platform::v0::{
2    get_token_perpetual_distribution_last_claim_request::Version as RequestVersion,
3    get_token_perpetual_distribution_last_claim_response::{
4        get_token_perpetual_distribution_last_claim_response_v0, Version as ResponseVersion,
5    },
6    GetTokenPerpetualDistributionLastClaimResponse, Proof, ResponseMetadata,
7};
8use dpp::{
9    dashcore::Network,
10    data_contract::associated_token::{
11        token_configuration::accessors::v0::TokenConfigurationV0Getters,
12        token_distribution_rules::accessors::v0::TokenDistributionRulesV0Getters,
13        token_perpetual_distribution::{
14            methods::v0::TokenPerpetualDistributionV0Accessors,
15            reward_distribution_moment::RewardDistributionMoment,
16        },
17    },
18    prelude::Identifier,
19    version::PlatformVersion,
20};
21use drive::drive::Drive;
22use get_token_perpetual_distribution_last_claim_response_v0::Result as RespResult;
23
24use crate::{verify::verify_tenderdash_proof, ContextProvider, Error};
25
26use super::FromProof;
27use dapi_grpc::platform::v0::GetTokenPerpetualDistributionLastClaimRequest;
28
29impl FromProof<GetTokenPerpetualDistributionLastClaimRequest> for RewardDistributionMoment {
30    type Request = GetTokenPerpetualDistributionLastClaimRequest;
31    type Response = GetTokenPerpetualDistributionLastClaimResponse;
32
33    /// Parse & verify the last‑claim proof returned by Platform.
34    fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
35        request: I,
36        response: O,
37        _network: Network,
38        platform_version: &PlatformVersion,
39        provider: &'a dyn ContextProvider,
40    ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
41    where
42        Self: Sized + 'a,
43    {
44        let request = request.into();
45        let response = response.into();
46
47        let RequestVersion::V0(req_v0) = request.version.ok_or(Error::EmptyVersion)?;
48
49        let token_id: [u8; 32] =
50            req_v0
51                .token_id
52                .as_slice()
53                .try_into()
54                .map_err(|_| Error::RequestError {
55                    error: "token_id must be 32 bytes".into(),
56                })?;
57
58        let identity_id: [u8; 32] =
59            req_v0
60                .identity_id
61                .as_slice()
62                .try_into()
63                .map_err(|_| Error::RequestError {
64                    error: "identity_id must be 32 bytes".into(),
65                })?;
66
67        let ResponseVersion::V0(resp_v0) = response.version.ok_or(Error::EmptyVersion)?;
68
69        let metadata = resp_v0
70            .metadata
71            .clone()
72            .ok_or(Error::EmptyResponseMetadata)?;
73
74        let result = resp_v0.result.clone().ok_or(Error::NoProofInResult)?;
75
76        match result {
77            RespResult::Proof(proof_msg) => {
78                let maybe_distribution_type = {
79                    let token_id_identifier = Identifier::from_vec(req_v0.token_id.clone())
80                        .map_err(|_| Error::RequestError {
81                            error: "token_id must be 32 bytes".into(),
82                        })?;
83
84                    let maybe_token_config =
85                        provider.get_token_configuration(&token_id_identifier)?;
86                    let maybe_dist_type = maybe_token_config
87                        .as_ref()
88                        .and_then(|cfg| cfg.distribution_rules().perpetual_distribution())
89                        .map(|perp| perp.distribution_type().clone());
90
91                    maybe_dist_type
92                };
93
94                match maybe_distribution_type {
95                    Some(distribution_type) => {
96                        let (root_hash, moment_opt) =
97                            Drive::verify_token_perpetual_distribution_last_paid_time(
98                                &proof_msg.grovedb_proof,
99                                token_id,
100                                identity_id,
101                                &distribution_type,
102                                false,
103                                platform_version,
104                            )?;
105
106                        verify_tenderdash_proof(&proof_msg, &metadata, &root_hash, provider)?;
107
108                        // May be None if identity has not yet claimed
109                        Ok((moment_opt, metadata, proof_msg))
110                    }
111                    None => Err(Error::RequestError {
112                        error: "Token distribution type not found with get_token_distribution()"
113                            .into(),
114                    }),
115                }
116            }
117
118            RespResult::LastClaim(_) => Err(Error::RequestError {
119                error: "Non-proof LastClaim response is not supported in rs-sdk".into(),
120            }),
121        }
122    }
123}