diff --git a/packages/dapi-grpc/build.rs b/packages/dapi-grpc/build.rs
index f9886501552..749adc20d62 100644
--- a/packages/dapi-grpc/build.rs
+++ b/packages/dapi-grpc/build.rs
@@ -73,7 +73,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; 46] = [
+ const VERSIONED_REQUESTS: [&str; 48] = [
"GetDataContractHistoryRequest",
"GetDataContractRequest",
"GetDataContractsRequest",
@@ -120,6 +120,8 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
"GetFinalizedEpochInfosRequest",
"GetAddressInfoRequest",
"GetAddressesInfosRequest",
+ "GetRecentAddressBalanceChangesRequest",
+ "GetRecentCompactedAddressBalanceChangesRequest",
];
const PROOF_ONLY_VERSIONED_REQUESTS: [&str; 1] = ["GetAddressesTrunkStateRequest"];
@@ -134,7 +136,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
// - "GetIdentityByNonUniquePublicKeyHashResponse"
//
// "GetEvonodesProposedEpochBlocksResponse" is used for 2 Requests
- const VERSIONED_RESPONSES: [&str; 44] = [
+ const VERSIONED_RESPONSES: [&str; 46] = [
"GetDataContractHistoryResponse",
"GetDataContractResponse",
"GetDataContractsResponse",
@@ -179,6 +181,8 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
"GetFinalizedEpochInfosResponse",
"GetAddressInfoResponse",
"GetAddressesInfosResponse",
+ "GetRecentAddressBalanceChangesResponse",
+ "GetRecentCompactedAddressBalanceChangesResponse",
];
const PROOF_ONLY_VERSIONED_RESPONSES: [&str; 1] = ["GetAddressesTrunkStateResponse"];
diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto
index 2384d5b1559..c8bd7ac1ec2 100644
--- a/packages/dapi-grpc/protos/platform/v0/platform.proto
+++ b/packages/dapi-grpc/protos/platform/v0/platform.proto
@@ -112,6 +112,10 @@ service Platform {
returns (GetAddressesTrunkStateResponse);
rpc getAddressesBranchState(GetAddressesBranchStateRequest)
returns (GetAddressesBranchStateResponse);
+ rpc getRecentAddressBalanceChanges(GetRecentAddressBalanceChangesRequest)
+ returns (GetRecentAddressBalanceChangesResponse);
+ rpc getRecentCompactedAddressBalanceChanges(GetRecentCompactedAddressBalanceChangesRequest)
+ returns (GetRecentCompactedAddressBalanceChangesResponse);
}
// Proof message includes cryptographic proofs for validating responses
@@ -1972,6 +1976,23 @@ message AddressInfoEntries {
repeated AddressInfoEntry address_info_entries = 1;
}
+message AddressBalanceChange {
+ bytes address = 1;
+ oneof operation {
+ uint64 set_balance = 2 [ jstype = JS_STRING ];
+ uint64 add_to_balance = 3 [ jstype = JS_STRING ];
+ }
+}
+
+message BlockAddressBalanceChanges {
+ uint64 block_height = 1 [ jstype = JS_STRING ];
+ repeated AddressBalanceChange changes = 2;
+}
+
+message AddressBalanceUpdateEntries {
+ repeated BlockAddressBalanceChanges block_changes = 1;
+}
+
message GetAddressInfoResponse {
message GetAddressInfoResponseV0 {
oneof result {
@@ -2032,4 +2053,50 @@ message GetAddressesBranchStateResponse {
oneof version { GetAddressesBranchStateResponseV0 v0 = 1; }
}
+message GetRecentAddressBalanceChangesRequest {
+ message GetRecentAddressBalanceChangesRequestV0 {
+ uint64 start_height = 1 [ jstype = JS_STRING ];
+ bool prove = 2;
+ }
+ oneof version { GetRecentAddressBalanceChangesRequestV0 v0 = 1; }
+}
+
+message GetRecentAddressBalanceChangesResponse {
+ message GetRecentAddressBalanceChangesResponseV0 {
+ oneof result {
+ AddressBalanceUpdateEntries address_balance_update_entries = 1;
+ Proof proof = 2;
+ }
+ ResponseMetadata metadata = 3;
+ }
+ oneof version { GetRecentAddressBalanceChangesResponseV0 v0 = 1; }
+}
+
+message CompactedBlockAddressBalanceChanges {
+ uint64 start_block_height = 1 [ jstype = JS_STRING ];
+ uint64 end_block_height = 2 [ jstype = JS_STRING ];
+ repeated AddressBalanceChange changes = 3;
+}
+
+message CompactedAddressBalanceUpdateEntries {
+ repeated CompactedBlockAddressBalanceChanges compacted_block_changes = 1;
+}
+
+message GetRecentCompactedAddressBalanceChangesRequest {
+ message GetRecentCompactedAddressBalanceChangesRequestV0 {
+ uint64 start_block_height = 1 [ jstype = JS_STRING ];
+ bool prove = 2;
+ }
+ oneof version { GetRecentCompactedAddressBalanceChangesRequestV0 v0 = 1; }
+}
+message GetRecentCompactedAddressBalanceChangesResponse {
+ message GetRecentCompactedAddressBalanceChangesResponseV0 {
+ oneof result {
+ CompactedAddressBalanceUpdateEntries compacted_address_balance_update_entries = 1;
+ Proof proof = 2;
+ }
+ ResponseMetadata metadata = 3;
+ }
+ oneof version { GetRecentCompactedAddressBalanceChangesResponseV0 v0 = 1; }
+}
diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs
index 8398e89f9ac..f7ce2717b3d 100644
--- a/packages/rs-dapi-client/src/transport/grpc.rs
+++ b/packages/rs-dapi-client/src/transport/grpc.rs
@@ -659,3 +659,21 @@ impl_transport_request_grpc!(
RequestSettings::default(),
get_addresses_branch_state
);
+
+// rpc getRecentAddressBalanceChanges(GetRecentAddressBalanceChangesRequest) returns (GetRecentAddressBalanceChangesResponse);
+impl_transport_request_grpc!(
+ platform_proto::GetRecentAddressBalanceChangesRequest,
+ platform_proto::GetRecentAddressBalanceChangesResponse,
+ PlatformGrpcClient,
+ RequestSettings::default(),
+ get_recent_address_balance_changes
+);
+
+// rpc getRecentCompactedAddressBalanceChanges(GetRecentCompactedAddressBalanceChangesRequest) returns (GetRecentCompactedAddressBalanceChangesResponse);
+impl_transport_request_grpc!(
+ platform_proto::GetRecentCompactedAddressBalanceChangesRequest,
+ platform_proto::GetRecentCompactedAddressBalanceChangesResponse,
+ PlatformGrpcClient,
+ RequestSettings::default(),
+ get_recent_compacted_address_balance_changes
+);
diff --git a/packages/rs-dapi/src/services/platform_service/mod.rs b/packages/rs-dapi/src/services/platform_service/mod.rs
index f0de37a0665..5c3f6b8a535 100644
--- a/packages/rs-dapi/src/services/platform_service/mod.rs
+++ b/packages/rs-dapi/src/services/platform_service/mod.rs
@@ -543,4 +543,16 @@ impl Platform for PlatformServiceImpl {
dapi_grpc::platform::v0::GetAddressesBranchStateRequest,
dapi_grpc::platform::v0::GetAddressesBranchStateResponse
);
+
+ drive_method!(
+ get_recent_address_balance_changes,
+ dapi_grpc::platform::v0::GetRecentAddressBalanceChangesRequest,
+ dapi_grpc::platform::v0::GetRecentAddressBalanceChangesResponse
+ );
+
+ drive_method!(
+ get_recent_compacted_address_balance_changes,
+ dapi_grpc::platform::v0::GetRecentCompactedAddressBalanceChangesRequest,
+ dapi_grpc::platform::v0::GetRecentCompactedAddressBalanceChangesResponse
+ );
}
diff --git a/packages/rs-dpp/src/balances/credits.rs b/packages/rs-dpp/src/balances/credits.rs
index 64bfad3dd9f..7245423cdc7 100644
--- a/packages/rs-dpp/src/balances/credits.rs
+++ b/packages/rs-dpp/src/balances/credits.rs
@@ -39,6 +39,39 @@ pub const MAX_CREDITS: Credits = 9223372036854775807 as Credits; //i64 Max
pub const CREDITS_PER_DUFF: Credits = 1000;
+/// An enum for credit operations
+#[derive(Debug, Clone, Copy, PartialEq, Eq, bincode::Encode, bincode::Decode)]
+pub enum CreditOperation {
+ /// We are setting credit amounts
+ SetCredits(Credits),
+ /// We are adding to credits
+ AddToCredits(Credits),
+}
+
+impl CreditOperation {
+ /// Merges two credit operations, where `other` is applied after `self`.
+ ///
+ /// The merge logic:
+ /// - SetCredits + SetCredits = SetCredits (take the later value)
+ /// - SetCredits + AddToCredits = SetCredits (original set value + added amount)
+ /// - AddToCredits + SetCredits = SetCredits (take the later value)
+ /// - AddToCredits + AddToCredits = AddToCredits (sum of both)
+ pub fn merge(&self, other: &CreditOperation) -> CreditOperation {
+ match (self, other) {
+ // If other is SetCredits, it overrides (it's the most recent set)
+ (_, CreditOperation::SetCredits(value)) => CreditOperation::SetCredits(*value),
+ // If self is SetCredits and other adds, add to the set value
+ (CreditOperation::SetCredits(set_val), CreditOperation::AddToCredits(add_val)) => {
+ CreditOperation::SetCredits(set_val.saturating_add(*add_val))
+ }
+ // If both are AddToCredits, sum them
+ (CreditOperation::AddToCredits(val1), CreditOperation::AddToCredits(val2)) => {
+ CreditOperation::AddToCredits(val1.saturating_add(*val2))
+ }
+ }
+ }
+}
+
/// Trait for signed and unsigned credits
pub trait Creditable {
/// Convert unsigned credit to singed
diff --git a/packages/rs-drive-abci/src/abci/app/execution_result.rs b/packages/rs-drive-abci/src/abci/app/execution_result.rs
index 43d6e61a34d..19d2514dae1 100644
--- a/packages/rs-drive-abci/src/abci/app/execution_result.rs
+++ b/packages/rs-drive-abci/src/abci/app/execution_result.rs
@@ -15,20 +15,21 @@ impl TryIntoPlatformVersioned