@@ -185,11 +185,11 @@ extension DerivationPathKeysModel {
185185/// Derives masternode provider Owner/Voting keys (ECDSA) from SwiftDashSDK,
186186/// replacing DashSync's `DSAuthenticationKeysDerivationPath`.
187187///
188- /// The DIP-3 paths — voting `m/9'/<coin>'/3'/1'`, owner `m/9'/<coin>'/3'/2'`
189- /// (ECDSA, fully hardened account path, soft key index; coin = 5' mainnet /
190- /// 1' testnet) — are resolved Rust-side by `providerKeyAtIndex`. They are NOT
191- /// rebuilt here: composing them app-side is what let the account path be
192- /// applied twice and produced keys off the intended branch.
188+ /// The DIP-3 voting and owner account paths (ECDSA, fully hardened account
189+ /// path, soft key index) are resolved Rust-side: `providerKeyAtIndex` derives
190+ /// every private key, and the addresses come from the running wallet's pool.
191+ /// Composing the account path app-side is what let it be applied twice and
192+ /// produced keys off the intended branch.
193193///
194194/// Internal (not private): `MasternodeKeyUsage` reuses `address(at:)` for
195195/// its owner/voting address join.
@@ -206,32 +206,17 @@ final class MasternodeProviderKeyDeriver {
206206 /// resolver the operator/platform families use — not a second copy of it.
207207 private let keyResolver : ProviderKeyResolver
208208
209- /// Index → base58 address of the provider pool, snapshotted once at init.
210- /// Sourced from the running wallet (`loadLiveAddresses`), falling back to
211- /// the derivation wallet's own pool (`loadDerivationAddresses`) when the
212- /// running wallet has no provider account yet — e.g. a just-imported
213- /// wallet whose registration hasn't completed. Empty only when neither
214- /// source has a pool, in which case there are genuinely no addresses to
215- /// join against.
209+ /// Index → base58 address of the running wallet's provider pool,
210+ /// snapshotted once at init. Empty when the wallet has no provider account
211+ /// yet, such as a just-imported wallet whose registration hasn't completed.
216212 private let poolAddresses : [ UInt32 : String ]
217213
218214 init ? ( key : MNKey ) {
219- // The network itself is no longer read here — it selected the coin
220- // type when this class composed the DIP-3 path app-side. The resolver
221- // owns that now; the check remains because a host with no running
222- // network has no wallet to derive from either.
223- guard SwiftDashSDKHost . shared . runningNetwork != nil else {
224- return nil
225- }
226-
227- let type : AccountType
228215 let kind : ManagedPlatformWallet . ProviderKeyKind
229216 switch key {
230217 case . voting :
231- type = . providerVotingKeys
232218 kind = . votingECDSA
233219 case . owner :
234- type = . providerOwnerKeys
235220 kind = . ownerECDSA
236221 case . operator , . evonodeOperator :
237222 // BLS / Ed25519 families have no address rows, so they use
@@ -243,41 +228,18 @@ final class MasternodeProviderKeyDeriver {
243228 return nil
244229 }
245230
246- // The derivation stack is a THROWAWAY key-wallet built from the
247- // mnemonic (see `SwiftDashSDKHost.derivationWallet`) — it has never
248- // processed a transaction, so its pools sit at the freshly-created
249- // `DEFAULT_SPECIAL_GAP_LIMIT` depth. It backs ONLY the fallback
250- // address pool below; private keys come from `keyResolver`. Nothing
251- // outlives this initializer: the wallet is owned by `derivationManager`,
252- // which is released on return, so holding either past the pool read
253- // would leave a reference into a freed graph.
254- guard let ( derivationManager , wallet , derivationWalletId ) =
255- SwiftDashSDKHost . shared . derivationWallet ( ) else {
256- return nil
257- }
258-
259- // Ensure the provider account exists so the fallback pool read below
260- // can resolve it.
261- _ = try? wallet . getAccount ( type : type )
262-
231+ self . poolAddresses = Self . loadLiveAddresses ( for : key )
263232 self . keyResolver = keyResolver
264-
265- let live = Self . loadLiveAddresses ( for : key )
266- self . poolIsLive = ! live . isEmpty
267- self . poolAddresses = live . isEmpty
268- ? Self . loadDerivationAddresses (
269- key : key , manager : derivationManager , walletId : derivationWalletId )
270- : live
233+ self . poolIsLive = ! poolAddresses . isEmpty
271234 }
272235
273- /// `true` when ``poolAddresses`` came from the running wallet's live pool.
236+ /// `true` when the running wallet had a provider pool to read .
274237 ///
275- /// `false` means the degraded derivation-wallet fallback, which only ever
276- /// holds `DEFAULT_SPECIAL_GAP_LIMIT` entries. Consumers that merely *look
277- /// up* an index are unaffected, but consumers that **enumerate** the pool
278- /// to decide what exists — the owner/voting address joins — can silently
279- /// under-report, so they must surface the incompleteness rather than
280- /// present a short list as the whole truth.
238+ /// `false` means ``poolAddresses`` is empty. Consumers that merely *look
239+ /// up* an index find nothing, and consumers that **enumerate** the pool
240+ /// to decide what exists — the owner/voting address joins — must surface
241+ /// that the answer may be incomplete rather than present an empty list as
242+ /// the whole truth.
281243 let poolIsLive : Bool
282244
283245 /// Snapshot the running wallet's provider address pool — the one SPV
@@ -306,47 +268,6 @@ final class MasternodeProviderKeyDeriver {
306268 return addresses
307269 }
308270
309- /// Degraded-path pool read from the derivation wallet itself, used when
310- /// the running wallet can't vend the account. This stack never processes
311- /// transactions, so its pool is only ever the freshly-created
312- /// `DEFAULT_SPECIAL_GAP_LIMIT` depth — enough to keep the low indexes
313- /// resolvable rather than showing nothing at all, but it is NOT a
314- /// substitute for the live pool (that shallowness is precisely the bug
315- /// this class's live read exists to fix).
316- private static func loadDerivationAddresses (
317- key : MNKey ,
318- manager : WalletManager ,
319- walletId : Data
320- ) -> [ UInt32 : String ] {
321- guard let collection = manager . getManagedAccountCollection ( walletId : walletId ) else {
322- return [ : ]
323- }
324- let account : ManagedAccount ?
325- switch key {
326- case . voting : account = collection . getProviderVotingKeysAccount ( )
327- case . owner : account = collection . getProviderOwnerKeysAccount ( )
328- case . operator , . evonodeOperator : account = nil
329- }
330- guard let pool = account ? . getAddressPool ( type : . single )
331- ?? account ? . getExternalAddressPool ( ) else {
332- return [ : ]
333- }
334-
335- // The pool exposes no count, so walk until it stops vending. The cap
336- // is a runaway guard, not a semantic window: this pool is created at
337- // gap-limit depth and never grows here.
338- var addresses : [ UInt32 : String ] = [ : ]
339- for index in 0 ..< Self . derivationPoolProbeCap {
340- guard let info = try? pool . getAddress ( at : index ) else { break }
341- addresses [ index ] = info . address
342- }
343- return addresses
344- }
345-
346- /// Runaway guard for the fallback pool walk — far above any gap-limit
347- /// depth the derivation wallet can hold.
348- private static let derivationPoolProbeCap : UInt32 = 200
349-
350271 func wif ( at index : UInt32 ) -> String ? {
351272 keyResolver . key ( at : index ) ? . privateKeyWIF
352273 }
@@ -355,11 +276,7 @@ final class MasternodeProviderKeyDeriver {
355276 keyResolver . key ( at : index ) ? . privateKeyHex
356277 }
357278
358- /// The pool address at `index`. Backed by the running wallet's live pool
359- /// whenever it's available: reading the throwaway derivation wallet as
360- /// the primary source would cap every consumer at that stack's initial
361- /// 5-entry pool, hiding every masternode whose owner/voting key sits at
362- /// a deeper index.
279+ /// The address at `index` of the running wallet's provider pool.
363280 func address ( at index : UInt32 ) -> String ? {
364281 poolAddresses [ index ]
365282 }
0 commit comments