dash_sdk/platform/transition/
top_up_address.rs1use std::collections::{BTreeMap, BTreeSet};
2
3use super::address_inputs::collect_address_infos_from_proof;
4use super::broadcast::BroadcastStateTransition;
5use super::put_settings::PutSettings;
6use super::validation::ensure_valid_state_transition_structure;
7use crate::{Error, Sdk};
8use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress};
9use dpp::dashcore::PrivateKey;
10use dpp::errors::consensus::basic::state_transition::TransitionNoOutputsError;
11use dpp::fee::Credits;
12use dpp::identity::signer::Signer;
13use dpp::prelude::{AddressNonce, AssetLockProof, UserFeeIncrease};
14use dpp::state_transition::address_funding_from_asset_lock_transition::methods::AddressFundingFromAssetLockTransitionMethodsV0;
15use dpp::state_transition::address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransition;
16use dpp::state_transition::proof_result::StateTransitionProofResult;
17use dpp::state_transition::StateTransition;
18use dpp::ProtocolError;
19use drive_proof_verifier::types::AddressInfos;
20
21#[async_trait::async_trait]
23pub trait TopUpAddress<S: Signer<PlatformAddress>> {
24 async fn top_up(
28 &self,
29 sdk: &Sdk,
30 asset_lock_proof: AssetLockProof,
31 asset_lock_private_key: PrivateKey,
32 fee_strategy: AddressFundsFeeStrategy,
33 signer: &S,
34 settings: Option<PutSettings>,
35 ) -> Result<AddressInfos, Error>;
36}
37
38pub type AddressWithBalance = (PlatformAddress, Option<Credits>);
39pub type AddressesWithBalances = BTreeMap<PlatformAddress, Option<Credits>>;
40
41#[async_trait::async_trait]
42impl<S: Signer<PlatformAddress>> TopUpAddress<S> for AddressWithBalance
43where
44 BTreeMap<PlatformAddress, Option<Credits>>: TopUpAddress<S>,
45{
46 async fn top_up(
47 &self,
48 sdk: &Sdk,
49 asset_lock_proof: AssetLockProof,
50 asset_lock_private_key: PrivateKey,
51 fee_strategy: AddressFundsFeeStrategy,
52 signer: &S,
53 settings: Option<PutSettings>,
54 ) -> Result<AddressInfos, Error> {
55 BTreeMap::from([(self.0, self.1)])
56 .top_up(
57 sdk,
58 asset_lock_proof,
59 asset_lock_private_key,
60 fee_strategy,
61 signer,
62 settings,
63 )
64 .await
65 }
66}
67
68#[async_trait::async_trait]
69impl<S: Signer<PlatformAddress>> TopUpAddress<S> for AddressesWithBalances {
70 async fn top_up(
71 &self,
72 sdk: &Sdk,
73 asset_lock_proof: AssetLockProof,
74 asset_lock_private_key: PrivateKey,
75 fee_strategy: AddressFundsFeeStrategy,
76 signer: &S,
77 settings: Option<PutSettings>,
78 ) -> Result<AddressInfos, Error> {
79 if self.is_empty() {
80 return Err(Error::from(TransitionNoOutputsError::new()));
81 }
82
83 let user_fee_increase = settings
84 .as_ref()
85 .and_then(|settings| settings.user_fee_increase)
86 .unwrap_or_default();
87
88 let state_transition = create_address_funding_from_asset_lock_transition(
89 asset_lock_proof,
90 asset_lock_private_key.inner.as_ref(),
91 BTreeMap::new(),
92 self.clone(),
93 fee_strategy,
94 signer,
95 user_fee_increase,
96 sdk,
97 )?;
98
99 ensure_valid_state_transition_structure(&state_transition, sdk.version())?;
100 let st_result = state_transition
101 .broadcast_and_wait::<StateTransitionProofResult>(sdk, settings)
102 .await?;
103 match st_result {
104 StateTransitionProofResult::VerifiedAddressInfos(address_infos) => {
105 let expected_addresses =
106 self.keys().copied().collect::<BTreeSet<PlatformAddress>>();
107 collect_address_infos_from_proof(address_infos, &expected_addresses)
108 }
109 other => Err(Error::InvalidProvedResponse(format!(
110 "address info proof was expected for {:?}, but received {:?}",
111 state_transition, other
112 ))),
113 }
114 }
115}
116
117#[allow(clippy::too_many_arguments)]
118fn create_address_funding_from_asset_lock_transition<S: Signer<PlatformAddress>>(
119 asset_lock_proof: AssetLockProof,
120 asset_lock_private_key: &[u8],
121 inputs: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
122 outputs: BTreeMap<PlatformAddress, Option<Credits>>,
123 fee_strategy: AddressFundsFeeStrategy,
124 signer: &S,
125 user_fee_increase: UserFeeIncrease,
126 sdk: &Sdk,
127) -> Result<StateTransition, ProtocolError> {
128 AddressFundingFromAssetLockTransition::try_from_asset_lock_with_signer(
129 asset_lock_proof,
130 asset_lock_private_key,
131 inputs,
132 outputs,
133 fee_strategy,
134 signer,
135 user_fee_increase,
136 sdk.version(),
137 )
138}