Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7fdeaa1
refactor(platform-wallet): lift CL-retry + funding resolver to asset_…
shumkov May 19, 2026
b6e307d
feat(dpp): add try_from_asset_lock_with_signers for AddressFundingFro…
shumkov May 19, 2026
ea8e000
feat(rs-sdk): add TopUpAddress::top_up_with_signers signer-pair variant
shumkov May 19, 2026
043b01c
feat(platform-wallet): fund_addresses_with_funding orchestration
shumkov May 19, 2026
39f6d15
feat(platform-wallet-ffi): platform_address_wallet_fund_with_funding_…
shumkov May 19, 2026
2165bb5
feat(swift-sdk): fundFromCoreAssetLock + resumeFundFromAssetLock
shumkov May 19, 2026
c547c4d
feat(SwiftExampleApp): FundPlatformAddressView for Core→Platform funding
shumkov May 19, 2026
ff31d50
refactor(SwiftExampleApp): inline "+" affordance on Platform Balance row
shumkov May 19, 2026
9889023
fix(SwiftExampleApp): correct Core account filter + live balance in F…
shumkov May 19, 2026
9efcf6e
feat(SwiftExampleApp): live progress UI for platform-address funding
shumkov May 19, 2026
ff7b54f
feat(SwiftExampleApp): resume surface for stuck platform-address fund…
shumkov May 19, 2026
06c1930
feat(SwiftExampleApp): show recipient platform address on asset-lock …
shumkov May 19, 2026
0753138
fix(SwiftExampleApp): show ChainLock as its own step in funding progress
shumkov May 19, 2026
0a0ba19
review: SAFETY comments, mainnet HRP, dismissal paths (reviewer findi…
shumkov May 19, 2026
3fd355b
review: snapshot-delta back-fill + recipient type plumbing (reviewer …
shumkov May 19, 2026
0279557
review: error loudly on Platform proof contract violations (reviewer …
shumkov May 19, 2026
431c809
review: document latency budget, cancellation, retry scope (reviewer …
shumkov May 19, 2026
43efe2e
review: MEDIUM fixes — stale recipient, tracked status, dep hygiene
shumkov May 19, 2026
e27dcba
chore(dpp): drop noisy entry/exit debug logs from AddressFunding signers
shumkov May 19, 2026
d756e2e
chore(platform-wallet): drop IdentityFunding alias, rename callers to…
shumkov May 19, 2026
9cd055b
chore: drop history-reference comments
shumkov May 20, 2026
c7828f8
rename: top_up — drop legacy fund_from_asset_lock + "with_funding" su…
shumkov May 20, 2026
2c3fb5f
docs(PersistentAssetLock): codify per-funding-type destination conven…
shumkov May 20, 2026
08c4443
chore(WalletDetailView): trim restates-what-the-type-says comments
shumkov May 20, 2026
3ea2f3a
review: dedupe FFI recipients + filter zero-balance Core accounts
shumkov May 20, 2026
723942a
chore: cargo fmt + fix stale Swift type reference in doc comment
shumkov May 20, 2026
974142d
chore(rs-sdk): allow too_many_arguments on top_up_with_signers
shumkov May 20, 2026
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
1 change: 1 addition & 0 deletions Cargo.lock

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

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use platform_version::version::PlatformVersion;

impl AddressFundingFromAssetLockTransitionMethodsV0 for AddressFundingFromAssetLockTransition {
#[cfg(feature = "state-transition-signing")]
async fn try_from_asset_lock_with_signer<S: Signer<PlatformAddress>>(
async fn try_from_asset_lock_with_signer_and_private_key<S: Signer<PlatformAddress>>(
asset_lock_proof: AssetLockProof,
asset_lock_proof_private_key: &[u8],
inputs: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
Expand All @@ -43,7 +43,7 @@ impl AddressFundingFromAssetLockTransitionMethodsV0 for AddressFundingFromAssetL
.address_funding_from_asset_lock_transition
{
0 => Ok(
AddressFundingFromAssetLockTransitionV0::try_from_asset_lock_with_signer::<S>(
AddressFundingFromAssetLockTransitionV0::try_from_asset_lock_with_signer_and_private_key::<S>(
asset_lock_proof,
asset_lock_proof_private_key,
inputs,
Expand All @@ -56,7 +56,52 @@ impl AddressFundingFromAssetLockTransitionMethodsV0 for AddressFundingFromAssetL
.await?,
),
version => Err(ProtocolError::UnknownVersionMismatch {
method: "AddressFundingFromAssetLockTransition::try_from_asset_lock_with_signer"
method:
"AddressFundingFromAssetLockTransition::try_from_asset_lock_with_signer_and_private_key"
.to_string(),
known_versions: vec![0],
received: version,
}),
}
}

#[cfg(all(feature = "state-transition-signing", feature = "core_key_wallet"))]
async fn try_from_asset_lock_with_signers<S, AS>(
asset_lock_proof: AssetLockProof,
asset_lock_proof_path: &::key_wallet::bip32::DerivationPath,
inputs: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
outputs: BTreeMap<PlatformAddress, Option<Credits>>,
fee_strategy: AddressFundsFeeStrategy,
signer: &S,
asset_lock_signer: &AS,
user_fee_increase: UserFeeIncrease,
platform_version: &PlatformVersion,
) -> Result<StateTransition, ProtocolError>
where
S: Signer<PlatformAddress>,
AS: ::key_wallet::signer::Signer,
{
match platform_version
.dpp
.state_transition_conversion_versions
.address_funding_from_asset_lock_transition
{
0 => Ok(
AddressFundingFromAssetLockTransitionV0::try_from_asset_lock_with_signers::<S, AS>(
asset_lock_proof,
asset_lock_proof_path,
inputs,
outputs,
fee_strategy,
signer,
asset_lock_signer,
user_fee_increase,
platform_version,
)
.await?,
),
version => Err(ProtocolError::UnknownVersionMismatch {
method: "AddressFundingFromAssetLockTransition::try_from_asset_lock_with_signers"
.to_string(),
known_versions: vec![0],
received: version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,24 @@ use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, Protoco
use platform_version::version::PlatformVersion;

pub trait AddressFundingFromAssetLockTransitionMethodsV0 {
/// Build an `AddressFundingFromAssetLock` state transition where
/// the asset-lock-proof signature is produced from a raw private
/// key held in-process.
///
/// `signer` signs each input's `AddressWitness` (one per
/// `inputs.keys()`) over the transition's signable bytes; the
/// outer state-transition signature is produced from
/// `asset_lock_proof_private_key` via
/// [`dashcore::signer::sign`].
///
/// Prefer [`Self::try_from_asset_lock_with_signers`] when the
/// asset-lock key lives outside Rust (Swift / hardware wallet /
/// HSM): the `_with_signers` variant routes asset-lock signing
/// through an external [`key_wallet::signer::Signer`] so the
/// private key never crosses the FFI boundary as raw bytes.
#[cfg(feature = "state-transition-signing")]
#[allow(clippy::too_many_arguments)]
async fn try_from_asset_lock_with_signer<S: Signer<PlatformAddress>>(
async fn try_from_asset_lock_with_signer_and_private_key<S: Signer<PlatformAddress>>(
asset_lock_proof: AssetLockProof,
asset_lock_proof_private_key: &[u8],
inputs: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
Expand All @@ -29,6 +44,36 @@ pub trait AddressFundingFromAssetLockTransitionMethodsV0 {
platform_version: &PlatformVersion,
) -> Result<StateTransition, ProtocolError>;

/// Build an `AddressFundingFromAssetLock` state transition where
/// the asset-lock-proof signature is produced by an external
/// [`key_wallet::signer::Signer`].
///
/// `signer` (`S: Signer<PlatformAddress>`) signs each input's
/// `AddressWitness` (same as the legacy
/// `try_from_asset_lock_with_signer_and_private_key` path), while
/// `asset_lock_signer` (`AS: ::key_wallet::signer::Signer`)
/// produces the outer state-transition ECDSA signature for the
/// key at `asset_lock_proof_path` — atomically deriving, signing,
/// and zeroising inside the signer's trust boundary. This is the
/// signing path used by hosts that hold their private keys outside
/// Rust (the iOS Swift SDK, hardware wallets, remote signers).
#[cfg(all(feature = "state-transition-signing", feature = "core_key_wallet"))]
#[allow(clippy::too_many_arguments)]
async fn try_from_asset_lock_with_signers<S, AS>(
asset_lock_proof: AssetLockProof,
asset_lock_proof_path: &::key_wallet::bip32::DerivationPath,
inputs: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
outputs: BTreeMap<PlatformAddress, Option<Credits>>,
fee_strategy: AddressFundsFeeStrategy,
signer: &S,
asset_lock_signer: &AS,
user_fee_increase: UserFeeIncrease,
platform_version: &PlatformVersion,
) -> Result<StateTransition, ProtocolError>
where
S: Signer<PlatformAddress>,
AS: ::key_wallet::signer::Signer;

/// Get State Transition Type
fn get_type() -> StateTransitionType {
StateTransitionType::AddressFundingFromAssetLock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use platform_version::version::PlatformVersion;

impl AddressFundingFromAssetLockTransitionMethodsV0 for AddressFundingFromAssetLockTransitionV0 {
#[cfg(feature = "state-transition-signing")]
async fn try_from_asset_lock_with_signer<S: Signer<PlatformAddress>>(
async fn try_from_asset_lock_with_signer_and_private_key<S: Signer<PlatformAddress>>(
asset_lock_proof: AssetLockProof,
asset_lock_proof_private_key: &[u8],
inputs: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
Expand All @@ -32,13 +32,6 @@ impl AddressFundingFromAssetLockTransitionMethodsV0 for AddressFundingFromAssetL
user_fee_increase: UserFeeIncrease,
_platform_version: &PlatformVersion,
) -> Result<StateTransition, ProtocolError> {
tracing::debug!("try_from_asset_lock_with_signer: Started");
tracing::debug!(
input_count = inputs.len(),
output_count = outputs.len(),
"try_from_asset_lock_with_signer"
);

// Create the unsigned transition
let mut address_funding_transition = AddressFundingFromAssetLockTransitionV0 {
asset_lock_proof,
Expand All @@ -65,7 +58,63 @@ impl AddressFundingFromAssetLockTransitionMethodsV0 for AddressFundingFromAssetL
}
address_funding_transition.input_witnesses = input_witnesses;

tracing::debug!("try_from_asset_lock_with_signer: Successfully created transition");
Ok(address_funding_transition.into())
}

#[cfg(all(feature = "state-transition-signing", feature = "core_key_wallet"))]
async fn try_from_asset_lock_with_signers<S, AS>(
asset_lock_proof: AssetLockProof,
asset_lock_proof_path: &::key_wallet::bip32::DerivationPath,
inputs: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
outputs: BTreeMap<PlatformAddress, Option<Credits>>,
fee_strategy: AddressFundsFeeStrategy,
signer: &S,
asset_lock_signer: &AS,
user_fee_increase: UserFeeIncrease,
_platform_version: &PlatformVersion,
) -> Result<StateTransition, ProtocolError>
where
S: Signer<PlatformAddress>,
AS: ::key_wallet::signer::Signer,
{
// Build the unsigned inner transition. The outer wrapper
// signature and the per-input witnesses are both
// `#[platform_signable(exclude_from_sig_hash)]`, so they
// don't affect the signable bytes the per-input signer
// produces — we can compute signable bytes once with both
// empty.
let mut address_funding_transition = AddressFundingFromAssetLockTransitionV0 {
asset_lock_proof,
inputs: inputs.clone(),
outputs,
fee_strategy,
user_fee_increase,
signature: Default::default(),
input_witnesses: Vec::new(),
};

let state_transition: StateTransition = address_funding_transition.clone().into();
let signable_bytes = state_transition.signable_bytes()?;

// Sign per-input witnesses up front so the input_witnesses
// field is populated before we hand the inner over to the
// outer ST for the asset-lock signature.
let mut input_witnesses: Vec<AddressWitness> = Vec::with_capacity(inputs.len());
for address in inputs.keys() {
input_witnesses.push(signer.sign_create_witness(address, &signable_bytes).await?);
}
address_funding_transition.input_witnesses = input_witnesses;

// Build the outer ST and route the asset-lock-proof signature
// through the external `Signer`. The derive + sign + zeroise
// sequence happens inside the signer — the host never sees a
// raw private key, only a 32-byte digest goes in and a
// serialised signature comes out.
let mut state_transition: StateTransition = address_funding_transition.into();
state_transition
.sign_with_core_signer(asset_lock_proof_path, asset_lock_signer)
.await?;

Ok(state_transition)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ mod tests {
fee_strategy: Vec<AddressFundsFeeStrategyStep>,
user_fee_increase: u16,
) -> StateTransition {
AddressFundingFromAssetLockTransitionV0::try_from_asset_lock_with_signer(
AddressFundingFromAssetLockTransitionV0::try_from_asset_lock_with_signer_and_private_key(
asset_lock_proof,
asset_lock_private_key,
inputs,
Expand Down
2 changes: 1 addition & 1 deletion packages/rs-drive-abci/tests/strategy_tests/strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2609,7 +2609,7 @@ impl NetworkStrategy {

tracing::debug!(?outputs, "Preparing funding transition");
let funding_transition =
AddressFundingFromAssetLockTransitionV0::try_from_asset_lock_with_signer(
AddressFundingFromAssetLockTransitionV0::try_from_asset_lock_with_signer_and_private_key(
asset_lock_proof,
asset_lock_private_key.as_slice(),
BTreeMap::new(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use dashcore::hashes::Hash;
use dpp::identity::accessors::IdentityGettersV0;
use platform_wallet::wallet::identity::types::funding::IdentityFunding;
use platform_wallet::AssetLockFunding;
use rs_sdk_ffi::{SignerHandle, VTableSigner};

use crate::check_ptr;
Expand Down Expand Up @@ -105,7 +105,7 @@ pub unsafe extern "C" fn platform_wallet_register_identity_with_funding_signer(
};
identity_wallet
.register_identity_with_funding(
IdentityFunding::FromWalletBalance {
AssetLockFunding::FromWalletBalance {
amount_duffs,
account_index,
},
Expand Down Expand Up @@ -141,7 +141,7 @@ pub unsafe extern "C" fn platform_wallet_register_identity_with_funding_signer(
/// user now wants to consume the lock from the
/// "Fund from unused Asset Lock" picker in `CreateIdentityView`.
///
/// The Rust side dispatches via [`IdentityFunding::FromExistingAssetLock`]
/// The Rust side dispatches via [`AssetLockFunding::FromExistingAssetLock`]
/// inside the same `register_identity_with_funding` helper used by the
/// wallet-balance path — the resume logic and IS→CL fallback live
/// there, not here. This FFI is a thin marshaler.
Expand Down Expand Up @@ -220,7 +220,7 @@ pub unsafe extern "C" fn platform_wallet_resume_identity_with_existing_asset_loc
};
identity_wallet
.register_identity_with_funding(
IdentityFunding::FromExistingAssetLock {
AssetLockFunding::FromExistingAssetLock {
out_point: resume_outpoint,
},
identity_index,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ pub unsafe fn parse_outputs(
}

// ---------------------------------------------------------------------------
// Funding address entry (for fund_from_asset_lock)
// Funding address entry (for top_up)
// ---------------------------------------------------------------------------

/// Address entry for asset lock funding. Exactly one must have `has_balance = false`.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
//!
//! Mirrors the structure of `platform_wallet::wallet::platform_addresses`.

mod fund_from_asset_lock;
mod sync;
mod top_up;
mod transfer;
mod wallet;
mod withdrawal;

// Re-export all FFI types and functions.
pub use fund_from_asset_lock::*;
pub use sync::*;
pub use top_up::*;
pub use transfer::*;
pub use wallet::*;
pub use withdrawal::*;
Expand Down
Loading
Loading