@midnight-ntwrk/wallet-sdk-shielded 1.0.0-beta.10

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.
Files changed (41) hide show
  1. package/dist/ShieldedWallet.d.ts +70 -0
  2. package/dist/ShieldedWallet.js +136 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +13 -0
  5. package/dist/v1/CoinsAndBalances.d.ts +24 -0
  6. package/dist/v1/CoinsAndBalances.js +46 -0
  7. package/dist/v1/CoreWallet.d.ts +49 -0
  8. package/dist/v1/CoreWallet.js +152 -0
  9. package/dist/v1/Keys.d.ts +8 -0
  10. package/dist/v1/Keys.js +16 -0
  11. package/dist/v1/Proving.d.ts +12 -0
  12. package/dist/v1/Proving.js +53 -0
  13. package/dist/v1/ProvingRecipe.d.ts +18 -0
  14. package/dist/v1/ProvingRecipe.js +3 -0
  15. package/dist/v1/RunningV1Variant.d.ts +46 -0
  16. package/dist/v1/RunningV1Variant.js +95 -0
  17. package/dist/v1/Serialization.d.ts +12 -0
  18. package/dist/v1/Serialization.js +103 -0
  19. package/dist/v1/Simulator.d.ts +22 -0
  20. package/dist/v1/Simulator.js +102 -0
  21. package/dist/v1/Submission.d.ts +31 -0
  22. package/dist/v1/Submission.js +69 -0
  23. package/dist/v1/Sync.d.ts +51 -0
  24. package/dist/v1/Sync.js +139 -0
  25. package/dist/v1/SyncProgress.d.ts +22 -0
  26. package/dist/v1/SyncProgress.js +25 -0
  27. package/dist/v1/Transacting.d.ts +69 -0
  28. package/dist/v1/Transacting.js +374 -0
  29. package/dist/v1/Transaction.d.ts +17 -0
  30. package/dist/v1/Transaction.js +76 -0
  31. package/dist/v1/TransactionHistory.d.ts +16 -0
  32. package/dist/v1/TransactionHistory.js +55 -0
  33. package/dist/v1/TransactionImbalances.d.ts +10 -0
  34. package/dist/v1/TransactionImbalances.js +30 -0
  35. package/dist/v1/V1Builder.d.ts +109 -0
  36. package/dist/v1/V1Builder.js +201 -0
  37. package/dist/v1/WalletError.d.ts +75 -0
  38. package/dist/v1/WalletError.js +59 -0
  39. package/dist/v1/index.d.ts +16 -0
  40. package/dist/v1/index.js +28 -0
  41. package/package.json +77 -0
