Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
24 changes: 12 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ members = [
]

[workspace.dependencies]
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "dca5b05b83a9a2d6fd7b650e7cce4356d1c2ec29" }
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }
dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }
dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }
key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }
key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }
dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }
dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "944e53a503a88daa0d7706d7d7c5f5350213d295" }

tokio-metrics = "0.5"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ class CoreTransactionBuilder internal constructor(network: Network) : AutoClosea
BIP44(0),
BIP32(1),
COIN_JOIN(2),

/**
* Pool every spendable transparent source: BIP44 + BIP32 + all DashPay
* contact-receiving accounts. Change returns to BIP44 (the first
* pooled source). CoinJoin stays out (separate privacy domain), as do
* a contact's watch-only external coins. The default for a plain send.
*/
ALL_SPENDABLE(3),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,19 @@ class ManagedPlatformWallet internal constructor(
)
}

/** Standard account derivation shape for [sendToAddresses]. */
/** Funding-source selector for [sendToAddresses] / [buildSignedPayment]. */
enum class AccountType(val ffiValue: Int) {
BIP44(0),
BIP32(1),

/**
* Pool every spendable transparent source — BIP44 + BIP32 + all
* DashPay contact-receiving accounts — with change returning to
* BIP44. CoinJoin is excluded (separate privacy domain), as are a
* contact's watch-only coins. The default for plain sends, so funds
* a contact paid us are spendable without picking an account.
*/
ALL_SPENDABLE(3),
}

