@midnight-ntwrk/wallet-sdk-dust-wallet 4.0.0 → 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.
@@ -7,6 +7,7 @@ import { type Balance, type CoinsAndBalancesCapability, type UtxoWithFullDustDet
7
7
  import { CoreWallet } from './v1/CoreWallet.js';
8
8
  import { type KeysCapability } from './v1/Keys.js';
9
9
  import { type SerializationCapability } from './v1/Serialization.js';
10
+ import { type NightUtxoSplitForDustRegistration } from './v1/Transacting.js';
10
11
  import { type DustFullInfo, type UtxoWithMeta } from './v1/types/Dust.js';
11
12
  import { type AnyTransaction } from './v1/types/ledger.js';
12
13
  import { type BaseV1Configuration, type DefaultV1Configuration, type V1Variant } from './v1/V1Builder.js';
@@ -41,7 +42,16 @@ export type DustWalletAPI<TStartAux = DustSecretKey, TSerialized = string> = {
41
42
  readonly state: rx.Observable<DustWalletState<TSerialized>>;
42
43
  start(secretKey: TStartAux): Promise<void>;
43
44
  createDustGenerationTransaction(currentTime: Date | undefined, ttl: Date, nightUtxos: Array<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined): Promise<UnprovenTransaction>;
45
+ splitNightUtxosForDustRegistration(currentTime: Date, nightUtxos: ReadonlyArray<UtxoWithMeta>, isRegistration: boolean): Promise<NightUtxoSplitForDustRegistration>;
46
+ attachDustRegistration(transaction: UnprovenTransaction, currentTime: Date, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined, feePayment: bigint): Promise<UnprovenTransaction>;
44
47
  addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Promise<UnprovenTransaction>;
48
+ /**
49
+ * Attaches a signature to the DustRegistration in segment 1's `dustActions` only. Unlike
50
+ * {@link addDustGenerationSignature}, this does NOT touch the unshielded offers — those should be signed separately
51
+ * via the unshielded-wallet signing path. Use this when the caller orchestrates signing across both packages (e.g.
52
+ * the facade's `signRecipe`).
53
+ */
54
+ addDustRegistrationSignature(transaction: UnprovenTransaction, signature: Signature): Promise<UnprovenTransaction>;
45
55
  calculateFee(transactions: ReadonlyArray<AnyTransaction>): Promise<bigint>;
46
56
  estimateFee(secretKey: DustSecretKey, transactions: ReadonlyArray<AnyTransaction>, ttl?: Date, currentTime?: Date): Promise<bigint>;
47
57
  balanceTransactions(secretKey: DustSecretKey, transactions: ReadonlyArray<AnyTransaction>, ttl: Date, currentTime?: Date): Promise<UnprovenTransaction>;
@@ -98,6 +98,20 @@ export function CustomDustWallet(configuration, builder) {
98
98
  })
99
99
  .pipe(Effect.runPromise);
100
100
  }
