@midnight-ntwrk/wallet-sdk-shielded 1.0.0-beta.9 → 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 ADDED
@@ -0,0 +1,131 @@
1
+ # @midnight-ntwrk/wallet-sdk-shielded
2
+
3
+ Manages shielded tokens on the Midnight network using zero-knowledge proofs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @midnight-ntwrk/wallet-sdk-shielded
9
+ ```
10
+
11
+ ## Overview
12
+
13
+ The Shielded Wallet handles private token operations where transaction values and addresses are hidden from observers
14
+ while maintaining verifiability. It provides:
15
+
16
+ - Zero-knowledge proof generation
17
+ - Coin commitment tracking
18
+ - Encrypted output decryption
19
+ - Shielded transfer transactions
20
+ - Transaction balancing for shielded tokens
21
+
22
+ ## Usage
23
+
24
+ ### Starting the Wallet
25
+
26
+ ```typescript
27
+ import { ShieldedWallet } from '@midnight-ntwrk/wallet-sdk-shielded';
28
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
29
+ import { randomBytes } from 'node:crypto';
30
+
31
+ // Configuration for the wallet
32
+ const configuration = {
33
+ networkId: 'preview',
34
+ provingServerUrl: new URL('http://localhost:6300'),
35
+ relayURL: new URL('ws://localhost:9944'),
36
+ indexerClientConnection: {
37
+ indexerHttpUrl: 'http://localhost:8088/api/v3/graphql',
38
+ indexerWsUrl: 'ws://localhost:8088/api/v3/graphql/ws',
39
+ },
40
+ };
41
+
42
+ // Create secret keys from a shielded seed
43
+ const seed = randomBytes(32);
44
+ const shieldedSecretKeys = ledger.ZswapSecretKeys.fromSeed(seed);
45
+
46
+ // Create and start the wallet
47
+ const shieldedWallet = ShieldedWallet(configuration).startWithSecretKeys(shieldedSecretKeys);
48
+
49
+ // Start syncing with the network
50
+ await shieldedWallet.start(shieldedSecretKeys);
51
+ ```
52
+
53
+ ### Alternative: Start with Seed Directly
54
+
55
+ ```typescript
56
+ // Start directly with a shielded seed
57
+ const shieldedWallet = ShieldedWallet(configuration).startWithShieldedSeed(seed);
58
+ await shieldedWallet.start(ledger.ZswapSecretKeys.fromSeed(seed));
59
+ ```
60
+
61
+ ### Restoring from Serialized State
62
+
63
+ ```typescript
64
+ // Restore a wallet from previously serialized state
65
+ const shieldedWallet = ShieldedWallet(configuration).restore(serializedState);
66
+ await shieldedWallet.start(shieldedSecretKeys);
67
+ ```
68
+
69
+ ### Observing State
70
+
71
+ ```typescript
72
+ wallet.state.subscribe((state) => {
73
+ console.log('Progress:', state.state.progress);
74
+ console.log('Coins:', state.state.coins);
75
+ });
76
+ ```
77
+
78
+ ### Creating Transfer Transactions
79
+
80
+ ```typescript
81
+ const tx = await wallet.transferTransaction(shieldedSecretKeys, [
82
+ { type: 'NIGHT', receiverAddress: 'mn_shield-addr1...', amount: 1000n },
83
+ ]);
84
+ ```
85
+
86
+ ### Balancing Transactions
87
+
88
+ ```typescript
89
+ const balancingTx = await wallet.balanceTransaction(shieldedSecretKeys, transactionToBalance);
90
+ ```
91
+
92
+ ### Finalizing Transactions
93
+
94
+ ```typescript
95
+ // Generates ZK proofs and finalizes the transaction
96
+ const finalizedTx = await wallet.finalizeTransaction(unprovenTx);
97
+ ```
98
+
99
+ ### Creating Swap Offers
100
+
101
+ ```typescript
102
+ const swapTx = await wallet.initSwap(
103
+ shieldedSecretKeys,
104
+ { NIGHT: 500n }, // inputs
105
+ [{ type: 'TOKEN_A', receiverAddress: shieldedAddress, amount: 100n }], // outputs
106
+ );
107
+ ```
108
+
109
+ ## Privacy Model
110
+
111
+ Shielded transactions use zero-knowledge proofs to hide:
112
+
113
+ - Transaction amounts
114
+ - Sender addresses
115
+ - Receiver addresses
116
+
117
+ While still proving:
118
+
119
+ - The sender has sufficient balance
120
+ - No tokens are created or destroyed
121
+ - The transaction is valid
122
+
123
+ ## Exports
124
+
125
+ - `ShieldedWallet` - Main wallet class
126
+ - `ShieldedWalletState` - Wallet state type
127
+ - Version 1 exports via `@midnight-ntwrk/wallet-sdk-shielded/v1`
128
+
129
+ ## License
130
+
131
+ Apache-2.0
@@ -1,8 +1,8 @@
1
1
  import { ProtocolState, ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
2
2
  import { BaseV1Configuration, DefaultV1Configuration, V1Variant, CoreWallet } from './v1/index.js';
3
- import * as ledger from '@midnight-ntwrk/ledger-v6';
3
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
4
4
  import * as rx from 'rxjs';
5
- import { ProvingRecipe } from './v1/ProvingRecipe.js';
5
+ import { BalancingResult } from './v1/Transacting.js';
6
6
  import { SerializationCapability } from './v1/Serialization.js';
7
7
  import { ProgressUpdate, TransactionHistoryCapability } from './v1/TransactionHistory.js';
8
8
  import { AvailableCoin, CoinsAndBalancesCapability, PendingCoin } from './v1/CoinsAndBalances.js';
@@ -18,6 +18,7 @@ export type ShieldedWalletCapabilities<TSerialized = string, TTransaction = ledg
18
18
  keys: KeysCapability<CoreWallet>;
19
19
  transactionHistory: TransactionHistoryCapability<CoreWallet, TTransaction>;
20
20
  };
21
+ export type UnboundTransaction = ledger.Transaction<ledger.SignatureEnabled, ledger.Proof, ledger.PreBinding>;
21
22
  export declare class ShieldedWalletState<TSerialized = string, TTransaction = ledger.FinalizedTransaction> {
22
23
  static readonly mapState: <TSerialized_1 = string, TTransaction_1 = ledger.FinalizedTransaction>(capabilities: ShieldedWalletCapabilities<TSerialized_1, TTransaction_1>) => (state: ProtocolState.ProtocolState<CoreWallet>) => ShieldedWalletState<TSerialized_1, TTransaction_1>;
23
24
  readonly protocolVersion: ProtocolVersion.ProtocolVersion;
@@ -49,10 +50,10 @@ export interface CustomizedShieldedWallet<TStartAux = ledger.ZswapSecretKeys, TT
49
50
  ]> {
50
51
  readonly state: rx.Observable<ShieldedWalletState<TSerialized, TTransaction>>;
51
52
  start(secretKeys: TStartAux): Promise<void>;
52
- balanceTransaction(secretKeys: ledger.ZswapSecretKeys, tx: ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>, newCoins: readonly ledger.ShieldedCoinInfo[]): Promise<ProvingRecipe<TTransaction>>;
53
- transferTransaction(secretKeys: ledger.ZswapSecretKeys, outputs: readonly TokenTransfer[]): Promise<ProvingRecipe<TTransaction>>;
54
- initSwap(secretKeys: ledger.ZswapSecretKeys, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: readonly TokenTransfer[]): Promise<ProvingRecipe<TTransaction>>;
55
- finalizeTransaction(recipe: ProvingRecipe<TTransaction>): Promise<TTransaction>;
53
+ balanceTransaction(secretKeys: ledger.ZswapSecretKeys, tx: ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>): Promise<BalancingResult>;
54
+ transferTransaction(secretKeys: ledger.ZswapSecretKeys, outputs: readonly TokenTransfer[]): Promise<ledger.UnprovenTransaction>;
55
+ initSwap(secretKeys: ledger.ZswapSecretKeys, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: readonly TokenTransfer[]): Promise<ledger.UnprovenTransaction>;
56
+ finalizeTransaction(transaction: ledger.UnprovenTransaction): Promise<TTransaction>;
56
57
  readonly submitTransaction: SubmitTransactionMethod<TTransaction>;
57
58
  serializeState(): Promise<TSerialized>;
58
59
  waitForSyncedState(allowedGap?: bigint): Promise<ShieldedWalletState<TSerialized, TTransaction>>;
@@ -1,6 +1,18 @@
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 { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
2
14
  import { V1Builder, V1Tag, CoreWallet } from './v1/index.js';
3
- import * as ledger from '@midnight-ntwrk/ledger-v6';
15
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
4
16
  import { Effect, Either } from 'effect';
5
17
  import * as rx from 'rxjs';
6
18
  import { WalletBuilder } from '@midnight-ntwrk/wallet-sdk-runtime';
@@ -95,10 +107,10 @@ export function CustomShieldedWallet(configuration, builder) {
95
107
  .dispatch({ [V1Tag]: (v1) => v1.initSwap(secretKeys, desiredInputs, desiredOutputs) })
96
108
  .pipe(Effect.runPromise);
97
109
  }
98
- finalizeTransaction(recipe) {
110
+ finalizeTransaction(transaction) {
99
111
  return this.runtime
100
112
  .dispatch({
101
- [V1Tag]: (v1) => v1.finalizeTransaction(recipe),
113
+ [V1Tag]: (v1) => v1.finalizeTransaction(transaction),
102
114
  })
103
115
  .pipe(Effect.runPromise);
104
116
  }
package/dist/index.js CHANGED
@@ -1 +1,13 @@
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
  export * from './ShieldedWallet.js';
@@ -1,5 +1,5 @@
1
1
  import { CoreWallet } from './CoreWallet.js';
2
- import * as ledger from '@midnight-ntwrk/ledger-v6';
2
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
3
3
  export type AvailableCoin = {
4
4
  coin: ledger.QualifiedShieldedCoinInfo;
5
5
  commitment: ledger.CoinCommitment;
@@ -1,4 +1,4 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
3
  import { Either } from 'effect';
4
4
  import { SyncProgress, SyncProgressData } from './SyncProgress.js';
@@ -1,4 +1,16 @@
1
- import * as ledger 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';
2
14
  import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
15
  import { Either, Iterable, pipe, Record, Array as Arr } from 'effect';
4
16
  import { createSyncProgress } from './SyncProgress.js';
@@ -1,9 +1,8 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { Effect } from 'effect';
3
- import { ProvingRecipe } from './ProvingRecipe.js';
4
3
  import { WalletError } from './WalletError.js';
5
4
  export interface ProvingService<TTransaction> {
6
- prove(recipe: ProvingRecipe<TTransaction>): Effect.Effect<TTransaction, WalletError>;
5
+ prove(transaction: ledger.UnprovenTransaction): Effect.Effect<TTransaction, WalletError>;
7
6
  }
8
7
  export type DefaultProvingConfiguration = {
9
8
  provingServerUrl: URL;
@@ -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 { HttpProverClient, ProverClient } from '@midnight-ntwrk/wallet-sdk-prover-client/effect';
2
- import * as ledger from '@midnight-ntwrk/ledger-v6';
14
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
3
15
  import { Effect, pipe } from 'effect';
4
16
  import { ProvingError } from './WalletError.js';
5
17
  export const makeDefaultProvingService = (configuration) => {
@@ -7,35 +19,18 @@ export const makeDefaultProvingService = (configuration) => {
7
19
  url: configuration.provingServerUrl,
8
20
  });
9
21
  return {
10
- prove(recipe) {
11
- switch (recipe.type) {
12
- case 'BalanceTransactionToProve':
13
- return pipe(ProverClient.ProverClient, Effect.flatMap((client) => client.proveTransaction(recipe.transactionToProve, ledger.CostModel.initialCostModel())), Effect.map((provenTx) => recipe.transactionToBalance.merge(provenTx.bind())), Effect.provide(clientLayer), Effect.catchAll((error) => Effect.fail(new ProvingError({
14
- message: error.message,
15
- cause: error,
16
- }))));
17
- case 'TransactionToProve':
18
- return pipe(ProverClient.ProverClient, Effect.flatMap((client) => client.proveTransaction(recipe.transaction, ledger.CostModel.initialCostModel())), Effect.map((proven) => proven.bind()), Effect.provide(clientLayer), Effect.catchAll((error) => Effect.fail(new ProvingError({
19
- message: error.message,
20
- cause: error,
21
- }))));
22
- case 'NothingToProve':
23
- return Effect.succeed(recipe.transaction);
24
- }
22
+ prove(transaction) {
23
+ return pipe(ProverClient.ProverClient, Effect.flatMap((client) => client.proveTransaction(transaction, ledger.CostModel.initialCostModel())), Effect.map((transaction) => transaction.bind()), Effect.provide(clientLayer), Effect.catchAll((error) => Effect.fail(new ProvingError({
24
+ message: error.message,
25
+ cause: error,
26
+ }))));
25
27
  },
26
28
  };
27
29
  };
28
30
  export const makeSimulatorProvingService = () => {
29
31
  return {
30
- prove(recipe) {
31
- switch (recipe.type) {
32
- case 'BalanceTransactionToProve':
33
- return pipe(Effect.succeed(recipe.transactionToProve.eraseProofs()), Effect.map((proven) => recipe.transactionToBalance.merge(proven)));
34
- case 'TransactionToProve':
35
- return Effect.succeed(recipe.transaction.eraseProofs());
36
- case 'NothingToProve':
37
- return Effect.succeed(recipe.transaction);
38
- }
32
+ prove(transaction) {
33
+ return Effect.succeed(transaction.eraseProofs());
39
34
  },
40
35
  };
41
36
  };
@@ -1,11 +1,10 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { Effect, Scope, Stream } from 'effect';
3
3
  import { WalletRuntimeError, Variant, StateChange } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
4
4
  import { ProvingService } from './Proving.js';
5
- import { ProvingRecipe } from './ProvingRecipe.js';
6
5
  import { SerializationCapability } from './Serialization.js';
7
6
  import { EventsSyncUpdate, SyncCapability, SyncService } from './Sync.js';
8
- import { TransactingCapability, TokenTransfer } from './Transacting.js';
7
+ import { TransactingCapability, TokenTransfer, BalancingResult } from './Transacting.js';
9
8
  import { WalletError } from './WalletError.js';
10
9
  import { CoinsAndBalancesCapability } from './CoinsAndBalances.js';
11
10
  import { KeysCapability } from './Keys.js';
@@ -37,10 +36,10 @@ export declare class RunningV1Variant<TSerialized, TSyncUpdate, TTransaction, TS
37
36
  constructor(scope: Scope.Scope, context: Variant.VariantContext<CoreWallet>, v1Context: RunningV1Variant.Context<TSerialized, TSyncUpdate, TTransaction, TStartAux>);
38
37
  startSyncInBackground(startAux: TStartAux): Effect.Effect<void>;
39
38
  startSync(startAux: TStartAux): Stream.Stream<void, WalletError, Scope.Scope>;
40
- balanceTransaction(secretKeys: ledger.ZswapSecretKeys, tx: ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>): Effect.Effect<ProvingRecipe<TTransaction>, WalletError>;
41
- transferTransaction(secretKeys: ledger.ZswapSecretKeys, outputs: ReadonlyArray<TokenTransfer>): Effect.Effect<ProvingRecipe<TTransaction>, WalletError>;
42
- initSwap(secretKeys: ledger.ZswapSecretKeys, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>): Effect.Effect<ProvingRecipe<TTransaction>, WalletError>;
43
- finalizeTransaction(recipe: ProvingRecipe<TTransaction>): Effect.Effect<TTransaction, WalletError>;
39
+ balanceTransaction(secretKeys: ledger.ZswapSecretKeys, tx: ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>): Effect.Effect<BalancingResult, WalletError>;
40
+ transferTransaction(secretKeys: ledger.ZswapSecretKeys, outputs: ReadonlyArray<TokenTransfer>): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
41
+ initSwap(secretKeys: ledger.ZswapSecretKeys, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
42
+ finalizeTransaction(transaction: ledger.UnprovenTransaction): Effect.Effect<TTransaction, WalletError>;
44
43
  submitTransaction: SubmitTransactionMethod<TTransaction>;
45
44
  serializeState(state: CoreWallet): TSerialized;
46
45
  }
@@ -66,28 +66,28 @@ export class RunningV1Variant {
66
66
  }
67
67
  balanceTransaction(secretKeys, tx) {
68
68
  return SubscriptionRef.modifyEffect(this.#context.stateRef, (state) => {
69
- return pipe(this.#v1Context.transactingCapability.balanceTransaction(secretKeys, state, tx), EitherOps.toEffect, Effect.map(({ recipe, newState }) => [recipe, newState]));
69
+ return pipe(this.#v1Context.transactingCapability.balanceTransaction(secretKeys, state, tx), EitherOps.toEffect);
70
70
  });
71
71
  }
72
72
  transferTransaction(secretKeys, outputs) {
73
73
  return SubscriptionRef.modifyEffect(this.#context.stateRef, (state) => {
74
- return pipe(this.#v1Context.transactingCapability.makeTransfer(secretKeys, state, outputs), EitherOps.toEffect, Effect.map(({ recipe, newState }) => [recipe, newState]));
74
+ return pipe(this.#v1Context.transactingCapability.makeTransfer(secretKeys, state, outputs), EitherOps.toEffect);
75
75
  });
76
76
  }
77
77
  initSwap(secretKeys, desiredInputs, desiredOutputs) {
78
78
  return SubscriptionRef.modifyEffect(this.#context.stateRef, (state) => {
79
- return pipe(this.#v1Context.transactingCapability.initSwap(secretKeys, state, desiredInputs, desiredOutputs), EitherOps.toEffect, Effect.map(({ recipe, newState }) => [recipe, newState]));
79
+ return pipe(this.#v1Context.transactingCapability.initSwap(secretKeys, state, desiredInputs, desiredOutputs), EitherOps.toEffect);
80
80
  });
81
81
  }
82
- finalizeTransaction(recipe) {
82
+ finalizeTransaction(transaction) {
83
83
  return this.#v1Context.provingService
84
- .prove(recipe)
85
- .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revertRecipe(state, recipe)))));
84
+ .prove(transaction)
85
+ .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revertTransaction(state, transaction)))));
86
86
  }
87
87
  submitTransaction = ((transaction, waitForStatus = 'InBlock') => {
88
88
  return this.#v1Context.submissionService
89
89
  .submitTransaction(transaction, waitForStatus)
90
- .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revert(state, transaction)))));
90
+ .pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revertTransaction(state, transaction)))));
91
91
  });
92
92
  serializeState(state) {
93
93
  return this.#v1Context.serializationCapability.serialize(state);
@@ -1,6 +1,18 @@
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
14
  import { WalletError } from './WalletError.js';
3
- import * as ledger from '@midnight-ntwrk/ledger-v6';
15
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
4
16
  import { CoreWallet } from './CoreWallet.js';
5
17
  const TxSchema = Schema.declare((input) => input instanceof ledger.Transaction).annotations({
6
18
  identifier: 'ledger.Transaction',
@@ -1,4 +1,4 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { Array as Arr, Effect, Scope, Stream, SubscriptionRef } from 'effect';
3
3
  export type SimulatorState = Readonly<{
4
4
  ledger: ledger.LedgerState;
@@ -1,4 +1,16 @@
1
- import * as ledger 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';
2
14
  import { Array as Arr, Effect, Encoding, pipe, Stream, SubscriptionRef, Clock } from 'effect';
3
15
  import { ArrayOps, EitherOps } from '@midnight-ntwrk/wallet-sdk-utilities';
4
16
  import * as crypto from 'crypto';
@@ -1,5 +1,5 @@
1
1
  import { Effect } from 'effect';
2
- import * as ledger from '@midnight-ntwrk/ledger-v6';
2
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
3
3
  import { WalletError } from './WalletError.js';
4
4
  import { Simulator } from './Simulator.js';
5
5
  import { SubmissionEvent as SubmissionEventImported } from '@midnight-ntwrk/wallet-sdk-node-client/effect';
@@ -1,3 +1,15 @@
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 { Deferred, Effect, Encoding, Exit, pipe, Scope } from 'effect';
2
14
  import { WalletError } from './WalletError.js';
3
15
  import { NodeClient, PolkadotNodeClient, SubmissionEvent as SubmissionEventImported, } from '@midnight-ntwrk/wallet-sdk-node-client/effect';
package/dist/v1/Sync.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
2
- import { Scope, Stream, Schema } from 'effect';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
+ import { Schema, Scope, Stream } from 'effect';
3
3
  import { CoreWallet } from './CoreWallet.js';
4
4
  import { Simulator, SimulatorState } from './Simulator.js';
5
5
  import { WalletError } from './WalletError.js';
@@ -16,6 +16,7 @@ export type IndexerClientConnection = {
16
16
  };
17
17
  export type DefaultSyncConfiguration = {
18
18
  indexerClientConnection: IndexerClientConnection;
19
+ batchSize?: number;
19
20
  };
20
21
  export type DefaultSyncContext = {
21
22
  transactionHistoryCapability: TransactionHistoryCapability<CoreWallet, ledger.FinalizedTransaction>;
@@ -25,11 +26,11 @@ export declare const SecretKeysResource: {
25
26
  create: (secretKeys: ledger.ZswapSecretKeys) => SecretKeysResource;
26
27
  };
27
28
  export type WalletSyncUpdate = {
28
- update: EventsSyncUpdate;
29
+ updates: EventsSyncUpdate[];
29
30
  secretKeys: SecretKeysResource;
30
31
  };
31
32
  export declare const WalletSyncUpdate: {
32
- create: (update: EventsSyncUpdate, secretKeys: ledger.ZswapSecretKeys) => WalletSyncUpdate;
33
+ create: (updates: EventsSyncUpdate[], secretKeys: ledger.ZswapSecretKeys) => WalletSyncUpdate;
33
34
  };
34
35
  export declare const EventsSyncUpdate: Schema.TaggedStruct<"EventsSyncUpdate", {
35
36
  id: typeof Schema.Number;
package/dist/v1/Sync.js CHANGED
@@ -1,8 +1,20 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
2
- import { Effect, ParseResult, Stream, Schema, pipe, Either } from 'effect';
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';
14
+ import { Chunk, Duration, Effect, Either, ParseResult, pipe, Schedule, Schema, Stream } from 'effect';
3
15
  import { CoreWallet } from './CoreWallet.js';
4
16
  import { ZswapEvents } from '@midnight-ntwrk/wallet-sdk-indexer-client';
5
- import { WsSubscriptionClient, ConnectionHelper } from '@midnight-ntwrk/wallet-sdk-indexer-client/effect';
17
+ import { ConnectionHelper, WsSubscriptionClient } from '@midnight-ntwrk/wallet-sdk-indexer-client/effect';
6
18
  import { SyncWalletError } from './WalletError.js';
7
19
  import { WsURL } from '@midnight-ntwrk/wallet-sdk-utilities/networking';
8
20
  import { EitherOps } from '@midnight-ntwrk/wallet-sdk-utilities';
@@ -27,9 +39,9 @@ export const SecretKeysResource = {
27
39
  },
28
40
  };
29
41
  export const WalletSyncUpdate = {
30
- create: (update, secretKeys) => {
42
+ create: (updates, secretKeys) => {
31
43
  return {
32
- update,
44
+ updates,
33
45
  secretKeys: SecretKeysResource.create(secretKeys),
34
46
  };
35
47
  },
@@ -85,15 +97,20 @@ export const makeEventsSyncService = (config) => {
85
97
  }
86
98
  const indexerWsUrl = indexerWsUrlResult.right;
87
99
  const appliedIndex = state.progress?.appliedIndex ?? 0n;
88
- return pipe(ZswapEvents.run({ id: Number(appliedIndex) }), Stream.provideLayer(WsSubscriptionClient.layer({ url: indexerWsUrl })), Stream.mapError((error) => new SyncWalletError(error)), Stream.mapEffect((subscription) => pipe(Schema.decodeUnknownEither(EventsSyncUpdateFromPayload)(subscription.zswapLedgerEvents), Either.mapLeft((err) => new SyncWalletError(err)), EitherOps.toEffect)), Stream.map((data) => WalletSyncUpdate.create(data, secretKeys)));
100
+ const batchSize = config.batchSize ?? 10;
101
+ return pipe(ZswapEvents.run({ id: Number(appliedIndex) }), Stream.provideLayer(WsSubscriptionClient.layer({ url: indexerWsUrl })), Stream.mapError((error) => new SyncWalletError(error)), Stream.mapEffect((subscription) => pipe(subscription.zswapLedgerEvents, Schema.decodeUnknownEither(EventsSyncUpdateFromPayload), Either.mapLeft((err) => new SyncWalletError(err)), EitherOps.toEffect)), Stream.groupedWithin(batchSize, Duration.millis(1)), Stream.map(Chunk.toArray), Stream.map((data) => WalletSyncUpdate.create(data, secretKeys)), Stream.schedule(Schedule.spaced(Duration.millis(4))));
89
102
  },
90
103
  };
91
104
  };
92
105
  export const makeEventsSyncCapability = () => {
93
106
  return {
94
107
  applyUpdate: (state, wrappedUpdate) => {
95
- const nextIndex = BigInt(wrappedUpdate.update.id);
96
- const highestRelevantWalletIndex = BigInt(wrappedUpdate.update.maxId);
108
+ if (wrappedUpdate.updates.length === 0) {
109
+ return state;
110
+ }
111
+ const lastUpdate = wrappedUpdate.updates.at(-1);
112
+ const nextIndex = BigInt(lastUpdate.id);
113
+ const highestRelevantWalletIndex = BigInt(lastUpdate.maxId);
97
114
  // in case the nextIndex is less than or equal to the appliedIndex
98
115
  // just update highestRelevantWalletIndex
99
116
  if (nextIndex <= state.progress.appliedIndex) {
@@ -103,7 +120,7 @@ export const makeEventsSyncCapability = () => {
103
120
  });
104
121
  }
105
122
  return wrappedUpdate.secretKeys((keys) => {
106
- return CoreWallet.updateProgress(CoreWallet.replayEvents(state, keys, [wrappedUpdate.update.event]), {
123
+ return CoreWallet.updateProgress(CoreWallet.replayEvents(state, keys, wrappedUpdate.updates.map((u) => u.event)), {
107
124
  highestRelevantWalletIndex,
108
125
  appliedIndex: nextIndex,
109
126
  isConnected: true,
@@ -1,12 +1,11 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { NetworkId } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
3
  import { Array as Arr, Either } from 'effect';
4
- import { ProvingRecipe } from './ProvingRecipe.js';
5
4
  import { CoreWallet } from './CoreWallet.js';
6
5
  import { WalletError } from './WalletError.js';
7
6
  import { CoinSelection } from '@midnight-ntwrk/wallet-sdk-capabilities';
8
7
  import { TransactionImbalances } from './TransactionImbalances.js';
9
- import { TransactionTrait } from './Transaction.js';
8
+ import { TransactionOps } from './TransactionOps.js';
10
9
  import { CoinsAndBalancesCapability } from './CoinsAndBalances.js';
11
10
  import { KeysCapability } from './Keys.js';
12
11
  export interface TokenTransfer {
@@ -14,21 +13,12 @@ export interface TokenTransfer {
14
13
  readonly type: ledger.RawTokenType;
15
14
  readonly receiverAddress: string;
16
15
  }
16
+ export type BalancingResult = ledger.UnprovenTransaction | undefined;
17
17
  export interface TransactingCapability<TSecrets, TState, TTransaction> {
18
- balanceTransaction(secrets: TSecrets, state: TState, tx: ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>): Either.Either<{
19
- recipe: ProvingRecipe<TTransaction>;
20
- newState: TState;
21
- }, WalletError>;
22
- makeTransfer(secrets: TSecrets, state: TState, outputs: ReadonlyArray<TokenTransfer>): Either.Either<{
23
- recipe: ProvingRecipe<TTransaction>;
24
- newState: TState;
25
- }, WalletError>;
26
- initSwap(secrets: TSecrets, state: TState, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>): Either.Either<{
27
- recipe: ProvingRecipe<TTransaction>;
28
- newState: TState;
29
- }, WalletError>;
30
- revert(state: TState, tx: TTransaction): Either.Either<TState, WalletError>;
31
- revertRecipe(state: TState, recipe: ProvingRecipe<TTransaction>): Either.Either<TState, WalletError>;
18
+ balanceTransaction(secrets: TSecrets, state: TState, tx: ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>): Either.Either<[BalancingResult, TState], WalletError>;
19
+ makeTransfer(secrets: TSecrets, state: TState, outputs: ReadonlyArray<TokenTransfer>): Either.Either<[ledger.UnprovenTransaction, TState], WalletError>;
20
+ initSwap(secrets: TSecrets, state: TState, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>): Either.Either<[ledger.UnprovenTransaction, TState], WalletError>;
21
+ revertTransaction(state: TState, transaction: TTransaction | ledger.UnprovenTransaction): Either.Either<TState, WalletError>;
32
22
  }
33
23
  export type DefaultTransactingConfiguration = {
34
24
  networkId: NetworkId.NetworkId;
@@ -44,24 +34,14 @@ export declare class TransactingCapabilityImplementation<TTransaction extends le
44
34
  #private;
45
35
  readonly networkId: NetworkId.NetworkId;
46
36
  readonly getCoinSelection: () => CoinSelection<ledger.QualifiedShieldedCoinInfo>;
47
- readonly txTrait: TransactionTrait<TTransaction>;
37
+ readonly txOps: TransactionOps<TTransaction>;
48
38
  readonly getCoins: () => CoinsAndBalancesCapability<CoreWallet>;
49
39
  readonly getKeys: () => KeysCapability<CoreWallet>;
50
- constructor(networkId: NetworkId.NetworkId, getCoinSelection: () => CoinSelection<ledger.QualifiedShieldedCoinInfo>, getCoins: () => CoinsAndBalancesCapability<CoreWallet>, getKeys: () => KeysCapability<CoreWallet>, txTrait: TransactionTrait<TTransaction>);
51
- balanceTransaction(secretKeys: ledger.ZswapSecretKeys, state: CoreWallet, tx: TTransaction): Either.Either<{
52
- recipe: ProvingRecipe<TTransaction>;
53
- newState: CoreWallet;
54
- }, WalletError>;
55
- makeTransfer(secretKeys: ledger.ZswapSecretKeys, state: CoreWallet, transfers: Arr.NonEmptyReadonlyArray<TokenTransfer>): Either.Either<{
56
- recipe: ProvingRecipe<TTransaction>;
57
- newState: CoreWallet;
58
- }, WalletError>;
59
- initSwap(secretKeys: ledger.ZswapSecretKeys, state: CoreWallet, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>): Either.Either<{
60
- recipe: ProvingRecipe<TTransaction>;
61
- newState: CoreWallet;
62
- }, WalletError>;
63
- revert(state: CoreWallet, tx: TTransaction): Either.Either<CoreWallet, WalletError>;
64
- revertRecipe(state: CoreWallet, recipe: ProvingRecipe<TTransaction>): Either.Either<CoreWallet, WalletError>;
40
+ constructor(networkId: NetworkId.NetworkId, getCoinSelection: () => CoinSelection<ledger.QualifiedShieldedCoinInfo>, getCoins: () => CoinsAndBalancesCapability<CoreWallet>, getKeys: () => KeysCapability<CoreWallet>, txOps: TransactionOps<TTransaction>);
41
+ balanceTransaction(secretKeys: ledger.ZswapSecretKeys, state: CoreWallet, tx: TTransaction): Either.Either<[BalancingResult, CoreWallet], WalletError>;
42
+ makeTransfer(secretKeys: ledger.ZswapSecretKeys, state: CoreWallet, transfers: Arr.NonEmptyReadonlyArray<TokenTransfer>): Either.Either<[ledger.UnprovenTransaction, CoreWallet], WalletError>;
43
+ initSwap(secretKeys: ledger.ZswapSecretKeys, state: CoreWallet, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>): Either.Either<[ledger.UnprovenTransaction, CoreWallet], WalletError>;
44
+ revertTransaction(state: CoreWallet, transaction: TTransaction | ledger.UnprovenTransaction): Either.Either<CoreWallet, WalletError>;
65
45
  balanceFallibleSection(secretKeys: ledger.ZswapSecretKeys, state: CoreWallet, imbalances: TransactionImbalances, coinSelection: CoinSelection<ledger.QualifiedShieldedCoinInfo>): Either.Either<{
66
46
  offer: ledger.ZswapOffer<ledger.PreProof> | undefined;
67
47
  newState: CoreWallet;
@@ -1,58 +1,53 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
2
- import { Array as Arr, Data, Either, Option, pipe, Record } from 'effect';
3
- import { ArrayOps, EitherOps } from '@midnight-ntwrk/wallet-sdk-utilities';
4
- import { BALANCE_TRANSACTION_TO_PROVE, NOTHING_TO_PROVE, TRANSACTION_TO_PROVE, } from './ProvingRecipe.js';
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';
14
+ import { Array as Arr, Either, Option, pipe, Record } from 'effect';
15
+ import { ArrayOps } from '@midnight-ntwrk/wallet-sdk-utilities';
5
16
  import { CoreWallet } from './CoreWallet.js';
6
17
  import { AddressError, InsufficientFundsError, OtherWalletError } from './WalletError.js';
7
18
  import { getBalanceRecipe, Imbalances, InsufficientFundsError as BalancingInsufficientFundsError, } from '@midnight-ntwrk/wallet-sdk-capabilities';
8
19
  import { MidnightBech32m, ShieldedAddress } from '@midnight-ntwrk/wallet-sdk-address-format';
9
20
  import { ShieldedCostModel, TransactionImbalances } from './TransactionImbalances.js';
10
- import { TransactionTrait } from './Transaction.js';
21
+ import { TransactionOps } from './TransactionOps.js';
11
22
  export const makeDefaultTransactingCapability = (config, getContext) => {
12
- return new TransactingCapabilityImplementation(config.networkId, () => getContext().coinSelection, () => getContext().coinsAndBalancesCapability, () => getContext().keysCapability, TransactionTrait.default);
23
+ return new TransactingCapabilityImplementation(config.networkId, () => getContext().coinSelection, () => getContext().coinsAndBalancesCapability, () => getContext().keysCapability, TransactionOps.default);
13
24
  };
14
25
  export const makeSimulatorTransactingCapability = (config, getContext) => {
15
- return new TransactingCapabilityImplementation(config.networkId, () => getContext().coinSelection, () => getContext().coinsAndBalancesCapability, () => getContext().keysCapability, TransactionTrait.proofErased);
26
+ return new TransactingCapabilityImplementation(config.networkId, () => getContext().coinSelection, () => getContext().coinsAndBalancesCapability, () => getContext().keysCapability, TransactionOps.proofErased);
16
27
  };
17
- class NoSelfOutputsError extends Data.TaggedError('NoSelfOutputs') {
18
- }
19
28
  export class TransactingCapabilityImplementation {
20
29
  networkId;
21
30
  getCoinSelection;
22
- txTrait;
31
+ txOps;
23
32
  getCoins;
24
33
  getKeys;
25
- constructor(networkId, getCoinSelection, getCoins, getKeys, txTrait) {
34
+ constructor(networkId, getCoinSelection, getCoins, getKeys, txOps) {
26
35
  this.getCoins = getCoins;
27
36
  this.networkId = networkId;
28
37
  this.getCoinSelection = getCoinSelection;
29
38
  this.getKeys = getKeys;
30
- this.txTrait = txTrait;
39
+ this.txOps = txOps;
31
40
  }
32
41
  balanceTransaction(secretKeys, state, tx) {
33
42
  return Either.gen(this, function* () {
34
43
  const coinSelection = this.getCoinSelection();
35
- const networkId = this.networkId;
36
- const initialImbalances = this.txTrait.getImbalances(tx);
44
+ const initialImbalances = this.txOps.getImbalances(tx);
37
45
  if (TransactionImbalances.areBalanced(initialImbalances)) {
38
- return {
39
- recipe: {
40
- type: NOTHING_TO_PROVE,
41
- transaction: tx,
42
- },
43
- newState: state,
44
- };
46
+ return [undefined, state];
45
47
  }
46
48
  const { newState: afterFallible, offer: maybeFallible } = yield* this.balanceFallibleSection(secretKeys, state, initialImbalances, coinSelection);
47
- const { newState: afterGuaranteed, offer: guaranteed } = yield* this.#balanceGuaranteedSection(secretKeys, afterFallible, initialImbalances, coinSelection, 0, Imbalances.empty());
48
- return {
49
- newState: afterGuaranteed,
50
- recipe: {
51
- type: BALANCE_TRANSACTION_TO_PROVE,
52
- transactionToBalance: tx,
53
- transactionToProve: ledger.Transaction.fromParts(networkId, guaranteed, maybeFallible),
54
- },
55
- };
49
+ const { newState: afterGuaranteed, offer: guaranteed } = yield* this.#balanceGuaranteedSection(secretKeys, afterFallible, initialImbalances, coinSelection, Imbalances.empty());
50
+ return [ledger.Transaction.fromParts(this.networkId, guaranteed, maybeFallible), afterGuaranteed];
56
51
  });
57
52
  }
58
53
  makeTransfer(secretKeys, state, transfers) {
@@ -67,17 +62,11 @@ export class TransactingCapabilityImplementation {
67
62
  const { initialOffersAndCoins, selfCoins } = yield* this.#processDesiredOutputs(state, positiveTransfers);
68
63
  const offerToBalance = pipe(initialOffersAndCoins, Arr.map((o) => o.outputOffer), ArrayOps.fold((a, b) => a.merge(b)));
69
64
  const unprovenTxToBalance = ledger.Transaction.fromParts(networkId, offerToBalance);
70
- const imbalances = TransactionTrait.unproven.getImbalances(unprovenTxToBalance);
71
- const { offer, newState } = yield* this.#balanceGuaranteedSection(secretKeys, state, imbalances, this.getCoinSelection(), selfCoins.length, Imbalances.empty());
65
+ const imbalances = TransactionOps.unproven.getImbalances(unprovenTxToBalance);
66
+ const { offer, newState } = yield* this.#balanceGuaranteedSection(secretKeys, state, imbalances, this.getCoinSelection(), Imbalances.empty());
72
67
  const finalState = CoreWallet.watchCoins(newState, secretKeys, selfCoins);
73
68
  const finalTx = unprovenTxToBalance.merge(ledger.Transaction.fromParts(networkId, offer));
74
- return {
75
- newState: finalState,
76
- recipe: {
77
- type: TRANSACTION_TO_PROVE,
78
- transaction: finalTx,
79
- },
80
- };
69
+ return [finalTx, finalState];
81
70
  });
82
71
  }
83
72
  initSwap(secretKeys, state, desiredInputs, desiredOutputs) {
@@ -97,57 +86,28 @@ export class TransactingCapabilityImplementation {
97
86
  const outputsParseResult = yield* this.#processDesiredOutputsPossiblyEmpty(state, desiredOutputs);
98
87
  const inputsParseResult = Imbalances.fromEntries(Record.toEntries(desiredInputs));
99
88
  const networkId = this.networkId;
100
- const { offer, newState } = yield* this.#balanceGuaranteedSection(secretKeys, state, TransactionImbalances.empty(), this.getCoinSelection(), outputsParseResult.selfCoins.length, inputsParseResult);
89
+ const { offer, newState } = yield* this.#balanceGuaranteedSection(secretKeys, state, TransactionImbalances.empty(), this.getCoinSelection(), inputsParseResult);
101
90
  const finalState = CoreWallet.watchCoins(newState, secretKeys, outputsParseResult.selfCoins);
102
91
  const balancingTx = ledger.Transaction.fromParts(networkId, offer);
103
92
  const finalTx = outputsParseResult.unprovenTxToBalance
104
93
  ? outputsParseResult.unprovenTxToBalance.merge(balancingTx)
105
94
  : balancingTx;
106
- return {
107
- newState: finalState,
108
- recipe: {
109
- type: TRANSACTION_TO_PROVE,
110
- transaction: finalTx,
111
- },
112
- };
95
+ return [finalTx, finalState];
113
96
  });
114
97
  }
115
- revert(state, tx) {
98
+ revertTransaction(state, transaction) {
116
99
  return Either.try({
117
100
  try: () => {
118
- return CoreWallet.revertTransaction(state, tx);
101
+ return CoreWallet.revertTransaction(state, transaction);
119
102
  },
120
103
  catch: (err) => {
121
104
  return new OtherWalletError({
122
- message: `Error while reverting transaction ${this.txTrait.id(tx)}`,
105
+ message: `Error while reverting transaction ${transaction.identifiers().at(0)}`,
123
106
  cause: err,
124
107
  });
125
108
  },
126
109
  });
127
110
  }
128
- revertRecipe(state, recipe) {
129
- const doRevert = (tx) => {
130
- return Either.try({
131
- try: () => {
132
- return CoreWallet.revertTransaction(state, tx);
133
- },
134
- catch: (err) => {
135
- return new OtherWalletError({
136
- message: `Error while reverting transaction ${TransactionTrait.unproven.id(tx)}`,
137
- cause: err,
138
- });
139
- },
140
- });
141
- };
142
- switch (recipe.type) {
143
- case TRANSACTION_TO_PROVE:
144
- return doRevert(recipe.transaction);
145
- case BALANCE_TRANSACTION_TO_PROVE:
146
- return doRevert(recipe.transactionToProve);
147
- case NOTHING_TO_PROVE:
148
- return Either.right(state);
149
- }
150
- }
151
111
  #prepareOffer(secretKeys, state, recipe, segment) {
152
112
  const [inputOffers, stateAfterSpends] = CoreWallet.spendCoins(state, secretKeys, recipe.inputs, segment);
153
113
  const stateAfterWatches = CoreWallet.watchCoins(stateAfterSpends, secretKeys, recipe.outputs);
@@ -199,7 +159,7 @@ export class TransactingCapabilityImplementation {
199
159
  },
200
160
  });
201
161
  }
202
- #balanceGuaranteedSection(secretKeys, state, imbalances, coinSelection, knownSelfOutputs, targetImbalances) {
162
+ #balanceGuaranteedSection(secretKeys, state, imbalances, coinSelection, targetImbalances) {
203
163
  return Either.gen(this, function* () {
204
164
  const balanceRecipe = yield* Either.try({
205
165
  try: () => getBalanceRecipe({
@@ -230,69 +190,11 @@ export class TransactingCapabilityImplementation {
230
190
  }
231
191
  },
232
192
  });
233
- if (balanceRecipe.outputs.length + knownSelfOutputs == 0) {
234
- return yield* Either.left(new NoSelfOutputsError({}));
235
- }
236
193
  return yield* pipe(this.#prepareOffer(secretKeys, state, balanceRecipe, 0), Either.fromOption(() => {
237
194
  return new OtherWalletError({
238
195
  message: 'Could not create a valid guaranteed offer',
239
196
  });
240
197
  }));
241
- }).pipe(EitherOps.flatMapLeft((err) => {
242
- if (err instanceof NoSelfOutputsError) {
243
- return this.#balanceGuaranteedWithSelfOutput(secretKeys, state, imbalances, coinSelection, targetImbalances);
244
- }
245
- else {
246
- return Either.left(err);
247
- }
248
- }));
249
- }
250
- #balanceGuaranteedWithSelfOutput(secretKeys, state, imbalances, coinSelection, targetImbalances) {
251
- return Either.gen(this, function* () {
252
- const additionalOutputValue = 100000n;
253
- const balanceRecipe = yield* Either.try({
254
- try: () => {
255
- return getBalanceRecipe({
256
- coins: this.getCoins()
257
- .getAvailableCoins(state)
258
- .map((c) => c.coin),
259
- initialImbalances: Imbalances.merge(imbalances.guaranteed, Imbalances.fromEntry(ledger.shieldedToken().raw, -1n * additionalOutputValue)),
260
- transactionCostModel: ShieldedCostModel,
261
- feeTokenType: '',
262
- coinSelection,
263
- targetImbalances,
264
- createOutput: (coin) => ledger.createShieldedCoinInfo(coin.type, coin.value),
265
- isCoinEqual: (a, b) => a.nonce === b.nonce,
266
- });
267
- },
268
- catch: (err) => {
269
- if (err instanceof BalancingInsufficientFundsError) {
270
- return new InsufficientFundsError({
271
- message: 'Insufficient funds',
272
- tokenType: err.tokenType,
273
- amount: imbalances.guaranteed.get(err.tokenType) ?? 0n,
274
- });
275
- }
276
- else {
277
- return new OtherWalletError({
278
- message: 'Balancing guaranteed section failed',
279
- cause: err,
280
- });
281
- }
282
- },
283
- });
284
- const additionalCoin = ledger.createShieldedCoinInfo(ledger.shieldedToken().raw, additionalOutputValue);
285
- const additionalOffer = pipe(additionalCoin, (coin) => ledger.ZswapOutput.new(coin, 0, this.getKeys().getCoinPublicKey(state).toHexString(), this.getKeys().getEncryptionPublicKey(state).toHexString()), (output) => ledger.ZswapOffer.fromOutput(output, ledger.shieldedToken().raw, additionalOutputValue));
286
- return yield* pipe(this.#prepareOffer(secretKeys, state, balanceRecipe, 0), Option.map(({ newState, offer }) => {
287
- return {
288
- newState: CoreWallet.watchCoins(newState, secretKeys, [additionalCoin]),
289
- offer: offer.merge(additionalOffer),
290
- };
291
- }), Either.fromOption(() => {
292
- return new OtherWalletError({
293
- message: 'Balancing guaranteed section failed',
294
- });
295
- }));
296
198
  });
297
199
  }
298
200
  #parseAddress(addr) {
@@ -349,7 +251,7 @@ export class TransactingCapabilityImplementation {
349
251
  const networkId = this.networkId;
350
252
  const offerToBalance = pipe(initialOffersAndCoins, Arr.map((o) => o.outputOffer), ArrayOps.fold((a, b) => a.merge(b)));
351
253
  const unprovenTxToBalance = ledger.Transaction.fromParts(networkId, offerToBalance);
352
- const imbalances = TransactionTrait.unproven.getImbalances(unprovenTxToBalance);
254
+ const imbalances = TransactionOps.unproven.getImbalances(unprovenTxToBalance);
353
255
  return {
354
256
  imbalances,
355
257
  selfCoins,
@@ -1,4 +1,4 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { CoreWallet } from './CoreWallet.js';
3
3
  export type ProgressUpdate = {
4
4
  appliedIndex: bigint | undefined;
@@ -1,3 +1,15 @@
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 { Imbalances } from '@midnight-ntwrk/wallet-sdk-capabilities';
2
14
  export const ShieldedCostModel = {
3
15
  inputFeeOverhead: 0n,
@@ -1,14 +1,14 @@
1
1
  import { Imbalances } from '@midnight-ntwrk/wallet-sdk-capabilities';
2
2
  import { TransactionImbalances } from './TransactionImbalances.js';
3
- import * as ledger from '@midnight-ntwrk/ledger-v6';
4
- export type TransactionTrait<Tx> = {
3
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
4
+ export type TransactionOps<Tx> = {
5
5
  getImbalances(tx: Tx): TransactionImbalances;
6
6
  id(tx: Tx): string;
7
7
  };
8
- export declare const TransactionTrait: {
9
- default: TransactionTrait<ledger.FinalizedTransaction>;
10
- proofErased: TransactionTrait<ledger.ProofErasedTransaction>;
11
- unproven: TransactionTrait<ledger.UnprovenTransaction>;
8
+ export declare const TransactionOps: {
9
+ default: TransactionOps<ledger.FinalizedTransaction>;
10
+ proofErased: TransactionOps<ledger.ProofErasedTransaction>;
11
+ unproven: TransactionOps<ledger.UnprovenTransaction>;
12
12
  shared: {
13
13
  getImbalances(tx: ledger.FinalizedTransaction | ledger.UnprovenTransaction | ledger.ProofErasedTransaction): TransactionImbalances;
14
14
  getGuaranteedImbalances: (tx: ledger.FinalizedTransaction | ledger.UnprovenTransaction | ledger.ProofErasedTransaction) => Imbalances;
@@ -1,9 +1,21 @@
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 { pipe } from 'effect';
2
14
  import { Imbalances } from '@midnight-ntwrk/wallet-sdk-capabilities';
3
- export const TransactionTrait = new (class {
15
+ export const TransactionOps = new (class {
4
16
  default = {
5
17
  getImbalances(tx) {
6
- return TransactionTrait.shared.getImbalances(tx);
18
+ return TransactionOps.shared.getImbalances(tx);
7
19
  },
8
20
  id(tx) {
9
21
  return tx.identifiers().at(0);
@@ -11,7 +23,7 @@ export const TransactionTrait = new (class {
11
23
  };
12
24
  proofErased = {
13
25
  getImbalances(tx) {
14
- return TransactionTrait.shared.getImbalances(tx);
26
+ return TransactionOps.shared.getImbalances(tx);
15
27
  },
16
28
  id(tx) {
17
29
  return tx.identifiers().at(0);
@@ -19,7 +31,7 @@ export const TransactionTrait = new (class {
19
31
  };
20
32
  unproven = {
21
33
  getImbalances(tx) {
22
- return TransactionTrait.shared.getImbalances(tx);
34
+ return TransactionOps.shared.getImbalances(tx);
23
35
  },
24
36
  id(tx) {
25
37
  return tx.identifiers().at(0);
@@ -27,8 +39,8 @@ export const TransactionTrait = new (class {
27
39
  };
28
40
  shared = {
29
41
  getImbalances(tx) {
30
- const guaranteedImbalances = TransactionTrait.shared.getGuaranteedImbalances(tx);
31
- const fallibleImbalances = TransactionTrait.shared.getFallibleImbalances(tx);
42
+ const guaranteedImbalances = TransactionOps.shared.getGuaranteedImbalances(tx);
43
+ const fallibleImbalances = TransactionOps.shared.getFallibleImbalances(tx);
32
44
  return pipe({
33
45
  guaranteed: guaranteedImbalances,
34
46
  fallible: fallibleImbalances,
@@ -1,4 +1,4 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { Either, Types } from 'effect';
3
3
  import { NetworkId } from '@midnight-ntwrk/wallet-sdk-abstractions';
4
4
  import { Variant, VariantBuilder } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
@@ -1,4 +1,16 @@
1
- import * as ledger 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';
2
14
  import { Effect, Scope } from 'effect';
3
15
  import { WalletSeed } from '@midnight-ntwrk/wallet-sdk-abstractions';
4
16
  import { makeDefaultProvingService } from './Proving.js';
@@ -1,4 +1,4 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
2
2
  import { LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
3
3
  export declare const WalletError: {
4
4
  proving(err: Error): WalletError;
@@ -1,3 +1,15 @@
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 { Data } from 'effect';
2
14
  export const WalletError = {
3
15
  proving(err) {
@@ -5,7 +5,6 @@ export * as Transacting from './Transacting.js';
5
5
  export * as TransactionHistory from './TransactionHistory.js';
6
6
  export * as Serialization from './Serialization.js';
7
7
  export * as Proving from './Proving.js';
8
- export * as ProvingRecipe from './ProvingRecipe.js';
9
8
  export * as CoinsAndBalances from './CoinsAndBalances.js';
10
9
  export * as Keys from './Keys.js';
11
10
  export * from './RunningV1Variant.js';
@@ -13,4 +12,4 @@ export * as Simulator from './Simulator.js';
13
12
  export * as Submission from './Submission.js';
14
13
  export * as WalletError from './WalletError.js';
15
14
  export * from './CoreWallet.js';
16
- export * from './Transaction.js';
15
+ export * from './TransactionOps.js';
package/dist/v1/index.js CHANGED
@@ -1,3 +1,15 @@
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
  export * from './V1Builder.js';
2
14
  export * as Sync from './Sync.js';
3
15
  export * as SyncProgress from './SyncProgress.js';
@@ -5,7 +17,6 @@ export * as Transacting from './Transacting.js';
5
17
  export * as TransactionHistory from './TransactionHistory.js';
6
18
  export * as Serialization from './Serialization.js';
7
19
  export * as Proving from './Proving.js';
8
- export * as ProvingRecipe from './ProvingRecipe.js';
9
20
  export * as CoinsAndBalances from './CoinsAndBalances.js';
10
21
  export * as Keys from './Keys.js';
11
22
  export * from './RunningV1Variant.js';
@@ -13,4 +24,4 @@ export * as Simulator from './Simulator.js';
13
24
  export * as Submission from './Submission.js';
14
25
  export * as WalletError from './WalletError.js';
15
26
  export * from './CoreWallet.js';
16
- export * from './Transaction.js';
27
+ export * from './TransactionOps.js';
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@midnight-ntwrk/wallet-sdk-shielded",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
- "author": "IOHK",
8
+ "author": "Midnight Foundation",
9
9
  "license": "Apache-2.0",
10
10
  "publishConfig": {
11
11
  "registry": "https://npm.pkg.github.com/"
@@ -28,17 +28,17 @@
28
28
  }
29
29
  },
30
30
  "dependencies": {
31
- "@midnight-ntwrk/ledger-v6": "6.1.0-alpha.5",
32
- "@midnight-ntwrk/wallet-sdk-abstractions": "1.0.0-beta.8",
33
- "@midnight-ntwrk/wallet-sdk-address-format": "3.0.0-beta.7",
34
- "@midnight-ntwrk/wallet-sdk-capabilities": "3.0.0-beta.7",
35
- "@midnight-ntwrk/wallet-sdk-indexer-client": "1.0.0-beta.11",
36
- "@midnight-ntwrk/wallet-sdk-node-client": "1.0.0-beta.9",
37
- "@midnight-ntwrk/wallet-sdk-prover-client": "1.0.0-beta.8",
38
- "@midnight-ntwrk/wallet-sdk-runtime": "1.0.0-beta.7",
39
- "@midnight-ntwrk/wallet-sdk-utilities": "1.0.0-beta.7",
31
+ "@midnight-ntwrk/ledger-v7": "7.0.0",
32
+ "@midnight-ntwrk/wallet-sdk-abstractions": "1.0.0",
33
+ "@midnight-ntwrk/wallet-sdk-address-format": "3.0.0",
34
+ "@midnight-ntwrk/wallet-sdk-capabilities": "3.0.0",
35
+ "@midnight-ntwrk/wallet-sdk-indexer-client": "1.0.0",
36
+ "@midnight-ntwrk/wallet-sdk-node-client": "1.0.0",
37
+ "@midnight-ntwrk/wallet-sdk-prover-client": "1.0.0",
38
+ "@midnight-ntwrk/wallet-sdk-runtime": "1.0.0",
39
+ "@midnight-ntwrk/wallet-sdk-utilities": "1.0.0",
40
40
  "@scure/base": "^1.1.9",
41
- "effect": "^3.17.3",
41
+ "effect": "^3.19.14",
42
42
  "isomorphic-ws": "^5.0.0",
43
43
  "node-fetch": "3.3.2",
44
44
  "rxjs": "^7.5",
@@ -49,7 +49,8 @@
49
49
  "typecheck": "tsc -b ./tsconfig.json --noEmit",
50
50
  "test": "vitest run",
51
51
  "lint": "eslint --max-warnings 0",
52
- "format": "prettier --write \"**/*.{ts,js,json,yaml,yml}\"",
52
+ "format": "prettier --write \"**/*.{ts,js,json,yaml,yml,md}\"",
53
+ "format:check": "prettier --check \"**/*.{ts,js,json,yaml,yml,md}\"",
53
54
  "dist": "tsc -b ./tsconfig.build.json",
54
55
  "dist:publish": "tsc -b ./tsconfig.publish.json",
55
56
  "clean": "rimraf --glob dist 'tsconfig.*.tsbuildinfo' && date +%s > .clean-timestamp",
@@ -66,11 +67,12 @@
66
67
  "@polkadot/types": "^16.4.1",
67
68
  "eslint": "^9.37.0",
68
69
  "fast-check": "^4.2.0",
70
+ "prettier": "^3.7.0",
69
71
  "publint": "~0.3.14",
70
72
  "rimraf": "^6.0.1",
71
- "testcontainers": "^11.4.0",
73
+ "testcontainers": "^11.10.0",
72
74
  "to-words": "^4.5.1",
73
75
  "typescript": "^5.9.3",
74
- "vitest": "^3.2.4"
76
+ "vitest": "^4.0.16"
75
77
  }
76
78
  }
@@ -1,18 +0,0 @@
1
- import * as ledger from '@midnight-ntwrk/ledger-v6';
2
- export declare const TRANSACTION_TO_PROVE = "TransactionToProve";
3
- export declare const BALANCE_TRANSACTION_TO_PROVE = "BalanceTransactionToProve";
4
- export declare const NOTHING_TO_PROVE = "NothingToProve";
5
- export type TransactionToProve = {
6
- readonly type: typeof TRANSACTION_TO_PROVE;
7
- readonly transaction: ledger.UnprovenTransaction;
8
- };
9
- export type BalanceTransactionToProve<Transaction> = {
10
- readonly type: typeof BALANCE_TRANSACTION_TO_PROVE;
11
- readonly transactionToProve: ledger.UnprovenTransaction;
12
- readonly transactionToBalance: Transaction;
13
- };
14
- export type NothingToProve<Transaction> = {
15
- readonly type: typeof NOTHING_TO_PROVE;
16
- readonly transaction: Transaction;
17
- };
18
- export type ProvingRecipe<Transaction> = TransactionToProve | BalanceTransactionToProve<Transaction> | NothingToProve<Transaction>;
@@ -1,3 +0,0 @@
1
- export const TRANSACTION_TO_PROVE = 'TransactionToProve';
2
- export const BALANCE_TRANSACTION_TO_PROVE = 'BalanceTransactionToProve';
3
- export const NOTHING_TO_PROVE = 'NothingToProve';