Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,5 @@ book/book/

# gRPC coverage report
grpc-coverage-report.txt

__pycache__/
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ yarn configure:tests:network

**DPP** (`packages/rs-dpp`, `packages/wasm-dpp`): Dash Platform Protocol implementation that defines data structures and validation rules.

**SDK** (`packages/js-dash-sdk`, `packages/rs-sdk`): Client libraries providing high-level interfaces for building applications on Dash Platform.
**SDK** (`packages/js-dash-sdk`, `packages/rs-sdk`): Client libraries providing high-level interfaces for building applications on Dash Platform. See [packages/rs-sdk/README.md](packages/rs-sdk/README.md) for the Rust SDK checklist for implementing new `Fetch`/`FetchMany` queries.

**WASM SDK** (`packages/wasm-sdk`): WebAssembly bindings for browser-based applications. See [AI_REFERENCE.md](packages/wasm-sdk/AI_REFERENCE.md) for comprehensive API documentation.

Expand Down
6 changes: 4 additions & 2 deletions packages/dapi-grpc/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
// Derive features for versioned messages
//
// "GetConsensusParamsRequest" is excluded as this message does not support proofs
const VERSIONED_REQUESTS: [&str; 55] = [
const VERSIONED_REQUESTS: [&str; 56] = [
"GetDataContractHistoryRequest",
"GetDataContractRequest",
"GetDataContractsRequest",
Expand Down Expand Up @@ -123,6 +123,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
"GetTokenDirectPurchasePricesRequest",
"GetTokenContractInfoRequest",
"GetTokenStatusesRequest",
"GetTokenPreProgrammedDistributionsRequest",
"GetTokenTotalSupplyRequest",
"GetGroupInfoRequest",
"GetGroupInfosRequest",
Expand Down Expand Up @@ -160,7 +161,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
// - "GetIdentityByNonUniquePublicKeyHashResponse"
//
// "GetEvonodesProposedEpochBlocksResponse" is used for 2 Requests
const VERSIONED_RESPONSES: [&str; 53] = [
const VERSIONED_RESPONSES: [&str; 54] = [
"GetDataContractHistoryResponse",
"GetDataContractResponse",
"GetDataContractsResponse",
Expand Down Expand Up @@ -197,6 +198,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
"GetTokenDirectPurchasePricesResponse",
"GetTokenContractInfoResponse",
"GetTokenStatusesResponse",
"GetTokenPreProgrammedDistributionsResponse",
"GetTokenTotalSupplyResponse",
"GetGroupInfoResponse",
"GetGroupInfosResponse",
Expand Down
9 changes: 9 additions & 0 deletions packages/rs-dapi-client/src/transport/grpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,15 @@ impl_transport_request_grpc!(
get_token_statuses
);

// rpc getTokenPreProgrammedDistributions(GetTokenPreProgrammedDistributionsRequest) returns (GetTokenPreProgrammedDistributionsResponse);
impl_transport_request_grpc!(
platform_proto::GetTokenPreProgrammedDistributionsRequest,
platform_proto::GetTokenPreProgrammedDistributionsResponse,
PlatformGrpcClient,
RequestSettings::default(),
get_token_pre_programmed_distributions
);

// rpc getTokenTotalSupply(GetTokenTotalSupplyRequest) returns (GetTokenTotalSupplyResponse);
impl_transport_request_grpc!(
platform_proto::GetTokenTotalSupplyRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ use dpp::data_contract::associated_token::token_configuration_convention::v0::To
use dpp::data_contract::associated_token::token_configuration_localization::v0::TokenConfigurationLocalizationV0;
use dpp::data_contract::associated_token::token_configuration_localization::TokenConfigurationLocalization;
use dpp::data_contract::associated_token::token_distribution_rules::v0::TokenDistributionRulesV0;
use dpp::data_contract::associated_token::token_distribution_rules::TokenDistributionRules;
use dpp::data_contract::associated_token::token_keeps_history_rules::v0::TokenKeepsHistoryRulesV0;
use dpp::data_contract::associated_token::token_marketplace_rules::v0::TokenMarketplaceRulesV0;
use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::DistributionFunction;
use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_recipient::TokenDistributionRecipient;
use dpp::data_contract::associated_token::token_perpetual_distribution::reward_distribution_type::RewardDistributionType;
use dpp::data_contract::associated_token::token_perpetual_distribution::v0::TokenPerpetualDistributionV0;
use dpp::data_contract::associated_token::token_perpetual_distribution::TokenPerpetualDistribution;
use dpp::data_contract::associated_token::token_pre_programmed_distribution::v0::TokenPreProgrammedDistributionV0;
use dpp::data_contract::associated_token::token_pre_programmed_distribution::TokenPreProgrammedDistribution;
use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers;
use dpp::data_contract::change_control_rules::v0::ChangeControlRulesV0;
use dpp::data_contract::config::DataContractConfig;
Expand All @@ -39,6 +42,7 @@ use dpp::version::PlatformVersion;
use drive::grovedb::TransactionArg;
use rand::rngs::StdRng;
use rand::SeedableRng;
use std::collections::BTreeMap;
use std::sync::LazyLock;

const IDENTITY_ID_1: Identifier = Identifier::new([1; 32]);
Expand Down Expand Up @@ -380,10 +384,31 @@ impl<C> Platform<C> {
}),
);

let mut token_configuration_2 = token_configuration.clone();
if let TokenConfiguration::V0(ref mut cfg) = token_configuration_2 {
if let TokenDistributionRules::V0(ref mut rules) = cfg.distribution_rules {
rules.pre_programmed_distribution = Some(TokenPreProgrammedDistribution::V0(
TokenPreProgrammedDistributionV0 {
distributions: BTreeMap::from([
(
1000,
BTreeMap::from([(IDENTITY_ID_1, 500), (IDENTITY_ID_2, 300)]),
),
(5000, BTreeMap::from([(IDENTITY_ID_1, 1000)])),
(
10000,
BTreeMap::from([(IDENTITY_ID_2, 750), (IDENTITY_ID_3, 250)]),
),
]),
},
));
}
}

let tokens = [
(0, token_configuration.clone()),
(1, token_configuration.clone()),
(2, token_configuration),
(1, token_configuration),
(2, token_configuration_2),
]
.into();

Expand Down
1 change: 1 addition & 0 deletions packages/rs-drive-proof-verifier/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod token_contract_info;
pub mod token_direct_purchase;
pub mod token_info;
pub mod token_perpetual_distribution_last_claim;
pub mod token_pre_programmed_distributions;
pub mod token_status;
pub mod token_total_supply;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::error::MapGroveDbError;
use crate::verify::verify_tenderdash_proof;
use crate::{types::TokenPreProgrammedDistributions, ContextProvider, Error};
use dapi_grpc::platform::v0::{
get_token_pre_programmed_distributions_request, GetTokenPreProgrammedDistributionsRequest,
GetTokenPreProgrammedDistributionsResponse, Proof, ResponseMetadata,
};
use dapi_grpc::platform::VersionedGrpcResponse;
use dpp::dashcore::Network;
use dpp::prelude::Identifier;
use dpp::version::PlatformVersion;
use drive::drive::tokens::distribution::queries::QueryPreProgrammedDistributionStartAt;
use drive::drive::Drive;

use super::FromProof;

impl FromProof<GetTokenPreProgrammedDistributionsRequest> for TokenPreProgrammedDistributions {
type Request = GetTokenPreProgrammedDistributionsRequest;
type Response = GetTokenPreProgrammedDistributionsResponse;

fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
request: I,
response: O,
_network: Network,
platform_version: &PlatformVersion,
provider: &'a dyn ContextProvider,
) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
where
Self: Sized + 'a,
{
let request: Self::Request = request.into();
let response: Self::Response = response.into();

let get_token_pre_programmed_distributions_request::Version::V0(req_v0) =
request.version.ok_or(Error::EmptyVersion)?;

let token_id: [u8; 32] =
req_v0
.token_id
.as_slice()
.try_into()
.map_err(|_| Error::RequestError {
error: "token_id must be 32 bytes".into(),
})?;

let start_at = match req_v0.start_at_info {
Some(start_at_info) => {
let start_at_recipient = match start_at_info.start_recipient {
Some(recipient_bytes) => {
let recipient_id =
Identifier::from_bytes(&recipient_bytes).map_err(|_| {
Error::RequestError {
error: "start_recipient must be 32 bytes".into(),
}
})?;
let included = start_at_info.start_recipient_included.unwrap_or(true);
Some((recipient_id, included))
}
None => None,
};

Some(QueryPreProgrammedDistributionStartAt {
start_at_time: start_at_info.start_time_ms,
start_at_recipient,
})
}
None => None,
};

let limit = req_v0
.limit
.map(|l| {
u16::try_from(l).map_err(|_| Error::RequestError {
error: "limit exceeds u16::MAX".into(),
})
})
.transpose()?;

let metadata = response
.metadata()
.or(Err(Error::EmptyResponseMetadata))?
.clone();

let proof = response.proof_owned().or(Err(Error::NoProofInResult))?;

let (root_hash, result): ([u8; 32], TokenPreProgrammedDistributions) =
Drive::verify_token_pre_programmed_distributions(
&proof.grovedb_proof,
token_id,
start_at,
limit,
false,
platform_version,
)
.map_drive_error(&proof, &metadata)?;

verify_tenderdash_proof(&proof, &metadata, &root_hash, provider)?;

if result.0.is_empty() {
Ok((None, metadata, proof))
} else {
Ok((Some(result), metadata, proof))
}
}
}
31 changes: 31 additions & 0 deletions packages/rs-drive-proof-verifier/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,37 @@ pub struct ProposerBlockCountById(pub u64);
/// Prices for direct purchase of tokens. Retrieved by [TokenPricingSchedule::fetch_many()].
pub type TokenDirectPurchasePrices = RetrievedObjects<Identifier, TokenPricingSchedule>;

/// Pre-programmed token distributions grouped by timestamp.
///
/// Each entry maps a timestamp (in milliseconds) to a collection of
/// `(Identifier, Credits)` pairs representing the recipients and their token amounts in credits.
#[derive(Debug, Clone, Default, derive_more::From)]
#[cfg_attr(
feature = "mocks",
derive(Encode, Decode, PlatformSerialize, PlatformDeserialize),
platform_serialize(unversioned)
)]
pub struct TokenPreProgrammedDistributions(
pub BTreeMap<TimestampMillis, BTreeMap<Identifier, Credits>>,
);