101
+ async splitNightUtxosForDustRegistration(currentTime, nightUtxos, isRegistration) {
102
+ return this.runtime
103
+ .dispatch({
104
+ [V1Tag]: (v1) => v1.splitNightUtxosForDustRegistration(currentTime, nightUtxos, isRegistration),
105
+ })
106
+ .pipe(Effect.runPromise);
107
+ }
108
+ async attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment) {
109
+ return this.runtime
110
+ .dispatch({
111
+ [V1Tag]: (v1) => v1.attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment),
112
+ })
113
+ .pipe(Effect.runPromise);
114
+ }
101
115
  addDustGenerationSignature(transaction, signature) {
102
116
  return this.runtime
103
117
  .dispatch({
@@ -105,6 +119,13 @@ export function CustomDustWallet(configuration, builder) {
105
119
  })
106
120
  .pipe(Effect.runPromise);
107
121
  }
122
+ addDustRegistrationSignature(transaction, signature) {
123
+ return this.runtime
124
+ .dispatch({
125
+ [V1Tag]: (v1) => v1.addDustRegistrationSignature(transaction, signature),
126
+ })
127
+ .pipe(Effect.runPromise);
128
+ }
108
129
  calculateFee(transactions) {
109
130
  return this.runtime
110
131
  .dispatch({
@@ -1,3 +1,4 @@
1
+ import { type CoinRecipe } from '@midnight-ntwrk/wallet-sdk-capabilities';
1
2
  import { type CoreWallet } from './CoreWallet.js';
2
3
  import { type KeysCapability } from './Keys.js';
3
4
  import { type DustGenerationDetails, type DustGenerationInfo, type Dust, type DustFullInfo, type UtxoWithMeta } from './types/Dust.js';
@@ -14,8 +15,8 @@ export type UtxoWithFullDustDetails = Readonly<{
14
15
  utxo: UtxoWithMeta;
15
16
  dust: DustGenerationDetails;
16
17
  }>;
17
- export type CoinSelection<TInput> = (coins: readonly CoinWithValue<TInput>[]) => CoinWithValue<TInput> | undefined;
18
- export declare const chooseCoin: <TInput>(coins: readonly CoinWithValue<TInput>[]) => CoinWithValue<TInput> | undefined;
18
+ export type CoinSelection = <TCoin extends CoinRecipe>(coins: readonly TCoin[]) => TCoin | undefined;
19
+ export declare const chooseCoin: CoinSelection;
19
20
  export type CoinsAndBalancesCapability<TState> = {
20
21
  getWalletBalance(state: TState, time: Date): Balance;
21
22
  getAvailableCoins(state: TState, time?: Date): readonly DustFullInfo[];
@@ -13,7 +13,10 @@
13
13
  import * as ledger from '@midnight-ntwrk/ledger-v8';
14
14
  import { DateOps } from '@midnight-ntwrk/wallet-sdk-utilities';
15
15
  import { pipe, Array as Arr, Order } from 'effect';
16
- export const chooseCoin = (coins) => coins.toSorted((a, b) => Number(a.value - b.value)).at(0);
16
+ export const chooseCoin = (coins) => coins
17
+ .filter((coin) => coin.value > 0n)
18
+ .toSorted((a, b) => Number(a.value - b.value))
19
+ .at(0);
17
20
  const FAKE_NONCE = '0'.repeat(64);
18
21
  export const makeDefaultCoinsAndBalancesCapability = (_config, getContext) => {
19
22
  const getWalletBalance = (state, time) => {
@@ -3,12 +3,12 @@ import { type TransactionHistoryService } from './TransactionHistory.js';
3
3
  import { type DustSecretKey, type Signature, type SignatureVerifyingKey, type FinalizedTransaction, type UnprovenTransaction } from '@midnight-ntwrk/ledger-v8';
4
4
  import { type WalletError } from './WalletError.js';
5
5
  import { type WalletRuntimeError, type Variant, StateChange } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
6
- import { type Dust, type UtxoWithMeta } from './types/Dust.js';
6
+ import { type UtxoWithMeta } from './types/Dust.js';
7
7
  import { type KeysCapability } from './Keys.js';
8
8
  import { type ChangesResult, type SyncCapability, type SyncService } from './Sync.js';
9
9
  import { type SimulatorState } from '@midnight-ntwrk/wallet-sdk-capabilities/simulation';
10
10
  import { type CoinsAndBalancesCapability, type CoinSelection } from './CoinsAndBalances.js';
11
- import { type TransactingCapability } from './Transacting.js';
11
+ import { type NightUtxoSplitForDustRegistration, type TransactingCapability } from './Transacting.js';
12
12
  import { type CoreWallet } from './CoreWallet.js';
13
13
  import { type SerializationCapability } from './Serialization.js';
14
14
  import { type AnyTransaction } from './types/ledger.js';
@@ -21,7 +21,7 @@ export declare namespace RunningV1Variant {
21
21
  transactingCapability: TransactingCapability<DustSecretKey, CoreWallet, TTransaction>;
22
22
  coinsAndBalancesCapability: CoinsAndBalancesCapability<CoreWallet>;
23
23
  keysCapability: KeysCapability<CoreWallet>;
24
- coinSelection: CoinSelection<Dust>;
24
+ coinSelection: CoinSelection;
25
25
  transactionHistoryService: TransactionHistoryService;
26
26
  };
27
27
  type AnyContext = Context<any, any, any, any>;
@@ -36,7 +36,10 @@ export declare class RunningV1Variant<TSerialized, TSyncUpdate, TTransaction, TS
36
36
  startSyncInBackground(startAux: TStartAux): Effect.Effect<void>;
37
37
  startSync(startAux: TStartAux): Stream.Stream<void, WalletError, Scope.Scope>;
38
38
  createDustGenerationTransaction(currentTime: Date | undefined, ttl: Date, nightUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined): Effect.Effect<UnprovenTransaction, WalletError>;
39
+ splitNightUtxosForDustRegistration(currentTime: Date, nightUtxos: ReadonlyArray<UtxoWithMeta>, isRegistration: boolean): Effect.Effect<NightUtxoSplitForDustRegistration, WalletError>;
40
+ attachDustRegistration(transaction: UnprovenTransaction, currentTime: Date, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined, feePayment: bigint): Effect.Effect<UnprovenTransaction, WalletError>;
39
41
  addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Effect.Effect<UnprovenTransaction, WalletError>;
42
+ addDustRegistrationSignature(transaction: UnprovenTransaction, signature: Signature): Effect.Effect<UnprovenTransaction, WalletError>;
40
43
  calculateFee(transactions: ReadonlyArray<AnyTransaction>): Effect.Effect<bigint, WalletError>;
41
44
  estimateFee(secretKey: DustSecretKey, transactions: ReadonlyArray<AnyTransaction>, ttl: Date, currentTime?: Date): Effect.Effect<bigint, WalletError>;
42
45
  balanceTransactions(secretKey: DustSecretKey, transactions: ReadonlyArray<AnyTransaction>, ttl: Date, currentTime?: Date): Effect.Effect<UnprovenTransaction, WalletError>;
@@ -82,19 +82,41 @@ export class RunningV1Variant {
82
82
  if (nightUtxos.some((utxo) => utxo.type !== nativeToken().raw)) {
83
83
  return Effect.fail(new OtherWalletError({ message: 'Token of a non-Night type received' }));
84
84
  }
85
- return Effect.Do.pipe(Effect.bind('currentState', () => SubscriptionRef.get(this.#context.stateRef)), Effect.bind('blockData', () => this.#v1Context.syncService.blockData()), Effect.let('currentTime', ({ blockData }) => currentTime ?? blockData.timestamp), Effect.let('utxosWithDustValue', ({ currentState, currentTime }) => {
86
- return this.#v1Context.coinsAndBalancesCapability.estimateDustGeneration(currentState, nightUtxos, currentTime);
87
- }), Effect.flatMap(({ utxosWithDustValue, currentTime }) => {
88
- return this.#v1Context.transactingCapability
89
- .createDustGenerationTransaction(currentTime, ttl, utxosWithDustValue, nightVerifyingKey, dustReceiverAddress)
85
+ return Effect.gen(this, function* () {
86
+ const currentState = yield* SubscriptionRef.get(this.#context.stateRef);
87
+ const blockData = yield* this.#v1Context.syncService.blockData();
88
+ const resolvedTime = currentTime ?? blockData.timestamp;
89
+ const utxosWithDustValue = this.#v1Context.coinsAndBalancesCapability.estimateDustGeneration(currentState, nightUtxos, resolvedTime);
90
+ return yield* this.#v1Context.transactingCapability
91
+ .createDustGenerationTransaction(resolvedTime, ttl, utxosWithDustValue, nightVerifyingKey, dustReceiverAddress)
90
92
  .pipe(EitherOps.toEffect);
91
- }));
93
+ });
94
+ }
95
+ splitNightUtxosForDustRegistration(currentTime, nightUtxos, isRegistration) {
96
+ if (nightUtxos.some((utxo) => utxo.type !== nativeToken().raw)) {
97
+ return Effect.fail(new OtherWalletError({ message: 'Token of a non-Night type received' }));
98
+ }
99
+ return Effect.gen(this, function* () {
100
+ const currentState = yield* SubscriptionRef.get(this.#context.stateRef);
101
+ const utxosWithDustValue = this.#v1Context.coinsAndBalancesCapability.estimateDustGeneration(currentState, nightUtxos, currentTime);
102
+ return this.#v1Context.transactingCapability.splitNightUtxosForDustRegistration(utxosWithDustValue, isRegistration);
103
+ });
104
+ }
105
+ attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment) {
106
+ return this.#v1Context.transactingCapability
107
+ .attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment)
108
+ .pipe(EitherOps.toEffect);
92
109
  }
93
110
  addDustGenerationSignature(transaction, signature) {
94
111
  return this.#v1Context.transactingCapability
95
112
  .addDustGenerationSignature(transaction, signature)
96
113
  .pipe(EitherOps.toEffect);
97
114
  }
115
+ addDustRegistrationSignature(transaction, signature) {
116
+ return this.#v1Context.transactingCapability
117
+ .addDustRegistrationSignature(transaction, signature)
118
+ .pipe(EitherOps.toEffect);
119
+ }
98
120
  calculateFee(transactions) {
99
121
  return pipe(this.#v1Context.syncService.blockData(), Effect.map((blockData) => pipe(transactions, Arr.map((transaction) => this.#v1Context.transactingCapability.calculateFee(transaction, blockData.ledgerParameters)), ArrayOps.sumBigInt)));
100
122
  }
@@ -6,11 +6,45 @@ import { CoreWallet } from './CoreWallet.js';
6
6
  import { type AnyTransaction, type Dust, type NetworkId, type TotalCostParameters } from './types/index.js';
7
7
  import { type CoinsAndBalancesCapability, type CoinSelection, type CoinWithValue, type UtxoWithFullDustDetails } from './CoinsAndBalances.js';
8
8
  import { type KeysCapability } from './Keys.js';
9
+ /**
10
+ * Result of splitting Night UTxOs into the guaranteed/fallible sections of a Dust registration or deregistration
11
+ * intent, together with the fee-payment allowance the registration may claim from dust generated by the guaranteed
12
+ * UTxO.
13
+ *
14
+ * For deregistration, `feePayment` is always `0n`.
15
+ */
16
+ export type NightUtxoSplitForDustRegistration = {
17
+ readonly guaranteedUtxos: ReadonlyArray<UtxoWithFullDustDetails>;
18
+ readonly fallibleUtxos: ReadonlyArray<UtxoWithFullDustDetails>;
19
+ readonly feePayment: bigint;
20
+ };
9
21
  export interface TransactingCapability<TSecrets, TState, _TTransaction> {
10
22
  readonly networkId: NetworkId;
11
23
  readonly costParams: TotalCostParameters;
12
24
  createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: ReadonlyArray<UtxoWithFullDustDetails>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined): Either.Either<UnprovenTransaction, WalletError>;
25
+ /**
26
+ * Decides which Night UTxOs belong in the guaranteed vs fallible section of a dust registration/deregistration
27
+ * transaction, and computes the fee-payment allowance the registration may claim from dust generated by the
28
+ * guaranteed UTxO.
29
+ *
30
+ * For deregistration (`isRegistration === false`) the fee-payment allowance is always `0n`.
31
+ */
32
+ splitNightUtxosForDustRegistration(utxosWithDustValue: ReadonlyArray<UtxoWithFullDustDetails>, isRegistration: boolean): NightUtxoSplitForDustRegistration;
33
+ /**
34
+ * Attaches a Dust registration / deregistration action onto the intent (at segment 1) of an unproven transaction
35
+ * whose offers have already been built (typically by the unshielded wallet's `rotateUtxos`). The Night UTxOs are
36
+ * assumed to already appear in the intent's guaranteed/fallible offers and to already be booked in the unshielded
37
+ * wallet state.
38
+ */
39
+ attachDustRegistration(transaction: UnprovenTransaction, currentTime: Date, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined, feePayment: bigint): Either.Either<UnprovenTransaction, WalletError>;
13
40
  addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Either.Either<UnprovenTransaction, WalletError>;
41
+ /**
42
+ * Attaches a signature to the DustRegistration in segment 1's `dustActions` only. Unlike
43
+ * {@link addDustGenerationSignature}, this does NOT touch the unshielded offers — those are expected to be signed via
44
+ * the unshielded-wallet signing path. Use this when the caller orchestrates signing across both packages (e.g. the
45
+ * facade's `signRecipe`).
46
+ */
47
+ addDustRegistrationSignature(transaction: UnprovenTransaction, signature: Signature): Either.Either<UnprovenTransaction, WalletError>;
14
48
  calculateFee(transaction: AnyTransaction, ledgerParams: LedgerParameters): bigint;
15
49
  estimateFee(secretKey: TSecrets, state: TState, transactions: ReadonlyArray<AnyTransaction>, ttl: Date, currentTime: Date, ledgerParams: LedgerParameters): Either.Either<bigint, WalletError>;
16
50
  balanceTransactions(secretKey: TSecrets, state: TState, transactions: ReadonlyArray<AnyTransaction>, ttl: Date, currentTime: Date, ledgerParams: LedgerParameters): Either.Either<[UnprovenTransaction, TState], WalletError>;
@@ -21,7 +55,7 @@ export type DefaultTransactingConfiguration = {
21
55
  costParameters: TotalCostParameters;
22
56
  };
23
57
  export type DefaultTransactingContext = {
24
- coinSelection: CoinSelection<Dust>;
58
+ coinSelection: CoinSelection;
25
59
  coinsAndBalancesCapability: CoinsAndBalancesCapability<CoreWallet>;
26
60
  keysCapability: KeysCapability<CoreWallet>;
27
61
  };
@@ -41,11 +75,14 @@ export declare const findAvailableSegmentId: (transaction: AnyTransaction) => Op
41
75
  export declare class TransactingCapabilityImplementation<TTransaction extends AnyTransaction> implements TransactingCapability<DustSecretKey, CoreWallet, TTransaction> {
42
76
  readonly networkId: string;
43
77
  readonly costParams: TotalCostParameters;
44
- readonly getCoinSelection: () => CoinSelection<Dust>;
78
+ readonly getCoinSelection: () => CoinSelection;
45
79
  readonly getCoins: () => CoinsAndBalancesCapability<CoreWallet>;
46
80
  readonly getKeys: () => KeysCapability<CoreWallet>;
47
- constructor(networkId: NetworkId, costParams: TotalCostParameters, getCoinSelection: () => CoinSelection<Dust>, getCoins: () => CoinsAndBalancesCapability<CoreWallet>, getKeys: () => KeysCapability<CoreWallet>);
81
+ constructor(networkId: NetworkId, costParams: TotalCostParameters, getCoinSelection: () => CoinSelection, getCoins: () => CoinsAndBalancesCapability<CoreWallet>, getKeys: () => KeysCapability<CoreWallet>);
48
82
  createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: ReadonlyArray<UtxoWithFullDustDetails>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined): Either.Either<UnprovenTransaction, WalletError>;
83
+ splitNightUtxosForDustRegistration(utxosWithDustValue: ReadonlyArray<UtxoWithFullDustDetails>, isRegistration: boolean): NightUtxoSplitForDustRegistration;
84
+ attachDustRegistration(transaction: UnprovenTransaction, currentTime: Date, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: DustAddress | undefined, feePayment: bigint): Either.Either<UnprovenTransaction, WalletError>;
85
+ addDustRegistrationSignature(transaction: UnprovenTransaction, signatureData: Signature): Either.Either<UnprovenTransaction, WalletError>;
49
86
  addDustGenerationSignature(transaction: UnprovenTransaction, signatureData: Signature): Either.Either<UnprovenTransaction, WalletError>;
50
87
  calculateFee(transaction: AnyTransaction, ledgerParams: LedgerParameters): bigint;
51
88
  dryRunFee(recipeInputs: ReadonlyArray<CoinWithValue<Dust>>, transactions: ReadonlyArray<FinalizedTransaction | UnprovenTransaction>, secretKey: DustSecretKey, state: CoreWallet, ttl: Date, currentTime: Date, ledgerParams: LedgerParameters): bigint;
@@ -108,6 +108,72 @@ export class TransactingCapabilityImplementation {
108
108
  });
109
109
  });
110
110
  }
111
+ splitNightUtxosForDustRegistration(utxosWithDustValue, isRegistration) {
112
+ const splitResult = this.getCoins().splitNightUtxos(utxosWithDustValue);
113
+ // Deregistration must not claim dust as fee payment (matches the historical
114
+ // `dustReceiverAddress === undefined` branch of createDustGenerationTransaction).
115
+ const feePayment = isRegistration
116
+ ? pipe(splitResult.guaranteed, IterableOps.filter((coin) => !coin.utxo.registeredForDustGeneration), IterableOps.map((coin) => coin.dust.generatedNow), BigIntOps.sumAll)
117
+ : 0n;
118
+ return {
119
+ guaranteedUtxos: splitResult.guaranteed,
120
+ fallibleUtxos: splitResult.fallible,
121
+ feePayment,
122
+ };
123
+ }
124
+ attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment) {
125
+ return Either.gen(this, function* () {
126
+ const intent = transaction.intents?.get(1);
127
+ if (!intent) {
128
+ return yield* Either.left(new TransactingError({
129
+ message: 'No intent found at segment 1; expected an intent built by rotateUtxos',
130
+ }));
131
+ }
132
+ if (intent.dustActions !== undefined && intent.dustActions.registrations.length > 0) {
133
+ return yield* Either.left(new TransactingError({ message: 'Intent at segment 1 already has a dust registration attached' }));
134
+ }
135
+ return yield* LedgerOps.ledgerTry(() => {
136
+ const receiver = dustReceiverAddress ? dustReceiverAddress.data : undefined;
137
+ const dustRegistration = new DustRegistration(SignatureMarker.signature, nightVerifyingKey, receiver, feePayment);
138
+ const dustActions = new DustActions(SignatureMarker.signature, ProofMarker.preProof, currentTime, [], [dustRegistration]);
139
+ // Intents fetched from `transaction.intents.get(...)` behave like value copies — assigning
140
+ // to a field doesn't propagate back. Match the addDustGenerationSignature pattern: copy the
141
+ // intent via serialize/deserialize, mutate the copy, then set it back into a fresh
142
+ // transaction's intents map.
143
+ const newIntent = Intent.deserialize(SignatureMarker.signature, ProofMarker.preProof, BindingMarker.preBinding, intent.serialize());
144
+ newIntent.dustActions = dustActions;
145
+ const newTransaction = Transaction.deserialize(SignatureMarker.signature, ProofMarker.preProof, BindingMarker.preBinding, transaction.serialize());
146
+ newTransaction.intents = newTransaction.intents.set(1, newIntent);
147
+ return newTransaction;
148
+ });
149
+ });
150
+ }
151
+ addDustRegistrationSignature(transaction, signatureData) {
152
+ return Either.gen(this, function* () {
153
+ const intent = transaction.intents?.get(1);
154
+ if (!intent) {
155
+ return yield* Either.left(new TransactingError({ message: 'No intent found in the transaction intents with segment = 1' }));
156
+ }
157
+ const { dustActions } = intent;
158
+ if (!dustActions) {
159
+ return yield* Either.left(new TransactingError({ message: 'No dustActions found in intent' }));
160
+ }
161
+ const [registration, ...restRegistrations] = dustActions.registrations;
162
+ if (!registration) {
163
+ return yield* Either.left(new TransactingError({ message: 'No registrations found in dustActions' }));
164
+ }
165
+ return yield* LedgerOps.ledgerTry(() => {
166
+ const signature = new SignatureEnabled(signatureData);
167
+ const registrationWithSignature = new DustRegistration(signature.instance, registration.nightKey, registration.dustAddress, registration.allowFeePayment, signature);
168
+ const newDustActions = new DustActions(signature.instance, ProofMarker.preProof, dustActions.ctime, dustActions.spends, [registrationWithSignature, ...restRegistrations]);
169
+ const newIntent = Intent.deserialize(signature.instance, ProofMarker.preProof, BindingMarker.preBinding, intent.serialize());
170
+ newIntent.dustActions = newDustActions;
171
+ const newTransaction = Transaction.deserialize(signature.instance, ProofMarker.preProof, BindingMarker.preBinding, transaction.serialize());
172
+ newTransaction.intents = newTransaction.intents.set(1, newIntent);
173
+ return newTransaction;
174
+ });
175
+ });
176
+ }
111
177
  addDustGenerationSignature(transaction, signatureData) {
112
178
  return Either.gen(this, function* () {
113
179
  const intent = transaction.intents?.get(1);
@@ -167,9 +233,7 @@ export class TransactingCapabilityImplementation {
167
233
  const [first, ...rest] = transactions.map((tx) => tx.eraseProofs());
168
234
  const mergedExisting = first ? rest.reduce((acc, tx) => acc.merge(tx), first) : undefined;
169
235
  const segmentId = mergedExisting ? Option.getOrElse(findAvailableSegmentId(mergedExisting), () => 1) : 1;
170
- // @TODO in ledger 8.1.0 will be able to set the segment id when constructing the tx
171
- const balancingTx = Transaction.fromParts(network, undefined, undefined, undefined);
172
- balancingTx.intents = new Map([[segmentId, intent]]);
236
+ const balancingTx = Transaction.fromParts(network).addIntent({ tag: 'specific', value: segmentId }, intent);
173
237
  const erasedBalancing = balancingTx.eraseProofs();
174
238
  const mergedTx = mergedExisting ? mergedExisting.merge(erasedBalancing) : erasedBalancing;
175
239
  return this.calculateFee(mergedTx, ledgerParams);
@@ -197,14 +261,15 @@ export class TransactingCapabilityImplementation {
197
261
  })),
198
262
  initialImbalances: CapImbalances.fromEntry('dust', currentFee),
199
263
  feeTokenType: 'dust',
264
+ coinSelection: this.getCoinSelection(),
200
265
  transactionCostModel: {
201
266
  inputFeeOverhead: 0n,
202
267
  outputFeeOverhead: 0n,
203
268
  },
204
269
  createOutput: (coin) => coin,
205
- isCoinEqual: (a, b) => a.type === b.type && a.value === b.value,
270
+ isCoinEqual: (a, b) => a.token.nonce === b.token.nonce,
206
271
  });
207
- const recipeInputs = recipe.inputs.map((input) => ({ token: input.token, value: input.value }));
272
+ const recipeInputs = recipe.inputs.map(({ token, value }) => ({ token, value }));
208
273
  const newFee = this.dryRunFee(recipeInputs, transactions, secretKey, state, ttl, currentTime, ledgerParams);
209
274
  const recipeAmountCoverage = recipeInputs.reduce((sum, input) => sum + input.value, 0n);
210
275
  return { currentFee: newFee, recipeInputs, converged: newFee <= recipeAmountCoverage };
@@ -243,8 +308,7 @@ export class TransactingCapabilityImplementation {
243
308
  const [first, ...rest] = transactions.map((tx) => tx.eraseProofs());
244
309
  const mergedExisting = first ? rest.reduce((acc, tx) => acc.merge(tx), first) : undefined;
245
310
  const segmentId = mergedExisting ? Option.getOrElse(findAvailableSegmentId(mergedExisting), () => 1) : 1;
246
- const feeTransaction = Transaction.fromParts(networkId, undefined, undefined, undefined);
247
- feeTransaction.intents = new Map([[segmentId, intent]]);
311
+ const feeTransaction = Transaction.fromParts(networkId).addIntent({ tag: 'specific', value: segmentId }, intent);
248
312
  return [feeTransaction, updatedState];
249
313
  });
250
314
  }));
