1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Broadcast trait representing the action of broadcasting a new identity state transition to Platform.
//!
//! The [BroadcastRequestForNewIdentity] trait is designed for the creation and broadcasting of new identity state transitions.
//! This involves the generation of a state transition object, signing it, and then broadcasting it to Platform.
//!
//! This trait is expected to be implemented by objects that encapsulate the necessary data and logic to perform
//! these operations, including the handling of asset lock proof and signing operations.
use std::fmt::Debug;

use dapi_grpc::platform::v0::wait_for_state_transition_result_request::{
    Version, WaitForStateTransitionResultRequestV0,
};
use dapi_grpc::platform::v0::{
    BroadcastStateTransitionRequest, WaitForStateTransitionResultRequest,
};

use dpp::serialization::PlatformSerializable;

use dpp::state_transition::StateTransition;

use crate::error::Error;

/// Trait implemented by objects that can be used to broadcast new identity state transitions.
///
/// [BroadcastRequestForNewIdentity] trait is used when a new identity needs to be created and broadcasted on Platform.
/// It encapsulates the data, the signing process, and the logic required to perform the broadcast operation.
///
/// Implementors of this trait will typically be responsible for creating an identity state transition,
/// signing it with the provided private key and signer, and preparing it for transport to Platform.
///
/// ## Example
///
/// To broadcast a new [Identity](dpp::prelude::Identity) state transition, you would typically
/// create an [IdentityCreateTransition](dpp::state_transition::identity_create_transition::IdentityCreateTransition),
/// sign it, and use the `broadcast_new_identity` method provided by this trait:
///
/// ```rust, ignore
///
/// use dash_sdk::{Sdk, platform::{BroadcastNewIdentity, IdentityCreateTransition}};
/// use dpp::identity::signer::Signer;
/// use dpp::prelude::{AssetLockProof, PrivateKey};
/// use dpp::version::PlatformVersion;
///
/// let mut sdk = Sdk::new_mock();
/// let asset_lock_proof = AssetLockProof::new(/* parameters for the asset lock proof */);
/// let private_key = PrivateKey::from(/* private key data */);
/// let signer = /* implementation of Signer trait */;
/// let platform_version = PlatformVersion::latest();
///
/// let identity_transition = IdentityCreateTransition::new(/* parameters for the transition */);
/// let result = identity_transition.broadcast_new_identity(asset_lock_proof, private_key, &signer, &platform_version);
///
/// match result {
///     Ok(transport_request) => {
///         // The transport_request can now be sent to Platform to broadcast the new identity.
///     }
///     Err(e) => {
///         // Handle the error
///     }
/// }
/// ```
///
/// As [BroadcastRequestForStateTransition] is a trait, it can be implemented for any type that represents
/// a new identity creation operation, allowing for flexibility in how new identities are broadcasted.
pub trait BroadcastRequestForStateTransition: Send + Debug + Clone {
    /// Converts the current instance into an instance of the `TransportRequest` type, ready for broadcasting.
    ///
    /// This method takes ownership of the instance upon which it's called (hence `self`), and attempts to perform the conversion,
    /// including signing the state transition with the provided private key and signer.
    ///
    /// # Arguments
    ///
    /// * `asset_lock_proof` - The proof that locks the asset which is used to create the identity.
    /// * `asset_lock_proof_private_key` - The private key associated with the asset lock proof.
    /// * `signer` - The signer to be used for signing the state transition.
    /// * `platform_version` - The version of Platform for which the state transition is intended.
    ///
    /// # Returns
    /// On success, this method yields an instance of the `TransportRequest` type (`T`), which can be used to broadcast the new identity state transition to Platform.
    /// On failure, it yields an [`Error`].
    ///
    /// # Error Handling
    /// This method propagates any errors encountered during the signing or conversion process.
    /// These are returned as [`Error`] instances.
    fn broadcast_request_for_state_transition(
        &self,
    ) -> Result<BroadcastStateTransitionRequest, Error>;

    fn wait_for_state_transition_result_request(
        &self,
    ) -> Result<WaitForStateTransitionResultRequest, Error>;
}

impl BroadcastRequestForStateTransition for StateTransition {
    fn broadcast_request_for_state_transition(
        &self,
    ) -> Result<BroadcastStateTransitionRequest, Error> {
        Ok(BroadcastStateTransitionRequest {
            state_transition: self.serialize_to_bytes()?,
        })
    }

    fn wait_for_state_transition_result_request(
        &self,
    ) -> Result<WaitForStateTransitionResultRequest, Error> {
        Ok(WaitForStateTransitionResultRequest {
            version: Some(Version::V0(WaitForStateTransitionResultRequestV0 {
                state_transition_hash: self.transaction_id()?.to_vec(),
                prove: true,
            })),
        })
    }
}