/**
Expand Down Expand Up @@ -142,7 +151,7 @@ class ManagedPlatformWallet internal constructor(
recipients: List<Pair<String, Long>>,
network: org.dashfoundation.dashsdk.Network,
coreSignerHandle: Long,
accountType: AccountType = AccountType.BIP44,
accountType: AccountType = AccountType.ALL_SPENDABLE,
accountIndex: Int = 0,
): String = gate.op {
require(accountIndex >= 0) { "accountIndex must be non-negative, got $accountIndex" }
Expand All @@ -153,6 +162,7 @@ class ManagedPlatformWallet internal constructor(
val builderAccountType = when (accountType) {
AccountType.BIP44 -> CoreTransactionBuilder.AccountType.BIP44
AccountType.BIP32 -> CoreTransactionBuilder.AccountType.BIP32
AccountType.ALL_SPENDABLE -> CoreTransactionBuilder.AccountType.ALL_SPENDABLE
}
mapNativeErrors {
val builder = CoreTransactionBuilder(network)
Expand Down Expand Up @@ -341,7 +351,7 @@ class ManagedPlatformWallet internal constructor(
recipients: List<Pair<String, Long>>,
network: org.dashfoundation.dashsdk.Network,
coreSignerHandle: Long,
accountType: AccountType = AccountType.BIP44,
accountType: AccountType = AccountType.ALL_SPENDABLE,
accountIndex: Int = 0,
opReturnData: ByteArray? = null,
preserveOutputOrder: Boolean = false,
Expand All @@ -365,6 +375,7 @@ class ManagedPlatformWallet internal constructor(
val builderAccountType = when (accountType) {
AccountType.BIP44 -> CoreTransactionBuilder.AccountType.BIP44
AccountType.BIP32 -> CoreTransactionBuilder.AccountType.BIP32
AccountType.ALL_SPENDABLE -> CoreTransactionBuilder.AccountType.ALL_SPENDABLE
}
mapNativeErrors {
// One atomic native operation: select + reserve + sign + register.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::error::*;
use crate::handle::*;
use crate::runtime::runtime;
use crate::{check_ptr, unwrap_option_or_return, unwrap_result_or_return};
use key_wallet::wallet::managed_wallet_info::transaction_building::AccountTypePreference;
use std::ffi::CString;
use std::os::raw::c_char;

Expand Down Expand Up @@ -65,7 +64,12 @@ pub unsafe extern "C" fn core_wallet_set_gap_limit(
account_index: u32,
gap_limit: u32,
) -> PlatformWalletFFIResult {
let source: AccountTypePreference = account_type.into();
let Some(source) = account_type.single_preference() else {
return PlatformWalletFFIResult::err(
PlatformWalletFFIResultCode::ErrorInvalidParameter,
"AllSpendable pools multiple accounts; set gap limits per account".to_string(),
);
};

let option = CORE_WALLET_STORAGE.with_item(handle, |wallet| {
runtime().block_on(wallet.set_gap_limit(source, account_index, gap_limit))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ mod tests {
&Address::dummy(Network::Testnet, usize::from(tag)),
1_000_000,
),
AccountTypePreference::BIP44,
&[AccountTypePreference::BIP44],
0,
signer,
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,37 @@ pub enum CoreAccountTypeFFI {
BIP44,
BIP32,
CoinJoin,
/// Pool every spendable transparent source: BIP44 + BIP32 + all DashPay
/// contact-receiving accounts (`platform_wallet::SEND_FUNDING_SOURCES`).
/// Change returns to BIP44 (the first pooled source). CoinJoin stays out
/// (separate privacy domain), as do a contact's watch-only external
/// coins. The default selector for a plain send.
AllSpendable,
}

impl From<CoreAccountTypeFFI> for AccountTypePreference {
fn from(value: CoreAccountTypeFFI) -> Self {
match value {
CoreAccountTypeFFI::BIP44 => AccountTypePreference::BIP44,
CoreAccountTypeFFI::BIP32 => AccountTypePreference::BIP32,
CoreAccountTypeFFI::CoinJoin => AccountTypePreference::CoinJoin,
impl CoreAccountTypeFFI {
/// The funding sources this selector pools, in funding order — handed to
/// [`CoreWallet::finalize_transaction`]'s multi-source API. Single-family
/// selectors keep their strict one-account semantics.
/// The single account family this selector names, or `None` for the
/// pooled [`AllSpendable`](Self::AllSpendable) — used by APIs that address
/// exactly one account (gap limits, per-account UTXO listing), which must
/// reject the pooled selector with a typed parameter error.
pub(crate) fn single_preference(self) -> Option<AccountTypePreference> {
match self {
CoreAccountTypeFFI::BIP44 => Some(AccountTypePreference::BIP44),
CoreAccountTypeFFI::BIP32 => Some(AccountTypePreference::BIP32),
CoreAccountTypeFFI::CoinJoin => Some(AccountTypePreference::CoinJoin),
CoreAccountTypeFFI::AllSpendable => None,
}
}

pub(crate) fn funding_sources(self) -> &'static [AccountTypePreference] {
match self {
CoreAccountTypeFFI::BIP44 => &[AccountTypePreference::BIP44],
CoreAccountTypeFFI::BIP32 => &[AccountTypePreference::BIP32],
CoreAccountTypeFFI::CoinJoin => &[AccountTypePreference::CoinJoin],
CoreAccountTypeFFI::AllSpendable => &platform_wallet::SEND_FUNDING_SOURCES,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
}
Expand Down Expand Up @@ -120,7 +143,7 @@ pub unsafe extern "C" fn core_wallet_tx_builder_finalize(
MnemonicResolverCoreSigner::new(core_signer_handle, wallet.wallet_id(), wallet.network());
let finalized = runtime().block_on(wallet.core().finalize_transaction(
inner,
account_type.into(),
account_type.funding_sources(),
account_index,
&signer,
));
Expand Down Expand Up @@ -255,7 +278,7 @@ pub unsafe extern "C" fn core_wallet_signed_payment_finalize(
// Atomic select + reserve + sign in one wallet-manager critical section.
let finalized = runtime().block_on(wallet.core().finalize_transaction(
inner,
account_type.into(),
account_type.funding_sources(),
account_index,
&signer,
));
Expand Down Expand Up @@ -391,11 +414,9 @@ fn managed_account(
source: AccountTypePreference,
account_index: u32,
) -> Option<&ManagedCoreFundsAccount> {
match source {
AccountTypePreference::BIP44 => accounts.standard_bip44_accounts.get(&account_index),
AccountTypePreference::BIP32 => accounts.standard_bip32_accounts.get(&account_index),
AccountTypePreference::CoinJoin => accounts.coinjoin_accounts.get(&account_index),
}
source
.account_type(account_index)
.and_then(|at| accounts.funds_account(&at))
}

impl FFITransactionBuilder {
Expand Down Expand Up @@ -710,7 +731,12 @@ pub unsafe extern "C" fn core_wallet_tx_builder_add_inputs_from_outpoints(
}

let wallet_id = wallet.wallet_id();
let source: AccountTypePreference = account_type.into();
let Some(source) = account_type.single_preference() else {
return PlatformWalletFFIResult::err(
PlatformWalletFFIResultCode::ErrorInvalidParameter,
"AllSpendable pools multiple accounts; this API addresses exactly one".to_string(),
);
};

let requested: Vec<OutPoint> = if outpoints_len == 0 {
Vec::new()
Expand Down
10 changes: 6 additions & 4 deletions packages/rs-platform-wallet-ffi/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -940,8 +940,9 @@ mod remove_wallet_lifecycle_tests {
SignedCoreTransaction::new_for_test(
dummy_tx(),
0,
AccountTypePreference::BIP44,
0,
vec![AccountTypePreference::BIP44
.account_type(0)
.expect("single account")],
0,
None,
core.test_generation_marker(),
Expand Down Expand Up @@ -1195,8 +1196,9 @@ mod remove_wallet_lifecycle_tests {
transaction: SignedCoreTransaction::new_for_test(
dummy_tx(),
0,
AccountTypePreference::BIP44,
0,
vec![AccountTypePreference::BIP44
.account_type(0)
.expect("single account")],
0,
None,
core.test_generation_marker(),
Expand Down
5 changes: 3 additions & 2 deletions packages/rs-platform-wallet-ffi/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,9 @@ mod destroy_tests {
SignedCoreTransaction::new_for_test(
dummy_tx(),
0,
AccountTypePreference::BIP44,
0,
vec![AccountTypePreference::BIP44
.account_type(0)
.expect("single account")],
0,
None,
// Bind the finalized payment to this exact wallet
Expand Down
2 changes: 1 addition & 1 deletion packages/rs-platform-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub use wallet::asset_lock::manager::AssetLockManager;
pub use wallet::asset_lock::tracked::{AssetLockStatus, TrackedAssetLock};
pub use wallet::asset_lock::AssetLockFunding;
pub use wallet::core::WalletBalance;
pub use wallet::core::{CoreWallet, SignedCoreTransaction};
pub use wallet::core::{CoreWallet, SignedCoreTransaction, SEND_FUNDING_SOURCES};
pub use wallet::signed_payment_registry::{
RegisterWrongGeneration, ReservationToken, SignedPaymentError, SignedPaymentRegistry,
};
Expand Down
Loading
Loading