@@ -10,7 +10,6 @@ import { type KeysCapability } from './Keys.js';
10
10
  import { type CoinsAndBalancesCapability, type CoinSelection, type DefaultCoinsAndBalancesContext } from './CoinsAndBalances.js';
11
11
  import { type DefaultTransactingConfiguration, type DefaultTransactingContext, type TransactingCapability } from './Transacting.js';
12
12
  import { type NetworkId } from './types/ledger.js';
13
- import { type Dust } from './types/Dust.js';
14
13
  import { type SerializationCapability } from './Serialization.js';
15
14
  import { type TotalCostParameters } from './types/transaction.js';
16
15
  export type BaseV1Configuration = {
@@ -43,7 +42,7 @@ export declare class V1Builder<TConfig extends BaseV1Configuration = BaseV1Confi
43
42
  withSerialization<TSerializationConfig, TSerializationContext extends Partial<RunningV1Variant.AnyContext>, TSerialized>(serializationCapability: (configuration: TSerializationConfig, getContext: () => TSerializationContext) => SerializationCapability<CoreWallet, null, TSerialized>): V1Builder<TConfig & TSerializationConfig, TContext & TSerializationContext, TSerialized, TSyncUpdate, TTransaction, TStartAux>;
44
43
  withTransactingDefaults(this: V1Builder<TConfig, TContext, TSerialized, TSyncUpdate, FinalizedTransaction, TStartAux>): V1Builder<TConfig & DefaultTransactingConfiguration, TContext & DefaultTransactingContext, TSerialized, TSyncUpdate, FinalizedTransaction, TStartAux>;
45
44
  withTransacting<TTransactingConfig, TTransactingContext extends Partial<RunningV1Variant.AnyContext>>(transactingCapability: (config: TTransactingConfig, getContext: () => TTransactingContext) => TransactingCapability<DustSecretKey, CoreWallet, TTransaction>): V1Builder<TConfig & TTransactingConfig, TContext & TTransactingContext, TSerialized, TSyncUpdate, TTransaction, TStartAux>;
46
- withCoinSelection<TCoinSelectionConfig, TCoinSelectionContext extends Partial<RunningV1Variant.AnyContext>>(coinSelection: (config: TCoinSelectionConfig, getContext: () => TCoinSelectionContext) => CoinSelection<Dust>): V1Builder<TConfig & TCoinSelectionConfig, TContext & TCoinSelectionContext, TSerialized, TSyncUpdate, TTransaction, TStartAux>;
45
+ withCoinSelection<TCoinSelectionConfig, TCoinSelectionContext extends Partial<RunningV1Variant.AnyContext>>(coinSelection: (config: TCoinSelectionConfig, getContext: () => TCoinSelectionContext) => CoinSelection): V1Builder<TConfig & TCoinSelectionConfig, TContext & TCoinSelectionContext, TSerialized, TSyncUpdate, TTransaction, TStartAux>;
47
46
  withCoinSelectionDefaults(): V1Builder<TConfig, TContext, TSerialized, TSyncUpdate, TTransaction, TStartAux>;
48
47
  withCoinsAndBalancesDefaults(): V1Builder<TConfig, TContext & DefaultCoinsAndBalancesContext, TSerialized, TSyncUpdate, TTransaction, TStartAux>;
49
48
  withCoinsAndBalances<TBalancesConfig, TBalancesContext extends Partial<RunningV1Variant.AnyContext>>(coinsAndBalancesCapability: (configuration: TBalancesConfig, getContext: () => TBalancesContext) => CoinsAndBalancesCapability<CoreWallet>): V1Builder<TConfig & TBalancesConfig, TContext & TBalancesContext, TSerialized, TSyncUpdate, TTransaction, TStartAux>;
@@ -66,7 +65,7 @@ declare namespace V1Builder {
66
65
  readonly serializationCapability: (configuration: TConfig, getContext: () => TContext) => SerializationCapability<CoreWallet, null, TSerialized>;
67
66
  };
68
67
  type HasCoinSelection<TConfig, TContext> = {
69
- readonly coinSelection: (configuration: TConfig, getContext: () => TContext) => CoinSelection<Dust>;
68
+ readonly coinSelection: (configuration: TConfig, getContext: () => TContext) => CoinSelection;
70
69
  };
71
70
  type HasCoinsAndBalances<TConfig, TContext> = {
72
71
  readonly coinsAndBalancesCapability: (configuration: TConfig, getContext: () => TContext) => CoinsAndBalancesCapability<CoreWallet>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midnight-ntwrk/wallet-sdk-dust-wallet",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -28,13 +28,13 @@
28
28
  }
29
29
  },
