@midnightntwrk/wallet-sdk-shielded 4.0.0-beta.2 → 4.0.0-beta.4
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 +18 -9
- package/dist/Restore.d.ts +40 -0
- package/dist/Restore.js +63 -0
- package/dist/ShieldedWallet.d.ts +248 -62
- package/dist/ShieldedWallet.js +366 -76
- package/dist/ShieldedWalletAPI.d.ts +179 -0
- package/dist/ShieldedWalletAPI.js +75 -0
- package/dist/SingleVariantShieldedWallet.d.ts +35 -0
- package/dist/SingleVariantShieldedWallet.js +240 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/v1/CoinsAndBalances.d.ts +1 -1
- package/dist/v1/CoreWallet.d.ts +48 -1
- package/dist/v1/CoreWallet.js +54 -1
- package/dist/v1/Migration.d.ts +95 -0
- package/dist/v1/Migration.js +82 -0
- package/dist/v1/RunningV1Variant.d.ts +1 -1
- package/dist/v1/RunningV1Variant.js +37 -8
- package/dist/v1/Serialization.js +1 -1
- package/dist/v1/Sync.d.ts +132 -9
- package/dist/v1/Sync.js +272 -36
- package/dist/v1/Transacting.d.ts +1 -1
- package/dist/v1/Transacting.js +3 -2
- package/dist/v1/TransactionHistory.d.ts +9 -2
- package/dist/v1/TransactionHistory.js +26 -5
- package/dist/v1/TransactionOps.d.ts +1 -1
- package/dist/v1/V1Builder.d.ts +87 -26
- package/dist/v1/V1Builder.js +109 -8
- package/dist/v1/WalletError.d.ts +27 -2
- package/dist/v1/WalletError.js +16 -0
- package/dist/v1/index.d.ts +2 -1
- package/dist/v1/index.js +5 -1
- package/dist/v2/CoinsAndBalances.d.ts +24 -0
- package/dist/v2/CoinsAndBalances.js +41 -0
- package/dist/v2/CoreWallet.d.ts +162 -0
- package/dist/v2/CoreWallet.js +305 -0
- package/dist/v2/Keys.d.ts +8 -0
- package/dist/v2/Keys.js +16 -0
- package/dist/v2/Migration.d.ts +112 -0
- package/dist/v2/Migration.js +96 -0
- package/dist/v2/RunningV2Variant.d.ts +40 -0
- package/dist/v2/RunningV2Variant.js +127 -0
- package/dist/v2/Serialization.d.ts +12 -0
- package/dist/v2/Serialization.js +93 -0
- package/dist/v2/Sync.d.ts +208 -0
- package/dist/v2/Sync.js +463 -0
- package/dist/v2/Transacting.d.ts +50 -0
- package/dist/v2/Transacting.js +259 -0
- package/dist/v2/TransactionHistory.d.ts +100 -0
- package/dist/v2/TransactionHistory.js +132 -0
- package/dist/v2/TransactionImbalances.d.ts +10 -0
- package/dist/v2/TransactionImbalances.js +30 -0
- package/dist/v2/TransactionOps.d.ts +17 -0
- package/dist/v2/TransactionOps.js +73 -0
- package/dist/v2/V2Builder.d.ts +154 -0
- package/dist/v2/V2Builder.js +273 -0
- package/dist/v2/WalletError.d.ts +99 -0
- package/dist/v2/WalletError.js +69 -0
- package/dist/v2/index.d.ts +13 -0
- package/dist/v2/index.js +26 -0
- package/package.json +16 -8
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contract every shielded wallet composition fulfils, and the state it emits.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Shared by the single-variant composition (`SingleVariantShieldedWallet.ts`) and the one that spans a protocol
|
|
6
|
+
* boundary (`ShieldedWallet.ts`), and kept apart from both so that neither has to import the other to speak the same
|
|
7
|
+
* API. Nothing here knows how many variants are running: a state emission arrives already bound to the capabilities
|
|
8
|
+
* of the variant that produced it, and everything below that binding is plain data.
|
|
9
|
+
*/
|
|
10
|
+
import type * as ledger from '@midnightntwrk/ledger-v9';
|
|
11
|
+
import { type AnyTx, type NetworkId, type ProtocolState, ProtocolVersion, type SyncProgress, type UnprovenTx } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
12
|
+
import { type ShieldedAddress, type ShieldedCoinPublicKey, type ShieldedEncryptionPublicKey } from '@midnightntwrk/wallet-sdk-address-format';
|
|
13
|
+
import type { ChainVersionProbe } from '@midnightntwrk/wallet-sdk-capabilities/chainVersion';
|
|
14
|
+
import type { V9UnboundTransaction } from '@midnightntwrk/wallet-sdk-capabilities/proving';
|
|
15
|
+
import { type Duration } from 'effect';
|
|
16
|
+
import type * as rx from 'rxjs';
|
|
17
|
+
import { type CoreWallet as V1CoreWallet } from './v1/CoreWallet.js';
|
|
18
|
+
import { type AvailableCoin, type CoinsAndBalancesCapability, type PendingCoin } from './v2/CoinsAndBalances.js';
|
|
19
|
+
import { type CoreWallet } from './v2/index.js';
|
|
20
|
+
import { type KeysCapability } from './v2/Keys.js';
|
|
21
|
+
import { type SerializationCapability } from './v2/Serialization.js';
|
|
22
|
+
import { type BatchUpdatesConfig, type IndexerClientConnection } from './v2/Sync.js';
|
|
23
|
+
import { type TokenTransfer } from './v2/Transacting.js';
|
|
24
|
+
import { type ShieldedHistoryStorage, type TransactionHistoryService } from './v2/TransactionHistory.js';
|
|
25
|
+
export type ShieldedWalletCapabilities<TSerialized = string> = {
|
|
26
|
+
serialization: SerializationCapability<CoreWallet, null, TSerialized>;
|
|
27
|
+
coinsAndBalances: CoinsAndBalancesCapability<CoreWallet>;
|
|
28
|
+
keys: KeysCapability<CoreWallet>;
|
|
29
|
+
};
|
|
30
|
+
export type ShieldedWalletServices = {
|
|
31
|
+
transactionHistory: TransactionHistoryService;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* A transaction that has been proven but not yet bound.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* Owned by the proving capability, which is what produces one, and re-exported here so the name stays where callers
|
|
38
|
+
* already reach for it. The shielded wallet neither builds nor consumes one itself.
|
|
39
|
+
*/
|
|
40
|
+
export type { V9UnboundTransaction };
|
|
41
|
+
/** The core state of whichever shielded variant produced an emission. */
|
|
42
|
+
export type ShieldedCoreState = V1CoreWallet | CoreWallet;
|
|
43
|
+
/**
|
|
44
|
+
* Everything a state emission projects, already bound to the variant that produced it.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* Binding is the point. The capabilities that understand a state and the state itself must be chosen together, in the
|
|
48
|
+
* branch where the producing variant is known; the two variants' capability types are structurally identical, so a
|
|
49
|
+
* capability of one would type-check against a state of the other and be wrong at runtime. Once bound there is
|
|
50
|
+
* nothing left to mis-pair, and everything below is version-agnostic plain data.
|
|
51
|
+
*/
|
|
52
|
+
type ShieldedProjections<TSerialized> = Readonly<{
|
|
53
|
+
balances: () => Record<ledger.RawTokenType, bigint>;
|
|
54
|
+
totalCoins: () => readonly (AvailableCoin | PendingCoin)[];
|
|
55
|
+
availableCoins: () => readonly AvailableCoin[];
|
|
56
|
+
pendingCoins: () => readonly PendingCoin[];
|
|
57
|
+
coinPublicKey: () => ShieldedCoinPublicKey;
|
|
58
|
+
encryptionPublicKey: () => ShieldedEncryptionPublicKey;
|
|
59
|
+
address: () => ShieldedAddress;
|
|
60
|
+
serialize: () => TSerialized;
|
|
61
|
+
}>;
|
|
62
|
+
/** The capability set a variant exposes for reading and serializing its own state. */
|
|
63
|
+
type ShieldedStateCapabilities<TState, TSerialized> = Readonly<{
|
|
64
|
+
serialization: SerializationCapability<TState, null, TSerialized>;
|
|
65
|
+
coinsAndBalances: CoinsAndBalancesCapability<TState>;
|
|
66
|
+
keys: KeysCapability<TState>;
|
|
67
|
+
}>;
|
|
68
|
+
export declare class ShieldedWalletState<TSerialized = string, _TTransaction = ledger.FinalizedTransaction> {
|
|
69
|
+
#private;
|
|
70
|
+
/**
|
|
71
|
+
* Wraps a state emission with the capabilities of the variant that produced it.
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* Call this inside a branch that has narrowed on the emission's `variantTag`, so `variant` and `state` are known to
|
|
75
|
+
* belong together. It is generic over the state type precisely so that pairing is checked.
|
|
76
|
+
*/
|
|
77
|
+
static readonly fromVariant: <TState, TSerialized_1 = string>(variant: ShieldedStateCapabilities<TState, TSerialized_1>, state: ProtocolState.ProtocolState<TState>) => ShieldedWalletState<TSerialized_1>;
|
|
78
|
+
readonly protocolVersion: ProtocolVersion.ProtocolVersion;
|
|
79
|
+
readonly state: ShieldedCoreState;
|
|
80
|
+
get balances(): Record<ledger.RawTokenType, bigint>;
|
|
81
|
+
get totalCoins(): readonly (AvailableCoin | PendingCoin)[];
|
|
82
|
+
get availableCoins(): readonly AvailableCoin[];
|
|
83
|
+
get pendingCoins(): readonly PendingCoin[];
|
|
84
|
+
get coinPublicKey(): ShieldedCoinPublicKey;
|
|
85
|
+
get encryptionPublicKey(): ShieldedEncryptionPublicKey;
|
|
86
|
+
get address(): ShieldedAddress;
|
|
87
|
+
get progress(): SyncProgress.SyncProgress;
|
|
88
|
+
constructor(protocolVersion: ProtocolVersion.ProtocolVersion, state: ShieldedCoreState, projections: ShieldedProjections<TSerialized>);
|
|
89
|
+
serialize(): TSerialized;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* What balancing a transaction with shielded coins produces: a transaction covering the shortfall, when there is one.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* A handle rather than a ledger transaction, because which ledger version built it is the variant's business and not
|
|
96
|
+
* the caller's. Absent when the wallet had nothing to add — the transaction was already balanced on the shielded
|
|
97
|
+
* side.
|
|
98
|
+
*/
|
|
99
|
+
export type ShieldedBalancingResult = UnprovenTx | undefined;
|
|
100
|
+
export type ShieldedWalletAPI<TStartAux extends ledger.ZswapSecretKeys = ledger.ZswapSecretKeys, TTransaction = ledger.FinalizedTransaction, TSerialized = string> = {
|
|
101
|
+
readonly state: rx.Observable<ShieldedWalletState<TSerialized, TTransaction>>;
|
|
102
|
+
start(secretKeys: TStartAux): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Balances a transaction with shielded coins.
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* No key material is passed: the wallet derives what its current variant needs from what it was started with. A
|
|
108
|
+
* caller-supplied key object could only ever belong to one ledger version, which is exactly what a wallet spanning
|
|
109
|
+
* a protocol boundary cannot assume.
|
|
110
|
+
*/
|
|
111
|
+
balanceTransaction(tx: AnyTx): Promise<ShieldedBalancingResult>;
|
|
112
|
+
transferTransaction(outputs: readonly TokenTransfer[]): Promise<UnprovenTx>;
|
|
113
|
+
initSwap(desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: readonly TokenTransfer[]): Promise<UnprovenTx>;
|
|
114
|
+
serializeState(): Promise<TSerialized>;
|
|
115
|
+
waitForSyncedState(allowedGap?: bigint): Promise<ShieldedWalletState<TSerialized, TTransaction>>;
|
|
116
|
+
getAddress(): Promise<ShieldedAddress>;
|
|
117
|
+
revertTransaction(transaction: AnyTx): Promise<void>;
|
|
118
|
+
stop(): Promise<void>;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The protocol version a ledger-v9-native chain hands over at.
|
|
122
|
+
*
|
|
123
|
+
* @deprecated Use {@link ProtocolVersion.V9NativeForkVersion} from `@midnightntwrk/wallet-sdk-abstractions` (or the
|
|
124
|
+
* umbrella package) — the value is a property of the chain, not of the shielded wallet, and lives with the version
|
|
125
|
+
* type now. This alias is the same value and will be removed in a later release.
|
|
126
|
+
*/
|
|
127
|
+
export declare const V9_NATIVE_FORK_VERSION: ProtocolVersion.ProtocolVersion;
|
|
128
|
+
/**
|
|
129
|
+
* The configuration a default {@link ShieldedWallet} is built from.
|
|
130
|
+
*
|
|
131
|
+
* @remarks
|
|
132
|
+
* Declared by this package rather than aliased to a variant's configuration. A wallet that spans a protocol boundary is
|
|
133
|
+
* built from more than one variant, so no single variant's configuration can be the wallet's public contract: the
|
|
134
|
+
* package states what it asks an application for, and maps it onto whichever variants it registers.
|
|
135
|
+
*
|
|
136
|
+
* The field types are still the ones the variants declare, because they are version-agnostic — `configuration.test.ts`
|
|
137
|
+
* asserts that this type remains interchangeable with what _both_ variants are built from, so a divergence surfaces
|
|
138
|
+
* as a compile error here instead of as a wallet that cannot be built for one of its variants.
|
|
139
|
+
*/
|
|
140
|
+
export type DefaultShieldedConfiguration = {
|
|
141
|
+
networkId: NetworkId.NetworkId;
|
|
142
|
+
indexerClientConnection: IndexerClientConnection;
|
|
143
|
+
batchUpdates?: BatchUpdatesConfig;
|
|
144
|
+
txHistoryStorage: ShieldedHistoryStorage;
|
|
145
|
+
transactionDetailsRetryWindow?: Duration.DurationInput;
|
|
146
|
+
/**
|
|
147
|
+
* Where each ledger version begins on this chain: under `v9`, the protocol version at which it hands over from
|
|
148
|
+
* ledger-v8 to ledger-v9.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* Required, and deliberately without a default: the wallet registers one variant either side of the boundary, so a
|
|
152
|
+
* wrong value does not degrade — it decides which ledger version reads the chain. Below `forks.v9` the ledger-v8
|
|
153
|
+
* variant is active; from it, the ledger-v9 one. The SDK cannot guess it, because it is a property of the chain the
|
|
154
|
+
* application points at, not of the SDK.
|
|
155
|
+
*
|
|
156
|
+
* A map keyed by ledger version rather than a single number, so the next hard fork adds a key instead of changing the
|
|
157
|
+
* shape of every application's configuration — see {@link ProtocolVersion.ForkSchedule}. A node reporting a 2.x
|
|
158
|
+
* runtime version reports protocol version `2000000`, which is therefore the value for a ledger-v9-native chain —
|
|
159
|
+
* published as `ProtocolVersion.V9NativeForkVersion`. The final mainnet fork constant is not yet fixed; it will
|
|
160
|
+
* join that one once it is, and this field keeps working unchanged.
|
|
161
|
+
*/
|
|
162
|
+
forks: ProtocolVersion.ForkSchedule;
|
|
163
|
+
/**
|
|
164
|
+
* How the wallet asks the chain which protocol version its timeline starts under, before it chooses a variant to
|
|
165
|
+
* start at.
|
|
166
|
+
*
|
|
167
|
+
* @remarks
|
|
168
|
+
* Optional, and defaulted rather than absent: left unset, the wallet asks the indexer named by
|
|
169
|
+
* {@link indexerClientConnection}, which it is about to synchronize from anyway. Supply one to ask something else —
|
|
170
|
+
* a cache, a node RPC, a value the application already holds — and have it answer the same question: the version of
|
|
171
|
+
* the chain's **first** block, not its latest. A fresh wallet reads history from the start, so the variant it needs
|
|
172
|
+
* is the one that can deserialize the first event it fetches; a probe reporting the tip of a chain that forked over
|
|
173
|
+
* its own history starts the wallet on a ledger version that cannot read what it is about to be served.
|
|
174
|
+
*
|
|
175
|
+
* The answer is best-effort wherever it comes from: a chain that cannot be reached leaves the wallet starting exactly
|
|
176
|
+
* where it started before there was a probe.
|
|
177
|
+
*/
|
|
178
|
+
chainVersionProbe?: ChainVersionProbe;
|
|
179
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// This file is part of MIDNIGHT-WALLET-SDK.
|
|
2
|
+
// Copyright (C) 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 '@midnightntwrk/wallet-sdk-abstractions';
|
|
14
|
+
export class ShieldedWalletState {
|
|
15
|
+
/**
|
|
16
|
+
* Wraps a state emission with the capabilities of the variant that produced it.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* Call this inside a branch that has narrowed on the emission's `variantTag`, so `variant` and `state` are known to
|
|
20
|
+
* belong together. It is generic over the state type precisely so that pairing is checked.
|
|
21
|
+
*/
|
|
22
|
+
static fromVariant = (variant, state) => new ShieldedWalletState(state.version, state.state, {
|
|
23
|
+
balances: () => variant.coinsAndBalances.getAvailableBalances(state.state),
|
|
24
|
+
totalCoins: () => variant.coinsAndBalances.getTotalCoins(state.state),
|
|
25
|
+
availableCoins: () => variant.coinsAndBalances.getAvailableCoins(state.state),
|
|
26
|
+
pendingCoins: () => variant.coinsAndBalances.getPendingCoins(state.state),
|
|
27
|
+
coinPublicKey: () => variant.keys.getCoinPublicKey(state.state),
|
|
28
|
+
encryptionPublicKey: () => variant.keys.getEncryptionPublicKey(state.state),
|
|
29
|
+
address: () => variant.keys.getAddress(state.state),
|
|
30
|
+
serialize: () => variant.serialization.serialize(state.state),
|
|
31
|
+
});
|
|
32
|
+
protocolVersion;
|
|
33
|
+
state;
|
|
34
|
+
#projections;
|
|
35
|
+
get balances() {
|
|
36
|
+
return this.#projections.balances();
|
|
37
|
+
}
|
|
38
|
+
get totalCoins() {
|
|
39
|
+
return this.#projections.totalCoins();
|
|
40
|
+
}
|
|
41
|
+
get availableCoins() {
|
|
42
|
+
return this.#projections.availableCoins();
|
|
43
|
+
}
|
|
44
|
+
get pendingCoins() {
|
|
45
|
+
return this.#projections.pendingCoins();
|
|
46
|
+
}
|
|
47
|
+
get coinPublicKey() {
|
|
48
|
+
return this.#projections.coinPublicKey();
|
|
49
|
+
}
|
|
50
|
+
get encryptionPublicKey() {
|
|
51
|
+
return this.#projections.encryptionPublicKey();
|
|
52
|
+
}
|
|
53
|
+
get address() {
|
|
54
|
+
return this.#projections.address();
|
|
55
|
+
}
|
|
56
|
+
get progress() {
|
|
57
|
+
return this.state.progress;
|
|
58
|
+
}
|
|
59
|
+
constructor(protocolVersion, state, projections) {
|
|
60
|
+
this.protocolVersion = protocolVersion;
|
|
61
|
+
this.state = state;
|
|
62
|
+
this.#projections = projections;
|
|
63
|
+
}
|
|
64
|
+
serialize() {
|
|
65
|
+
return this.#projections.serialize();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The protocol version a ledger-v9-native chain hands over at.
|
|
70
|
+
*
|
|
71
|
+
* @deprecated Use {@link ProtocolVersion.V9NativeForkVersion} from `@midnightntwrk/wallet-sdk-abstractions` (or the
|
|
72
|
+
* umbrella package) — the value is a property of the chain, not of the shielded wallet, and lives with the version
|
|
73
|
+
* type now. This alias is the same value and will be removed in a later release.
|
|
74
|
+
*/
|
|
75
|
+
export const V9_NATIVE_FORK_VERSION = ProtocolVersion.V9NativeForkVersion;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A shielded wallet composed from a single variant, which answers for the whole protocol timeline.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* The composition for a wallet that is not expected to meet a protocol boundary — a test harness, a simulator-driven
|
|
6
|
+
* wallet, an application pinned to one protocol version. Its one variant is registered from the minimum supported
|
|
7
|
+
* version, so it stamps every transaction at that floor and accepts one of any version; the price is that it cannot
|
|
8
|
+
* cross a protocol boundary. The wallet that can is `ShieldedWallet`, in `ShieldedWallet.ts`.
|
|
9
|
+
*/
|
|
10
|
+
import * as ledger from '@midnightntwrk/ledger-v9';
|
|
11
|
+
import { type Variant, type VariantBuilder, type WalletLike } from '@midnightntwrk/wallet-sdk-runtime/abstractions';
|
|
12
|
+
import { type DefaultShieldedConfiguration, type ShieldedWalletAPI } from './ShieldedWalletAPI.js';
|
|
13
|
+
import { type BaseV2Configuration, type DefaultV2Configuration, type V2Variant } from './v2/index.js';
|
|
14
|
+
import { type WalletSyncUpdate } from './v2/Sync.js';
|
|
15
|
+
export type CustomizedShieldedWallet<TStartAux extends ledger.ZswapSecretKeys = ledger.ZswapSecretKeys, TTransaction = ledger.FinalizedTransaction, TSyncUpdate = WalletSyncUpdate, TSerialized = string> = ShieldedWalletAPI<TStartAux, TTransaction, TSerialized> & WalletLike.WalletLike<[Variant.VersionedVariant<V2Variant<TSerialized, TSyncUpdate, TTransaction, TStartAux>>]>;
|
|
16
|
+
export interface CustomizedShieldedWalletClass<TStartAux extends ledger.ZswapSecretKeys = ledger.ZswapSecretKeys, TTransaction = ledger.FinalizedTransaction, TSyncUpdate = WalletSyncUpdate, TSerialized = string, TConfig extends BaseV2Configuration = DefaultShieldedConfiguration> extends WalletLike.BaseWalletClass<[
|
|
17
|
+
Variant.VersionedVariant<V2Variant<TSerialized, TSyncUpdate, TTransaction, TStartAux>>
|
|
18
|
+
]> {
|
|
19
|
+
configuration: TConfig;
|
|
20
|
+
startWithSeed(seed: Uint8Array): CustomizedShieldedWallet<TStartAux, TTransaction, TSyncUpdate, TSerialized>;
|
|
21
|
+
startWithSecretKeys(secretKeys: ledger.ZswapSecretKeys): CustomizedShieldedWallet<TStartAux, TTransaction, TSyncUpdate, TSerialized>;
|
|
22
|
+
restore(serializedState: TSerialized): CustomizedShieldedWallet<TStartAux, TTransaction, TSyncUpdate, TSerialized>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Builds a shielded wallet class over a single variant.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* One variant, and therefore one ledger version: this is the composition for a wallet that is not expected to meet a
|
|
29
|
+
* protocol boundary — a test harness, a simulator-driven wallet, an application pinned to one protocol version. The
|
|
30
|
+
* wallet this package ships is `ShieldedWallet`, which registers a variant either side of the boundary.
|
|
31
|
+
* @param configuration What the variant is built from.
|
|
32
|
+
* @param builder The variant builder.
|
|
33
|
+
* @returns The wallet class.
|
|
34
|
+
*/
|
|
35
|
+
export declare function CustomShieldedWallet<TConfig extends BaseV2Configuration = DefaultV2Configuration, TStartAux extends ledger.ZswapSecretKeys = ledger.ZswapSecretKeys, TTransaction = ledger.FinalizedTransaction, TSyncUpdate = WalletSyncUpdate, TSerialized = string>(configuration: TConfig, builder: VariantBuilder.VariantBuilder<V2Variant<TSerialized, TSyncUpdate, TTransaction, TStartAux>, TConfig>): CustomizedShieldedWalletClass<TStartAux, TTransaction, TSyncUpdate, TSerialized, TConfig>;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// This file is part of MIDNIGHT-WALLET-SDK.
|
|
2
|
+
// Copyright (C) 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
|
+
/**
|
|
14
|
+
* A shielded wallet composed from a single variant, which answers for the whole protocol timeline.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* The composition for a wallet that is not expected to meet a protocol boundary — a test harness, a simulator-driven
|
|
18
|
+
* wallet, an application pinned to one protocol version. Its one variant is registered from the minimum supported
|
|
19
|
+
* version, so it stamps every transaction at that floor and accepts one of any version; the price is that it cannot
|
|
20
|
+
* cross a protocol boundary. The wallet that can is `ShieldedWallet`, in `ShieldedWallet.ts`.
|
|
21
|
+
*/
|
|
22
|
+
import * as ledger from '@midnightntwrk/ledger-v9';
|
|
23
|
+
import { ProtocolVersion, WalletSeed, WalletTransaction, } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
24
|
+
import { WalletBuilder } from '@midnightntwrk/wallet-sdk-runtime';
|
|
25
|
+
import { StartMaterial, } from '@midnightntwrk/wallet-sdk-runtime/abstractions';
|
|
26
|
+
import { EitherOps, HList, Poly } from '@midnightntwrk/wallet-sdk-utilities';
|
|
27
|
+
import { Effect, Either, Option, Ref } from 'effect';
|
|
28
|
+
import * as rx from 'rxjs';
|
|
29
|
+
import { variantForSnapshot } from './Restore.js';
|
|
30
|
+
import { ShieldedWalletState, } from './ShieldedWalletAPI.js';
|
|
31
|
+
import { V2Tag, CoreWallet, } from './v2/index.js';
|
|
32
|
+
/**
|
|
33
|
+
* Builds a shielded wallet class over a single variant.
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* One variant, and therefore one ledger version: this is the composition for a wallet that is not expected to meet a
|
|
37
|
+
* protocol boundary — a test harness, a simulator-driven wallet, an application pinned to one protocol version. The
|
|
38
|
+
* wallet this package ships is `ShieldedWallet`, which registers a variant either side of the boundary.
|
|
39
|
+
* @param configuration What the variant is built from.
|
|
40
|
+
* @param builder The variant builder.
|
|
41
|
+
* @returns The wallet class.
|
|
42
|
+
*/
|
|
43
|
+
export function CustomShieldedWallet(configuration, builder) {
|
|
44
|
+
const buildArgs = [configuration];
|
|
45
|
+
const BaseWallet = WalletBuilder.init()
|
|
46
|
+
.withVariant(ProtocolVersion.MinSupportedVersion, builder)
|
|
47
|
+
.build(...buildArgs);
|
|
48
|
+
return class CustomShieldedWalletImplementation extends BaseWallet {
|
|
49
|
+
static startWithSecretKeys(secretKeys) {
|
|
50
|
+
return CustomShieldedWalletImplementation.startFirst(CustomShieldedWalletImplementation, CoreWallet.initEmpty(secretKeys, CustomShieldedWalletImplementation.configuration.networkId));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Builds a wallet from a seed, and remembers the seed.
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* The seed is the only key material that crosses a protocol boundary, so a wallet built this way can start
|
|
57
|
+
* synchronization on any variant it is ever migrated to — each derives its own from the seed. A wallet built from
|
|
58
|
+
* key objects instead can only start the variants it was given objects for.
|
|
59
|
+
*/
|
|
60
|
+
static startWithSeed(seed) {
|
|
61
|
+
const walletSeed = WalletSeed.WalletSeed(seed);
|
|
62
|
+
const secretKeys = ledger.ZswapSecretKeys.fromSeed(walletSeed);
|
|
63
|
+
const wallet = CustomShieldedWalletImplementation.startWithSecretKeys(secretKeys);
|
|
64
|
+
wallet.#retainSeed(walletSeed);
|
|
65
|
+
return wallet;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Restores a wallet from a snapshot, into whichever registered variant wrote it.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* The snapshot declares the protocol version it was written at, so the variant that can read it is a lookup rather
|
|
72
|
+
* than an assumption. A snapshot written before snapshots declared a version, or a serialization format this
|
|
73
|
+
* wallet does not recognise as an envelope at all, restores into the head variant — which is what every restore
|
|
74
|
+
* did before there was more than one variant to choose between.
|
|
75
|
+
* @param serializedState The serialized wallet state.
|
|
76
|
+
* @returns A wallet started from that state, on the variant that owns its protocol version.
|
|
77
|
+
* @throws UnsupportedSnapshotVersionError if the snapshot declares a version no registered variant reads.
|
|
78
|
+
*/
|
|
79
|
+
static restore(serializedState) {
|
|
80
|
+
const headVariant = HList.head(CustomShieldedWalletImplementation.allVariants());
|
|
81
|
+
const routed =
|
|
82
|
+
// Routing reads a serialized envelope, which only a wallet keeping the default string serialization has. A
|
|
83
|
+
// custom format is left with the behaviour it has always had.
|
|
84
|
+
typeof serializedState === 'string'
|
|
85
|
+
? variantForSnapshot(serializedState, (version) => CustomShieldedWalletImplementation.variantFor(version), headVariant)
|
|
86
|
+
: Either.right(headVariant);
|
|
87
|
+
const variant = routed.pipe(Either.getOrThrow);
|
|
88
|
+
const deserialized = variant.variant.deserializeState(serializedState).pipe(Either.getOrThrow);
|
|
89
|
+
return CustomShieldedWalletImplementation.startAtVariant(CustomShieldedWalletImplementation, variant, deserialized);
|
|
90
|
+
}
|
|
91
|
+
state;
|
|
92
|
+
/**
|
|
93
|
+
* What the application started this wallet with, kept so synchronization can be started again.
|
|
94
|
+
*
|
|
95
|
+
* @remarks
|
|
96
|
+
* A migration starts a fresh variant whose sync has never run, and sync needs key material. That material cannot
|
|
97
|
+
* come from the state — it is deliberately absent from anything serialized — and does not exist when the wallet
|
|
98
|
+
* is first constructed, so it is held here, in memory, for the lifetime of the wallet. Cleared by {@link stop} so
|
|
99
|
+
* a stopped wallet cannot be silently resurrected by a late activation.
|
|
100
|
+
*
|
|
101
|
+
* A retained seed answers for every variant. Retained key objects answer only for the variants they were supplied
|
|
102
|
+
* for, and accumulate per variant tag as `start` is called, which is the same product a caller holding key
|
|
103
|
+
* objects for both protocol versions would hand over at once.
|
|
104
|
+
*/
|
|
105
|
+
#retainedStartMaterial = Ref.unsafeMake(Option.none());
|
|
106
|
+
/** Remembers a seed, which supersedes any key objects retained for individual variants. */
|
|
107
|
+
#retainSeed(seed) {
|
|
108
|
+
Ref.set(this.#retainedStartMaterial, Option.some(StartMaterial.fromSeed(seed))).pipe(Effect.runSync);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Starts synchronization on a variant that has just become current, with key material it can use.
|
|
112
|
+
*
|
|
113
|
+
* @remarks
|
|
114
|
+
* The derivation is the activating variant's own, so a wallet retaining a seed hands each variant key material
|
|
115
|
+
* built by its own ledger version. A wallet retaining key objects for other variants only cannot answer, and says
|
|
116
|
+
* so rather than handing over keys the variant would silently misuse.
|
|
117
|
+
*/
|
|
118
|
+
#resumeSyncOn(variantTag, running) {
|
|
119
|
+
return Ref.get(this.#retainedStartMaterial).pipe(Effect.flatMap(Option.match({
|
|
120
|
+
// Stopped, or never started: there is nothing to resume and nothing to resume it with.
|
|
121
|
+
onNone: () => Effect.void,
|
|
122
|
+
onSome: (retained) => EitherOps.toEffect(StartMaterial.requireAuxFor(retained, variantTag, (seed) => CustomShieldedWalletImplementation.allVariantsRecord()[variantTag].variant.startAux.fromSeed(seed))).pipe(Effect.flatMap((aux) => running.startSyncInBackground(aux))),
|
|
123
|
+
})));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Whether the activation watcher has been registered.
|
|
127
|
+
*
|
|
128
|
+
* @remarks
|
|
129
|
+
* Registration is per wallet, not per `start`: watchers accumulate, so registering on every call would restart sync
|
|
130
|
+
* once per historical `start` on the next activation. Flipped with `getAndSet` so concurrent `start` calls cannot
|
|
131
|
+
* both observe it unset.
|
|
132
|
+
*/
|
|
133
|
+
#watcherRegistered = Ref.unsafeMake(false);
|
|
134
|
+
constructor(runtime, scope) {
|
|
135
|
+
super(runtime, scope);
|
|
136
|
+
this.state = this.rawState.pipe(rx.map((emission) =>
|
|
137
|
+
// One variant, so the pairing is trivial here; the forking wallet narrows on `variantTag` first.
|
|
138
|
+
ShieldedWalletState.fromVariant(CustomShieldedWalletImplementation.allVariantsRecord()[V2Tag].variant, emission)), rx.shareReplay({ refCount: true, bufferSize: 1 }));
|
|
139
|
+
}
|
|
140
|
+
start(secretKeys) {
|
|
141
|
+
return Effect.gen(this, function* () {
|
|
142
|
+
const current = yield* this.runtime.currentVariant;
|
|
143
|
+
yield* Ref.update(this.#retainedStartMaterial, (retained) => Option.some(Option.match(retained, {
|
|
144
|
+
onNone: () => StartMaterial.forVariant(Poly.getTag(current), secretKeys),
|
|
145
|
+
// A retained seed already answers for every variant, including ones this wallet has not met, so key
|
|
146
|
+
// objects for one of them add nothing. Otherwise the objects accumulate per variant tag.
|
|
147
|
+
onSome: (existing) => existing._tag === 'FromSeed'
|
|
148
|
+
? existing
|
|
149
|
+
: StartMaterial.forVariants([...existing.byTag, [Poly.getTag(current), secretKeys]]),
|
|
150
|
+
})));
|
|
151
|
+
// Registered before the first dispatch, and only once: `onVariantActivation` resolves only after its
|
|
152
|
+
// subscription is live, so an activation racing this call is queued rather than missed.
|
|
153
|
+
const alreadyRegistered = yield* Ref.getAndSet(this.#watcherRegistered, true);
|
|
154
|
+
if (!alreadyRegistered) {
|
|
155
|
+
yield* this.runtime.onVariantActivation({
|
|
156
|
+
[V2Tag]: (v2) => this.#resumeSyncOn(V2Tag, v2),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
yield* this.runtime.dispatch({ [V2Tag]: (v2) => v2.startSyncInBackground(secretKeys) });
|
|
160
|
+
}).pipe(Effect.runPromise);
|
|
161
|
+
}
|
|
162
|
+
async stop() {
|
|
163
|
+
// Released before the runtime is torn down: the key material outlives neither the wallet nor an in-flight
|
|
164
|
+
// activation.
|
|
165
|
+
Ref.set(this.#retainedStartMaterial, Option.none()).pipe(Effect.runSync);
|
|
166
|
+
await super.stop();
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The key material this wallet's one variant uses, from what it was started with.
|
|
170
|
+
*
|
|
171
|
+
* @remarks
|
|
172
|
+
* Typed as the variant's own start-aux, which for a single-variant wallet is whatever the application handed to
|
|
173
|
+
* `start` — there is no other variant to derive for, so a retained seed is only ever used through the variant's
|
|
174
|
+
* own derivation.
|
|
175
|
+
*/
|
|
176
|
+
#requireAux() {
|
|
177
|
+
return Effect.gen(this, function* () {
|
|
178
|
+
const current = yield* this.runtime.currentVariant;
|
|
179
|
+
const variantTag = Poly.getTag(current);
|
|
180
|
+
const retained = yield* Ref.get(this.#retainedStartMaterial);
|
|
181
|
+
return yield* Option.match(retained, {
|
|
182
|
+
onNone: () => Effect.fail(new StartMaterial.MissingStartAuxError({
|
|
183
|
+
message: `This wallet holds no key material: it has not been started, or it has been stopped. Start it ` +
|
|
184
|
+
`before asking it to build a transaction.`,
|
|
185
|
+
variantTag,
|
|
186
|
+
})),
|
|
187
|
+
onSome: (material) => EitherOps.toEffect(StartMaterial.requireAuxFor(material, variantTag, (seed) => CustomShieldedWalletImplementation.allVariantsRecord()[V2Tag].variant.startAux.fromSeed(seed))),
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/** The whole of the protocol timeline: one variant answers for every version this wallet will ever see. */
|
|
192
|
+
static #epoch = ProtocolVersion.epochOf(ProtocolVersion.MinSupportedVersion, ProtocolVersion.MinSupportedVersion);
|
|
193
|
+
balanceTransaction(tx) {
|
|
194
|
+
return this.runtime
|
|
195
|
+
.dispatch({
|
|
196
|
+
[V2Tag]: (v2) => Effect.all([
|
|
197
|
+
this.#requireAux(),
|
|
198
|
+
EitherOps.toEffect(WalletTransaction.unwrapWithin(tx, CustomShieldedWalletImplementation.#epoch)),
|
|
199
|
+
]).pipe(Effect.flatMap(([keys, unwrapped]) => v2.balanceTransaction(keys, unwrapped)), Effect.map((result) => result === undefined
|
|
200
|
+
? undefined
|
|
201
|
+
: WalletTransaction.adopt('Unproven', result, ProtocolVersion.MinSupportedVersion))),
|
|
202
|
+
})
|
|
203
|
+
.pipe(Effect.runPromise);
|
|
204
|
+
}
|
|
205
|
+
transferTransaction(outputs) {
|
|
206
|
+
return this.runtime
|
|
207
|
+
.dispatch({
|
|
208
|
+
[V2Tag]: (v2) => this.#requireAux().pipe(Effect.flatMap((keys) => v2.transferTransaction(keys, outputs)), Effect.map((tx) => WalletTransaction.adopt('Unproven', tx, ProtocolVersion.MinSupportedVersion))),
|
|
209
|
+
})
|
|
210
|
+
.pipe(Effect.runPromise);
|
|
211
|
+
}
|
|
212
|
+
initSwap(desiredInputs, desiredOutputs) {
|
|
213
|
+
return this.runtime
|
|
214
|
+
.dispatch({
|
|
215
|
+
[V2Tag]: (v2) => this.#requireAux().pipe(Effect.flatMap((keys) => v2.initSwap(keys, desiredInputs, desiredOutputs)), Effect.map((tx) => WalletTransaction.adopt('Unproven', tx, ProtocolVersion.MinSupportedVersion))),
|
|
216
|
+
})
|
|
217
|
+
.pipe(Effect.runPromise);
|
|
218
|
+
}
|
|
219
|
+
revertTransaction(transaction) {
|
|
220
|
+
return this.runtime
|
|
221
|
+
.dispatch({
|
|
222
|
+
[V2Tag]: (v2) => Either.match(WalletTransaction.unwrapWithin(transaction, CustomShieldedWalletImplementation.#epoch), { onLeft: () => Effect.void, onRight: (unwrapped) => v2.revertTransaction(unwrapped) }),
|
|
223
|
+
})
|
|
224
|
+
.pipe(Effect.runPromise);
|
|
225
|
+
}
|
|
226
|
+
waitForSyncedState(allowedGap = 0n) {
|
|
227
|
+
return rx.firstValueFrom(this.state.pipe(rx.filter((state) => state.state.progress.isCompleteWithin(allowedGap))));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Serializes the most recent state It's preferable to use [[ShieldedWalletState.serialize]] instead, to know
|
|
231
|
+
* exactly, which state is serialized
|
|
232
|
+
*/
|
|
233
|
+
serializeState() {
|
|
234
|
+
return rx.firstValueFrom(this.state).then((state) => state.serialize());
|
|
235
|
+
}
|
|
236
|
+
getAddress() {
|
|
237
|
+
return rx.firstValueFrom(this.state).then((state) => state.address);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
export * from './ShieldedWalletAPI.js';
|
|
2
|
+
export * from './SingleVariantShieldedWallet.js';
|
|
1
3
|
export * from './ShieldedWallet.js';
|
|
2
|
-
export
|
|
4
|
+
export * as Restore from './Restore.js';
|
|
5
|
+
export { type ShieldedTransactionHistoryEntry, ShieldedSectionSchema, mergeShieldedSections, } from './v2/TransactionHistory.js';
|
package/dist/index.js
CHANGED
|
@@ -10,5 +10,8 @@
|
|
|
10
10
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
|
+
export * from './ShieldedWalletAPI.js';
|
|
14
|
+
export * from './SingleVariantShieldedWallet.js';
|
|
13
15
|
export * from './ShieldedWallet.js';
|
|
14
|
-
export
|
|
16
|
+
export * as Restore from './Restore.js';
|
|
17
|
+
export { ShieldedSectionSchema, mergeShieldedSections, } from './v2/TransactionHistory.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CoreWallet } from './CoreWallet.js';
|
|
2
|
-
import type * as ledger from '@
|
|
2
|
+
import type * as ledger from '@midnight-ntwrk/ledger-v8';
|
|
3
3
|
export type AvailableCoin = {
|
|
4
4
|
coin: ledger.QualifiedShieldedCoinInfo;
|
|
5
5
|
commitment: ledger.CoinCommitment;
|
package/dist/v1/CoreWallet.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as ledger from '@
|
|
1
|
+
import * as ledger from '@midnight-ntwrk/ledger-v8';
|
|
2
2
|
import { ProtocolVersion, SyncProgress } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
3
3
|
import { Either } from 'effect';
|
|
4
4
|
import { type WalletError } from './WalletError.js';
|
|
@@ -35,6 +35,53 @@ export declare const CoreWallet: {
|
|
|
35
35
|
restore(localState: ledger.ZswapLocalState, secretKeys: ledger.ZswapSecretKeys, syncProgress: Omit<SyncProgress.SyncProgressData, "isConnected">, protocolVersion: bigint, networkId: string): CoreWallet;
|
|
36
36
|
restoreWithCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, coinHashes: CoinHashesMap, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: string): Either.Either<CoreWallet, WalletError>;
|
|
37
37
|
initEmpty(keys: ledger.ZswapSecretKeys, networkId: string): CoreWallet;
|
|
38
|
+
/**
|
|
39
|
+
* Records an observed protocol version on the wallet, never going backwards.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* The version is a signal, not a measurement: writing one outside the running variant's activation range is what
|
|
43
|
+
* makes it hand over to the next variant. A source that briefly reports an older version — a reconnect replaying
|
|
44
|
+
* from an earlier cursor, say — must therefore not be able to drag the wallet back below a boundary it has already
|
|
45
|
+
* crossed, which would ask the runtime to migrate backwards. Taking the maximum makes that unrepresentable.
|
|
46
|
+
* @param wallet The wallet to annotate.
|
|
47
|
+
* @param version The protocol version just observed.
|
|
48
|
+
* @returns `wallet` unchanged if it already records `version` or a later one, otherwise a copy recording `version`.
|
|
49
|
+
*/
|
|
50
|
+
withProtocolVersion(wallet: CoreWallet, version: ProtocolVersion.ProtocolVersion): CoreWallet;
|
|
51
|
+
/**
|
|
52
|
+
* Projects a wallet inherited from the previous ledger version onto a fresh state of this one.
|
|
53
|
+
*
|
|
54
|
+
* @remarks
|
|
55
|
+
* No coin data crosses the boundary here, and that is a decision rather than an oversight. This is the oldest variant
|
|
56
|
+
* the wallet registers and no ledger version below it exists, so nothing ever hands a state to this projection: it
|
|
57
|
+
* is shape parity with the twin at `src/v2`, which is the variant a real crossing lands in. That twin adopts the
|
|
58
|
+
* previous wallet's local state whole, by deserializing its bytes — the two ledger majors share the
|
|
59
|
+
* `zswap-local-state` codec — because the chain's state translation continues the commitment tree across the fork
|
|
60
|
+
* and the indexer re-emits none of the ledger-v8 timeline (see `src/v2/Migration.ts`). Mirroring that into a seam
|
|
61
|
+
* no chain can reach would buy nothing, so this side stays as it is.
|
|
62
|
+
*
|
|
63
|
+
* What crosses is therefore identity and position: the public keys — which decide whose coins the far side can
|
|
64
|
+
* decrypt — the network, the protocol version that triggered the hand-over, kept so the new variant starts inside
|
|
65
|
+
* its own activation range rather than immediately signalling backwards, and the cursor the previous variant
|
|
66
|
+
* stopped at.
|
|
67
|
+
*
|
|
68
|
+
* **Sync progress is parked at the fork, not rewound**: the previous wallet's cursor crosses unchanged. A fork does
|
|
69
|
+
* not restart the timeline — event ids run onwards from whatever the indexer had reached when it happened, never
|
|
70
|
+
* from zero — so resuming from the inherited cursor is what puts this wallet in front of what comes next. Rewinding
|
|
71
|
+
* to zero would park it on a stretch of history that this ledger version's events do not occupy. What does not
|
|
72
|
+
* cross is `isConnected`: no sync is running behind this state yet.
|
|
73
|
+
*
|
|
74
|
+
* Coin hashes start empty for the same reason the tree does: they are commitments and nullifiers computed under the
|
|
75
|
+
* previous ledger's codec, and this version recomputes its own from the keys and whatever state it ends up with.
|
|
76
|
+
* @param previous The plain data read off the previous ledger version's wallet.
|
|
77
|
+
* @returns A wallet of this ledger version holding no coins, positioned at the fork.
|
|
78
|
+
*/
|
|
79
|
+
fromPreviousVersion(previous: {
|
|
80
|
+
readonly publicKeys: PublicKeys;
|
|
81
|
+
readonly networkId: string;
|
|
82
|
+
readonly protocolVersion: bigint;
|
|
83
|
+
readonly progress: SyncProgress.SyncProgressData;
|
|
84
|
+
}): CoreWallet;
|
|
38
85
|
applyCollapsedUpdate(wallet: CoreWallet, collapsed: ledger.MerkleTreeCollapsedUpdate): CoreWallet;
|
|
39
86
|
apply<TOffer extends ledger.ZswapOffer<ledger.Proofish>>(wallet: CoreWallet, secretKeys: ledger.ZswapSecretKeys, offer: TOffer): CoreWallet;
|
|
40
87
|
replayEventsWithChanges(wallet: CoreWallet, secretKeys: ledger.ZswapSecretKeys, events: ledger.Event[]): [CoreWallet, ledger.ZswapStateChanges[]];
|