impl TokenPreProgrammedDistributions {
/// Get the inner map.
pub fn into_inner(self) -> BTreeMap<TimestampMillis, BTreeMap<Identifier, Credits>> {
self.0
}
}

impl FromIterator<(TimestampMillis, BTreeMap<Identifier, Credits>)>
for TokenPreProgrammedDistributions
{
fn from_iter<T: IntoIterator<Item = (TimestampMillis, BTreeMap<Identifier, Credits>)>>(
iter: T,
) -> Self {
Self(iter.into_iter().collect())
}
}

/// Address balance changes for a single block.
#[derive(Debug, Clone)]
#[cfg_attr(
Expand Down
5 changes: 0 additions & 5 deletions packages/rs-drive-proof-verifier/src/types/evonode_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ pub struct EvoNodeStatus {
derive(Encode, Decode, PlatformSerialize, PlatformDeserialize),
platform_serialize(unversioned)
)]

/// Information about protocol and software components versions.
pub struct Version {
/// Information about software components versions.
Expand Down Expand Up @@ -96,7 +95,6 @@ pub struct TenderdashProtocol {
derive(Encode, Decode, PlatformSerialize, PlatformDeserialize),
platform_serialize(unversioned)
)]

/// Drive protocol versions.
pub struct DriveProtocol {
/// Latest version supported by the node.
Expand All @@ -112,7 +110,6 @@ pub struct DriveProtocol {
derive(Encode, Decode, PlatformSerialize, PlatformDeserialize),
platform_serialize(unversioned)
)]