30
30
  "dependencies": {
31
- "@midnight-ntwrk/ledger-v8": "^8.0.3",
32
- "@midnight-ntwrk/wallet-sdk-abstractions": "2.1.0",
33
- "@midnight-ntwrk/wallet-sdk-address-format": "3.1.1",
34
- "@midnight-ntwrk/wallet-sdk-capabilities": "3.3.0",
35
- "@midnight-ntwrk/wallet-sdk-indexer-client": "1.2.1",
36
- "@midnight-ntwrk/wallet-sdk-runtime": "1.0.3",
37
- "@midnight-ntwrk/wallet-sdk-utilities": "1.1.1",
31
+ "@midnight-ntwrk/ledger-v8": "^8.1.0",
32
+ "@midnight-ntwrk/wallet-sdk-abstractions": "^2.1.0",
33
+ "@midnight-ntwrk/wallet-sdk-address-format": "^3.1.2",
34
+ "@midnight-ntwrk/wallet-sdk-capabilities": "^3.3.1",
35
+ "@midnight-ntwrk/wallet-sdk-indexer-client": "^1.2.2",
36
+ "@midnight-ntwrk/wallet-sdk-runtime": "^1.0.4",
37
+ "@midnight-ntwrk/wallet-sdk-utilities": "^1.2.0",
38
38
  "effect": "^3.19.19",
39
39
  "rxjs": "^7.8.2"
40
40
  },
@@ -50,6 +50,6 @@
50
50
  "publint": "publint --strict"
51
51
  },
52
52
  "devDependencies": {
53
- "@midnight-ntwrk/wallet-sdk-hd": "3.0.2"
53
+ "@midnight-ntwrk/wallet-sdk-hd": "^3.0.2"
54
54
  }
55
55
  }