@@ -0,0 +1,70 @@
1
+ import { ProtocolState, ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
2
+ import { BaseV1Configuration, DefaultV1Configuration, V1Variant, CoreWallet } from './v1/index.js';
3
+ import * as ledger from '@midnight-ntwrk/ledger-v6';
4
+ import * as rx from 'rxjs';
5
+ import { ProvingRecipe } from './v1/ProvingRecipe.js';
6
+ import { SerializationCapability } from './v1/Serialization.js';
7
+ import { ProgressUpdate, TransactionHistoryCapability } from './v1/TransactionHistory.js';
8
+ import { AvailableCoin, CoinsAndBalancesCapability, PendingCoin } from './v1/CoinsAndBalances.js';
9
+ import { KeysCapability } from './v1/Keys.js';
10
+ import { ShieldedAddress, ShieldedCoinPublicKey, ShieldedEncryptionPublicKey } from '@midnight-ntwrk/wallet-sdk-address-format';
11
+ import { SubmissionEvent, SubmissionEventCases } from './v1/Submission.js';
12
+ import { TokenTransfer } from './v1/Transacting.js';
13
+ import { WalletSyncUpdate } from './v1/Sync.js';
14
+ import { Variant, VariantBuilder, WalletLike } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
15
+ export type ShieldedWalletCapabilities<TSerialized = string, TTransaction = ledger.FinalizedTransaction> = {
16
+ serialization: SerializationCapability<CoreWallet, null, TSerialized>;
17
+ coinsAndBalances: CoinsAndBalancesCapability<CoreWallet>;
18
+ keys: KeysCapability<CoreWallet>;
19
+ transactionHistory: TransactionHistoryCapability<CoreWallet, TTransaction>;
20
+ };
21
+ export declare class ShieldedWalletState<TSerialized = string, TTransaction = ledger.FinalizedTransaction> {
22
+ 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
+ readonly protocolVersion: ProtocolVersion.ProtocolVersion;
24
+ readonly state: CoreWallet;
25
+ readonly capabilities: ShieldedWalletCapabilities<TSerialized, TTransaction>;
26
+ get balances(): Record<ledger.RawTokenType, bigint>;
27
+ get totalCoins(): readonly (AvailableCoin | PendingCoin)[];
28
+ get availableCoins(): readonly AvailableCoin[];
29
+ get pendingCoins(): readonly PendingCoin[];
30
+ get coinPublicKey(): ShieldedCoinPublicKey;
31
+ get encryptionPublicKey(): ShieldedEncryptionPublicKey;
32
+ get address(): ShieldedAddress;
33
+ get progress(): ProgressUpdate;
34
+ get transactionHistory(): readonly TTransaction[];
35
+ constructor(state: ProtocolState.ProtocolState<CoreWallet>, capabilities: ShieldedWalletCapabilities<TSerialized, TTransaction>);
36
+ serialize(): TSerialized;
37
+ }
38
+ export type SubmitTransactionMethod<TTransaction> = {
39
+ (transaction: TTransaction, waitForStatus: 'Submitted'): Promise<SubmissionEventCases.Submitted>;
40
+ (transaction: TTransaction, waitForStatus: 'InBlock'): Promise<SubmissionEventCases.InBlock>;
41
+ (transaction: TTransaction, waitForStatus: 'Finalized'): Promise<SubmissionEventCases.Finalized>;
42
+ (transaction: TTransaction): Promise<SubmissionEventCases.InBlock>;
43
+ (transaction: TTransaction, waitForStatus?: 'Submitted' | 'InBlock' | 'Finalized'): Promise<SubmissionEvent>;
44
+ };
45
+ export type ShieldedWallet = CustomizedShieldedWallet<ledger.ZswapSecretKeys, ledger.FinalizedTransaction, WalletSyncUpdate, string>;
46
+ export type ShieldedWalletClass = CustomizedShieldedWalletClass<ledger.ZswapSecretKeys, ledger.FinalizedTransaction, WalletSyncUpdate, string>;
47
+ export interface CustomizedShieldedWallet<TStartAux = ledger.ZswapSecretKeys, TTransaction = ledger.FinalizedTransaction, TSyncUpdate = WalletSyncUpdate, TSerialized = string> extends WalletLike.WalletLike<[
48
+ Variant.VersionedVariant<V1Variant<TSerialized, TSyncUpdate, TTransaction, TStartAux>>
49
+ ]> {
50
+ readonly state: rx.Observable<ShieldedWalletState<TSerialized, TTransaction>>;
51
+ 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>;
56
+ readonly submitTransaction: SubmitTransactionMethod<TTransaction>;
57
+ serializeState(): Promise<TSerialized>;
58
+ waitForSyncedState(allowedGap?: bigint): Promise<ShieldedWalletState<TSerialized, TTransaction>>;
59
+ getAddress(): Promise<ShieldedAddress>;
60
+ }
61
+ export interface CustomizedShieldedWalletClass<TStartAux = ledger.ZswapSecretKeys, TTransaction = ledger.FinalizedTransaction, TSyncUpdate = WalletSyncUpdate, TSerialized = string, TConfig extends BaseV1Configuration = DefaultV1Configuration> extends WalletLike.BaseWalletClass<[
62
+ Variant.VersionedVariant<V1Variant<TSerialized, TSyncUpdate, TTransaction, TStartAux>>
63
+ ]> {
64
+ configuration: TConfig;
65
+ startWithShieldedSeed(seed: Uint8Array): CustomizedShieldedWallet<TStartAux, TTransaction, TSyncUpdate, TSerialized>;
66
+ startWithSecretKeys(secretKeys: ledger.ZswapSecretKeys): CustomizedShieldedWallet<TStartAux, TTransaction, TSyncUpdate, TSerialized>;
67
+ restore(serializedState: TSerialized): CustomizedShieldedWallet<TStartAux, TTransaction, TSyncUpdate, TSerialized>;
68
+ }
69
+ export declare function ShieldedWallet(configuration: DefaultV1Configuration): ShieldedWalletClass;
70
+ export declare function CustomShieldedWallet<TConfig extends BaseV1Configuration = DefaultV1Configuration, TStartAux = ledger.ZswapSecretKeys, TTransaction = ledger.FinalizedTransaction, TSyncUpdate = WalletSyncUpdate, TSerialized = string>(configuration: TConfig, builder: VariantBuilder.VariantBuilder<V1Variant<TSerialized, TSyncUpdate, TTransaction, TStartAux>, TConfig>): CustomizedShieldedWalletClass<TStartAux, TTransaction, TSyncUpdate, TSerialized, TConfig>;
@@ -0,0 +1,136 @@
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 { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
14
+ import { V1Builder, V1Tag, CoreWallet } from './v1/index.js';
15
+ import * as ledger from '@midnight-ntwrk/ledger-v6';
16
+ import { Effect, Either } from 'effect';
17
+ import * as rx from 'rxjs';
18
+ import { WalletBuilder } from '@midnight-ntwrk/wallet-sdk-runtime';
19
+ export class ShieldedWalletState {
20
+ static mapState = (capabilities) => (state) => {
21
+ return new ShieldedWalletState(state, capabilities);
22
+ };
23
+ protocolVersion;
24
+ state;
25
+ capabilities;
26
+ get balances() {
27
+ return this.capabilities.coinsAndBalances.getAvailableBalances(this.state);
28
+ }
29
+ get totalCoins() {
30
+ return this.capabilities.coinsAndBalances.getTotalCoins(this.state);
31
+ }
32
+ get availableCoins() {
33
+ return this.capabilities.coinsAndBalances.getAvailableCoins(this.state);
34
+ }
35
+ get pendingCoins() {
36
+ return this.capabilities.coinsAndBalances.getPendingCoins(this.state);
37
+ }
38
+ get coinPublicKey() {
39
+ return this.capabilities.keys.getCoinPublicKey(this.state);
40
+ }
41
+ get encryptionPublicKey() {
42
+ return this.capabilities.keys.getEncryptionPublicKey(this.state);
43
+ }
44
+ get address() {
45
+ return this.capabilities.keys.getAddress(this.state);
46
+ }
47
+ get progress() {
48
+ return this.capabilities.transactionHistory.progress(this.state);
49
+ }
50
+ get transactionHistory() {
51
+ return this.capabilities.transactionHistory.transactionHistory(this.state);
52
+ }
53
+ constructor(state, capabilities) {
54
+ this.protocolVersion = state.version;
55
+ this.state = state.state;
56
+ this.capabilities = capabilities;
57
+ }
58
+ serialize() {
59
+ return this.capabilities.serialization.serialize(this.state);
60
+ }
61
+ }
62
+ export function ShieldedWallet(configuration) {
63
+ return CustomShieldedWallet(configuration, new V1Builder().withDefaults());
64
+ }
65
+ export function CustomShieldedWallet(configuration, builder) {
66
+ const buildArgs = [configuration];
67
+ const BaseWallet = WalletBuilder.init()
68
+ .withVariant(ProtocolVersion.MinSupportedVersion, builder)
69
+ .build(...buildArgs);
70
+ return class CustomShieldedWalletImplementation extends BaseWallet {
71
+ static startWithSecretKeys(secretKeys) {
72
+ return CustomShieldedWalletImplementation.startFirst(CustomShieldedWalletImplementation, CoreWallet.initEmpty(secretKeys, CustomShieldedWalletImplementation.configuration.networkId));
73
+ }
74
+ static startWithShieldedSeed(seed) {
75
+ const secretKeys = ledger.ZswapSecretKeys.fromSeed(seed);
76
+ return CustomShieldedWalletImplementation.startWithSecretKeys(secretKeys);
77
+ }
78
+ static restore(serializedState) {
79
+ const deserialized = CustomShieldedWalletImplementation.allVariantsRecord()[V1Tag].variant.deserializeState(serializedState)
80
+ .pipe(Either.getOrThrow);
81
+ return CustomShieldedWalletImplementation.startFirst(CustomShieldedWalletImplementation, deserialized);
82
+ }
83
+ state;
84
+ constructor(runtime, scope) {
85
+ super(runtime, scope);
86
+ this.state = this.rawState.pipe(rx.map(ShieldedWalletState.mapState(CustomShieldedWalletImplementation.allVariantsRecord()[V1Tag].variant)), rx.shareReplay({ refCount: true, bufferSize: 1 }));
87
+ }
88
+ start(secretKeys) {
89
+ return this.runtime.dispatch({ [V1Tag]: (v1) => v1.startSyncInBackground(secretKeys) }).pipe(Effect.runPromise);
90
+ }
91
+ balanceTransaction(secretKeys, tx) {
92
+ return this.runtime
93
+ .dispatch({
94
+ [V1Tag]: (v1) => v1.balanceTransaction(secretKeys, tx),
95
+ })
96
+ .pipe(Effect.runPromise);
97
+ }
98
+ transferTransaction(secretKeys, outputs) {
99
+ return this.runtime
100
+ .dispatch({
101
+ [V1Tag]: (v1) => v1.transferTransaction(secretKeys, outputs),
102
+ })
103
+ .pipe(Effect.runPromise);
104
+ }
105
+ initSwap(secretKeys, desiredInputs, desiredOutputs) {
106
+ return this.runtime
107
+ .dispatch({ [V1Tag]: (v1) => v1.initSwap(secretKeys, desiredInputs, desiredOutputs) })
108
+ .pipe(Effect.runPromise);
109
+ }
110
+ finalizeTransaction(recipe) {
111
+ return this.runtime
112
+ .dispatch({
113
+ [V1Tag]: (v1) => v1.finalizeTransaction(recipe),
114
+ })
115
+ .pipe(Effect.runPromise);
116
+ }
117
+ submitTransaction = ((tx, waitForStatus = 'InBlock') => {
118
+ return this.runtime
119
+ .dispatch({ [V1Tag]: (v1) => v1.submitTransaction(tx, waitForStatus) })
120
+ .pipe(Effect.runPromise);
121
+ });
122
+ waitForSyncedState(allowedGap = 0n) {
123
+ return rx.firstValueFrom(this.state.pipe(rx.filter((state) => state.state.progress.isCompleteWithin(allowedGap))));
124
+ }
125
+ /**
126
+ * Serializes the most recent state
127
+ * It's preferable to use [[ShieldedWalletState.serialize]] instead, to know exactly, which state is serialized
128
+ */
129
+ serializeState() {
130
+ return rx.firstValueFrom(this.state).then((state) => state.serialize());
131
+ }
132
+ getAddress() {
133
+ return rx.firstValueFrom(this.state).then((state) => state.address);
134
+ }
135
+ };
136
+ }
@@ -0,0 +1 @@
1
+ export * from './ShieldedWallet.js';
package/dist/index.js ADDED
@@ -0,0 +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.
13
+ export * from './ShieldedWallet.js';
@@ -0,0 +1,24 @@
1
+ import { CoreWallet } from './CoreWallet.js';
2
+ import * as ledger from '@midnight-ntwrk/ledger-v6';
3
+ export type AvailableCoin = {
4
+ coin: ledger.QualifiedShieldedCoinInfo;
5
+ commitment: ledger.CoinCommitment;
6
+ nullifier: ledger.Nullifier;
7
+ };
8
+ export type PendingCoin = {
9
+ coin: ledger.ShieldedCoinInfo;
10
+ ttl: Date | undefined;
11
+ commitment: ledger.CoinCommitment;
12
+ nullifier: ledger.Nullifier;
13
+ };
14
+ export type Coin = AvailableCoin | PendingCoin;
15
+ export type Balances = Record<ledger.RawTokenType, bigint>;
16
+ export type CoinsAndBalancesCapability<TState> = {
17
+ getAvailableBalances(state: TState): Balances;
18
+ getPendingBalances(state: TState): Balances;
19
+ getTotalBalances(state: TState): Balances;
20
+ getAvailableCoins(state: TState): readonly AvailableCoin[];
21
+ getPendingCoins(state: TState): readonly PendingCoin[];
22
+ getTotalCoins(state: TState): ReadonlyArray<AvailableCoin | PendingCoin>;
23
+ };
24
+ export declare const makeDefaultCoinsAndBalancesCapability: () => CoinsAndBalancesCapability<CoreWallet>;
@@ -0,0 +1,46 @@
1
+ import { pipe, Array } from 'effect';
2
+ import { RecordOps } from '@midnight-ntwrk/wallet-sdk-utilities';
3
+ const calculateBalances = (coins) => coins.reduce((acc, { coin }) => ({
4
+ ...acc,
5
+ [coin.type]: acc[coin.type] === undefined ? coin.value : acc[coin.type] + coin.value,
6
+ }), {});
7
+ export const makeDefaultCoinsAndBalancesCapability = () => {
8
+ const getAvailableBalances = (state) => {
9
+ const availableCoins = getAvailableCoins(state);
10
+ return calculateBalances(availableCoins);
11
+ };
12
+ const getPendingBalances = (state) => {
13
+ const pendingCoins = getPendingCoins(state);
14
+ return calculateBalances(pendingCoins);
15
+ };
16
+ const getTotalBalances = (state) => {
17
+ const availableBalances = getAvailableBalances(state);
18
+ const pendingBalances = getPendingBalances(state);
19
+ return pipe([availableBalances, pendingBalances], RecordOps.mergeWithAccumulator(0n, (a, b) => a + b));
20
+ };
21
+ const getAvailableCoins = (state) => {
22
+ const pendingSpends = new Set([...state.state.pendingSpends.values()].map(([coin]) => coin.nonce));
23
+ return pipe([...state.state.coins], Array.filter((coin) => !pendingSpends.has(coin.nonce)), Array.map((coin) => {
24
+ return {
25
+ coin,
26
+ commitment: state.coinHashes[coin.nonce].commitment,
27
+ nullifier: state.coinHashes[coin.nonce].nullifier,
28
+ };
29
+ }));
30
+ };
31
+ const getPendingCoins = (state) => pipe([...state.state.pendingOutputs.values()], Array.map(([coin, ttl]) => ({
32
+ coin,
33
+ ttl,
34
+ commitment: state.coinHashes[coin.nonce].commitment,
35
+ nullifier: state.coinHashes[coin.nonce].nullifier,
36
+ })));
37
+ const getTotalCoins = (state) => [...getAvailableCoins(state), ...getPendingCoins(state)];
38
+ return {
39
+ getAvailableBalances,
40
+ getPendingBalances,
41
+ getTotalBalances,
42
+ getAvailableCoins,
43
+ getPendingCoins,
44
+ getTotalCoins,
45
+ };
46
+ };
@@ -0,0 +1,49 @@
1
+ import * as ledger from '@midnight-ntwrk/ledger-v6';
2
+ import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
+ import { Either } from 'effect';
4
+ import { SyncProgress, SyncProgressData } from './SyncProgress.js';
5
+ import { WalletError } from './WalletError.js';
6
+ export type PublicKeys = {
7
+ coinPublicKey: ledger.CoinPublicKey;
8
+ encryptionPublicKey: ledger.EncPublicKey;
9
+ };
10
+ export declare const PublicKeys: {
11
+ fromSecretKeys: (secretKeys: ledger.ZswapSecretKeys) => PublicKeys;
12
+ };
13
+ export type CoinHashesMap = Readonly<Record<ledger.Nonce, {
14
+ nullifier: ledger.Nullifier;
15
+ commitment: ledger.CoinCommitment;
16
+ }>>;
17
+ export declare const CoinHashesMap: {
18
+ empty: {};
19
+ pickAllCoins(state: ledger.ZswapLocalState): readonly ledger.ShieldedCoinInfo[];
20
+ assertValid(map: CoinHashesMap, state: ledger.ZswapLocalState): Either.Either<void, Set<ledger.Nonce>>;
21
+ updateWithCoins(secretKeys: ledger.ZswapSecretKeys, existing: CoinHashesMap, coins: Iterable<ledger.ShieldedCoinInfo>): CoinHashesMap;
22
+ updateWithNewCoins(secretKeys: ledger.ZswapSecretKeys, existing: CoinHashesMap, coins: Iterable<ledger.ShieldedCoinInfo>): CoinHashesMap;
23
+ init(secretKeys: ledger.ZswapSecretKeys, coins: Iterable<ledger.ShieldedCoinInfo>): CoinHashesMap;
24
+ };
25
+ export type CoreWallet = Readonly<{
26
+ state: ledger.ZswapLocalState;
27
+ publicKeys: PublicKeys;
28
+ protocolVersion: ProtocolVersion.ProtocolVersion;
29
+ progress: SyncProgress;
30
+ networkId: string;
31
+ txHistoryArray: readonly ledger.FinalizedTransaction[];
32
+ coinHashes: CoinHashesMap;
33
+ }>;
34
+ export declare const CoreWallet: {
35
+ init(localState: ledger.ZswapLocalState, secretKeys: ledger.ZswapSecretKeys, networkId: string): CoreWallet;
36
+ empty(publicKeys: PublicKeys, networkId: string): CoreWallet;
37
+ restore(localState: ledger.ZswapLocalState, secretKeys: ledger.ZswapSecretKeys, txHistory: readonly ledger.FinalizedTransaction[], syncProgress: Omit<SyncProgressData, "isConnected">, protocolVersion: bigint, networkId: string): CoreWallet;
38
+ restoreWithCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, txHistory: readonly ledger.FinalizedTransaction[], coinHashes: CoinHashesMap, syncProgress: SyncProgressData, protocolVersion: bigint, networkId: string): Either.Either<CoreWallet, WalletError>;
39
+ initEmpty(keys: ledger.ZswapSecretKeys, networkId: string): CoreWallet;
40
+ applyCollapsedUpdate(wallet: CoreWallet, collapsed: ledger.MerkleTreeCollapsedUpdate): CoreWallet;
41
+ apply<TOffer extends ledger.ZswapOffer<ledger.Proofish>>(wallet: CoreWallet, secretKeys: ledger.ZswapSecretKeys, offer: TOffer): CoreWallet;
42
+ replayEvents(wallet: CoreWallet, secretKeys: ledger.ZswapSecretKeys, events: ledger.Event[]): CoreWallet;
43
+ updateProgress(wallet: CoreWallet, { appliedIndex, highestRelevantWalletIndex, highestIndex, highestRelevantIndex, isConnected, }: Partial<SyncProgressData>): CoreWallet;
44
+ addTransaction(wallet: CoreWallet, tx: ledger.FinalizedTransaction): CoreWallet;
45
+ revertTransaction<TTx extends ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>>(wallet: CoreWallet, _tx: TTx): CoreWallet;
46
+ updateTxHistory(wallet: CoreWallet, newTxs: readonly ledger.FinalizedTransaction[]): CoreWallet;
47
+ spendCoins(wallet: CoreWallet, secretKeys: ledger.ZswapSecretKeys, coins: ReadonlyArray<ledger.QualifiedShieldedCoinInfo>, segment: number): [ReadonlyArray<ledger.ZswapOffer<ledger.PreProof>>, CoreWallet];
48
+ watchCoins(wallet: CoreWallet, secretKeys: ledger.ZswapSecretKeys, coins: ReadonlyArray<ledger.ShieldedCoinInfo>): CoreWallet;
49
+ };
@@ -0,0 +1,152 @@
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-v6';
14
+ import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
15
+ import { Either, Iterable, pipe, Record, Array as Arr } from 'effect';
16
+ import { createSyncProgress } from './SyncProgress.js';
17
+ import { InvalidCoinHashesError } from './WalletError.js';
18
+ export const PublicKeys = {
19
+ fromSecretKeys: (secretKeys) => {
20
+ return {
21
+ coinPublicKey: secretKeys.coinPublicKey,
22
+ encryptionPublicKey: secretKeys.encryptionPublicKey,
23
+ };
24
+ },
25
+ };
26
+ export const CoinHashesMap = {
27
+ empty: {},
28
+ pickAllCoins(state) {
29
+ return [...state.coins, ...state.pendingOutputs.values().map(([coin]) => coin)];
30
+ },
31
+ assertValid(map, state) {
32
+ const coins = CoinHashesMap.pickAllCoins(state);
33
+ const coinNonces = new Set(Iterable.map(coins, (coin) => coin.nonce));
34
+ const definedNonces = new Set(Object.keys(map));
35
+ const missingNonces = coinNonces.difference(definedNonces);
36
+ return missingNonces.size === 0 ? Either.void : Either.left(missingNonces);
37
+ },
38
+ updateWithCoins(secretKeys, existing, coins) {
39
+ return Record.fromIterableWith(coins, (coin) => [
40
+ coin.nonce,
41
+ existing[coin.nonce] ?? {
42
+ commitment: ledger.coinCommitment(coin, secretKeys.coinPublicKey),
43
+ nullifier: ledger.coinNullifier(coin, secretKeys.coinSecretKey),
44
+ },
45
+ ]);
46
+ },
47
+ updateWithNewCoins(secretKeys, existing, coins) {
48
+ const newMap = CoinHashesMap.updateWithCoins(secretKeys, CoinHashesMap.empty, coins);
49
+ return Record.union(existing, newMap, (a) => a);
50
+ },
51
+ init(secretKeys, coins) {
52
+ return CoinHashesMap.updateWithCoins(secretKeys, {}, coins);
53
+ },
54
+ };
55
+ export const CoreWallet = {
56
+ init(localState, secretKeys, networkId) {
57
+ const publicKeys = PublicKeys.fromSecretKeys(secretKeys);
58
+ const coinHashes = CoinHashesMap.init(secretKeys, CoinHashesMap.pickAllCoins(localState));
59
+ const progress = createSyncProgress();
60
+ const protocolVersion = ProtocolVersion.MinSupportedVersion;
61
+ return { state: localState, publicKeys, networkId, coinHashes, txHistoryArray: [], progress, protocolVersion };
62
+ },
63
+ empty(publicKeys, networkId) {
64
+ return {
65
+ state: new ledger.ZswapLocalState(),
66
+ publicKeys,
67
+ networkId,
68
+ coinHashes: CoinHashesMap.empty,
69
+ txHistoryArray: [],
70
+ progress: createSyncProgress(),
71
+ protocolVersion: ProtocolVersion.MinSupportedVersion,
72
+ };
73
+ },
74
+ restore(localState, secretKeys, txHistory, syncProgress, protocolVersion, networkId) {
75
+ const publicKeys = PublicKeys.fromSecretKeys(secretKeys);
76
+ const coinHashes = CoinHashesMap.init(secretKeys, CoinHashesMap.pickAllCoins(localState));
77
+ return {
78
+ state: localState,
79
+ publicKeys,
80
+ networkId,
81
+ coinHashes,
82
+ txHistoryArray: txHistory,
83
+ progress: createSyncProgress(syncProgress),
84
+ protocolVersion: ProtocolVersion.ProtocolVersion(protocolVersion),
85
+ };
86
+ },
87
+ restoreWithCoinHashes(publicKeys, localState, txHistory, coinHashes, syncProgress, protocolVersion, networkId) {
88
+ return CoinHashesMap.assertValid(coinHashes, localState).pipe(Either.mapBoth({
89
+ onLeft: (missingNonces) => new InvalidCoinHashesError({ message: 'Missing coin hashes for coins present in the state', missingNonces }),
90
+ onRight: () => ({
91
+ state: localState,
92
+ publicKeys,
93
+ networkId,
94
+ coinHashes,
95
+ txHistoryArray: txHistory,
96
+ progress: createSyncProgress(syncProgress),
97
+ protocolVersion: ProtocolVersion.ProtocolVersion(protocolVersion),
98
+ }),
99
+ }));
100
+ },
101
+ initEmpty(keys, networkId) {
102
+ return this.empty(PublicKeys.fromSecretKeys(keys), networkId);
103
+ },
104
+ applyCollapsedUpdate(wallet, collapsed) {
105
+ const newState = wallet.state.applyCollapsedUpdate(collapsed);
106
+ return { ...wallet, state: newState };
107
+ },
108
+ apply(wallet, secretKeys, offer) {
109
+ const newState = wallet.state.apply(secretKeys, offer);
110
+ const newCoinHashes = CoinHashesMap.updateWithCoins(secretKeys, wallet.coinHashes, CoinHashesMap.pickAllCoins(newState));
111
+ return { ...wallet, state: newState, coinHashes: newCoinHashes };
112
+ },
113
+ replayEvents(wallet, secretKeys, events) {
114
+ const newState = wallet.state.replayEvents(secretKeys, events);
115
+ const newCoinHashes = CoinHashesMap.updateWithCoins(secretKeys, wallet.coinHashes, CoinHashesMap.pickAllCoins(newState));
116
+ return { ...wallet, state: newState, coinHashes: newCoinHashes };
117
+ },
118
+ updateProgress(wallet, { appliedIndex, highestRelevantWalletIndex, highestIndex, highestRelevantIndex, isConnected, }) {
119
+ const updatedProgress = createSyncProgress({
120
+ appliedIndex: appliedIndex ?? wallet.progress.appliedIndex,
121
+ highestRelevantWalletIndex: highestRelevantWalletIndex ?? wallet.progress.highestRelevantWalletIndex,
122
+ highestIndex: highestIndex ?? wallet.progress.highestIndex,
123
+ highestRelevantIndex: highestRelevantIndex ?? wallet.progress.highestRelevantIndex,
124
+ isConnected: isConnected ?? wallet.progress.isConnected,
125
+ });
126
+ return { ...wallet, progress: updatedProgress };
127
+ },
128
+ addTransaction(wallet, tx) {
129
+ return { ...wallet, txHistoryArray: [...wallet.txHistoryArray, tx] };
130
+ },
131
+ /* not implemented until this is done https://shielded.atlassian.net/browse/PM-19678 */
132
+ revertTransaction(wallet, _tx) {
133
+ return wallet;
134
+ },
135
+ updateTxHistory(wallet, newTxs) {
136
+ return { ...wallet, txHistoryArray: [...wallet.txHistoryArray, ...newTxs] };
137
+ },
138
+ spendCoins(wallet, secretKeys, coins, segment) {
139
+ const [offers, newLocalState] = pipe(coins, Arr.reduce([[], wallet.state], ([accOffers, localState], coinToSpend) => {
140
+ const [nextState, newInput] = localState.spend(secretKeys, coinToSpend, segment);
141
+ const inputOffer = ledger.ZswapOffer.fromInput(newInput, coinToSpend.type, coinToSpend.value);
142
+ return [accOffers.concat([inputOffer]), nextState];
143
+ }));
144
+ const updated = { ...wallet, state: newLocalState };
145
+ return [offers, updated];
146
+ },
147
+ watchCoins(wallet, secretKeys, coins) {
148
+ const newLocalState = coins.reduce((localState, coin) => localState.watchFor(wallet.publicKeys.coinPublicKey, coin), wallet.state);
149
+ const newCoinHashes = CoinHashesMap.updateWithNewCoins(secretKeys, wallet.coinHashes, coins);
150
+ return { ...wallet, state: newLocalState, coinHashes: newCoinHashes };
151
+ },
152
+ };
@@ -0,0 +1,8 @@
1
+ import type { CoreWallet } from './CoreWallet.js';
2
+ import { ShieldedAddress, ShieldedCoinPublicKey, ShieldedEncryptionPublicKey } from '@midnight-ntwrk/wallet-sdk-address-format';
3
+ export type KeysCapability<TState> = {
4
+ getCoinPublicKey(state: TState): ShieldedCoinPublicKey;
5
+ getEncryptionPublicKey(state: TState): ShieldedEncryptionPublicKey;
6
+ getAddress(state: TState): ShieldedAddress;
7
+ };
8
+ export declare const makeDefaultKeysCapability: () => KeysCapability<CoreWallet>;
@@ -0,0 +1,16 @@
1
+ import { ShieldedAddress, ShieldedCoinPublicKey, ShieldedEncryptionPublicKey, } from '@midnight-ntwrk/wallet-sdk-address-format';
2
+ export const makeDefaultKeysCapability = () => {
3
+ return {
4
+ getCoinPublicKey: (state) => {
5
+ return new ShieldedCoinPublicKey(Buffer.from(state.publicKeys.coinPublicKey, 'hex'));
6
+ },
7
+ getEncryptionPublicKey: (state) => {
8
+ return new ShieldedEncryptionPublicKey(Buffer.from(state.publicKeys.encryptionPublicKey, 'hex'));
9
+ },
10
+ getAddress: (state) => {
11
+ const coinPublicKey = new ShieldedCoinPublicKey(Buffer.from(state.publicKeys.coinPublicKey, 'hex'));
12
+ const encryptionPublicKey = new ShieldedEncryptionPublicKey(Buffer.from(state.publicKeys.encryptionPublicKey, 'hex'));
13
+ return new ShieldedAddress(coinPublicKey, encryptionPublicKey);
14
+ },
15
+ };
16
+ };
@@ -0,0 +1,12 @@
1
+ import * as ledger from '@midnight-ntwrk/ledger-v6';
2
+ import { Effect } from 'effect';
3
+ import { ProvingRecipe } from './ProvingRecipe.js';
4
+ import { WalletError } from './WalletError.js';
5
+ export interface ProvingService<TTransaction> {
6
+ prove(recipe: ProvingRecipe<TTransaction>): Effect.Effect<TTransaction, WalletError>;
7
+ }
8
+ export type DefaultProvingConfiguration = {
9
+ provingServerUrl: URL;
10
+ };
11
+ export declare const makeDefaultProvingService: (configuration: DefaultProvingConfiguration) => ProvingService<ledger.FinalizedTransaction>;
12
+ export declare const makeSimulatorProvingService: () => ProvingService<ledger.ProofErasedTransaction>;
@@ -0,0 +1,53 @@
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 { HttpProverClient, ProverClient } from '@midnight-ntwrk/wallet-sdk-prover-client/effect';
14
+ import * as ledger from '@midnight-ntwrk/ledger-v6';
15
+ import { Effect, pipe } from 'effect';
16
+ import { ProvingError } from './WalletError.js';
17
+ export const makeDefaultProvingService = (configuration) => {
18
+ const clientLayer = HttpProverClient.layer({
19
+ url: configuration.provingServerUrl,
20
+ });
21
+ return {
22
+ prove(recipe) {
23
+ switch (recipe.type) {
24
+ case 'BalanceTransactionToProve':
25
+ 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({
26
+ message: error.message,
27
+ cause: error,
28
+ }))));
29
+ case 'TransactionToProve':
30
+ 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({
31
+ message: error.message,
32
+ cause: error,
33
+ }))));
34
+ case 'NothingToProve':
35
+ return Effect.succeed(recipe.transaction);
36
+ }
37
+ },
38
+ };
39
+ };
40
+ export const makeSimulatorProvingService = () => {
41
+ return {
42
+ prove(recipe) {
43
+ switch (recipe.type) {
44
+ case 'BalanceTransactionToProve':
45
+ return pipe(Effect.succeed(recipe.transactionToProve.eraseProofs()), Effect.map((proven) => recipe.transactionToBalance.merge(proven)));
46
+ case 'TransactionToProve':
47
+ return Effect.succeed(recipe.transaction.eraseProofs());
48
+ case 'NothingToProve':
49
+ return Effect.succeed(recipe.transaction);
50
+ }
51
+ },
52
+ };
53
+ };
@@ -0,0 +1,18 @@
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>;
@@ -0,0 +1,3 @@
1
+ export const TRANSACTION_TO_PROVE = 'TransactionToProve';
2
+ export const BALANCE_TRANSACTION_TO_PROVE = 'BalanceTransactionToProve';
3
+ export const NOTHING_TO_PROVE = 'NothingToProve';