Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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,106 @@
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(),
}
})?;
// Default to inclusive: if omitted the start recipient is included.
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