@midnight-ntwrk/wallet-sdk-dust-wallet 1.0.0-beta.8 → 1.0.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,98 @@
1
- # Wallet SDK Dust Wallet
1
+ # @midnight-ntwrk/wallet-sdk-dust-wallet
2
2
 
3
- TBD
3
+ Manages dust tokens (transaction fees) on the Midnight network.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @midnight-ntwrk/wallet-sdk-dust-wallet
9
+ ```
10
+
11
+ ## Overview
12
+
13
+ The Dust Wallet handles dust operations on the Midnight network. Dust tokens are required to pay transaction fees. This
14
+ package provides:
15
+
16
+ - Dust coin management and tracking
17
+ - Balance synchronization with the network
18
+ - Transaction fee calculation
19
+ - Dust generation from Night UTXOs
20
+ - Fee balancing for transactions
21
+
22
+ ## Usage
23
+
24
+ ### Starting the Wallet
25
+
26
+ ```typescript
27
+ import { DustWallet } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
28
+
29
+ await dustWallet.start(dustSecretKey);
30
+ ```
31
+
32
+ ### Observing State
33
+
34
+ ```typescript
35
+ dustWallet.state.subscribe((state) => {
36
+ console.log('Progress:', state.state.progress);
37
+ console.log('Balance:', state.state.balance);
38
+ console.log('Dust Address:', state.dustAddress);
39
+ });
40
+
41
+ // Or wait for sync
42
+ const syncedState = await dustWallet.waitForSyncedState();
43
+ ```
44
+
45
+ ### Balancing Transaction Fees
46
+
47
+ ```typescript
48
+ // Add fee balancing to a transaction
49
+ const feeBalancingTx = await dustWallet.balanceTransactions(dustSecretKey, [transactionToBalance], ttl);
50
+ ```
51
+
52
+ ### Calculating Fees
53
+
54
+ ```typescript
55
+ const fee = await dustWallet.calculateFee([transaction]);
56
+ ```
57
+
58
+ ### Dust Generation
59
+
60
+ Register Night UTXOs to generate dust:
61
+
62
+ ```typescript
63
+ const dustGenerationTx = await dustWallet.createDustGenerationTransaction(
64
+ previousState,
65
+ ttl,
66
+ nightUtxos,
67
+ nightVerifyingKey,
68
+ dustReceiverAddress,
69
+ );
70
+
71
+ // Add signature for dust registration
72
+ const signedTx = await dustWallet.addDustGenerationSignature(dustGenerationTx, signature);
73
+ ```
74
+
75
+ ## Exports
76
+
77
+ - `DustWallet` - Main wallet class
78
+ - `DustWalletState` - Wallet state type
79
+ - `DustCoreWallet` - Core wallet implementation
80
+ - `Keys` - Key management utilities
81
+ - `Simulator` - Dust simulation utilities
82
+ - `SyncService` - Synchronization service
83
+ - `Transacting` - Transaction utilities
84
+ - `CoinsAndBalances` - Coin and balance management
85
+
86
+ ## V1 Builder
87
+
88
+ Use the V1 builder pattern for wallet construction:
89
+
90
+ ```typescript
91
+ import { V1Builder, RunningV1Variant } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
92
+
93
+ // Build a V1 dust wallet variant
94
+ ```
95
+
96
+ ## License
97
+
98
+ Apache-2.0
@@ -1,10 +1,15 @@
1
1
  import { DustCoreWallet } from './DustCoreWallet.js';
2
- import { DustGenerationInfo, DustToken, DustTokenFullInfo } from './types/Dust.js';
2
+ import { KeysCapability } from './Keys.js';
3
+ import { DustGenerationDetails, DustGenerationInfo, DustToken, DustTokenFullInfo, UtxoWithMeta } from './types/Dust.js';
3
4
  export type Balance = bigint;
4
5
  export type CoinWithValue<TToken> = {
5
6
  token: TToken;
6
7
  value: Balance;
7
8
  };
9
+ export type UtxoWithFullDustDetails = Readonly<{
10
+ utxo: UtxoWithMeta;
11
+ dust: DustGenerationDetails;
12
+ }>;
8
13
  export type CoinSelection<TInput> = (coins: readonly CoinWithValue<TInput>[], amountNeeded: Balance) => CoinWithValue<TInput>[];
9
14
  export declare const chooseCoin: <TInput>(coins: readonly CoinWithValue<TInput>[], amountNeeded: Balance) => CoinWithValue<TInput>[];
10
15
  export type CoinsAndBalancesCapability<TState> = {
@@ -15,5 +20,24 @@ export type CoinsAndBalancesCapability<TState> = {
15
20
  getAvailableCoinsWithGeneratedDust(state: TState, currentTime: Date): ReadonlyArray<CoinWithValue<DustToken>>;
16
21
  getAvailableCoinsWithFullInfo(state: TState, blockTime: Date): readonly DustTokenFullInfo[];
17
22
  getGenerationInfo(state: TState, token: DustToken): DustGenerationInfo | undefined;
23
+ /**
24
+ * Splits provided Night utxos into the ones that will be used as inputs in the guaranteed and fallible sections
25
+ */
26
+ splitNightUtxos(nightUtxos: ReadonlyArray<UtxoWithFullDustDetails>): {
27
+ guaranteed: ReadonlyArray<UtxoWithFullDustDetails>;
28
+ fallible: ReadonlyArray<UtxoWithFullDustDetails>;
29
+ };
30
+ /**
31
+ * Estimate how much Dust would be available to use if the Utxos provided were used for Dust generation from their beginning.
32
+ * This function is particularly useful for the purpose of registering for Dust generation and selecting the Utxo to be used for paying fees and approving the registration itself.
33
+ * @param state Current state of the wallet
34
+ * @param nightUtxos Existing Night utxos
35
+ * @param currentTime Current time
36
+ * @returns Estimated Dust generation per Utxo
37
+ */
38
+ estimateDustGeneration(state: TState, nightUtxos: ReadonlyArray<UtxoWithMeta>, currentTime: Date): ReadonlyArray<UtxoWithFullDustDetails>;
18
39
  };
19
- export declare const makeDefaultCoinsAndBalancesCapability: () => CoinsAndBalancesCapability<DustCoreWallet>;
40
+ export type DefaultCoinsAndBalancesContext = {
41
+ keysCapability: KeysCapability<DustCoreWallet>;
42
+ };
43
+ export declare const makeDefaultCoinsAndBalancesCapability: (config: object, getContext: () => DefaultCoinsAndBalancesContext) => CoinsAndBalancesCapability<DustCoreWallet>;
@@ -1,6 +1,18 @@
1
- import { Array, pipe } from 'effect';
2
- import { updatedValue } from '@midnight-ntwrk/ledger-v6';
1
+ // This file is part of MIDNIGHT-WALLET-SDK.
2
+ // Copyright (C) 2025 Midnight Foundation
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // You may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
3
14
  import { DateOps } from '@midnight-ntwrk/wallet-sdk-utilities';
15
+ import { pipe, Array as Arr, Order } from 'effect';
4
16
  export const chooseCoin = (coins, amountNeeded) => {
5
17
  let sum = 0n;
6
18
  const sorted = coins.toSorted((a, b) => Number(a.value - b.value));
@@ -13,13 +25,14 @@ export const chooseCoin = (coins, amountNeeded) => {
13
25
  }
14
26
  return result;
15
27
  };
16
- export const makeDefaultCoinsAndBalancesCapability = () => {
28
+ const FAKE_NONCE = '0'.repeat(64);
29
+ export const makeDefaultCoinsAndBalancesCapability = (config, getContext) => {
17
30
  const getWalletBalance = (state, time) => {
18
31
  return state.state.walletBalance(time);
19
32
  };
20
33
  const getAvailableCoins = (state) => {
21
34
  const pendingSpends = new Set([...state.pendingDustTokens.values()].map((coin) => coin.nonce));
22
- return pipe(state.state.utxos, Array.filter((coin) => !pendingSpends.has(coin.nonce)));
35
+ return pipe(state.state.utxos, Arr.filter((coin) => !pendingSpends.has(coin.nonce)));
23
36
  };
24
37
  const getPendingCoins = (state) => state.pendingDustTokens;
25
38
  const getTotalCoins = (state) => [
@@ -41,7 +54,7 @@ export const makeDefaultCoinsAndBalancesCapability = () => {
41
54
  for (const coin of available) {
42
55
  const genInfo = getGenerationInfo(state, coin);
43
56
  if (genInfo) {
44
- const generatedValue = updatedValue(coin.ctime, coin.initialValue, genInfo, currentTime, state.state.params);
57
+ const generatedValue = ledger.updatedValue(coin.ctime, coin.initialValue, genInfo, currentTime, state.state.params);
45
58
  result.push({ token: coin, value: generatedValue });
46
59
  }
47
60
  }
@@ -53,19 +66,60 @@ export const makeDefaultCoinsAndBalancesCapability = () => {
53
66
  for (const coin of available) {
54
67
  const genInfo = getGenerationInfo(state, coin);
55
68
  if (genInfo) {
56
- const generatedValue = updatedValue(coin.ctime, coin.initialValue, genInfo, blockTime, state.state.params);
57
69
  result.push({
58
70
  token: coin,
59
- dtime: genInfo.dtime,
60
- maxCap: genInfo.value * state.state.params.nightDustRatio,
61
- maxCapReachedAt: DateOps.addSeconds(coin.ctime, state.state.params.timeToCapSeconds),
62
- generatedNow: generatedValue,
63
- rate: genInfo.value * state.state.params.generationDecayRate,
71
+ ...getFullDustInfo(state.state.params, genInfo, coin, blockTime),
64
72
  });
65
73
  }
66
74
  }
67
75
  return result;
68
76
  };
77
+ const getFullDustInfo = (parameters, genInfo, coin, currentTime) => {
78
+ const generatedValue = ledger.updatedValue(coin.ctime, coin.initialValue, genInfo, currentTime, parameters);
79
+ return {
80
+ dtime: genInfo.dtime,
81
+ maxCap: genInfo.value * parameters.nightDustRatio,
82
+ maxCapReachedAt: DateOps.addSeconds(coin.ctime, parameters.timeToCapSeconds),
83
+ generatedNow: generatedValue,
84
+ rate: genInfo.value * parameters.generationDecayRate,
85
+ };
86
+ };
87
+ const estimateDustGeneration = (state, nightUtxos, currentTime) => {
88
+ const dustPublicKey = getContext().keysCapability.getDustPublicKey(state);
89
+ return pipe(nightUtxos, Arr.map((utxo) => {
90
+ const genInfo = fakeGenerationInfo(utxo, dustPublicKey);
91
+ const fakeDustCoin = fakeDustToken(dustPublicKey, utxo);
92
+ const details = getFullDustInfo(state.state.params, genInfo, fakeDustCoin, currentTime);
93
+ return { utxo, dust: details };
94
+ }));
95
+ };
96
+ /**
97
+ * Create a fake generation info for a given Utxo. It allows to estimate the Dust generation from it
98
+ */
99
+ const fakeGenerationInfo = (utxo, dustPublicKey) => {
100
+ return {
101
+ value: utxo.value,
102
+ owner: dustPublicKey,
103
+ nonce: FAKE_NONCE,
104
+ dtime: undefined,
105
+ };
106
+ };
107
+ /**
108
+ * Create a fake dust coin for a given Utxo. It allows to estimate full details of the Dust generation from it
109
+ */
110
+ const fakeDustToken = (dustPublicKey, utxo) => ({
111
+ initialValue: 0n,
112
+ owner: dustPublicKey,
113
+ nonce: 0n,
114
+ seq: 0,
115
+ ctime: utxo.ctime,
116
+ backingNight: '',
117
+ mtIndex: 0n,
118
+ });
119
+ const splitNightUtxos = (utxos) => {
120
+ const [guaranteed, fallible] = pipe(utxos, Arr.sort(pipe(Order.bigint, Order.reverse, Order.mapInput((coin) => coin.dust.generatedNow))), Arr.splitAt(1));
121
+ return { guaranteed, fallible };
122
+ };
69
123
  return {
70
124
  getWalletBalance,
71
125
  getAvailableCoins,
@@ -74,5 +128,7 @@ export const makeDefaultCoinsAndBalancesCapability = () => {
74
128
  getAvailableCoinsWithGeneratedDust,
75
129
  getAvailableCoinsWithFullInfo,
76
130
  getGenerationInfo,
131
+ estimateDustGeneration,
132
+ splitNightUtxos,
77
133
  };
78
134
  };
@@ -1,4 +1,4 @@
1
- import { Bindingish, DustLocalState, DustNullifier, DustParameters, DustPublicKey, DustSecretKey, Proofish, Signaturish, Transaction, Event } from '@midnight-ntwrk/ledger-v6';
1
+ import { Bindingish, DustLocalState, DustNullifier, DustParameters, DustPublicKey, DustSecretKey, Proofish, Signaturish, Transaction, Event } from '@midnight-ntwrk/ledger-v7';
2
2
  import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
3
  import { SyncProgress } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
4
4
  import { DustToken, DustTokenWithNullifier } from './types/Dust.js';
@@ -1,4 +1,16 @@
1
- import { DustLocalState, } from '@midnight-ntwrk/ledger-v6';
1
+ // This file is part of MIDNIGHT-WALLET-SDK.
2
+ // Copyright (C) 2025 Midnight Foundation
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // You may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ import { DustLocalState, } from '@midnight-ntwrk/ledger-v7';
2
14
  import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
15
  import { SyncProgress } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
4
16
  import { DateOps } from '@midnight-ntwrk/wallet-sdk-utilities';
@@ -40,6 +52,7 @@ export class DustCoreWallet {
40
52
  applyEvents(secretKey, events, currentTime) {
41
53
  if (!events.length)
42
54
  return this;
55
+ // TODO: replace currentTime with `updatedState.syncTime` introduced in ledger-6.2.0-rc.1
43
56
  const updatedState = this.state.replayEvents(secretKey, events).processTtls(currentTime);
44
57
  let updatedPending = this.pendingDustTokens;
45
58
  if (updatedPending.length) {
@@ -1,15 +1,15 @@
1
- import { DustParameters, DustPublicKey, DustSecretKey, FinalizedTransaction, Signature, SignatureVerifyingKey, UnprovenTransaction } from '@midnight-ntwrk/ledger-v6';
1
+ import { DustParameters, DustPublicKey, DustSecretKey, FinalizedTransaction, Signature, SignatureVerifyingKey, UnprovenTransaction } from '@midnight-ntwrk/ledger-v7';
2
2
  import { ProtocolState, ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
3
  import { Variant, WalletLike } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
4
- import { ProvingRecipe, TransactionHistory } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
4
+ import { TransactionHistory } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
5
5
  import * as rx from 'rxjs';
6
- import { Balance, CoinsAndBalancesCapability } from './CoinsAndBalances.js';
6
+ import { Balance, CoinsAndBalancesCapability, UtxoWithFullDustDetails } from './CoinsAndBalances.js';
7
7
  import { DustCoreWallet } from './DustCoreWallet.js';
8
8
  import { KeysCapability } from './Keys.js';
9
9
  import { SerializationCapability } from './Serialization.js';
10
10
  import { SubmitTransactionMethod } from './Submission.js';
11
11
  import { DustToken, DustTokenFullInfo, UtxoWithMeta } from './types/Dust.js';
12
- import { AnyTransaction, NetworkId } from './types/ledger.js';
12
+ import { AnyTransaction } from './types/ledger.js';
13
13
  import { DefaultV1Configuration, DefaultV1Variant } from './V1Builder.js';
14
14
  export type DustWalletCapabilities = {
15
15
  serialization: SerializationCapability<DustCoreWallet, null, string>;
@@ -30,22 +30,24 @@ export declare class DustWalletState {
30
30
  constructor(state: ProtocolState.ProtocolState<DustCoreWallet>, capabilities: DustWalletCapabilities);
31
31
  walletBalance(time: Date): Balance;
32
32
  availableCoinsWithFullInfo(time: Date): readonly DustTokenFullInfo[];
33
+ estimateDustGeneration(nightUtxos: ReadonlyArray<UtxoWithMeta>, currentTime: Date): ReadonlyArray<UtxoWithFullDustDetails>;
33
34
  serialize(): string;
34
35
  }
35
36
  export interface DustWallet extends WalletLike.WalletLike<[Variant.VersionedVariant<DefaultV1Variant>]> {
36
37
  readonly state: rx.Observable<DustWalletState>;
37
38
  start(secretKey: DustSecretKey): Promise<void>;
38
- createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: Array<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Promise<UnprovenTransaction>;
39
- addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Promise<ProvingRecipe.ProvingRecipe<FinalizedTransaction>>;
40
- calculateFee(transaction: AnyTransaction): Promise<bigint>;
41
- addFeePayment(secretKey: DustSecretKey, transaction: UnprovenTransaction, currentTime: Date, ttl: Date): Promise<ProvingRecipe.ProvingRecipe<FinalizedTransaction>>;
42
- finalizeTransaction(recipe: ProvingRecipe.ProvingRecipe<FinalizedTransaction>): Promise<FinalizedTransaction>;
39
+ createDustGenerationTransaction(currentTime: Date | undefined, ttl: Date, nightUtxos: Array<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Promise<UnprovenTransaction>;
40
+ addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Promise<UnprovenTransaction>;
41
+ calculateFee(transactions: ReadonlyArray<AnyTransaction>): Promise<bigint>;
42
+ balanceTransactions(secretKey: DustSecretKey, transactions: ReadonlyArray<AnyTransaction>, ttl: Date, currentTime?: Date): Promise<UnprovenTransaction>;
43
+ proveTransaction(transaction: UnprovenTransaction): Promise<FinalizedTransaction>;
43
44
  readonly submitTransaction: SubmitTransactionMethod<FinalizedTransaction>;
44
45
  serializeState(): Promise<string>;
45
46
  waitForSyncedState(allowedGap?: bigint): Promise<DustWalletState>;
46
47
  }
47
48
  export interface DustWalletClass extends WalletLike.BaseWalletClass<[Variant.VersionedVariant<DefaultV1Variant>]> {
48
- startWithSeed(seed: Uint8Array, dustParameters: DustParameters, networkId: NetworkId): DustWallet;
49
+ startWithSeed(seed: Uint8Array, dustParameters: DustParameters): DustWallet;
50
+ startWithSecretKey(secretKey: DustSecretKey, dustParameters: DustParameters): DustWallet;
49
51
  restore(serializedState: string): DustWallet;
50
52
  }
51
53
  export declare function DustWallet(configuration: DefaultV1Configuration): DustWalletClass;
@@ -1,7 +1,19 @@
1
- import { DustSecretKey, } from '@midnight-ntwrk/ledger-v6';
1
+ // This file is part of MIDNIGHT-WALLET-SDK.
2
+ // Copyright (C) 2025 Midnight Foundation
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // You may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ import { DustSecretKey, } from '@midnight-ntwrk/ledger-v7';
2
14
  import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
- import { WalletBuilder } from '@midnight-ntwrk/wallet-sdk-runtime';
4
15
  import { DustAddress } from '@midnight-ntwrk/wallet-sdk-address-format';
16
+ import { WalletBuilder } from '@midnight-ntwrk/wallet-sdk-runtime';
5
17
  import { Effect, Either } from 'effect';
6
18
  import * as rx from 'rxjs';
7
19
  import { DustCoreWallet } from './DustCoreWallet.js';
@@ -48,6 +60,9 @@ export class DustWalletState {
48
60
  availableCoinsWithFullInfo(time) {
49
61
  return this.capabilities.coinsAndBalances.getAvailableCoinsWithFullInfo(this.state, time);
50
62
  }
63
+ estimateDustGeneration(nightUtxos, currentTime) {
64
+ return this.capabilities.coinsAndBalances.estimateDustGeneration(this.state, nightUtxos, currentTime);
65
+ }
51
66
  serialize() {
52
67
  return this.capabilities.serialization.serialize(this.state);
53
68
  }
@@ -57,9 +72,12 @@ export function DustWallet(configuration) {
57
72
  .withVariant(ProtocolVersion.MinSupportedVersion, new V1Builder().withDefaults())
58
73
  .build(configuration);
59
74
  return class DustWalletImplementation extends BaseWallet {
60
- static startWithSeed(seed, dustParameters, networkId) {
75
+ static startWithSeed(seed, dustParameters) {
61
76
  const dustSecretKey = DustSecretKey.fromSeed(seed);
62
- return DustWalletImplementation.startFirst(DustWalletImplementation, DustCoreWallet.initEmpty(dustParameters, dustSecretKey, networkId));
77
+ return DustWalletImplementation.startFirst(DustWalletImplementation, DustCoreWallet.initEmpty(dustParameters, dustSecretKey, configuration.networkId));
78
+ }
79
+ static startWithSecretKey(secretKey, dustParameters) {
80
+ return DustWalletImplementation.startFirst(DustWalletImplementation, DustCoreWallet.initEmpty(dustParameters, secretKey, configuration.networkId));
63
81
  }
64
82
  static restore(serializedState) {
65
83
  const deserialized = DustWalletImplementation.allVariantsRecord()[V1Tag].variant.deserializeState(serializedState)
@@ -88,24 +106,24 @@ export function DustWallet(configuration) {
88
106
  })
89
107
  .pipe(Effect.runPromise);
90
108
  }
91
- calculateFee(transaction) {
109
+ calculateFee(transactions) {
92
110
  return this.runtime
93
111
  .dispatch({
94
- [V1Tag]: (v1) => v1.calculateFee(transaction),
112
+ [V1Tag]: (v1) => v1.calculateFee(transactions),
95
113
  })
96
114
  .pipe(Effect.runPromise);
97
115
  }
98
- addFeePayment(secretKey, transaction, currentTime, ttl) {
116
+ balanceTransactions(secretKey, transactions, ttl, currentTime) {
99
117
  return this.runtime
100
118
  .dispatch({
101
- [V1Tag]: (v1) => v1.addFeePayment(secretKey, transaction, currentTime, ttl),
119
+ [V1Tag]: (v1) => v1.balanceTransactions(secretKey, transactions, ttl, currentTime),
102
120
  })
103
121
  .pipe(Effect.runPromise);
104
122
  }
105
- finalizeTransaction(recipe) {
123
+ proveTransaction(transaction) {
106
124
  return this.runtime
107
125
  .dispatch({
108
- [V1Tag]: (v1) => v1.finalizeTransaction(recipe),
126
+ [V1Tag]: (v1) => v1.proveTransaction(transaction),
109
127
  })
110
128
  .pipe(Effect.runPromise);
111
129
  }
package/dist/Keys.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { DustPublicKey } from '@midnight-ntwrk/ledger-v6';
1
+ import { DustPublicKey } from '@midnight-ntwrk/ledger-v7';
2
2
  import { DustAddress } from '@midnight-ntwrk/wallet-sdk-address-format';
3
3
  import { DustCoreWallet } from './DustCoreWallet.js';
4
4
  export type KeysCapability<TState> = {
@@ -1,6 +1,6 @@
1
1
  import { Effect, Stream, Scope } from 'effect';
2
- import { DustSecretKey, Signature, SignatureVerifyingKey, FinalizedTransaction, UnprovenTransaction } from '@midnight-ntwrk/ledger-v6';
3
- import { Proving, ProvingRecipe, WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
2
+ import { DustSecretKey, Signature, SignatureVerifyingKey, FinalizedTransaction, UnprovenTransaction } from '@midnight-ntwrk/ledger-v7';
3
+ import { Proving, WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
4
4
  import { WalletRuntimeError, Variant, StateChange } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
5
5
  import { DustToken, UtxoWithMeta } from './types/Dust.js';
6
6
  import { KeysCapability } from './Keys.js';
@@ -35,10 +35,10 @@ export declare class RunningV1Variant<TSerialized, TSyncUpdate, TTransaction, TS
35
35
  constructor(scope: Scope.Scope, context: Variant.VariantContext<DustCoreWallet>, v1Context: RunningV1Variant.Context<TSerialized, TSyncUpdate, TTransaction, TStartAux>);
36
36
  startSyncInBackground(startAux: TStartAux): Effect.Effect<void>;
37
37
  startSync(startAux: TStartAux): Stream.Stream<void, WalletError.WalletError, Scope.Scope>;
38
- createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Effect.Effect<UnprovenTransaction, WalletError.WalletError>;
39
- addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Effect.Effect<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
40
- calculateFee(transaction: AnyTransaction): Effect.Effect<bigint, WalletError.WalletError>;
41
- addFeePayment(secretKey: DustSecretKey, transaction: UnprovenTransaction, currentTime: Date, ttl: Date): Effect.Effect<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
42
- finalizeTransaction(recipe: ProvingRecipe.ProvingRecipe<TTransaction>): Effect.Effect<TTransaction, WalletError.WalletError>;
38
+ createDustGenerationTransaction(currentTime: Date | undefined, ttl: Date, nightUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Effect.Effect<UnprovenTransaction, WalletError.WalletError>;
39
+ addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Effect.Effect<UnprovenTransaction, WalletError.WalletError>;
40
+ calculateFee(transactions: ReadonlyArray<AnyTransaction>): Effect.Effect<bigint, WalletError.WalletError>;
41
+ balanceTransactions(secretKey: DustSecretKey, transactions: ReadonlyArray<AnyTransaction>, ttl: Date, currentTime?: Date): Effect.Effect<UnprovenTransaction, WalletError.WalletError>;
42
+ proveTransaction(transaction: UnprovenTransaction): Effect.Effect<TTransaction, WalletError.WalletError>;
43
43
  submitTransaction: SubmitTransactionMethod<TTransaction>;
44
44
  }
@@ -1,8 +1,20 @@
1
- import { Effect, SubscriptionRef, Stream, pipe, Scope, Sink, Console, Duration, Schedule } from 'effect';
2
- import { nativeToken, updatedValue, } from '@midnight-ntwrk/ledger-v6';
1
+ // This file is part of MIDNIGHT-WALLET-SDK.
2
+ // Copyright (C) 2025 Midnight Foundation
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // You may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ import { Effect, SubscriptionRef, Stream, pipe, Scope, Sink, Console, Duration, Schedule, Array as Arr } from 'effect';
14
+ import { nativeToken, } from '@midnight-ntwrk/ledger-v7';
3
15
  import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
4
16
  import { WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
5
- import { EitherOps, LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
17
+ import { ArrayOps, EitherOps } from '@midnight-ntwrk/wallet-sdk-utilities';
6
18
  import { StateChange, VersionChangeType, } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
7
19
  const progress = (state) => {
8
20
  const appliedIndex = state.progress?.appliedIndex ?? 0n;
@@ -69,19 +81,9 @@ export class RunningV1Variant {
69
81
  if (nightUtxos.some((utxo) => utxo.type !== nativeToken().raw)) {
70
82
  return Effect.fail(WalletError.WalletError.other('Token of a non-Night type received'));
71
83
  }
72
- return Effect.Do.pipe(Effect.bind('currentState', () => SubscriptionRef.get(this.#context.stateRef)), Effect.bind('utxosWithDustValue', ({ currentState }) => LedgerOps.ledgerTry(() => {
73
- const dustPublicKey = this.#v1Context.keysCapability.getDustPublicKey(currentState);
74
- return nightUtxos.map((utxo) => {
75
- const genInfo = {
76
- value: utxo.value,
77
- owner: dustPublicKey,
78
- nonce: LedgerOps.randomNonce(),
79
- dtime: undefined,
80
- };
81
- const dustValue = updatedValue(utxo.ctime, 0n, genInfo, currentTime, currentState.state.params);
82
- return { token: utxo, value: dustValue };
83
- });
84
- })), Effect.flatMap(({ utxosWithDustValue }) => {
84
+ 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 }) => {
85
+ return this.#v1Context.coinsAndBalancesCapability.estimateDustGeneration(currentState, nightUtxos, currentTime);
86
+ }), Effect.flatMap(({ utxosWithDustValue, currentTime }) => {
85
87
  return this.#v1Context.transactingCapability
86
88
  .createDustGenerationTransaction(currentTime, ttl, utxosWithDustValue, nightVerifyingKey, dustReceiverAddress)
87
89
  .pipe(EitherOps.toEffect);
@@ -92,22 +94,22 @@ export class RunningV1Variant {
92
94
  .addDustGenerationSignature(transaction, signature)
93
95
  .pipe(EitherOps.toEffect);
94
96
  }
95
- calculateFee(transaction) {
96
- return pipe(this.#v1Context.syncService.ledgerParameters(), Effect.map((params) => this.#v1Context.transactingCapability.calculateFee(transaction, params)));
97
+ calculateFee(transactions) {
98
+ return pipe(this.#v1Context.syncService.blockData(), Effect.map((blockData) => pipe(transactions, Arr.map((transaction) => this.#v1Context.transactingCapability.calculateFee(transaction, blockData.ledgerParameters)), ArrayOps.sumBigInt)));
97
99
  }
98
- addFeePayment(secretKey, transaction, currentTime, ttl) {
100
+ balanceTransactions(secretKey, transactions, ttl, currentTime) {
99
101
  return SubscriptionRef.modifyEffect(this.#context.stateRef, (state) => {
100
- return pipe(this.#v1Context.syncService.ledgerParameters(), Effect.flatMap((params) => this.#v1Context.transactingCapability.addFeePayment(secretKey, state, transaction, currentTime, ttl, params)), Effect.map(({ recipe, newState }) => [recipe, newState]));
102
+ return pipe(this.#v1Context.syncService.blockData(), Effect.flatMap((blockData) => this.#v1Context.transactingCapability.balanceTransactions(secretKey, state, transactions, ttl, currentTime ?? blockData.timestamp, blockData.ledgerParameters)));
101
103
  });
102
104
  }
103
- finalizeTransaction(recipe) {
105
+ proveTransaction(transaction) {
104
106
  return this.#v1Context.provingService
105
- .prove(recipe)
106
- .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revertRecipe(state, recipe)))));
107
+ .prove(transaction)
108
+ .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revertTransaction(state, transaction)))));
107
109
  }
108
110
  submitTransaction = ((transaction, waitForStatus = 'InBlock') => {
109
111
  return this.#v1Context.submissionService
110
112
  .submitTransaction(transaction, waitForStatus)
111
- .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revert(state, transaction)))));
113
+ .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revertTransaction(state, transaction)))));
112
114
  });
113
115
  }
@@ -1,5 +1,17 @@
1
+ // This file is part of MIDNIGHT-WALLET-SDK.
2
+ // Copyright (C) 2025 Midnight Foundation
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // You may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
1
13
  import { Effect, ParseResult, Either, pipe, Schema } from 'effect';
2
- import * as ledger from '@midnight-ntwrk/ledger-v6';
14
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
3
15
  import { WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
4
16
  import { DustCoreWallet } from './DustCoreWallet.js';
5
17
  const StateSchema = Schema.declare((input) => input instanceof ledger.DustLocalState).annotations({
@@ -1,5 +1,5 @@
1
1
  import { Effect, Either, Scope, Stream, SubscriptionRef } from 'effect';
2
- import { LedgerState, BlockContext, UserAddress, SignatureVerifyingKey, WellFormedStrictness, TransactionResult, ProofErasedTransaction, SyntheticCost } from '@midnight-ntwrk/ledger-v6';
2
+ import { LedgerState, BlockContext, UserAddress, SignatureVerifyingKey, WellFormedStrictness, TransactionResult, ProofErasedTransaction, SyntheticCost } from '@midnight-ntwrk/ledger-v7';
3
3
  import { LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
4
4
  import { NetworkId } from './types/ledger.js';
5
5
  export type SimulatorState = Readonly<{
@@ -11,6 +11,7 @@ export type SimulatorState = Readonly<{
11
11
  }>;
12
12
  export declare class Simulator {
13
13
  #private;
14
+ static blockHash: (blockTime: Date) => Effect.Effect<string>;
14
15
  static nextBlockContext: (blockTime: Date) => Effect.Effect<BlockContext>;
15
16
  static init(networkId: NetworkId): Effect.Effect<Simulator, never, Scope.Scope>;
16
17
  static apply(simulatorState: SimulatorState, tx: ProofErasedTransaction, strictness: WellFormedStrictness, blockContext: BlockContext, blockFullness?: SyntheticCost): Either.Either<[{
package/dist/Simulator.js CHANGED
@@ -1,12 +1,25 @@
1
+ // This file is part of MIDNIGHT-WALLET-SDK.
2
+ // Copyright (C) 2025 Midnight Foundation
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // You may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
1
13
  import { Effect, Encoding, pipe, Stream, SubscriptionRef } from 'effect';
2
- import { LedgerState, ClaimRewardsTransaction, SignatureErased, Transaction, WellFormedStrictness, TransactionContext, } from '@midnight-ntwrk/ledger-v6';
14
+ import { LedgerState, ClaimRewardsTransaction, SignatureErased, Transaction, WellFormedStrictness, TransactionContext, } from '@midnight-ntwrk/ledger-v7';
3
15
  import { DateOps, EitherOps, LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
4
16
  import * as crypto from 'crypto';
5
17
  const simpleHash = (input) => {
6
18
  return Encoding.decodeHex(input).pipe(EitherOps.toEffect, Effect.andThen((parsed) => Effect.promise(() => crypto.subtle.digest('SHA-256', parsed))), Effect.andThen((out) => Encoding.encodeHex(new Uint8Array(out))), Effect.orDie);
7
19
  };
8
20
  export class Simulator {
9
- static nextBlockContext = (blockTime) => pipe(DateOps.dateToSeconds(blockTime).toString(16), (str) => (str.length % 2 == 0 ? str : str.padStart(str.length + 1, '0')), simpleHash, Effect.map((hash) => ({
21
+ static blockHash = (blockTime) => pipe(DateOps.dateToSeconds(blockTime).toString(16), (str) => (str.length % 2 == 0 ? str : str.padStart(str.length + 1, '0')), simpleHash);
22
+ static nextBlockContext = (blockTime) => pipe(Simulator.blockHash(blockTime), Effect.map((hash) => ({
10
23
  parentBlockHash: hash,
11
24
  secondsSinceEpoch: DateOps.dateToSeconds(blockTime),
12
25
  secondsSinceEpochErr: 1,
@@ -32,6 +45,8 @@ export class Simulator {
32
45
  static apply(simulatorState, tx, strictness, blockContext, blockFullness) {
33
46
  return LedgerOps.ledgerTry(() => {
34
47
  blockFullness = blockFullness ?? tx.cost(simulatorState.ledger.parameters);
48
+ const detailedBlockFullness = simulatorState.ledger.parameters.normalizeFullness(blockFullness);
49
+ const computedBlockFullness = Math.max(detailedBlockFullness.readTime, detailedBlockFullness.computeTime, detailedBlockFullness.blockUsage, detailedBlockFullness.bytesWritten, detailedBlockFullness.bytesChurned);
35
50
  const blockNumber = blockContext.secondsSinceEpoch;
36
51
  const blockTime = DateOps.secondsToDate(blockNumber);
37
52
  const verifiedTransaction = tx.wellFormed(simulatorState.ledger, strictness, blockTime);
@@ -39,7 +54,7 @@ export class Simulator {
39
54
  const [newLedgerState, txResult] = simulatorState.ledger.apply(verifiedTransaction, transactionContext);
40
55
  const newSimulatorState = {
41
56
  ...simulatorState,
42
- ledger: newLedgerState.postBlockUpdate(blockTime, blockFullness),
57
+ ledger: newLedgerState.postBlockUpdate(blockTime, detailedBlockFullness, computedBlockFullness),
43
58
  lastTx: tx,
44
59
  lastTxResult: txResult,
45
60
  lastTxNumber: blockNumber,
@@ -1,6 +1,6 @@
1
1
  import { Effect } from 'effect';
2
2
  import { SubmissionEvent as SubmissionEventImported } from '@midnight-ntwrk/wallet-sdk-node-client/effect';
3
- import { FinalizedTransaction, ProofErasedTransaction } from '@midnight-ntwrk/ledger-v6';
3
+ import { FinalizedTransaction, ProofErasedTransaction } from '@midnight-ntwrk/ledger-v7';
4
4
  import { WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
5
5
  import { Simulator } from './Simulator.js';
6
6
  import { NetworkId } from './types/ledger.js';