@midnight-ntwrk/wallet-sdk-facade 4.0.1 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,10 @@
1
+ > [!IMPORTANT]
2
+ > **This package has moved.** The `@midnight-ntwrk` scope is published only
3
+ > during the migration window and will stop receiving updates. Please migrate to
4
+ > [`@midnightntwrk/wallet-sdk-facade`](https://www.npmjs.com/package/@midnightntwrk/wallet-sdk-facade).
5
+
6
+ ---
7
+
1
8
  # @midnight-ntwrk/wallet-sdk-facade
2
9
 
3
10
  > **Note:** It is recommended to use the [`@midnight-ntwrk/wallet-sdk`](../wallet-sdk/README.md) barrel package, which
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ import { type AnyTransaction, type CoinsAndBalances as DustCoinsAndBalances } fr
6
6
  import { type DefaultShieldedConfiguration, type ShieldedWalletAPI, type ShieldedWalletState } from '@midnight-ntwrk/wallet-sdk-shielded';
7
7
  import type { DefaultUnshieldedConfiguration, UnshieldedWalletAPI } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
8
8
  import { type UnshieldedWalletState } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
9
+ import { Clock } from '@midnight-ntwrk/wallet-sdk-utilities';
9
10
  import { Schema } from 'effect';
10
11
  import { TransactionHistoryStorage } from '@midnight-ntwrk/wallet-sdk-abstractions';
11
12
  import { type Observable } from 'rxjs';
@@ -137,14 +138,16 @@ export declare class FacadeState {
137
138
  constructor(shielded: ShieldedWalletState, unshielded: UnshieldedWalletState, dust: DustWalletState, pending: PendingTransactions.PendingTransactions<ledger.FinalizedTransaction>);
138
139
  }
139
140
  /**
140
- * A clock abstraction for obtaining the current time. By default, the facade uses the system clock. For testing with a
141
- * simulator, inject a custom clock (e.g., one backed by the simulator's time).
141
+ * Clock abstraction for obtaining the current time. By default, the facade uses the system clock
142
+ * ({@link Clock.systemClock}); for testing with a simulator, inject a custom clock (e.g. one backed by the simulator's
143
+ * time).
144
+ *
145
+ * Re-exported from `@midnight-ntwrk/wallet-sdk-utilities` as a namespace so the type is `Clock.Clock` and the default is
146
+ * `Clock.systemClock`. Forwarding the same symbol — rather than re-declaring its members individually — keeps the
147
+ * umbrella `wallet-sdk` package's star-exports unambiguous and lets lower-level packages (e.g. dust-wallet) share it
148
+ * without a circular dependency.
142
149
  */
143
- export type Clock = {
144
- readonly now: () => Date;
145
- };
146
- /** Default clock using real system time. */
147
- export declare const systemClock: Clock;
150
+ export { Clock };
148
151
  /**
149
152
  * The Terms and Conditions returned by the indexer, containing a URL for display and a SHA-256 hash for content
150
153
  * verification.
@@ -177,7 +180,7 @@ type MaybePromise<T> = T | Promise<T>;
177
180
  export type InitParams<TConfig extends DefaultConfiguration> = {
178
181
  configuration: TConfig;
179
182
  /** Optional factory for the clock abstraction. Defaults to system clock (`() => new Date()`). */
180
- clock?: (config: TConfig) => MaybePromise<Clock>;
183
+ clock?: (config: TConfig) => MaybePromise<Clock.Clock>;
181
184
  submissionService?: (config: TConfig) => MaybePromise<SubmissionService<ledger.FinalizedTransaction>>;
182
185
  pendingTransactionsService?: (config: TConfig) => MaybePromise<PendingTransactionsService<ledger.FinalizedTransaction>>;
183
186
  provingService?: (config: TConfig) => MaybePromise<ProvingService<UnboundTransaction>>;
@@ -225,7 +228,7 @@ export declare class WalletFacade {
225
228
  * - `pendingTransactionsService` - needs to implement {@link PendingTransactionsService} for a
226
229
  * {@link ledger.FinalizedTransaction} to keep track of pending transactions, default uses in-memory implementation
227
230
  * - `provingService` - needs to implement {@link ProvingService} to prove it, default uses proving server
228
- * - `clock` - needs to implement {@link Clock} for getting current time, default uses system clock
231
+ * - `clock` - needs to implement {@link Clock.Clock} for getting current time, default uses system clock
229
232
  */
230
233
  static init<TConfig extends DefaultConfiguration>(initParams: InitParams<TConfig>): Promise<WalletFacade>;
231
234
  readonly shielded: ShieldedWalletAPI;
@@ -234,7 +237,7 @@ export declare class WalletFacade {
234
237
  readonly submissionService: SubmissionService<ledger.FinalizedTransaction>;
235
238
  readonly pendingTransactionsService: PendingTransactionsService<ledger.FinalizedTransaction>;
236
239
  readonly provingService: ProvingService<UnboundTransaction>;
237
- readonly clock: Clock;
240
+ readonly clock: Clock.Clock;
238
241
  /**
239
242
  * Constructor is private on purpose - much of initialization of the facade is potentially asynchronous, and adding
240
243
  * new parameters is a breaking change to the users Use {@link WalletFacade.init} instead
@@ -307,6 +310,19 @@ export declare class WalletFacade {
307
310
  payFees?: boolean;
308
311
  }): Promise<UnprovenTransactionRecipe>;
309
312
  registerNightUtxosForDustGeneration(nightUtxos: readonly UtxoWithMeta[], nightVerifyingKey: ledger.SignatureVerifyingKey, signDustRegistration: (payload: Uint8Array) => ledger.Signature, dustReceiverAddress?: DustAddress): Promise<UnprovenTransactionRecipe>;
313
+ /**
314
+ * Waits until the dust projected to be generated by the given Night UTxOs reaches `requiredAmount`, re-checking every
315
+ * second. Pair with {@link estimateRegistration} to pick `requiredAmount`, then call before
316
+ * {@link registerNightUtxosForDustGeneration} so the registration covers its own fee.
317
+ *
318
+ * @param nightUtxos - Night UTxOs to project generation for; the same set passed to the registration.
319
+ * @param requiredAmount - Dust threshold to wait for. Resolves immediately if `<= 0n`.
320
+ * @param opts.timeoutMs - Deadline, in ms, for the threshold to be reached. Rejects otherwise. Default `300_000`.
321
+ * @throws If `nightUtxos` is empty, or if `requiredAmount` is not reached within `opts.timeoutMs`.
322
+ */
323
+ waitForGeneratedDust(nightUtxos: readonly UtxoWithMeta[], requiredAmount: bigint, opts?: {
324
+ timeoutMs?: number;
325
+ }): Promise<void>;
310
326
  deregisterFromDustGeneration(nightUtxos: UtxoWithMeta[], nightVerifyingKey: ledger.SignatureVerifyingKey, signDustRegistration: (payload: Uint8Array) => ledger.Signature): Promise<UnprovenTransactionRecipe>;
311
327
  revert(txOrRecipe: AnyTransaction | BalancingRecipe): Promise<void>;
312
328
  revertTransaction(tx: AnyTransaction): Promise<void>;
@@ -315,4 +331,3 @@ export declare class WalletFacade {
315
331
  queryTxHistoryByHash(hash: TransactionHistoryStorage.TransactionHash): Promise<WalletEntry | undefined>;
316
332
  getAllFromTxHistory(): Promise<WalletEntry[]>;
317
333
  }
318
- export {};
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ import { makeDefaultProvingService, } from '@midnight-ntwrk/wallet-sdk-capabilit
16
16
  import { ShieldedSectionSchema, mergeShieldedSections, } from '@midnight-ntwrk/wallet-sdk-shielded';
17
17
  import { UnshieldedSectionSchema } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
18
18
  import { DustSectionSchema, mergeDustSections } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
19
+ import { Clock } from '@midnight-ntwrk/wallet-sdk-utilities';
19
20
  import { FetchTermsAndConditions as FetchTermsAndConditionsQuery } from '@midnight-ntwrk/wallet-sdk-indexer-client';
20
21
  import { QueryRunner } from '@midnight-ntwrk/wallet-sdk-indexer-client/effect';
21
22
  import { Array as Arr, pipe, Schema } from 'effect';
@@ -98,8 +99,17 @@ export class FacadeState {
98
99
  }
99
100
  }
100
101
  const DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour
101
- /** Default clock using real system time. */
102
- export const systemClock = { now: () => new Date() };
102
+ /**
103
+ * Clock abstraction for obtaining the current time. By default, the facade uses the system clock
104
+ * ({@link Clock.systemClock}); for testing with a simulator, inject a custom clock (e.g. one backed by the simulator's
105
+ * time).
106
+ *
107
+ * Re-exported from `@midnight-ntwrk/wallet-sdk-utilities` as a namespace so the type is `Clock.Clock` and the default is
108
+ * `Clock.systemClock`. Forwarding the same symbol — rather than re-declaring its members individually — keeps the
109
+ * umbrella `wallet-sdk` package's star-exports unambiguous and lets lower-level packages (e.g. dust-wallet) share it
110
+ * without a circular dependency.
111
+ */
112
+ export { Clock };
103
113
  export class WalletFacade {
104
114
  static makeDefaultSubmissionService(config) {
105
115
  return makeDefaultSubmissionService(config);
@@ -164,7 +174,7 @@ export class WalletFacade {
164
174
  * - `pendingTransactionsService` - needs to implement {@link PendingTransactionsService} for a
165
175
  * {@link ledger.FinalizedTransaction} to keep track of pending transactions, default uses in-memory implementation
166
176
  * - `provingService` - needs to implement {@link ProvingService} to prove it, default uses proving server
167
- * - `clock` - needs to implement {@link Clock} for getting current time, default uses system clock
177
+ * - `clock` - needs to implement {@link Clock.Clock} for getting current time, default uses system clock
168
178
  */
169
179
  static async init(initParams) {
170
180
  const submissionService = await Promise.resolve(initParams.submissionService
@@ -179,7 +189,7 @@ export class WalletFacade {
179
189
  const shielded = await Promise.resolve(initParams.shielded(initParams.configuration));
180
190
  const unshielded = await Promise.resolve(initParams.unshielded(initParams.configuration));
181
191
  const dust = await Promise.resolve(initParams.dust(initParams.configuration));
182
- const clock = await Promise.resolve(initParams.clock ? initParams.clock(initParams.configuration) : systemClock);
192
+ const clock = await Promise.resolve(initParams.clock ? initParams.clock(initParams.configuration) : Clock.systemClock);
183
193
  return new WalletFacade(shielded, unshielded, dust, submissionService, pendingTransactionsService, provingService, initParams.configuration.txHistoryStorage, clock);
184
194
  }
185
195
  shielded;
@@ -197,7 +207,7 @@ export class WalletFacade {
197
207
  *
198
208
  * @private
199
209
  */
200
- constructor(shieldedWallet, unshieldedWallet, dustWallet, submissionService, pendingTransactionsService, provingService, txHistoryStorage, clock = systemClock) {
210
+ constructor(shieldedWallet, unshieldedWallet, dustWallet, submissionService, pendingTransactionsService, provingService, txHistoryStorage, clock = Clock.systemClock) {
201
211
  this.shielded = shieldedWallet;
202
212
  this.unshielded = unshieldedWallet;
203
213
  this.dust = dustWallet;
@@ -260,7 +270,21 @@ export class WalletFacade {
260
270
  await this.unshielded.revertTransaction(txWithOffers);
261
271
  throw error;
262
272
  }
263
- // Step 4 — Sign via the standard signRecipe pathway, which now stamps both the unshielded
273
+ // Step 4 (first-time registration only) — Fail fast if the dust generated so far by the
274
+ // unregistered guaranteed UTxOs is below the registration's own fee. Submitting would fail
275
+ // on-chain with BalanceCheckOverspend. Skip for re-registration (all guaranteed UTxOs already
276
+ // registered) since `feePayment` is 0 by design and the caller is expected to balance the fee
277
+ // externally via `balanceUnprovenTransaction({ tokenKindsToBalance: ['dust'] })`.
278
+ const hasUnregisteredGuaranteed = split.guaranteedUtxos.some((u) => !u.utxo.registeredForDustGeneration);
279
+ if (isRegistration && hasUnregisteredGuaranteed) {
280
+ const fee = await this.dust.calculateFee([txWithDustActions]);
281
+ if (split.feePayment < fee) {
282
+ await this.unshielded.revertTransaction(txWithOffers);
283
+ throw Error(`Insufficient generated dust to cover registration fee (have ${split.feePayment}, need ${fee}). ` +
284
+ `Use WalletFacade.waitForGeneratedDust(utxos, ${fee}) before retrying.`);
285
+ }
286
+ }
287
+ // Step 5 — Sign via the standard signRecipe pathway, which now stamps both the unshielded
264
288
  // offers and the dust registration. Signing failures also need to release the booking.
265
289
  try {
266
290
  const signedRecipe = await this.signRecipe({ type: 'UNPROVEN_TRANSACTION', transaction: txWithDustActions }, signDustRegistration);
@@ -590,6 +614,23 @@ export class WalletFacade {
590
614
  transaction: dustRegistrationTx,
591
615
  };
592
616
  }
617
+ /**
618
+ * Waits until the dust projected to be generated by the given Night UTxOs reaches `requiredAmount`, re-checking every
619
+ * second. Pair with {@link estimateRegistration} to pick `requiredAmount`, then call before
620
+ * {@link registerNightUtxosForDustGeneration} so the registration covers its own fee.
621
+ *
622
+ * @param nightUtxos - Night UTxOs to project generation for; the same set passed to the registration.
623
+ * @param requiredAmount - Dust threshold to wait for. Resolves immediately if `<= 0n`.
624
+ * @param opts.timeoutMs - Deadline, in ms, for the threshold to be reached. Rejects otherwise. Default `300_000`.
625
+ * @throws If `nightUtxos` is empty, or if `requiredAmount` is not reached within `opts.timeoutMs`.
626
+ */
627
+ async waitForGeneratedDust(nightUtxos, requiredAmount, opts) {
628
+ await this.dust.waitForGeneratedDust(nightUtxos.map(({ utxo, meta }) => ({
629
+ ...utxo,
630
+ ctime: meta.ctime,
631
+ registeredForDustGeneration: meta.registeredForDustGeneration,
632
+ })), requiredAmount, this.clock, opts);
633
+ }
593
634
  async deregisterFromDustGeneration(nightUtxos, nightVerifyingKey, signDustRegistration) {
594
635
  const dustDeregistrationTx = await this.createDustActionTransaction({ type: 'deregistration' }, nightUtxos, nightVerifyingKey, signDustRegistration);
595
636
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midnight-ntwrk/wallet-sdk-facade",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -8,14 +8,16 @@
8
8
  "author": "Midnight Foundation",
9
9
  "license": "Apache-2.0",
10
10
  "publishConfig": {
11
- "registry": "https://npm.pkg.github.com/"
11
+ "registry": "https://registry.npmjs.org/",
12
+ "access": "public"
12
13
  },
13
14
  "files": [
14
15
  "dist/"
15
16
  ],
16
17
  "repository": {
17
18
  "type": "git",
18
- "url": "git+https://github.com/midnight-ntwrk/artifacts.git"
19
+ "url": "git+https://github.com/midnightntwrk/midnight-wallet.git",
20
+ "directory": "packages/facade"
19
21
  },
20
22
  "exports": {
21
23
  ".": {
@@ -28,14 +30,14 @@
28
30
  "@midnight-ntwrk/wallet-sdk-abstractions": "^2.1.0",
29
31
  "@midnight-ntwrk/wallet-sdk-address-format": "^3.1.2",
30
32
  "@midnight-ntwrk/wallet-sdk-capabilities": "^3.3.1",
31
- "@midnight-ntwrk/wallet-sdk-dust-wallet": "^4.1.0",
32
- "@midnight-ntwrk/wallet-sdk-indexer-client": "^1.2.2",
33
- "@midnight-ntwrk/wallet-sdk-shielded": "^3.0.1",
33
+ "@midnight-ntwrk/wallet-sdk-dust-wallet": "^4.2.0",
34
+ "@midnight-ntwrk/wallet-sdk-indexer-client": "^1.2.3",
35
+ "@midnight-ntwrk/wallet-sdk-shielded": "^3.0.2",
34
36
  "@midnight-ntwrk/wallet-sdk-unshielded-wallet": "^3.1.0",
35
37
  "rxjs": "^7.8.2"
36
38
  },
37
39
  "devDependencies": {
38
- "@midnight-ntwrk/wallet-sdk-hd": "^3.0.2",
40
+ "@midnight-ntwrk/wallet-sdk-hd": "^3.0.3",
39
41
  "@midnight-ntwrk/wallet-sdk-utilities": "^1.2.0"
40
42
  },
41
43
  "scripts": {