/// Information about current time used by the node.
pub struct Time {
/// Local time of the node. Unix timestamp since epoch.
Expand All @@ -131,7 +128,6 @@ pub struct Time {
derive(Encode, Decode, PlatformSerialize, PlatformDeserialize),
platform_serialize(unversioned)
)]

/// Evo node identification information.
pub struct Node {
/// Node ID
Expand All @@ -145,7 +141,6 @@ pub struct Node {
derive(Encode, Decode, PlatformSerialize, PlatformDeserialize),
platform_serialize(unversioned)
)]

/// Layer 2 blockchain information
pub struct Chain {
/// Whether the node is catching up with the network.
Expand Down
2 changes: 1 addition & 1 deletion packages/rs-sdk-ffi/src/token/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ pub use identity_balances::dash_sdk_identity_fetch_token_balances;
pub use identity_token_infos::dash_sdk_identity_fetch_token_infos;
pub use info::dash_sdk_token_get_identity_infos;
pub use perpetual_distribution_last_claim::dash_sdk_token_get_perpetual_distribution_last_claim;
// pub use pre_programmed_distributions::dash_sdk_token_get_pre_programmed_distributions; // TODO: Not yet implemented
pub use pre_programmed_distributions::dash_sdk_token_get_pre_programmed_distributions;
pub use status::dash_sdk_token_get_statuses;
pub use total_supply::dash_sdk_token_get_total_supply;
Loading
Loading