@midnight-ntwrk/wallet-sdk-facade 5.0.0-beta.2 → 5.0.0-beta.3

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/dist/index.d.ts CHANGED
@@ -1,17 +1,19 @@
1
- import * as ledger from '@midnightntwrk/ledger-v9';
1
+ import * as ledgerV9 from '@midnightntwrk/ledger-v9';
2
2
  import { type DefaultSubmissionConfiguration, type SubmissionService } from '@midnight-ntwrk/wallet-sdk-capabilities';
3
- import { type DefaultProvingConfiguration, type ProvingService, type UnboundTransaction } from '@midnight-ntwrk/wallet-sdk-capabilities/proving';
3
+ import { type AnyVersionUnboundTransaction, type AnyVersionUnprovenTransaction, type DefaultProvingConfiguration, type VersionedProvingService } from '@midnight-ntwrk/wallet-sdk-capabilities/proving';
4
4
  import { type DefaultDustConfiguration, type DustWalletAPI, type DustWalletState } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
5
- import { type AnyTransaction, type CoinsAndBalances as DustCoinsAndBalances } from '@midnight-ntwrk/wallet-sdk-dust-wallet/v1';
5
+ import { type CoinsAndBalances as DustCoinsAndBalances } from '@midnight-ntwrk/wallet-sdk-dust-wallet/v2';
6
6
  import { type DefaultShieldedConfiguration, type ShieldedWalletAPI, type ShieldedWalletState } from '@midnight-ntwrk/wallet-sdk-shielded';
7
7
  import type { DefaultUnshieldedConfiguration, SignSegment, UnshieldedWalletAPI } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
8
8
  import { type UnshieldedWalletState } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
9
9
  import { Clock } from '@midnight-ntwrk/wallet-sdk-utilities';
10
- import { Schema } from 'effect';
11
- import { TransactionHistoryStorage } from '@midnight-ntwrk/wallet-sdk-abstractions';
10
+ import { type DateTime, Option, Schema } from 'effect';
11
+ import { type AnyTx, type FinalizedTx, ProtocolVersion, TransactionHistoryStorage, type UnboundTx, type UnprovenTx } from '@midnight-ntwrk/wallet-sdk-abstractions';
12
+ import * as ledgerV8 from '@midnight-ntwrk/ledger-v8';
13
+ import { type WalletSeeds } from '@midnight-ntwrk/wallet-sdk-hd';
12
14
  import { type Observable } from 'rxjs';
13
15
  import { type DefaultPendingTransactionsServiceConfiguration, PendingTransactions, type PendingTransactionsService } from '@midnight-ntwrk/wallet-sdk-capabilities';
14
- import { type BlockData, type BlockDataFetcher, type ValidateTxOptions, ValidationFetchError, type ValidationService, WellFormedError, type WellFormedStrictnessFlags } from '@midnight-ntwrk/wallet-sdk-capabilities/validation';
16
+ import { type AnyLedgerParameters, type AnyVersionValidatableTransaction, type BlockData, type BlockDataFetcher, type ValidateTxOptions, ValidationFetchError, type VersionedValidationService, WellFormedError, type WellFormedStrictnessFlags } from '@midnight-ntwrk/wallet-sdk-capabilities/validation';
15
17
  import { type DustAddress, type ShieldedAddress, type UnshieldedAddress } from '@midnight-ntwrk/wallet-sdk-address-format';
16
18
  /**
17
19
  * Full entry schema for transaction history. The common entry data and wallet-specific sections (`shielded`,
@@ -101,6 +103,15 @@ export type FinalizedWalletEntry = WalletEntry & {
101
103
  export declare const isPendingWalletEntry: (entry: WalletEntry) => entry is PendingWalletEntry;
102
104
  export declare const isFinalizedWalletEntry: (entry: WalletEntry) => entry is FinalizedWalletEntry;
103
105
  export declare function mergeWalletEntries(existing: WalletEntry, incoming: WalletEntry): WalletEntry;
106
+ /**
107
+ * Every transaction shape the facade will take from a caller.
108
+ *
109
+ * @remarks
110
+ * Now a handle: what an application carries between facade calls is sealed together with the protocol version it was
111
+ * built at, so it can be routed rather than guessed about. The name is kept because it is what these signatures have
112
+ * always been stated in terms of.
113
+ */
114
+ export type AnyTransaction = AnyTx;
104
115
  type TokenKind = 'dust' | 'shielded' | 'unshielded';
105
116
  type TokenKindsToBalance = 'all' | TokenKind[];
