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
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ where
///
/// * This function may return an `Error::Execution` if the identity balance is not found.
/// * This function may return an `Error::Drive` if there's an issue with applying drive operations.
pub(in crate::execution) fn validate_fees_of_event_v0(
pub(super) fn validate_fees_of_event_v0(
&self,
event: &ExecutionEvent,
block_info: &BlockInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ mod token_selling_tests {

use super::*;

use crate::error::Error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify if the import is needed.

The Error import was added but doesn't appear to be used in the visible code. Please verify if this import is actually needed or if it can be removed.


🏁 Script executed:

#!/bin/bash
# Search for usage of Error type in this file
rg -n "Error::" packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs

Length of output: 426


🏁 Script executed:

#!/bin/bash
# Search for any plain uses of `Error` (excluding `StateError`, `ConsensusError`, etc.)
rg -En '\bError\b' packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs

Length of output: 182


#!/bin/bash
# Search for standalone uses of `Error` in the test file to confirm if the import is used
rg -n -w Error packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs

Remove unused Error import

The use crate::error::Error; on line 10 of
packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs
is not referenced in this test module and can be dropped:

- use crate::error::Error;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
use crate::error::Error;
// (The `use crate::error::Error;` import has been removed as it was unused)
🤖 Prompt for AI Agents
In
packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs
at line 10, the import statement 'use crate::error::Error;' is not used anywhere
in the file. Remove this unused import to clean up the code and avoid
unnecessary dependencies.

use dpp::{
dashcore::secp256k1::hashes::hex::{Case, DisplayHex},
prelude::{DataContract, Identity, IdentityPublicKey},
tokens::token_pricing_schedule::TokenPricingSchedule,
};
use drive::verify::RootHash;
use simple_signer::signer::SimpleSigner;

#[test]
fn test_successful_direct_purchase_single_price() {
let platform_version = PlatformVersion::latest();
Expand Down Expand Up @@ -332,7 +334,7 @@ mod token_selling_tests {

assert_matches!(
processing_result.execution_results().as_slice(),
[StateTransitionExecutionResult::PaidConsensusError(
[PaidConsensusError(
ConsensusError::StateError(StateError::TokenDirectPurchaseUserPriceTooLow(_)),
_
)]
Expand Down Expand Up @@ -571,6 +573,165 @@ mod token_selling_tests {
}
}

#[test]
fn test_direct_purchase_from_yourself() {
let platform_version = PlatformVersion::latest();
let mut platform = TestPlatformBuilder::new()
.with_latest_protocol_version()
.build_with_mock_rpc()
.set_genesis_state();

let mut rng = StdRng::seed_from_u64(54321);
// Create an identity that will be both seller and buyer
let (self_trader, self_trader_signer, self_trader_key) =
setup_identity(&mut platform, rng.gen(), dash_to_credits!(10.0));

let single_price = TokenPricingSchedule::SinglePrice(dash_to_credits!(1));

let mut identity_contract_nonce: u64 = 2;
let (contract, token_id) = create_token_with_pricing(
platform_version,
&mut platform,
&self_trader,
&self_trader_signer,
&self_trader_key,
Some(single_price.clone()),
&mut identity_contract_nonce,
);

// Set the price
let set_price_transition =
BatchTransition::new_token_change_direct_purchase_price_transition(
token_id,
self_trader.id(),
contract.id(),
0,
Some(single_price.clone()),
None,
None,
&self_trader_key,
identity_contract_nonce,
0,
&self_trader_signer,
platform_version,
None,
)
.unwrap();

let platform_state = platform.state.load();
let processing_result = process_test_state_transition(
&mut platform,
set_price_transition,
&platform_state,
platform_version,
);

assert_matches!(
processing_result.execution_results().as_slice(),
[StateTransitionExecutionResult::SuccessfulExecution(..)]
);

// Check initial token balance (should have some tokens as the owner)
let initial_token_balance = platform
.drive
.fetch_identity_token_balance(
token_id.to_buffer(),
self_trader.id().to_buffer(),
None,
platform_version,
)
.expect("expected to fetch token balance");

// Now purchase tokens from yourself
let purchase_transition = BatchTransition::new_token_direct_purchase_transition(
token_id,
self_trader.id(), // Buyer is the same as seller
contract.id(),
0,
5, // Buying 5 tokens
dash_to_credits!(5), // Paying for 5 tokens
&self_trader_key,
identity_contract_nonce + 1,
0,
&self_trader_signer,
platform_version,
None,
)
.unwrap();

let initial_credit_balance = platform
.drive
.fetch_identity_balance(self_trader.id().to_buffer(), None, platform_version)
.expect("expected to fetch credit balance");

let transaction = platform.drive.grove.start_transaction();

let processing_result = platform
.platform
.process_raw_state_transitions(
&[purchase_transition
.serialize_to_bytes()
.expect("expected documents batch serialized state transition")],
&platform_state,
&BlockInfo::default(),
&transaction,
platform_version,
false,
None,
)
.expect("expected to process state transition");

platform
.validate_token_aggregated_balance(&transaction, platform_version)
.expect("expected to validate token aggregated balances");

platform
.drive
.grove
.commit_transaction(transaction)
.unwrap()
.expect("expected to commit transaction");

assert_matches!(
processing_result.execution_results().as_slice(),
[StateTransitionExecutionResult::SuccessfulExecution(..)]
);

// Check token balance after purchase
let final_token_balance = platform
.drive
.fetch_identity_token_balance(
token_id.to_buffer(),
self_trader.id().to_buffer(),
None,
platform_version,
)
.expect("expected to fetch token balance");

// Token balance should increase by 5
assert_eq!(
final_token_balance,
initial_token_balance.map(|b| b + 5).or(Some(5))
);

// Check credit balance - should only be reduced by fees, not by the purchase price
// (since the money goes back to yourself)
let final_credit_balance = platform
.drive
.fetch_identity_balance(self_trader.id().to_buffer(), None, platform_version)
.expect("expected to fetch credit balance");

// The difference should be just the transaction fees
let credit_diff = initial_credit_balance.unwrap() - final_credit_balance.unwrap();

// Assert that the difference is much less than the purchase price (just fees)
assert!(
credit_diff < dash_to_credits!(0.01),
"Credit difference should only be transaction fees, but was: {}",
credit_diff
);
}

// Helper functions
//
// /\_/\
Expand All @@ -596,7 +757,7 @@ mod token_selling_tests {

/// Creates a token contract with the given owner identity and configuration, and sets the price.
fn create_token_with_pricing(
platform_version: &dpp::version::PlatformVersion,
platform_version: &PlatformVersion,
platform: &mut TempPlatform<MockCoreRPCLike>,
seller: &Identity,
seller_signer: &SimpleSigner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,26 @@ impl DriveHighLevelBatchOperationConverter for TokenDirectPurchaseTransitionActi
allow_saturation: false,
}));

ops.push(IdentityOperation(
IdentityOperationType::RemoveFromIdentityBalance {
identity_id: owner_id.to_buffer(),
balance_to_remove: self.total_agreed_price(),
},
));
ops.push(IdentityOperation(
IdentityOperationType::AddToIdentityBalance {
identity_id: self
.base()
.data_contract_fetch_info()
.contract
.owner_id()
.to_buffer(),
added_balance: self.total_agreed_price(),
},
));
if owner_id != self.base().data_contract_fetch_info().contract.owner_id() {
// We can not send to ourselves
ops.push(IdentityOperation(
IdentityOperationType::RemoveFromIdentityBalance {
identity_id: owner_id.to_buffer(),
balance_to_remove: self.total_agreed_price(),
},
));
ops.push(IdentityOperation(
IdentityOperationType::AddToIdentityBalance {
identity_id: self
.base()
.data_contract_fetch_info()
.contract
.owner_id()
.to_buffer(),
added_balance: self.total_agreed_price(),
},
));
}

let token_configuration = self.base().token_configuration()?;
if token_configuration
Expand Down
Loading