106
117
  declare const TokenKindsToBalance: {
@@ -113,28 +124,34 @@ declare const TokenKindsToBalance: {
113
124
  };
114
125
  export type FinalizedTransactionRecipe = {
115
126
  type: 'FINALIZED_TRANSACTION';
116
- originalTransaction: ledger.FinalizedTransaction;
117
- balancingTransaction: ledger.UnprovenTransaction;
118
- blockData?: BlockData;
127
+ /** The protocol version this recipe was built for, and so the version its parts have to be proved at. */
128
+ protocolVersion: ProtocolVersion.ProtocolVersion;
129
+ originalTransaction: FinalizedTx;
130
+ balancingTransaction: UnprovenTx;
131
+ blockData?: BlockData<AnyLedgerParameters>;
119
132
  };
120
133
  export type UnboundTransactionRecipe = {
121
134
  type: 'UNBOUND_TRANSACTION';
122
- baseTransaction: UnboundTransaction;
123
- balancingTransaction?: ledger.UnprovenTransaction | undefined;
124
- blockData?: BlockData;
135
+ /** The protocol version this recipe was built for, and so the version its parts have to be proved at. */
136
+ protocolVersion: ProtocolVersion.ProtocolVersion;
137
+ baseTransaction: UnboundTx;
138
+ balancingTransaction?: UnprovenTx | undefined;
139
+ blockData?: BlockData<AnyLedgerParameters>;
125
140
  };
126
141
  export type UnprovenTransactionRecipe = {
127
142
  type: 'UNPROVEN_TRANSACTION';
128
- transaction: ledger.UnprovenTransaction;
129
- blockData?: BlockData;
143
+ /** The protocol version this recipe was built for, and so the version its parts have to be proved at. */
144
+ protocolVersion: ProtocolVersion.ProtocolVersion;
145
+ transaction: UnprovenTx;
146
+ blockData?: BlockData<AnyLedgerParameters>;
130
147
  };
131
148
  export type BalancingRecipe = FinalizedTransactionRecipe | UnboundTransactionRecipe | UnprovenTransactionRecipe;
132
149
  export declare const BalancingRecipe: {
133
150
  isRecipe: (value: unknown) => value is BalancingRecipe;
134
- getTransactions: (recipe: BalancingRecipe) => readonly AnyTransaction[];
151
+ getTransactions: (recipe: BalancingRecipe) => readonly AnyTx[];
135
152
  };
136
153
  export interface TokenTransfer<AddressType extends ShieldedAddress | UnshieldedAddress> {
137
- type: ledger.RawTokenType;
154
+ type: ledgerV9.RawTokenType;
138
155
  receiverAddress: AddressType;
139
156
  amount: bigint;
140
157
  }
@@ -148,25 +165,191 @@ export type UnshieldedTokenTransfer = {
148
165
  };
149
166
  export type CombinedTokenTransfer = ShieldedTokenTransfer | UnshieldedTokenTransfer;
150
167
  export type CombinedSwapInputs = {
151
- shielded?: Record<ledger.RawTokenType, bigint>;
152
- unshielded?: Record<ledger.RawTokenType, bigint>;
168
+ shielded?: Record<ledgerV9.RawTokenType, bigint>;
169
+ unshielded?: Record<ledgerV9.RawTokenType, bigint>;
153
170
  };
154
171
  export type CombinedSwapOutputs = CombinedTokenTransfer;
155
172
  export type TransactionIdentifier = string;
156
173
  export type UtxoWithMeta = {
157
- utxo: ledger.Utxo;
174
+ utxo: ledgerV9.Utxo;
158
175
  meta: {
159
176
  ctime: Date;
160
177
  registeredForDustGeneration: boolean;
161
178
  };
162
179
  };
180
+ /** The protocol version each of the three wallets has reached. */
181
+ export type WalletProtocolVersions = Readonly<{
182
+ shielded: ProtocolVersion.ProtocolVersion;
183
+ unshielded: ProtocolVersion.ProtocolVersion;
184
+ dust: ProtocolVersion.ProtocolVersion;
185
+ }>;
186
+ /**
187
+ * The lowest of the protocol versions the three wallets have reached.
188
+ *
189
+ * @remarks
190
+ * The three wallets follow the same chain but not in lock-step: each recognises a protocol version change when its own
191
+ * synchronization reaches it, so around a fork they disagree for a while. A transaction spans all three, so the one
192
+ * still behind is what bounds the facade as a whole — the highest version every wallet is known to be at.
193
+ * @param versions The version each wallet has reached.
194
+ * @returns The lowest of the three.
195
+ */
196
+ export declare const lowestProtocolVersion: (versions: WalletProtocolVersions) => ProtocolVersion.ProtocolVersion;
197
+ /**
198
+ * One ledger version's key objects per side of a protocol boundary.
199
+ *
200
+ * @remarks
201
+ * The escape hatch for a caller that holds key objects rather than a seed. Both sides are required: key objects belong
202
+ * to one ledger version's runtime and neither can be derived from the other, so a facade given one side alone would
203
+ * hold wallets that cannot read half the chain. That is the shape seeds exist to avoid, and a product with one side
204
+ * optional would reintroduce it.
205
+ */
206
+ export type FacadeKeysByEpoch = Readonly<{
207
+ /** The ledger-v8's key objects. */
208
+ v8: Readonly<{
209
+ shielded: ledgerV8.ZswapSecretKeys;
210
+ dust: ledgerV8.DustSecretKey;
211
+ }>;
212
+ /** The ledger-v9's key objects. */
213
+ v9: Readonly<{
214
+ shielded: ledgerV9.ZswapSecretKeys;
215
+ dust: ledgerV9.DustSecretKey;
216
+ }>;
217
+ }>;
218
+ /** What the facade will start its wallets from: seeds, or both ledger versions' key objects. */
219
+ export type FacadeStartMaterial = WalletSeeds | FacadeKeysByEpoch;
220
+ /** How the wallets are started. */
221
+ export type FacadeStartOptions = Readonly<{
222
+ /**
223
+ * Leaves the dust wallet unstarted in the background, to be driven a step at a time with `doSync`.
224
+ *
225
+ * @remarks
226
+ * Requires a dust wallet built with the projections sync service; see `makeEventLessSyncService`.
227
+ */
228
+ manualSync?: boolean;
229
+ }>;
230
+ /** Which of the three wallets a reading is about. */
231
+ export type WalletKind = keyof WalletProtocolVersions;
232
+ /**
233
+ * Whether the three wallets agree about which side of a protocol boundary the chain is on.
234
+ *
235
+ * @remarks
236
+ * `Settled` is the ordinary state, and says which protocol version the facade is acting at. `Crossing` is the window
237
+ * around a fork during which the wallets disagree: each one learns of the change when its own synchronization reaches
238
+ * it, so for a while some have crossed and some have not. Nothing the facade builds during that window can span the
239
+ * boundary, so it stays bound to the version the laggards are still on — which is what `from` reports, and what
240
+ * `activeProtocolVersion` answers.
241
+ *
242
+ * A difference in version _within_ one epoch is not a crossing: two versions on the same side of the boundary are the
243
+ * same ledger version, and a wallet lagging there is ordinary synchronization.
244
+ */
245
+ export type ProtocolPhase = Readonly<{
246
+ _tag: 'Settled';
247
+ version: ProtocolVersion.ProtocolVersion;
248
+ }> | Readonly<{
249
+ _tag: 'Crossing';
250
+ /** The version the facade is still bound to: the epoch the wallets that have not crossed are in. */
251
+ from: ProtocolVersion.ProtocolVersion;
252
+ /** The version the wallets that have crossed have reached. */
253
+ to: ProtocolVersion.ProtocolVersion;
254
+ /** The wallets still on the near side, in a fixed order, so an application can say what it is waiting for. */
255
+ behind: readonly WalletKind[];
256
+ }>;
257
+ /**
258
+ * Reads whether the wallets are settled on one side of a protocol boundary, or still crossing it.
259
+ *
260
+ * @remarks
261
+ * Derived entirely from the version each wallet has reported and where the boundary lies — the same two facts every
262
+ * other version-routing decision in the SDK is made from, so this reading cannot disagree with them.
263
+ * @param versions The version each wallet has reached.
264
+ * @param forkVersion The version at which the chain hands over to the next ledger version.
265
+ * @returns The reading. See {@link ProtocolPhase}.
266
+ */
267
+ export declare const protocolPhaseOf: (versions: WalletProtocolVersions, forkVersion: ProtocolVersion.ProtocolVersion) => ProtocolPhase;
268
+ /**
269
+ * What has become of a transaction the wallet submitted.
270
+ *
271
+ * @remarks
272
+ * Tagged rather than a status string, and deliberately: `Orphaned` and `Rejected` are different facts about the world
273
+ * and the difference matters to what an application should do next. A rejection is the chain's verdict — the node saw
274
+ * the transaction and refused it. An orphaned transaction has no verdict at all and never will: its bytes were
275
+ * authored under a protocol version the chain has moved past, and nothing can include them afterwards. The wallet has
276
+ * already unbooked its coins and recorded the rejection either way; what differs is what an application can tell a
277
+ * user, and whether re-submitting the same bytes could ever help.
278
+ */
279
+ export type PendingStatus = Readonly<{
280
+ _tag: 'Submitted';
281
+ }> | Readonly<{
282
+ _tag: 'Confirmed';
283
+ segments: readonly Readonly<{
284
+ id: number;
285
+ success: boolean;
286
+ }>[];
287
+ }> | Readonly<{
288
+ _tag: 'Rejected';
289
+ segments: readonly Readonly<{
290
+ id: number;
291
+ success: boolean;
292
+ }>[];
293
+ }> | Readonly<{
294
+ _tag: 'Orphaned';
295
+ /** The protocol version the transaction was authored for. */
296
+ authoredFor: ProtocolVersion.ProtocolVersion;
297
+ /** The protocol version the chain had reached when the wallet gave up on it. */
298
+ chainNow: ProtocolVersion.ProtocolVersion;
299
+ }>;
300
+ /** A transaction the wallet has submitted and the chain has not finished answering for. */
301
+ export type PendingTransaction = Readonly<{
302
+ /** The transaction itself, as the handle an application carries. */
303
+ transaction: FinalizedTx;
304
+ /** When the wallet recorded it as pending. */
305
+ submittedAt: DateTime.Utc;
306
+ /**
307
+ * The protocol version it was authored for, when the wallet had observed one.
308
+ *
309
+ * @remarks
310
+ * `Option.none()` means the wallet never learned which version it was authored against. Such a transaction is never
311
+ * orphaned — an unobserved version is not evidence of anything.
312
+ */
313
+ authoredFor: Option.Option<ProtocolVersion.ProtocolVersion>;
314
+ /** What has become of it. See {@link PendingStatus}. */
315
+ status: PendingStatus;
316
+ }>;
317
+ /**
318
+ * The pending transactions as an application reads them.
319
+ *
320
+ * @remarks
321
+ * A projection over the pending set the services keep, not a second copy of it: the facts are the same, stated as a
322
+ * list of transactions with a status each rather than as the bag the machinery works in.
323
+ * @param pending The pending set.
324
+ * @returns One entry per transaction, in the order the wallet recorded them.
325
+ */
326
+ export declare const pendingTransactionsOf: (pending: PendingTransactions.PendingTransactions<FinalizedTx>) => readonly PendingTransaction[];
163
327
  export declare class FacadeState {
328
+ #private;
164
329
  readonly shielded: ShieldedWalletState;
165
330
  readonly unshielded: UnshieldedWalletState;
166
331
  readonly dust: DustWalletState;
167
- readonly pending: PendingTransactions.PendingTransactions<ledger.FinalizedTransaction>;
332
+ readonly pending: readonly PendingTransaction[];
333
+ /** The protocol version each of the three wallets has reached. */
334
+ get protocolVersion(): WalletProtocolVersions;
335
+ /**
336
+ * The protocol version the facade as a whole can act at: the lowest the three wallets have reached.
337
+ *
338
+ * @remarks
339
+ * Around a protocol boundary the three wallets cross at slightly different moments, and a transaction needs all
340
+ * three. This is the version every one of them is known to understand.
341
+ */
342
+ get activeProtocolVersion(): ProtocolVersion.ProtocolVersion;
343
+ /**
344
+ * Whether the three wallets are settled on one side of the protocol boundary, or still crossing it.
345
+ *
346
+ * @remarks
347
+ * Additive, and the reading `protocolVersion` alone cannot give: three versions that differ tell an application
348
+ * nothing about whether the difference matters. See {@link ProtocolPhase}.
349
+ */
350
+ get protocol(): ProtocolPhase;
168
351
  get isSynced(): boolean;
169
- constructor(shielded: ShieldedWalletState, unshielded: UnshieldedWalletState, dust: DustWalletState, pending: PendingTransactions.PendingTransactions<ledger.FinalizedTransaction>);
352
+ constructor(shielded: ShieldedWalletState, unshielded: UnshieldedWalletState, dust: DustWalletState, pending: PendingTransactions.PendingTransactions<FinalizedTx>, forkVersion?: ProtocolVersion.ProtocolVersion);
170
353
  }
171
354
  /**
172
355
  * Clock abstraction for obtaining the current time. By default, the facade uses the system clock
@@ -205,41 +388,108 @@ export type FetchTermsAndConditionsConfiguration = {
205
388
  indexerWsUrl?: string;
206
389
  };
207
390
  };
208
- export type DefaultConfiguration = DefaultUnshieldedConfiguration & DefaultShieldedConfiguration & DefaultDustConfiguration & DefaultSubmissionConfiguration & DefaultPendingTransactionsServiceConfiguration & Partial<DefaultProvingConfiguration>;
391
+ /**
392
+ * The fork schedule the facade presets when a configuration names none: {@link ProtocolVersion.V9NativeForkSchedule},
393
+ * ledger-v9 from the version a 2.x node reports.
394
+ *
395
+ * @remarks
396
+ * Where a chain forks is a fact about the chain, which is why each wallet package requires `forks` and presets nothing.
397
+ * The facade is the one place a preset decides nothing the SDK has not already decided: every chain the 2.x node line
398
+ * runs hands over at this version, so an application copying the constant into its configuration only restates it. A
399
+ * chain that hands over elsewhere states its own `forks`, which wins.
400
+ */
401
+ export declare const DefaultForkSchedule: ProtocolVersion.ForkSchedule;
402
+ /** What the three wallets and the default services are built from, as the wallet packages take it. */
403
+ type WalletsConfiguration = DefaultUnshieldedConfiguration & DefaultShieldedConfiguration & DefaultDustConfiguration & DefaultSubmissionConfiguration & DefaultPendingTransactionsServiceConfiguration & DefaultProvingConfiguration;
404
+ /**
405
+ * The configuration {@link WalletFacade.init} takes: what the three wallets and the default services are built from.
406
+ *
407
+ * @remarks
408
+ * The one difference from the wallets' own configurations is that `forks` may be left out — see
409
+ * {@link DefaultForkSchedule} for what is then preset, and {@link ResolvedConfiguration} for what a factory is handed.
410
+ */
411
+ export type DefaultConfiguration = Omit<WalletsConfiguration, 'forks'> & {
412
+ /**
413
+ * Where each ledger version begins on this chain — see {@link ProtocolVersion.ForkSchedule}. Left out, the facade
414
+ * presets {@link DefaultForkSchedule}.
415
+ */
416
+ forks?: ProtocolVersion.ForkSchedule;
417
+ };
418
+ /**
419
+ * A {@link DefaultConfiguration} with what the facade presets filled in: `forks` is always present, the schedule the
420
+ * configuration named or {@link DefaultForkSchedule}.
421
+ *
422
+ * @remarks
423
+ * What every factory in {@link InitParams} is handed, so that a wallet can be built from it directly: the wallet
424
+ * packages require `forks`, and this is what lets `shielded: (config) => ShieldedWallet(config)` compile. Code
425
+ * outside a factory gets the same from {@link WalletFacade.resolveConfiguration}.
426
+ * @typeParam TConfig The configuration as given, which may extend {@link DefaultConfiguration} with settings of its own.
427
+ */
428
+ export type ResolvedConfiguration<TConfig extends DefaultConfiguration = DefaultConfiguration> = TConfig & {
429
+ forks: ProtocolVersion.ForkSchedule;
430
+ };
209
431
  type MaybePromise<T> = T | Promise<T>;
210
432
  /**
211
433
  * Parameters object for {@link WalletFacade.init}. It features configuration and bunch of initializers for the wallets
212
434
  * and services, all of them are in a form of a function that takes the configuration and returns proper implementation,
213
435
  * either synchronously or wrapped in a Promise. Services are optional to provide ({@link WalletFacade.init} will provide
214
- * default implementations), but all 3 wallets: shielded, unshielded and Dust one need to be present
436
+ * default implementations), but all 3 wallets: shielded, unshielded and Dust one need to be present.
215
437
  */
216
438
  export type InitParams<TConfig extends DefaultConfiguration> = {
217
439
  configuration: TConfig;
218
440
  /** Optional factory for the clock abstraction. Defaults to system clock (`() => new Date()`). */
219
- clock?: (config: TConfig) => MaybePromise<Clock.Clock>;
220
- submissionService?: (config: TConfig) => MaybePromise<SubmissionService<ledger.FinalizedTransaction>>;
221
- pendingTransactionsService?: (config: TConfig) => MaybePromise<PendingTransactionsService<ledger.FinalizedTransaction>>;
222
- provingService?: (config: TConfig) => MaybePromise<ProvingService<UnboundTransaction>>;
441
+ clock?: (config: ResolvedConfiguration<TConfig>) => MaybePromise<Clock.Clock>;
442
+ submissionService?: (config: ResolvedConfiguration<TConfig>) => MaybePromise<SubmissionService<FinalizedTx>>;
443
+ pendingTransactionsService?: (config: ResolvedConfiguration<TConfig>) => MaybePromise<PendingTransactionsService<FinalizedTx>>;
444
+ provingService?: (config: ResolvedConfiguration<TConfig>) => MaybePromise<VersionedProvingService<AnyVersionUnboundTransaction, AnyVersionUnprovenTransaction>>;
223
445
  /**
224
446
  * Optional factory for the block-data fetcher used by validation. Defaults to an HTTP indexer-backed fetcher built
225
447
  * from `configuration.indexerClientConnection`. Override for simulator-based tests with
226
448
  * `makeSimulatorBlockDataFetcher(simulator)` from `@midnight-ntwrk/wallet-sdk-capabilities/validation`.
227
449
  */
228
- fetchBlockData?: (config: TConfig) => MaybePromise<BlockDataFetcher>;
229
- validationService?: (config: TConfig, deps: {
450
+ fetchBlockData?: (config: ResolvedConfiguration<TConfig>) => MaybePromise<BlockDataFetcher>;
451
+ validationService?: (config: ResolvedConfiguration<TConfig>, deps: {
230
452
  fetchBlockData: BlockDataFetcher;
231
453
  clock: Clock.Clock;
232
- }) => MaybePromise<ValidationService>;
233
- shielded: (config: TConfig) => MaybePromise<ShieldedWalletAPI>;
234
- unshielded: (config: TConfig) => MaybePromise<UnshieldedWalletAPI>;
235
- dust: (config: TConfig) => MaybePromise<DustWalletAPI>;
454
+ }) => MaybePromise<VersionedValidationService<AnyVersionValidatableTransaction, AnyLedgerParameters>>;
455
+ shielded: (config: ResolvedConfiguration<TConfig>) => MaybePromise<ShieldedWalletAPI>;
456
+ unshielded: (config: ResolvedConfiguration<TConfig>) => MaybePromise<UnshieldedWalletAPI>;
457
+ dust: (config: ResolvedConfiguration<TConfig>) => MaybePromise<DustWalletAPI>;
236
458
  };
237
- export { type BlockDataFetcher, type ValidateTxOptions, type ValidationService, ValidationFetchError, WellFormedError, type WellFormedStrictnessFlags, };
459
+ export { type BlockDataFetcher, type ValidateTxOptions, type VersionedValidationService, ValidationFetchError, WellFormedError, type WellFormedStrictnessFlags, };
238
460
  export declare class WalletFacade {
239
461
  #private;
240
462
  private static makeDefaultSubmissionService;
241
463
  private static makeDefaultPendingTransactionsService;
464
+ /**
465
+ * Builds the proving service a configuration describes.
466
+ *
467
+ * @remarks
468
+ * Handed the same fork schedule the wallets are built with, because a proving backend is chosen by the epoch a
469
+ * transaction belongs to and the two ends of that question must not be able to compute the boundary differently.
470
+ */
242
471
  private static makeDefaultProvingService;
472
+ /**
473
+ * Fills in what the facade presets — `forks`, as {@link DefaultForkSchedule} — so that the result is a configuration a
474
+ * wallet package can be built from.
475
+ *
476
+ * @remarks
477
+ * {@link WalletFacade.init} does this itself, once and before anything is built, so the wallets, the default services
478
+ * and the facade's own boundary cannot be given different schedules, and no factory needs to call it. It is public
479
+ * for code outside a factory that needs the configuration the facade will use: an application building a wallet
480
+ * package directly, or reading `forks` back to author a transaction for the right ledger version. Resolving twice
481
+ * is the same as resolving once, so `init` may be handed the result.
482
+ * @example
483
+ * ```typescript
484
+ * const configuration = WalletFacade.resolveConfiguration({ networkId: 'undeployed', ... });
485
+ * const facade = await WalletFacade.init({ configuration, shielded: (config) => ShieldedWallet(config), ... });
486
+ * const authoredForV9 = protocolVersion >= configuration.forks.v9;
487
+ * ```;
488
+ *
489
+ * @param configuration The configuration as given, with or without `forks`.
490
+ * @returns The same configuration with `forks` present: the schedule it named, or {@link DefaultForkSchedule}.
491
+ */
492
+ static resolveConfiguration<TConfig extends DefaultConfiguration>(configuration: TConfig): ResolvedConfiguration<TConfig>;
243
493
  /**
244
494
  * Fetches the current Terms and Conditions from the network indexer.
245
495
  *
@@ -261,7 +511,9 @@ export declare class WalletFacade {
261
511
  * and initialization of necessary components. Specifically - it requires following fields:
262
512
  *
263
513
  * - `configuration` - holding a configuration, which needs to extend {@link DefaultConfiguration} - this way allows to
264
- * convey use-case-specific settings in the same way, as the SDK works by default
514
+ * convey use-case-specific settings in the same way, as the SDK works by default. `forks` may be left out; every
515
+ * factory below is handed a {@link ResolvedConfiguration}, which always has it — what
516
+ * {@link WalletFacade.resolveConfiguration} returns
265
517
  * - `shielded` - a function taking the configuration and returning shielded wallet (or a promise with such)
266
518
  * implementing {@link ShieldedWalletAPI}
267
519
  * - `unshielded` - a function taking the configuration and returning unshielded wallet (or a promise with such)
@@ -270,21 +522,22 @@ export declare class WalletFacade {
270
522
  * {@link DustWalletAPI} There are some optional services/abstractions to provide, too. If not provided - default
271
523
  * implementations will be used, each of them is initialized by a function taking the configuration and returning
272
524
  * proper implementation (wrapped in a {@link Promise} or not).
273
- * - `submissionService` - needs to implement {@link SubmissionService} for a {@link ledger.FinalizedTransaction} to
525
+ * - `submissionService` - needs to implement {@link SubmissionService} for a {@link ledgerV9.FinalizedTransaction} to
274
526
  * submit transactions to the network, default uses Node RPC connection
275
527
  * - `pendingTransactionsService` - needs to implement {@link PendingTransactionsService} for a
276
- * {@link ledger.FinalizedTransaction} to keep track of pending transactions, default uses in-memory implementation
277
- * - `provingService` - needs to implement {@link ProvingService} to prove it, default uses proving server
528
+ * {@link ledgerV9.FinalizedTransaction} to keep track of pending transactions, default uses in-memory
529
+ * implementation
530
+ * - `provingService` - needs to implement {@link VersionedProvingService} to prove it, default uses proving server
278
531
  * - `clock` - needs to implement {@link Clock.Clock} for getting current time, default uses system clock
279
532
  */
280
533
  static init<TConfig extends DefaultConfiguration>(initParams: InitParams<TConfig>): Promise<WalletFacade>;
281
534
  readonly shielded: ShieldedWalletAPI;
282
535
  readonly unshielded: UnshieldedWalletAPI;
283
536
  readonly dust: DustWalletAPI;
284
- readonly submissionService: SubmissionService<ledger.FinalizedTransaction>;
285
- readonly pendingTransactionsService: PendingTransactionsService<ledger.FinalizedTransaction>;
286
- readonly provingService: ProvingService<UnboundTransaction>;
287
- readonly validationService: ValidationService;
537
+ readonly submissionService: SubmissionService<FinalizedTx>;
538
+ readonly pendingTransactionsService: PendingTransactionsService<FinalizedTx>;
539
+ readonly provingService: VersionedProvingService<AnyVersionUnboundTransaction, AnyVersionUnprovenTransaction>;
540
+ readonly validationService: VersionedValidationService<AnyVersionValidatableTransaction, AnyLedgerParameters>;
288
541
  readonly clock: Clock.Clock;
289
542
  /**
290
543
  * Constructor is private on purpose - much of initialization of the facade is potentially asynchronous, and adding
@@ -293,6 +546,49 @@ export declare class WalletFacade {
293
546
  * @private
294
547
  */
295
548
  private constructor();
549
+ /**
550
+ * The protocol version the facade is currently acting at.
551
+ *
552
+ * @remarks
553
+ * The lowest the three wallets have reached, once they have all reported; the minimum supported version until then,
554
+ * which is the epoch a wallet with no history belongs to. It is what a transaction the facade builds is stamped
555
+ * with, and what the side of the boundary it accepts transactions from is measured against.
556
+ */
557
+ private currentVersion;
558
+ /** The range of protocol versions on the same side of the boundary as a given one. */
559
+ private epochOf;
560
+ /** The range of protocol versions on the facade's current side of the boundary. */
561
+ private currentEpoch;
562
+ /**
563
+ * Reads a transaction an application handed in, refusing one built on the other side of the boundary.
564
+ *
565
+ * @remarks
566
+ * The enforcement point for everything that enters the facade — a transaction the wallets built, or one an
567
+ * application authored and sealed with `WalletTransaction.adopt`. Only the current epoch is accepted, because a
568
+ * transaction of the other one cannot be merged, proved or submitted alongside anything the facade would build for
569
+ * it. Both a stranded ledger-v8 transaction after the crossing and a ledger-v9 transaction offered before it are
570
+ * refused here, by name, with the versions written down.
571
+ * @param handle The handle to read.
572
+ * @returns The carried transaction.
573
+ * @throws {@link ProtocolVersionMismatchError} When the transaction was built on the other side of the boundary.
574
+ */
575
+ private accept;
576
+ /**
577
+ * Seals a transaction the facade or a wallet produced, at the version its bytes were fixed by.
578
+ *
579
+ * @remarks
580
+ * The version is the caller's to state, never read from the facade here, because the two can differ: a crossing can
581
+ * land while a transaction is at the prover, and what comes back is still the bytes of the ledger version that made
582
+ * them. A caller sealing something it has just built passes the version it is building at; a caller sealing
583
+ * something that has travelled through an await passes the version stamped on the handle it started from.
584
+ * @param stage How far along the building of the transaction the sealed handle is.
585
+ * @param transaction The transaction to seal.
586
+ * @param protocolVersion The version the transaction's bytes were fixed by.
587
+ * @returns The sealed handle.
588
+ */
589
+ private seal;
590
+ /** The ledger primitives the facade signs with on its current side of the boundary. */
591
+ private authoring;
296
592
  private defaultTtl;
297
593
  /**
298
594
  * Checks whether a transaction is structurally well-formed before passing it to a balance or submit method.
@@ -339,7 +635,14 @@ export declare class WalletFacade {
339
635
  * @throws {@link WellFormedError} If the transaction fails any enabled check.
340
636
  * @throws {@link ValidationFetchError} If the block-data fetch fails.
341
637
  */
342
- validateTransaction(tx: ledger.FinalizedTransaction | UnboundTransaction | ledger.UnprovenTransaction, options: ValidateTxOptions): Promise<void>;
638
+ validateTransaction(tx: AnyTx, options: ValidateTxOptions<AnyLedgerParameters>): Promise<void>;
639
+ /**
640
+ * Merges two unproven transactions of the same epoch, or returns whichever there is.
641
+ *
642
+ * @remarks
643
+ * Both are unwrapped before merging, which is where a pair from different epochs is refused: a merge across the
644
+ * boundary is not a failure to compute, it is unrepresentable, and saying so is the whole point of the stamp.
645
+ */
343
646
  private mergeUnprovenTransactions;
344
647
  private createDustActionTransaction;
345
648
  state(): Observable<FacadeState>;
@@ -354,7 +657,7 @@ export declare class WalletFacade {
354
657
  * @returns The transaction identifier.
355
658
  * @throws {@link WellFormedError} — call {@link validateTransaction} first to get this error early.
356
659
  */
357
- submitTransaction(tx: ledger.FinalizedTransaction): Promise<TransactionIdentifier>;
660
+ submitTransaction(tx: FinalizedTx): Promise<TransactionIdentifier>;
358
661
  /**
359
662
  * Balances a finalized transaction by adding shielded, unshielded, and dust inputs/outputs as needed.
360
663
  *
@@ -367,10 +670,7 @@ export declare class WalletFacade {
367
670
  * @param options - TTL for the balancing transaction, and optional subset of token kinds to balance.
368
671
  * @returns A {@link FinalizedTransactionRecipe} containing the original and balancing transactions.
369
672
  */
370
- balanceFinalizedTransaction(tx: ledger.FinalizedTransaction, secretKeys: {
371
- shieldedSecretKeys: ledger.ZswapSecretKeys;
372
- dustSecretKey: ledger.DustSecretKey;
373
- }, options: {
673
+ balanceFinalizedTransaction(tx: FinalizedTx, options: {
374
674
  ttl: Date;
375
675
  tokenKindsToBalance?: TokenKindsToBalance;
376
676
  }): Promise<FinalizedTransactionRecipe>;
@@ -386,10 +686,7 @@ export declare class WalletFacade {
386
686
  * @param options - TTL for the balancing transaction, and optional subset of token kinds to balance.
387
687
  * @returns An {@link UnboundTransactionRecipe} containing the base and optional balancing transactions.
388
688
  */
389
- balanceUnboundTransaction(tx: UnboundTransaction, secretKeys: {
390
- shieldedSecretKeys: ledger.ZswapSecretKeys;
391
- dustSecretKey: ledger.DustSecretKey;
392
- }, options: {
689
+ balanceUnboundTransaction(tx: UnboundTx, options: {
393
690
  ttl: Date;
394
691
  tokenKindsToBalance?: TokenKindsToBalance;
395
692
  }): Promise<UnboundTransactionRecipe>;
@@ -405,29 +702,41 @@ export declare class WalletFacade {
405
702
  * @param options - TTL for the balancing transaction, and optional subset of token kinds to balance.
406
703
  * @returns An {@link UnprovenTransactionRecipe} containing the balanced transaction.
407
704
  */
408
- balanceUnprovenTransaction(tx: ledger.UnprovenTransaction, secretKeys: {
409
- shieldedSecretKeys: ledger.ZswapSecretKeys;
410
- dustSecretKey: ledger.DustSecretKey;
411
- }, options: {
705
+ balanceUnprovenTransaction(tx: UnprovenTx, options: {
412
706
  ttl: Date;
413
707
  tokenKindsToBalance?: TokenKindsToBalance;
414
708
  }): Promise<UnprovenTransactionRecipe>;
415
- finalizeRecipe(recipe: BalancingRecipe): Promise<ledger.FinalizedTransaction>;
709
+ finalizeRecipe(recipe: BalancingRecipe): Promise<FinalizedTx>;
416
710
  signRecipe(recipe: BalancingRecipe, signSegment: SignSegment): Promise<BalancingRecipe>;
417
- signUnprovenTransaction(tx: ledger.UnprovenTransaction, signSegment: SignSegment): Promise<ledger.UnprovenTransaction>;
418
- signUnboundTransaction(tx: UnboundTransaction, signSegment: SignSegment): Promise<UnboundTransaction>;
419
- finalizeTransaction(tx: ledger.UnprovenTransaction): Promise<ledger.FinalizedTransaction>;
711
+ signUnprovenTransaction(tx: UnprovenTx, signSegment: SignSegment): Promise<UnprovenTx>;
712
+ signUnboundTransaction(tx: UnboundTx, signSegment: SignSegment): Promise<UnboundTx>;
713
+ /**
714
+ * Proves and binds an unproven transaction, and records it as pending.
715
+ *
716
+ * @remarks
717
+ * Proved at the version stamped on the transaction itself, which is the version that fixed its bytes, and sealed at
718
+ * that same version: proving is a long await, so the wallets can move under it, and neither the prover a
719
+ * transaction is routed to nor the stamp it comes back with may be decided by where they have moved to.
720
+ *
721
+ * Where they have moved to decides one thing only, and it is decided again once the proof is back: a crossing while
722
+ * the transaction was in flight leaves it belonging to an epoch the wallets have left, and no chain they are on can
723
+ * include it. Such a transaction is refused rather than sealed, and nothing is recorded as pending for it — a
724
+ * pending entry would only wait out a TTL for an inclusion that cannot happen — while the reservations it made in
725
+ * the three wallets are given back like those of any other failure here.
726
+ * @param tx The unproven transaction.
727
+ * @returns The finalized transaction, stamped with the version it was authored at.
728
+ * @throws {@link ProtocolVersionMismatchError} When the wallets left the transaction's epoch while it was being
729
+ * proved, or were never in it.
730
+ */
731
+ finalizeTransaction(tx: UnprovenTx): Promise<FinalizedTx>;
420
732
  /** Estimates the fee for the given transaction only. This lacks the fees of the balancing transaction. */
421
- calculateTransactionFee(tx: AnyTransaction): Promise<bigint>;
733
+ calculateTransactionFee(tx: AnyTx): Promise<bigint>;
422
734
  /** Calculates the total fee for the given transaction plus the fee of the balancing transaction. */
423
- estimateTransactionFee(tx: AnyTransaction, secretKey: ledger.DustSecretKey, options?: {
735
+ estimateTransactionFee(tx: AnyTx, options?: {
424
736
  ttl?: Date;
425
737
  currentTime?: Date;
426
738
  }): Promise<bigint>;
427
- transferTransaction(outputs: CombinedTokenTransfer[], secretKeys: {
428
- shieldedSecretKeys: ledger.ZswapSecretKeys;
429
- dustSecretKey: ledger.DustSecretKey;
430
- }, options: {
739
+ transferTransaction(outputs: CombinedTokenTransfer[], options: {
431
740
  ttl: Date;
432
741
  payFees?: boolean;
433
742
  }): Promise<UnprovenTransactionRecipe>;
@@ -442,14 +751,11 @@ export declare class WalletFacade {
442
751
  fee: bigint;
443
752
  dustGenerationEstimations: ReadonlyArray<DustCoinsAndBalances.UtxoWithFullDustDetails>;
444
753
  }>;
445
- initSwap(desiredInputs: CombinedSwapInputs, desiredOutputs: CombinedSwapOutputs[], secretKeys: {
446
- shieldedSecretKeys: ledger.ZswapSecretKeys;
447
- dustSecretKey: ledger.DustSecretKey;
448
- }, options: {
754
+ initSwap(desiredInputs: CombinedSwapInputs, desiredOutputs: CombinedSwapOutputs[], options: {
449
755
  ttl: Date;
450
756
  payFees?: boolean;
451
757
  }): Promise<UnprovenTransactionRecipe>;
452
- registerNightUtxosForDustGeneration(nightUtxos: readonly UtxoWithMeta[], nightVerifyingKey: ledger.SignatureVerifyingKey, signDustRegistration: SignSegment, dustReceiverAddress?: DustAddress): Promise<UnprovenTransactionRecipe>;
758
+ registerNightUtxosForDustGeneration(nightUtxos: readonly UtxoWithMeta[], nightVerifyingKey: ledgerV9.SignatureVerifyingKey, signDustRegistration: SignSegment, dustReceiverAddress?: DustAddress): Promise<UnprovenTransactionRecipe>;
453
759
  /**
454
760
  * Waits until the dust projected to be generated by the given Night UTxOs reaches `requiredAmount`, re-checking every
455
761
  * second. Pair with {@link estimateRegistration} to pick `requiredAmount`, then call before
@@ -463,10 +769,47 @@ export declare class WalletFacade {
463
769
  waitForGeneratedDust(nightUtxos: readonly UtxoWithMeta[], requiredAmount: bigint, opts?: {
464
770
  timeoutMs?: number;
465
771
  }): Promise<void>;
466
- deregisterFromDustGeneration(nightUtxos: UtxoWithMeta[], nightVerifyingKey: ledger.SignatureVerifyingKey, signDustRegistration: SignSegment): Promise<UnprovenTransactionRecipe>;
467
- revert(txOrRecipe: AnyTransaction | BalancingRecipe): Promise<void>;
468
- revertTransaction(tx: AnyTransaction): Promise<void>;
469
- start(shieldedSecretKeys: ledger.ZswapSecretKeys, dustSecretKey: ledger.DustSecretKey): Promise<void>;
772
+ deregisterFromDustGeneration(nightUtxos: UtxoWithMeta[], nightVerifyingKey: ledgerV9.SignatureVerifyingKey, signDustRegistration: SignSegment): Promise<UnprovenTransactionRecipe>;
773
+ revert(txOrRecipe: AnyTx | BalancingRecipe, reason?: string): Promise<void>;
774
+ /**
775
+ * The finalized entry recording `tx`, if sync has written one, even under the hash aggregation gave it on-chain. A
776
+ * transaction whose stamp no epoch can read has no entry, rather than an error, so a verdict on it still resolves.
777
+ */
778
+ private finalizedEntryFor;
779
+ /** Sync can record inclusion before the independent pending-status poller observes it. */
780
+ private reconcileFinalizedTransaction;
781
+ revertTransaction(tx: AnyTx, reason?: string): Promise<void>;
782
+ /**
783
+ * Starts the wallets and their background synchronization.
784
+ *
785
+ * @remarks
786
+ * Seeds, not key objects. A seed is the only key material that crosses a protocol boundary — every ledger version
787
+ * derives its own keys from the same seed and arrives at the same identity — so a wallet started from seeds can
788
+ * follow the chain across a fork, and one started from key objects of a single ledger version cannot. Derive them
789
+ * once with `WalletSeeds.fromMasterSeed` and hand them over.
790
+ *
791
+ * {@link FacadeKeysByEpoch} is the escape hatch for a caller that will not part with a seed. It requires **both**
792
+ * ledger versions' key objects, because a wallet holding one side could not read the other side of the chain, and
793
+ * it costs the caller an import of both ledger packages and the same derivation performed twice. A seed costs
794
+ * neither.
795
+ * @example
796
+ * ```typescript
797
+ * await facade.start(WalletSeeds.fromMasterSeed(masterSeed));
798
+ * ```;
799
+ *
800
+ * @param material The three wallets' seeds, or both ledger versions' key objects.
801
+ * @param options `manualSync` leaves the dust wallet unstarted in the background; drive it explicitly with
802
+ * {@link doSync} instead (requires a dust wallet built with the projections sync service, see
803
+ * `makeEventLessSyncService`).
804
+ */
805
+ start(material: FacadeStartMaterial, options?: FacadeStartOptions): Promise<void>;
806
+ /**
807
+ * Runs a single dust synchronization pass and resolves when it completes. Only the dust wallet supports manual sync;
808
+ * the shielded and unshielded wallets keep syncing in the background via {@link start}.
809
+ *
810
+ * @param material The same material {@link start} was given.
811
+ */
812
+ doSync(material: FacadeStartMaterial): Promise<void>;
470
813
  stop(): Promise<void>;
471
814
  queryTxHistoryByHash(hash: TransactionHistoryStorage.TransactionHash): Promise<WalletEntry | undefined>;
472
815
  getAllFromTxHistory(): Promise<WalletEntry[]>;