@midnightntwrk/wallet-sdk-shielded 4.0.0-rc.0 → 4.0.0-rc.1
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/dist/Restore.d.ts +27 -10
- package/dist/Restore.js +33 -24
- package/dist/ShieldedWallet.js +21 -4
- package/dist/SingleVariantShieldedWallet.js +7 -3
- package/dist/SnapshotFormat.d.ts +12 -0
- package/dist/SnapshotFormat.js +24 -0
- package/dist/v1/CoreWallet.d.ts +20 -1
- package/dist/v1/CoreWallet.js +5 -1
- package/dist/v1/Serialization.d.ts +2 -1
- package/dist/v1/Serialization.js +26 -4
- package/dist/v1/TransactionHistory.d.ts +4 -4
- package/dist/v1/TransactionHistory.js +22 -13
- package/dist/v1/V1Builder.js +3 -0
- package/dist/v1/WalletError.d.ts +24 -1
- package/dist/v1/WalletError.js +15 -0
- package/dist/v2/CoreWallet.d.ts +16 -3
- package/dist/v2/CoreWallet.js +17 -13
- package/dist/v2/Migration.d.ts +2 -0
- package/dist/v2/Migration.js +1 -0
- package/dist/v2/Serialization.d.ts +2 -1
- package/dist/v2/Serialization.js +23 -5
- package/dist/v2/TransactionHistory.d.ts +4 -4
- package/dist/v2/TransactionHistory.js +22 -13
- package/dist/v2/V2Builder.js +3 -0
- package/dist/v2/WalletError.d.ts +24 -1
- package/dist/v2/WalletError.js +15 -0
- package/package.json +5 -5
package/dist/Restore.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ProtocolVersion } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
2
|
-
import { Either, Option } from 'effect';
|
|
1
|
+
import { ProtocolVersion, type SnapshotFormat } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
2
|
+
import { type Either, Option } from 'effect';
|
|
3
3
|
declare const UnsupportedSnapshotVersionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
4
4
|
readonly _tag: "@midnightntwrk/wallet-sdk-shielded/Restore/UnsupportedSnapshotVersionError";
|
|
5
5
|
} & Readonly<A>;
|
|
@@ -17,24 +17,41 @@ export declare class UnsupportedSnapshotVersionError extends UnsupportedSnapshot
|
|
|
17
17
|
}> {
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
* Reads the protocol version a serialized wallet snapshot declares.
|
|
20
|
+
* Reads the protocol version a serialized shielded wallet snapshot declares.
|
|
21
21
|
*
|
|
22
22
|
* @param serialized The serialized wallet state.
|
|
23
23
|
* @returns The declared version, or `Option.none()` when the snapshot declares none or cannot be read at all.
|
|
24
24
|
*/
|
|
25
25
|
export declare const peekProtocolVersion: (serialized: string) => Option.Option<ProtocolVersion.ProtocolVersion>;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Reads which variant wrote a serialized shielded wallet snapshot, when it says.
|
|
28
28
|
*
|
|
29
29
|
* @remarks
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* Shielded snapshots carry nothing in their shape that says which variant wrote them, so only the name counts; a
|
|
31
|
+
* snapshot written before snapshots named their writer reads as naming none.
|
|
32
|
+
* @param serialized The serialized wallet state.
|
|
33
|
+
* @returns The writer, or `Option.none()` when the snapshot predates the field, names a writer this build does not
|
|
34
|
+
* know, or cannot be read at all.
|
|
35
|
+
*/
|
|
36
|
+
export declare const peekWriter: (serialized: string) => Option.Option<SnapshotFormat.SnapshotWriter>;
|
|
37
|
+
/**
|
|
38
|
+
* Chooses the variant that should read a serialized shielded wallet snapshot.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* The rule is {@link SnapshotRouting.routeSnapshot}'s: the variant that wrote the snapshot when it says which and that
|
|
42
|
+
* variant is registered, otherwise the variant that owns the declared version, otherwise the head variant. The
|
|
43
|
+
* envelope is read once here, not once per question.
|
|
33
44
|
* @param serialized The serialized wallet state.
|
|
34
45
|
* @param variantFor Resolves the variant registered for a protocol version.
|
|
35
46
|
* @param headVariant The variant a snapshot with no declared version is restored into.
|
|
36
|
-
* @
|
|
37
|
-
*
|
|
47
|
+
* @param variantWrittenBy Resolves the registered variant that a snapshot names as its writer, if it is registered.
|
|
48
|
+
* Defaults to none, which is the routing every caller had before snapshots named their writer.
|
|
49
|
+
* @param activationOf The protocol version a registered variant starts answering for, as the wallet registered it. The
|
|
50
|
+
* writer takes a snapshot only from that version upwards; below it the version routes, since the runtime cannot hand
|
|
51
|
+
* over backwards. Defaults to the minimum version, which lets the writer take any snapshot, for compositions that
|
|
52
|
+
* pass no writer resolver either.
|
|
53
|
+
* @returns The variant to restore with, or {@link UnsupportedSnapshotVersionError} when the writer is not registered and
|
|
54
|
+
* the declared version is one no registered variant owns.
|
|
38
55
|
*/
|
|
39
|
-
export declare const variantForSnapshot: <TVariant>(serialized: string, variantFor: (version: ProtocolVersion.ProtocolVersion) => Option.Option<TVariant>, headVariant: TVariant) => Either.Either<TVariant, UnsupportedSnapshotVersionError>;
|
|
56
|
+
export declare const variantForSnapshot: <TVariant>(serialized: string, variantFor: (version: ProtocolVersion.ProtocolVersion) => Option.Option<TVariant>, headVariant: TVariant, variantWrittenBy?: (writer: SnapshotFormat.SnapshotWriter) => Option.Option<TVariant>, activationOf?: (variant: TVariant) => ProtocolVersion.ProtocolVersion) => Either.Either<TVariant, UnsupportedSnapshotVersionError>;
|
|
40
57
|
export {};
|
package/dist/Restore.js
CHANGED
|
@@ -10,8 +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
|
-
import { ProtocolVersion } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
14
|
-
import { Data,
|
|
13
|
+
import { ProtocolVersion, SnapshotRouting } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
14
|
+
import { Data, Option } from 'effect';
|
|
15
15
|
/**
|
|
16
16
|
* Raised when a snapshot declares a protocol version that no registered variant is able to read.
|
|
17
17
|
*
|
|
@@ -23,41 +23,50 @@ import { Data, Either, Option, Schema } from 'effect';
|
|
|
23
23
|
export class UnsupportedSnapshotVersionError extends Data.TaggedError('@midnightntwrk/wallet-sdk-shielded/Restore/UnsupportedSnapshotVersionError') {
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
26
|
+
* Reads the protocol version a serialized shielded wallet snapshot declares.
|
|
27
27
|
*
|
|
28
|
-
* @
|
|
29
|
-
*
|
|
30
|
-
* snapshots written by _any_ variant, including ones whose full schema this build does not have, so it must not
|
|
31
|
-
* assert anything it does not need. Everything it cannot make sense of is reported as "no version declared", leaving
|
|
32
|
-
* the real diagnosis to the deserializer that eventually reads the whole thing.
|
|
28
|
+
* @param serialized The serialized wallet state.
|
|
29
|
+
* @returns The declared version, or `Option.none()` when the snapshot declares none or cannot be read at all.
|
|
33
30
|
*/
|
|
34
|
-
const
|
|
35
|
-
protocolVersion: Schema.optional(ProtocolVersion.ProtocolVersionSchema),
|
|
36
|
-
});
|
|
31
|
+
export const peekProtocolVersion = (serialized) => SnapshotRouting.readEnvelope(serialized).protocolVersion;
|
|
37
32
|
/**
|
|
38
|
-
* Reads
|
|
33
|
+
* Reads which variant wrote a serialized shielded wallet snapshot, when it says.
|
|
39
34
|
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* Shielded snapshots carry nothing in their shape that says which variant wrote them, so only the name counts; a
|
|
37
|
+
* snapshot written before snapshots named their writer reads as naming none.
|
|
40
38
|
* @param serialized The serialized wallet state.
|
|
41
|
-
* @returns The
|
|
39
|
+
* @returns The writer, or `Option.none()` when the snapshot predates the field, names a writer this build does not
|
|
40
|
+
* know, or cannot be read at all.
|
|
42
41
|
*/
|
|
43
|
-
export const
|
|
42
|
+
export const peekWriter = (serialized) => SnapshotRouting.readEnvelope(serialized).writer;
|
|
44
43
|
/**
|
|
45
|
-
* Chooses the variant that should read a serialized wallet snapshot.
|
|
44
|
+
* Chooses the variant that should read a serialized shielded wallet snapshot.
|
|
46
45
|
*
|
|
47
46
|
* @remarks
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
47
|
+
* The rule is {@link SnapshotRouting.routeSnapshot}'s: the variant that wrote the snapshot when it says which and that
|
|
48
|
+
* variant is registered, otherwise the variant that owns the declared version, otherwise the head variant. The
|
|
49
|
+
* envelope is read once here, not once per question.
|
|
51
50
|
* @param serialized The serialized wallet state.
|
|
52
51
|
* @param variantFor Resolves the variant registered for a protocol version.
|
|
53
52
|
* @param headVariant The variant a snapshot with no declared version is restored into.
|
|
54
|
-
* @
|
|
55
|
-
*
|
|
53
|
+
* @param variantWrittenBy Resolves the registered variant that a snapshot names as its writer, if it is registered.
|
|
54
|
+
* Defaults to none, which is the routing every caller had before snapshots named their writer.
|
|
55
|
+
* @param activationOf The protocol version a registered variant starts answering for, as the wallet registered it. The
|
|
56
|
+
* writer takes a snapshot only from that version upwards; below it the version routes, since the runtime cannot hand
|
|
57
|
+
* over backwards. Defaults to the minimum version, which lets the writer take any snapshot, for compositions that
|
|
58
|
+
* pass no writer resolver either.
|
|
59
|
+
* @returns The variant to restore with, or {@link UnsupportedSnapshotVersionError} when the writer is not registered and
|
|
60
|
+
* the declared version is one no registered variant owns.
|
|
56
61
|
*/
|
|
57
|
-
export const variantForSnapshot = (serialized, variantFor, headVariant) => Option.
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
export const variantForSnapshot = (serialized, variantFor, headVariant, variantWrittenBy = () => Option.none(), activationOf = () => ProtocolVersion.MinSupportedVersion) => SnapshotRouting.routeSnapshot({
|
|
63
|
+
activationOf,
|
|
64
|
+
envelope: SnapshotRouting.readEnvelope(serialized),
|
|
65
|
+
variantFor,
|
|
66
|
+
headVariant,
|
|
67
|
+
variantWrittenBy,
|
|
68
|
+
unsupported: (protocolVersion) => new UnsupportedSnapshotVersionError({
|
|
60
69
|
message: `No registered variant reads shielded wallet snapshots of protocol version ${protocolVersion}.`,
|
|
61
70
|
protocolVersion,
|
|
62
|
-
})
|
|
71
|
+
}),
|
|
63
72
|
});
|
package/dist/ShieldedWallet.js
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
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
|
-
import { ProtocolVersion, WalletSeed, WalletTransaction, } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
13
|
+
import { ProtocolVersion, WalletSeed, WalletTransaction, SnapshotFormat, } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
14
14
|
import { makeIndexerChainVersionProbe, } from '@midnightntwrk/wallet-sdk-capabilities/chainVersion';
|
|
15
15
|
import { WalletBuilder } from '@midnightntwrk/wallet-sdk-runtime';
|
|
16
16
|
import { StartMaterial, Variant, } from '@midnightntwrk/wallet-sdk-runtime/abstractions';
|
|
17
17
|
import { EitherOps, HList } from '@midnightntwrk/wallet-sdk-utilities';
|
|
18
|
-
import { Duration, Effect, Either, Option, Ref, pipe } from 'effect';
|
|
18
|
+
import { Duration, Effect, Either, Match, Option, Ref, pipe } from 'effect';
|
|
19
19
|
import * as rx from 'rxjs';
|
|
20
20
|
import { variantForSnapshot } from './Restore.js';
|
|
21
21
|
import { ShieldedWalletState, } from './ShieldedWalletAPI.js';
|
|
@@ -167,9 +167,26 @@ export function CustomForkingShieldedWallet(configuration, v1, v2) {
|
|
|
167
167
|
wallet.#retainKeys({ v8: Option.some(keys.v8), v9: Option.some(keys.v9) });
|
|
168
168
|
return wallet;
|
|
169
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* The registered variant a snapshot names as its writer, if that variant is registered.
|
|
172
|
+
*
|
|
173
|
+
* @remarks
|
|
174
|
+
* Snapshots name their writer by the ordinal in the variant's name, and each variant registers under its tag; this
|
|
175
|
+
* is the one place the two are paired, so routing can send a snapshot home whatever version it carries.
|
|
176
|
+
* @param writer The writer a snapshot names.
|
|
177
|
+
* @returns That variant, or none when this composition does not register it.
|
|
178
|
+
*/
|
|
179
|
+
static variantWrittenBy(writer) {
|
|
180
|
+
// Exhaustive on purpose: a writer added to `SNAPSHOT_WRITERS` must fail here at compile time, never fall
|
|
181
|
+
// through to a variant that did not write the snapshot.
|
|
182
|
+
const tag = Match.value(writer).pipe(Match.when(SnapshotFormat.V1_SNAPSHOT_WRITER, () => V1Tag), Match.when(SnapshotFormat.V2_SNAPSHOT_WRITER, () => V2Tag), Match.exhaustive);
|
|
183
|
+
return Option.fromNullable(ForkingShieldedWalletImplementation.allVariants().find((variant) => Variant.getVersionedVariantTag(variant) === tag));
|
|
184
|
+
}
|
|
170
185
|
static tryRestore(serializedState) {
|
|
171
186
|
const headVariant = HList.head(ForkingShieldedWalletImplementation.allVariants());
|
|
172
|
-
return variantForSnapshot(serializedState, (version) => ForkingShieldedWalletImplementation.variantFor(version), headVariant).
|
|
187
|
+
return variantForSnapshot(serializedState, (version) => ForkingShieldedWalletImplementation.variantFor(version), headVariant, (writer) => ForkingShieldedWalletImplementation.variantWrittenBy(writer),
|
|
188
|
+
// Each variant's activation as registered here, so a writer never takes a snapshot from below its own range.
|
|
189
|
+
(variant) => variant.sinceVersion).pipe(
|
|
173
190
|
// Stated with its result type because the resolved variant is either of the two, so its deserializer is
|
|
174
191
|
// either of theirs: what comes back is a state of whichever one wrote the snapshot, which is what
|
|
175
192
|
// `startAtVariant` takes.
|
|
@@ -182,7 +199,7 @@ export function CustomForkingShieldedWallet(configuration, v1, v2) {
|
|
|
182
199
|
}));
|
|
183
200
|
}
|
|
184
201
|
static restore(serializedState) {
|
|
185
|
-
return Either.
|
|
202
|
+
return Either.getOrThrowWith(ForkingShieldedWalletImplementation.tryRestore(serializedState), (error) => error);
|
|
186
203
|
}
|
|
187
204
|
state;
|
|
188
205
|
/**
|
|
@@ -82,10 +82,14 @@ export function CustomShieldedWallet(configuration, builder) {
|
|
|
82
82
|
// Routing reads a serialized envelope, which only a wallet keeping the default string serialization has. A
|
|
83
83
|
// custom format is left with the behaviour it has always had.
|
|
84
84
|
typeof serializedState === 'string'
|
|
85
|
-
? variantForSnapshot(serializedState, (version) => CustomShieldedWalletImplementation.variantFor(version), headVariant
|
|
85
|
+
? variantForSnapshot(serializedState, (version) => CustomShieldedWalletImplementation.variantFor(version), headVariant,
|
|
86
|
+
// A custom composition registers one variant, so there is no other writer to route to.
|
|
87
|
+
() => Option.none())
|
|
86
88
|
: Either.right(headVariant);
|
|
87
|
-
const variant = routed.pipe(Either.
|
|
88
|
-
const deserialized = variant.variant
|
|
89
|
+
const variant = routed.pipe(Either.getOrThrowWith((error) => error));
|
|
90
|
+
const deserialized = variant.variant
|
|
91
|
+
.deserializeState(serializedState)
|
|
92
|
+
.pipe(Either.getOrThrowWith((error) => error));
|
|
89
93
|
return CustomShieldedWalletImplementation.startAtVariant(CustomShieldedWalletImplementation, variant, deserialized);
|
|
90
94
|
}
|
|
91
95
|
state;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The format version this build writes into a shielded snapshot. It versions the encoded shape of the snapshot and is
|
|
3
|
+
* not `protocolVersion`, which is the chain's hard-fork number and lives inside it.
|
|
4
|
+
*
|
|
5
|
+
* Snapshots written before this field existed carry the same fields under a different name for the same shape, so a
|
|
6
|
+
* missing `version` reads as this one and no upgrade runs. The field earns its keep on the day the shape does change:
|
|
7
|
+
* that shape becomes `v2` and a single v1-to-v2 step is written, rather than every reader having to guess.
|
|
8
|
+
*
|
|
9
|
+
* Declared here, with no ledger import, so that both variants share one constant and neither pulls the other's ledger
|
|
10
|
+
* into its module graph to read it.
|
|
11
|
+
*/
|
|
12
|
+
export declare const SNAPSHOT_FORMAT_VERSION = "v1";
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
* The format version this build writes into a shielded snapshot. It versions the encoded shape of the snapshot and is
|
|
15
|
+
* not `protocolVersion`, which is the chain's hard-fork number and lives inside it.
|
|
16
|
+
*
|
|
17
|
+
* Snapshots written before this field existed carry the same fields under a different name for the same shape, so a
|
|
18
|
+
* missing `version` reads as this one and no upgrade runs. The field earns its keep on the day the shape does change:
|
|
19
|
+
* that shape becomes `v2` and a single v1-to-v2 step is written, rather than every reader having to guess.
|
|
20
|
+
*
|
|
21
|
+
* Declared here, with no ledger import, so that both variants share one constant and neither pulls the other's ledger
|
|
22
|
+
* into its module graph to read it.
|
|
23
|
+
*/
|
|
24
|
+
export const SNAPSHOT_FORMAT_VERSION = 'v1';
|
package/dist/v1/CoreWallet.d.ts
CHANGED
|
@@ -28,12 +28,31 @@ export type CoreWallet = Readonly<{
|
|
|
28
28
|
progress: SyncProgress.SyncProgress;
|
|
29
29
|
networkId: string;
|
|
30
30
|
coinHashes: CoinHashesMap;
|
|
31
|
+
/**
|
|
32
|
+
* The transaction history that a 1.0.0 snapshot embedded, as the hex-encoded proven ledger transactions it was
|
|
33
|
+
* written with. Carried across a restore and written back out untouched, so upgrading does not destroy it; this SDK
|
|
34
|
+
* keeps history in its own storage and never reads or adds to this list.
|
|
35
|
+
*
|
|
36
|
+
* Absent for every snapshot written since the field was dropped from the schema, and absent means absent — it is not
|
|
37
|
+
* written back as an empty list, so those snapshots keep the bytes they had.
|
|
38
|
+
*/
|
|
39
|
+
legacyTxHistory?: readonly string[];
|
|
40
|
+
/**
|
|
41
|
+
* The V2 variant's mid-crossing marker, when a snapshot this variant was handed happened to carry one.
|
|
42
|
+
*
|
|
43
|
+
* This variant has no such state: it never crosses into itself, so it neither sets this nor reads it. It is kept only
|
|
44
|
+
* so that reading such a snapshot and writing it back does not quietly discard the field — the same reason
|
|
45
|
+
* {@link legacyTxHistory} is kept, and the same failure it exists to prevent. `Restore.ts` routes a snapshot to the
|
|
46
|
+
* variant that owns its `protocolVersion`, so in a build registering both twins this is never populated; it is the
|
|
47
|
+
* reader's promise not to lose what it cannot represent, not a state this variant can be in.
|
|
48
|
+
*/
|
|
49
|
+
foreignCoinHashesPending?: true;
|
|
31
50
|
}>;
|
|
32
51
|
export declare const CoreWallet: {
|
|
33
52
|
init(localState: ledger.ZswapLocalState, secretKeys: ledger.ZswapSecretKeys, networkId: string): CoreWallet;
|
|
34
53
|
empty(publicKeys: PublicKeys, networkId: string): CoreWallet;
|
|
35
54
|
restore(localState: ledger.ZswapLocalState, secretKeys: ledger.ZswapSecretKeys, syncProgress: Omit<SyncProgress.SyncProgressData, "isConnected">, protocolVersion: bigint, networkId: string): CoreWallet;
|
|
36
|
-
restoreWithCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, coinHashes: CoinHashesMap, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: string): Either.Either<CoreWallet, WalletError>;
|
|
55
|
+
restoreWithCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, coinHashes: CoinHashesMap, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: string, legacyTxHistory?: readonly string[], foreignCoinHashesPending?: true): Either.Either<CoreWallet, WalletError>;
|
|
37
56
|
initEmpty(keys: ledger.ZswapSecretKeys, networkId: string): CoreWallet;
|
|
38
57
|
/**
|
|
39
58
|
* Records an observed protocol version on the wallet, never going backwards.
|
package/dist/v1/CoreWallet.js
CHANGED
|
@@ -81,7 +81,7 @@ export const CoreWallet = {
|
|
|
81
81
|
protocolVersion: ProtocolVersion.ProtocolVersion(protocolVersion),
|
|
82
82
|
};
|
|
83
83
|
},
|
|
84
|
-
restoreWithCoinHashes(publicKeys, localState, coinHashes, syncProgress, protocolVersion, networkId) {
|
|
84
|
+
restoreWithCoinHashes(publicKeys, localState, coinHashes, syncProgress, protocolVersion, networkId, legacyTxHistory, foreignCoinHashesPending) {
|
|
85
85
|
return CoinHashesMap.assertValid(coinHashes, localState).pipe(Either.mapBoth({
|
|
86
86
|
onLeft: (missingNonces) => new InvalidCoinHashesError({ message: 'Missing coin hashes for coins present in the state', missingNonces }),
|
|
87
87
|
onRight: () => ({
|
|
@@ -91,6 +91,10 @@ export const CoreWallet = {
|
|
|
91
91
|
coinHashes,
|
|
92
92
|
progress: SyncProgress.createSyncProgress(syncProgress),
|
|
93
93
|
protocolVersion: ProtocolVersion.ProtocolVersion(protocolVersion),
|
|
94
|
+
// Spread conditionally: a snapshot that carried no embedded history must not gain a `legacyTxHistory` key,
|
|
95
|
+
// so that re-serializing it writes no `txHistory` field it did not already have.
|
|
96
|
+
...(legacyTxHistory === undefined ? {} : { legacyTxHistory }),
|
|
97
|
+
...(foreignCoinHashesPending === undefined ? {} : { foreignCoinHashesPending }),
|
|
94
98
|
}),
|
|
95
99
|
}));
|
|
96
100
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Either } from 'effect';
|
|
2
|
-
import { WalletError } from './WalletError.js';
|
|
2
|
+
import { type WalletError } from './WalletError.js';
|
|
3
3
|
import { CoreWallet } from './CoreWallet.js';
|
|
4
4
|
import { type NetworkId } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
5
5
|
export type SerializationCapability<TWallet, TAux, TSerialized> = {
|
|
@@ -9,4 +9,5 @@ export type SerializationCapability<TWallet, TAux, TSerialized> = {
|
|
|
9
9
|
export type DefaultSerializationConfiguration = {
|
|
10
10
|
networkId: NetworkId.NetworkId;
|
|
11
11
|
};
|
|
12
|
+
export { SNAPSHOT_FORMAT_VERSION } from '../SnapshotFormat.js';
|
|
12
13
|
export declare const makeDefaultV1SerializationCapability: () => SerializationCapability<CoreWallet, null, string>;
|
package/dist/v1/Serialization.js
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { Effect, ParseResult, Either, pipe, Schema } from 'effect';
|
|
14
|
-
import { WalletError } from './WalletError.js';
|
|
15
14
|
import * as ledger from '@midnight-ntwrk/ledger-v8';
|
|
16
15
|
import { CoreWallet } from './CoreWallet.js';
|
|
16
|
+
import { SnapshotFormat } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
17
17
|
const StateSchema = Schema.declare((input) => input instanceof ledger.ZswapLocalState).annotations({
|
|
18
18
|
identifier: 'ledger.ZswapLocalState',
|
|
19
19
|
});
|
|
@@ -39,8 +39,14 @@ const StateFromUInt8Array = () => Schema.asSchema(Schema.transformOrFail(Uint8Ar
|
|
|
39
39
|
}),
|
|
40
40
|
}));
|
|
41
41
|
const HexedState = () => pipe(Schema.Uint8ArrayFromHex, Schema.compose(StateFromUInt8Array()));
|
|
42
|
+
// The format version lives beside the twins, not in either of them, so the V2 variant can read it without loading
|
|
43
|
+
// ledger-v8. Re-exported here because the version is part of this variant's serialization surface.
|
|
44
|
+
export { SNAPSHOT_FORMAT_VERSION } from '../SnapshotFormat.js';
|
|
45
|
+
import { SNAPSHOT_FORMAT_VERSION } from '../SnapshotFormat.js';
|
|
42
46
|
export const makeDefaultV1SerializationCapability = () => {
|
|
43
47
|
const SnapshotSchema = Schema.Struct({
|
|
48
|
+
version: SnapshotFormat.versionField('shielded', SNAPSHOT_FORMAT_VERSION),
|
|
49
|
+
writtenBy: SnapshotFormat.writtenByField(),
|
|
44
50
|
publicKeys: Schema.Struct({
|
|
45
51
|
coinPublicKey: Schema.String,
|
|
46
52
|
encryptionPublicKey: Schema.String,
|
|
@@ -53,27 +59,43 @@ export const makeDefaultV1SerializationCapability = () => {
|
|
|
53
59
|
key: Schema.String,
|
|
54
60
|
value: Schema.Struct({ nullifier: Schema.String, commitment: Schema.String }),
|
|
55
61
|
}),
|
|
62
|
+
// 1.0.0 embedded the transaction history here, as hex-encoded proven ledger transactions. The field was dropped
|
|
63
|
+
// from this schema when history moved to its own storage, and because Effect Schema ignores keys it does not
|
|
64
|
+
// know, those snapshots restored without complaint and lost the history on the next write. Declaring it optional
|
|
65
|
+
// carries it back out untouched. Optional, not defaulted: a snapshot written without it keeps its exact bytes.
|
|
66
|
+
txHistory: Schema.optional(Schema.Array(Schema.String)),
|
|
67
|
+
// The V2 variant's mid-crossing marker. This variant is never in that state and never reads this, but the twins
|
|
68
|
+
// share one format version, so a V2-written snapshot is this schema's shape too — and a key this schema did not
|
|
69
|
+
// declare would be ignored on the way in and dropped on the way out, which is exactly how `txHistory` above was
|
|
70
|
+
// lost. Declared here so it is carried instead. See `CoreWallet.foreignCoinHashesPending`.
|
|
71
|
+
coinHashesPending: Schema.optional(Schema.Literal(true)),
|
|
56
72
|
});
|
|
57
73
|
return {
|
|
58
74
|
serialize: (wallet) => {
|
|
59
75
|
const buildSnapshot = (w) => ({
|
|
76
|
+
version: SNAPSHOT_FORMAT_VERSION,
|
|
77
|
+
writtenBy: SnapshotFormat.V1_SNAPSHOT_WRITER,
|
|
60
78
|
publicKeys: w.publicKeys,
|
|
61
79
|
state: w.state,
|
|
62
80
|
protocolVersion: w.protocolVersion,
|
|
63
81
|
networkId: w.networkId,
|
|
64
|
-
offset: w.progress?.appliedIndex,
|
|
65
82
|
coinHashes: w.coinHashes,
|
|
83
|
+
// Optional fields are spread in only when present, so the snapshot object never carries an `undefined` key:
|
|
84
|
+
// the bytes must not depend on `JSON.stringify` dropping one.
|
|
85
|
+
...(w.progress?.appliedIndex !== undefined ? { offset: w.progress.appliedIndex } : {}),
|
|
86
|
+
...(w.legacyTxHistory !== undefined ? { txHistory: w.legacyTxHistory } : {}),
|
|
87
|
+
...(w.foreignCoinHashesPending !== undefined ? { coinHashesPending: w.foreignCoinHashesPending } : {}),
|
|
66
88
|
});
|
|
67
89
|
return pipe(wallet, buildSnapshot, Schema.encodeSync(SnapshotSchema), JSON.stringify);
|
|
68
90
|
},
|
|
69
91
|
deserialize: (aux, serialized) => {
|
|
70
|
-
return pipe(serialized,
|
|
92
|
+
return pipe(serialized, SnapshotFormat.readSnapshot({ surface: 'shielded', reads: [SNAPSHOT_FORMAT_VERSION], schema: SnapshotSchema }), Either.flatMap((snapshot) => CoreWallet.restoreWithCoinHashes(snapshot.publicKeys, snapshot.state, snapshot.coinHashes, {
|
|
71
93
|
appliedIndex: snapshot.offset ?? 0n,
|
|
72
94
|
highestRelevantWalletIndex: 0n,
|
|
73
95
|
highestIndex: 0n,
|
|
74
96
|
highestRelevantIndex: 0n,
|
|
75
97
|
isConnected: false,
|
|
76
|
-
}, snapshot.protocolVersion, snapshot.networkId)));
|
|
98
|
+
}, snapshot.protocolVersion, snapshot.networkId, snapshot.txHistory, snapshot.coinHashesPending)));
|
|
77
99
|
},
|
|
78
100
|
};
|
|
79
101
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TransactionHistoryStorage } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
2
2
|
import type * as ledger from '@midnight-ntwrk/ledger-v8';
|
|
3
3
|
import { Duration, Effect, Schema } from 'effect';
|
|
4
|
-
import { TransactionHistoryError } from './WalletError.js';
|
|
4
|
+
import { BlocklessFinalizedEntryError, TransactionHistoryError } from './WalletError.js';
|
|
5
5
|
export declare const QualifiedShieldedCoinInfoSchema: Schema.Struct<{
|
|
6
6
|
type: typeof Schema.String;
|
|
7
7
|
nonce: typeof Schema.String;
|
|
@@ -39,11 +39,11 @@ export declare const ShieldedTransactionHistoryEntrySchema: Schema.Struct<Readon
|
|
|
39
39
|
submittedAt: typeof Schema.Date;
|
|
40
40
|
}>, Schema.Struct<{
|
|
41
41
|
status: Schema.Literal<["finalized"]>;
|
|
42
|
-
finalizedBlock: Schema.Struct<{
|
|
42
|
+
finalizedBlock: Schema.optional<Schema.Struct<{
|
|
43
43
|
hash: typeof Schema.String;
|
|
44
44
|
height: typeof Schema.Number;
|
|
45
45
|
timestamp: typeof Schema.Date;
|
|
46
|
-
}
|
|
46
|
+
}>>;
|
|
47
47
|
}>, Schema.Struct<{
|
|
48
48
|
status: Schema.Literal<["rejected"]>;
|
|
49
49
|
rejectedAt: typeof Schema.Date;
|
|
@@ -92,7 +92,7 @@ export type TransactionDetails = {
|
|
|
92
92
|
};
|
|
93
93
|
export type TransactionHistoryService = {
|
|
94
94
|
put(changes: ledger.ZswapStateChanges, metadata: TransactionDetails, protocolVersion: number): Effect.Effect<void, TransactionHistoryError>;
|
|
95
|
-
getTransactionDetails(hash: TransactionHistoryStorage.TransactionHash): Effect.Effect<TransactionDetails, TransactionHistoryError>;
|
|
95
|
+
getTransactionDetails(hash: TransactionHistoryStorage.TransactionHash): Effect.Effect<TransactionDetails, TransactionHistoryError | BlocklessFinalizedEntryError>;
|
|
96
96
|
};
|
|
97
97
|
export declare const mergeShieldedSections: (existing: ShieldedSection, incoming: ShieldedSection) => ShieldedSection;
|
|
98
98
|
export declare const makeDefaultTransactionHistoryService: (config: DefaultTransactionHistoryConfiguration, _getContext: () => unknown) => TransactionHistoryService;
|
|
@@ -14,7 +14,7 @@ import { TransactionHistoryStorage } from '@midnightntwrk/wallet-sdk-abstraction
|
|
|
14
14
|
import { Duration, Array as EArray, Effect, Schedule, Schema } from 'effect';
|
|
15
15
|
import { TransactionHistoryDetail } from '@midnightntwrk/wallet-sdk-indexer-client';
|
|
16
16
|
import { HttpQueryClient } from '@midnightntwrk/wallet-sdk-indexer-client/effect';
|
|
17
|
-
import { TransactionHistoryError } from './WalletError.js';
|
|
17
|
+
import { BlocklessFinalizedEntryError, TransactionHistoryError } from './WalletError.js';
|
|
18
18
|
export const QualifiedShieldedCoinInfoSchema = Schema.Struct({
|
|
19
19
|
type: Schema.String,
|
|
20
20
|
nonce: Schema.String,
|
|
@@ -116,17 +116,26 @@ export const makeSimulatorTransactionHistoryService = (config, _getContext) => {
|
|
|
116
116
|
getTransactionDetails: (hash) => Effect.tryPromise({
|
|
117
117
|
try: () => txHistoryStorage.get(hash),
|
|
118
118
|
catch: (e) => new TransactionHistoryError({ message: `Failed to get transaction details for ${hash}`, cause: e }),
|
|
119
|
-
}).pipe(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
119
|
+
}).pipe(
|
|
120
|
+
// Two distinct failures, reported distinctly. Storage may never have heard of the transaction; or it holds a
|
|
121
|
+
// finalized entry restored from a history written before the lifecycle field existed, which records no block.
|
|
122
|
+
// This service backs the simulator, where storage is the only source, so neither case can be repaired here.
|
|
123
|
+
Effect.flatMap((entry) => !isFinalized(entry)
|
|
124
|
+
? Effect.fail(new TransactionHistoryError({ message: `No transaction found in storage for hash: ${hash}` }))
|
|
125
|
+
: entry.lifecycle.finalizedBlock === undefined
|
|
126
|
+
? Effect.fail(new BlocklessFinalizedEntryError({
|
|
127
|
+
message: `Transaction ${hash} is finalized but its history entry records no block (restored from a pre-lifecycle history)`,
|
|
128
|
+
hash,
|
|
129
|
+
}))
|
|
130
|
+
: Effect.succeed({
|
|
131
|
+
hash: entry.hash,
|
|
132
|
+
block: {
|
|
133
|
+
hash: entry.lifecycle.finalizedBlock.hash,
|
|
134
|
+
height: entry.lifecycle.finalizedBlock.height,
|
|
135
|
+
timestamp: entry.lifecycle.finalizedBlock.timestamp.getTime(),
|
|
136
|
+
},
|
|
137
|
+
status: entry.status ?? 'SUCCESS',
|
|
138
|
+
identifiers: entry.identifiers,
|
|
139
|
+
}))),
|
|
131
140
|
};
|
|
132
141
|
};
|
package/dist/v1/V1Builder.js
CHANGED
|
@@ -203,6 +203,9 @@ export class V1Builder {
|
|
|
203
203
|
message: 'Failed to migrate shielded wallet state into this variant',
|
|
204
204
|
cause: error,
|
|
205
205
|
}))),
|
|
206
|
+
// The version the state was left at: where the chain was when a snapshot was written, or what the chain answered
|
|
207
|
+
// when a fresh state was stamped from it. The runtime starts at this version rather than the variant's lower bound.
|
|
208
|
+
protocolVersionOf: (state) => state.protocolVersion,
|
|
206
209
|
deserializeState: (serialized) => {
|
|
207
210
|
return v1Context.serializationCapability.deserialize(null, serialized);
|
|
208
211
|
},
|
package/dist/v1/WalletError.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { type SnapshotFormat } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
1
2
|
import type * as ledger from '@midnight-ntwrk/ledger-v8';
|
|
2
3
|
import { type LedgerOps } from '@midnightntwrk/wallet-sdk-utilities';
|
|
3
4
|
export declare const WalletError: {
|
|
4
5
|
other(err: unknown): WalletError;
|
|
5
6
|
submission(err: unknown): WalletError;
|
|
6
7
|
};
|
|
7
|
-
export type WalletError = OtherWalletError | InsufficientFundsError | SubmissionError | AddressError | SyncWalletError | InvalidCoinHashesError | TransactingError | OutOfOrderSyncUpdateError | LedgerOps.LedgerError;
|
|
8
|
+
export type WalletError = SnapshotFormat.SnapshotRestoreError | OtherWalletError | InsufficientFundsError | SubmissionError | AddressError | SyncWalletError | InvalidCoinHashesError | TransactingError | OutOfOrderSyncUpdateError | LedgerOps.LedgerError;
|
|
8
9
|
declare const OtherWalletError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
9
10
|
readonly _tag: "Wallet.Other";
|
|
10
11
|
} & Readonly<A>;
|
|
@@ -71,6 +72,28 @@ export declare class TransactionHistoryError extends TransactionHistoryError_bas
|
|
|
71
72
|
cause?: unknown;
|
|
72
73
|
}> {
|
|
73
74
|
}
|
|
75
|
+
declare const BlocklessFinalizedEntryError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
76
|
+
readonly _tag: "Wallet.BlocklessFinalizedEntry";
|
|
77
|
+
} & Readonly<A>;
|
|
78
|
+
/**
|
|
79
|
+
* A finalized history entry that records no block, met where a block is needed.
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* Only an entry restored from a history written before the lifecycle field existed looks like this: it is known to have
|
|
83
|
+
* been finalized, but the block it landed in was never recorded, and none is invented. It is its own error rather
|
|
84
|
+
* than a message on {@link TransactionHistoryError} so that a caller which can fetch the block by hash matches on the
|
|
85
|
+
* tag.
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* if (error._tag === 'Wallet.BlocklessFinalizedEntry') fetchBlockFor(error.hash);
|
|
89
|
+
* ```;
|
|
90
|
+
*/
|
|
91
|
+
export declare class BlocklessFinalizedEntryError extends BlocklessFinalizedEntryError_base<{
|
|
92
|
+
readonly message: string;
|
|
93
|
+
/** The transaction whose history entry records no block. */
|
|
94
|
+
readonly hash: string;
|
|
95
|
+
}> {
|
|
96
|
+
}
|
|
74
97
|
declare const OutOfOrderSyncUpdateError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
75
98
|
readonly _tag: "Wallet.OutOfOrderSyncUpdate";
|
|
76
99
|
} & Readonly<A>;
|
package/dist/v1/WalletError.js
CHANGED
|
@@ -51,6 +51,21 @@ export class TransactingError extends Data.TaggedError('Wallet.Transacting') {
|
|
|
51
51
|
}
|
|
52
52
|
export class TransactionHistoryError extends Data.TaggedError('Wallet.TransactionHistory') {
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* A finalized history entry that records no block, met where a block is needed.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* Only an entry restored from a history written before the lifecycle field existed looks like this: it is known to have
|
|
59
|
+
* been finalized, but the block it landed in was never recorded, and none is invented. It is its own error rather
|
|
60
|
+
* than a message on {@link TransactionHistoryError} so that a caller which can fetch the block by hash matches on the
|
|
61
|
+
* tag.
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* if (error._tag === 'Wallet.BlocklessFinalizedEntry') fetchBlockFor(error.hash);
|
|
65
|
+
* ```;
|
|
66
|
+
*/
|
|
67
|
+
export class BlocklessFinalizedEntryError extends Data.TaggedError('Wallet.BlocklessFinalizedEntry') {
|
|
68
|
+
}
|
|
54
69
|
/**
|
|
55
70
|
* A batch of zswap ledger events was not in ascending id order: an event arrived at or below the one before it, or at
|
|
56
71
|
* or below the applied cursor.
|
package/dist/v2/CoreWallet.d.ts
CHANGED
|
@@ -43,12 +43,21 @@ export type CoreWallet = Readonly<{
|
|
|
43
43
|
* inhabitant, so "pending" and "absent" are the only two states.
|
|
44
44
|
*/
|
|
45
45
|
coinHashesPending?: true;
|
|
46
|
+
/**
|
|
47
|
+
* The transaction history that a 1.0.0 snapshot embedded, as the hex-encoded proven ledger transactions it was
|
|
48
|
+
* written with. Carried across a restore and across the ledger-version boundary, and written back out untouched, so
|
|
49
|
+
* upgrading does not destroy it; this SDK keeps history in its own storage and never reads or adds to this list.
|
|
50
|
+
*
|
|
51
|
+
* Absent for every snapshot written since the field was dropped from the schema, and absent means absent — it is not
|
|
52
|
+
* written back as an empty list, so those snapshots keep the bytes they had.
|
|
53
|
+
*/
|
|
54
|
+
legacyTxHistory?: readonly string[];
|
|
46
55
|
}>;
|
|
47
56
|
export declare const CoreWallet: {
|
|
48
57
|
init(localState: ledger.ZswapLocalState, secretKeys: ledger.ZswapSecretKeys, networkId: string): CoreWallet;
|
|
49
58
|
empty(publicKeys: PublicKeys, networkId: string): CoreWallet;
|
|
50
59
|
restore(localState: ledger.ZswapLocalState, secretKeys: ledger.ZswapSecretKeys, syncProgress: Omit<SyncProgress.SyncProgressData, "isConnected">, protocolVersion: bigint, networkId: string): CoreWallet;
|
|
51
|
-
restoreWithCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, coinHashes: CoinHashesMap, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: string): Either.Either<CoreWallet, WalletError>;
|
|
60
|
+
restoreWithCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, coinHashes: CoinHashesMap, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: string, legacyTxHistory?: readonly string[]): Either.Either<CoreWallet, WalletError>;
|
|
52
61
|
/**
|
|
53
62
|
* Restores a wallet whose coin hashes were never computed — a snapshot taken mid-crossing.
|
|
54
63
|
*
|
|
@@ -64,9 +73,10 @@ export declare const CoreWallet: {
|
|
|
64
73
|
* @param syncProgress Where the snapshot's reading had got to.
|
|
65
74
|
* @param protocolVersion The version the snapshot was written under.
|
|
66
75
|
* @param networkId The network the snapshot claims.
|
|
76
|
+
* @param legacyTxHistory The transaction history the snapshot embedded, when it carried one.
|
|
67
77
|
* @returns A wallet holding that state, its coin hashes still pending.
|
|
68
78
|
*/
|
|
69
|
-
restoreWithPendingCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: string): CoreWallet;
|
|
79
|
+
restoreWithPendingCoinHashes(publicKeys: PublicKeys, localState: ledger.ZswapLocalState, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: string, legacyTxHistory?: readonly string[]): CoreWallet;
|
|
70
80
|
initEmpty(keys: ledger.ZswapSecretKeys, networkId: string): CoreWallet;
|
|
71
81
|
/**
|
|
72
82
|
* Records an observed protocol version on the wallet, never going backwards.
|
|
@@ -105,7 +115,9 @@ export declare const CoreWallet: {
|
|
|
105
115
|
* the first place in this variant where keys and state meet. The same step releases the spends the state crossed
|
|
106
116
|
* with: those transactions belong to the ledger version the chain has left behind and can never be included, so
|
|
107
117
|
* nothing else would ever free the coins they reserved.
|
|
108
|
-
* @param previous The identity and position read off the previous ledger version's wallet, and its decoded state.
|
|
118
|
+
* @param previous The identity and position read off the previous ledger version's wallet, and its decoded state. Its
|
|
119
|
+
* embedded transaction history, when it holds one, crosses too: the far side writes it back out and nothing there
|
|
120
|
+
* could rebuild it.
|
|
109
121
|
* @returns A wallet of this ledger version holding what its predecessor held, positioned at the fork.
|
|
110
122
|
*/
|
|
111
123
|
fromPreviousVersion(previous: {
|
|
@@ -114,6 +126,7 @@ export declare const CoreWallet: {
|
|
|
114
126
|
readonly networkId: string;
|
|
115
127
|
readonly protocolVersion: bigint;
|
|
116
128
|
readonly progress: SyncProgress.SyncProgressData;
|
|
129
|
+
readonly legacyTxHistory?: readonly string[];
|
|
117
130
|
}): CoreWallet;
|
|
118
131
|
/**
|
|
119
132
|
* Finishes a crossing at the first sync update: the reservations released, then the coin hashes computed.
|
package/dist/v2/CoreWallet.js
CHANGED
|
@@ -102,7 +102,7 @@ export const CoreWallet = {
|
|
|
102
102
|
protocolVersion: ProtocolVersion.ProtocolVersion(protocolVersion),
|
|
103
103
|
};
|
|
104
104
|
},
|
|
105
|
-
restoreWithCoinHashes(publicKeys, localState, coinHashes, syncProgress, protocolVersion, networkId) {
|
|
105
|
+
restoreWithCoinHashes(publicKeys, localState, coinHashes, syncProgress, protocolVersion, networkId, legacyTxHistory) {
|
|
106
106
|
return CoinHashesMap.assertValid(coinHashes, localState).pipe(Either.mapBoth({
|
|
107
107
|
onLeft: (missingNonces) => new InvalidCoinHashesError({ message: 'Missing coin hashes for coins present in the state', missingNonces }),
|
|
108
108
|
onRight: () => ({
|
|
@@ -112,6 +112,9 @@ export const CoreWallet = {
|
|
|
112
112
|
coinHashes,
|
|
113
113
|
progress: SyncProgress.createSyncProgress(syncProgress),
|
|
114
114
|
protocolVersion: ProtocolVersion.ProtocolVersion(protocolVersion),
|
|
115
|
+
// Spread conditionally: a snapshot that carried no embedded history must not gain a `legacyTxHistory` key,
|
|
116
|
+
// so that re-serializing it writes no `txHistory` field it did not already have.
|
|
117
|
+
...(legacyTxHistory === undefined ? {} : { legacyTxHistory }),
|
|
115
118
|
}),
|
|
116
119
|
}));
|
|
117
120
|
},
|
|
@@ -130,9 +133,10 @@ export const CoreWallet = {
|
|
|
130
133
|
* @param syncProgress Where the snapshot's reading had got to.
|
|
131
134
|
* @param protocolVersion The version the snapshot was written under.
|
|
132
135
|
* @param networkId The network the snapshot claims.
|
|
136
|
+
* @param legacyTxHistory The transaction history the snapshot embedded, when it carried one.
|
|
133
137
|
* @returns A wallet holding that state, its coin hashes still pending.
|
|
134
138
|
*/
|
|
135
|
-
restoreWithPendingCoinHashes(publicKeys, localState, syncProgress, protocolVersion, networkId) {
|
|
139
|
+
restoreWithPendingCoinHashes(publicKeys, localState, syncProgress, protocolVersion, networkId, legacyTxHistory) {
|
|
136
140
|
return {
|
|
137
141
|
state: localState,
|
|
138
142
|
publicKeys,
|
|
@@ -141,6 +145,7 @@ export const CoreWallet = {
|
|
|
141
145
|
coinHashesPending: true,
|
|
142
146
|
progress: SyncProgress.createSyncProgress(syncProgress),
|
|
143
147
|
protocolVersion: ProtocolVersion.ProtocolVersion(protocolVersion),
|
|
148
|
+
...(legacyTxHistory === undefined ? {} : { legacyTxHistory }),
|
|
144
149
|
};
|
|
145
150
|
},
|
|
146
151
|
initEmpty(keys, networkId) {
|
|
@@ -185,7 +190,9 @@ export const CoreWallet = {
|
|
|
185
190
|
* the first place in this variant where keys and state meet. The same step releases the spends the state crossed
|
|
186
191
|
* with: those transactions belong to the ledger version the chain has left behind and can never be included, so
|
|
187
192
|
* nothing else would ever free the coins they reserved.
|
|
188
|
-
* @param previous The identity and position read off the previous ledger version's wallet, and its decoded state.
|
|
193
|
+
* @param previous The identity and position read off the previous ledger version's wallet, and its decoded state. Its
|
|
194
|
+
* embedded transaction history, when it holds one, crosses too: the far side writes it back out and nothing there
|
|
195
|
+
* could rebuild it.
|
|
189
196
|
* @returns A wallet of this ledger version holding what its predecessor held, positioned at the fork.
|
|
190
197
|
*/
|
|
191
198
|
fromPreviousVersion(previous) {
|
|
@@ -197,6 +204,7 @@ export const CoreWallet = {
|
|
|
197
204
|
coinHashesPending: true,
|
|
198
205
|
progress: SyncProgress.createSyncProgress({ ...previous.progress, isConnected: false }),
|
|
199
206
|
protocolVersion: ProtocolVersion.ProtocolVersion(previous.protocolVersion),
|
|
207
|
+
...(previous.legacyTxHistory === undefined ? {} : { legacyTxHistory: previous.legacyTxHistory }),
|
|
200
208
|
};
|
|
201
209
|
},
|
|
202
210
|
/**
|
|
@@ -238,16 +246,12 @@ export const CoreWallet = {
|
|
|
238
246
|
* @returns `wallet` unchanged if its hashes were never pending, otherwise a copy holding them.
|
|
239
247
|
*/
|
|
240
248
|
resolveCoinHashes(wallet, secretKeys) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
coinHashes: CoinHashesMap.init(secretKeys, CoinHashesMap.pickAllCoins(wallet.state)),
|
|
248
|
-
progress: wallet.progress,
|
|
249
|
-
protocolVersion: wallet.protocolVersion,
|
|
250
|
-
};
|
|
249
|
+
if (wallet.coinHashesPending === undefined)
|
|
250
|
+
return wallet;
|
|
251
|
+
// Rebuilt by spread rather than from a list of fields, so nothing the wallet carried can be left behind: only the
|
|
252
|
+
// marker is shed, and the embedded transaction history of a 1.0.0 snapshot survives the first update after crossing.
|
|
253
|
+
const { coinHashesPending: _pending, ...carried } = wallet;
|
|
254
|
+
return { ...carried, coinHashes: CoinHashesMap.init(secretKeys, CoinHashesMap.pickAllCoins(wallet.state)) };
|
|
251
255
|
},
|
|
252
256
|
applyCollapsedUpdate(wallet, collapsed) {
|
|
253
257
|
const newState = wallet.state.applyCollapsedUpdate(collapsed);
|
package/dist/v2/Migration.d.ts
CHANGED
|
@@ -72,6 +72,8 @@ export type PreviousLedgerWallet = Readonly<{
|
|
|
72
72
|
state: Readonly<{
|
|
73
73
|
serialize: () => Uint8Array;
|
|
74
74
|
}>;
|
|
75
|
+
/** The transaction history a 1.0.0 snapshot embedded, when the previous wallet was restored from one. */
|
|
76
|
+
legacyTxHistory?: readonly string[];
|
|
75
77
|
}>;
|
|
76
78
|
/**
|
|
77
79
|
* The migration across a ledger-version boundary: the local state crosses as bytes, identity and position beside it.
|
package/dist/v2/Migration.js
CHANGED
|
@@ -92,5 +92,6 @@ export const makeCrossLedgerMigration = () => ({
|
|
|
92
92
|
networkId: previousState.networkId,
|
|
93
93
|
protocolVersion: previousState.protocolVersion,
|
|
94
94
|
progress: previousState.progress,
|
|
95
|
+
...(previousState.legacyTxHistory === undefined ? {} : { legacyTxHistory: previousState.legacyTxHistory }),
|
|
95
96
|
})), EitherOps.toEffect),
|
|
96
97
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Either } from 'effect';
|
|
2
|
-
import { WalletError } from './WalletError.js';
|
|
2
|
+
import { type WalletError } from './WalletError.js';
|
|
3
3
|
import { CoreWallet } from './CoreWallet.js';
|
|
4
|
+
export { SNAPSHOT_FORMAT_VERSION } from '../SnapshotFormat.js';
|
|
4
5
|
import { type NetworkId } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
5
6
|
export type SerializationCapability<TWallet, TAux, TSerialized> = {
|
|
6
7
|
serialize(wallet: TWallet): TSerialized;
|
package/dist/v2/Serialization.js
CHANGED
|
@@ -11,9 +11,12 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { Effect, ParseResult, Either, pipe, Schema } from 'effect';
|
|
14
|
-
import { WalletError } from './WalletError.js';
|
|
15
14
|
import * as ledger from '@midnightntwrk/ledger-v9';
|
|
16
15
|
import { CoreWallet } from './CoreWallet.js';
|
|
16
|
+
import { SNAPSHOT_FORMAT_VERSION } from '../SnapshotFormat.js';
|
|
17
|
+
// Re-exported because the version this variant writes is part of its serialization surface, as on the V1 twin.
|
|
18
|
+
export { SNAPSHOT_FORMAT_VERSION } from '../SnapshotFormat.js';
|
|
19
|
+
import { SnapshotFormat } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
17
20
|
const StateSchema = Schema.declare((input) => input instanceof ledger.ZswapLocalState).annotations({
|
|
18
21
|
identifier: 'ledger.ZswapLocalState',
|
|
19
22
|
});
|
|
@@ -41,6 +44,13 @@ const StateFromUInt8Array = () => Schema.asSchema(Schema.transformOrFail(Uint8Ar
|
|
|
41
44
|
const HexedState = () => pipe(Schema.Uint8ArrayFromHex, Schema.compose(StateFromUInt8Array()));
|
|
42
45
|
export const makeDefaultV2SerializationCapability = () => {
|
|
43
46
|
const SnapshotSchema = Schema.Struct({
|
|
47
|
+
// The version names the snapshot's shape, not the variant that wrote it, and the constant lives in
|
|
48
|
+
// `../SnapshotFormat.ts` so the twins cannot drift apart. Both variants write this shape — the V2 variant adds
|
|
49
|
+
// only optional fields to it, which is not a new version. A V1 reader never meets a V2 snapshot anyway:
|
|
50
|
+
// `../Restore.ts` routes each snapshot to the variant it names as its writer, and by the variant that owns its
|
|
51
|
+
// `protocolVersion` when it names none.
|
|
52
|
+
version: SnapshotFormat.versionField('shielded', SNAPSHOT_FORMAT_VERSION),
|
|
53
|
+
writtenBy: SnapshotFormat.writtenByField(),
|
|
44
54
|
publicKeys: Schema.Struct({
|
|
45
55
|
coinPublicKey: Schema.String,
|
|
46
56
|
encryptionPublicKey: Schema.String,
|
|
@@ -58,22 +68,30 @@ export const makeDefaultV2SerializationCapability = () => {
|
|
|
58
68
|
// `CoreWallet.coinHashesPending`). Optional twice over — a wallet that is not mid-crossing has nothing to declare,
|
|
59
69
|
// and snapshots written before the field existed must keep decoding unchanged.
|
|
60
70
|
coinHashesPending: Schema.optional(Schema.Literal(true)),
|
|
71
|
+
// The transaction history a 1.0.0 snapshot embedded. Read back and written out untouched, never added to; absent
|
|
72
|
+
// for every snapshot written since, and kept absent for them. See `CoreWallet.legacyTxHistory`.
|
|
73
|
+
txHistory: Schema.optional(Schema.Array(Schema.String)),
|
|
61
74
|
});
|
|
62
75
|
return {
|
|
63
76
|
serialize: (wallet) => {
|
|
64
77
|
const buildSnapshot = (w) => ({
|
|
78
|
+
version: SNAPSHOT_FORMAT_VERSION,
|
|
79
|
+
writtenBy: SnapshotFormat.V2_SNAPSHOT_WRITER,
|
|
65
80
|
publicKeys: w.publicKeys,
|
|
66
81
|
state: w.state,
|
|
67
82
|
protocolVersion: w.protocolVersion,
|
|
68
83
|
networkId: w.networkId,
|
|
69
|
-
offset: w.progress?.appliedIndex,
|
|
70
84
|
coinHashes: w.coinHashes,
|
|
85
|
+
// Optional fields are spread in only when present, so the snapshot object never carries an `undefined` key:
|
|
86
|
+
// the bytes must not depend on `JSON.stringify` dropping one.
|
|
87
|
+
...(w.progress?.appliedIndex !== undefined ? { offset: w.progress.appliedIndex } : {}),
|
|
88
|
+
...(w.legacyTxHistory !== undefined ? { txHistory: w.legacyTxHistory } : {}),
|
|
71
89
|
...(w.coinHashesPending !== undefined ? { coinHashesPending: w.coinHashesPending } : {}),
|
|
72
90
|
});
|
|
73
91
|
return pipe(wallet, buildSnapshot, Schema.encodeSync(SnapshotSchema), JSON.stringify);
|
|
74
92
|
},
|
|
75
93
|
deserialize: (aux, serialized) => {
|
|
76
|
-
return pipe(serialized,
|
|
94
|
+
return pipe(serialized, SnapshotFormat.readSnapshot({ surface: 'shielded', reads: [SNAPSHOT_FORMAT_VERSION], schema: SnapshotSchema }), Either.flatMap((snapshot) => {
|
|
77
95
|
const progress = {
|
|
78
96
|
appliedIndex: snapshot.offset ?? 0n,
|
|
79
97
|
highestRelevantWalletIndex: 0n,
|
|
@@ -85,8 +103,8 @@ export const makeDefaultV2SerializationCapability = () => {
|
|
|
85
103
|
// its state is full and its hash map is empty by construction, because the migration that wrote it had no
|
|
86
104
|
// secret keys. Every other snapshot goes on being checked against its own state.
|
|
87
105
|
return snapshot.coinHashesPending === true
|
|
88
|
-
? Either.right(CoreWallet.restoreWithPendingCoinHashes(snapshot.publicKeys, snapshot.state, progress, snapshot.protocolVersion, snapshot.networkId))
|
|
89
|
-
: CoreWallet.restoreWithCoinHashes(snapshot.publicKeys, snapshot.state, snapshot.coinHashes, progress, snapshot.protocolVersion, snapshot.networkId);
|
|
106
|
+
? Either.right(CoreWallet.restoreWithPendingCoinHashes(snapshot.publicKeys, snapshot.state, progress, snapshot.protocolVersion, snapshot.networkId, snapshot.txHistory))
|
|
107
|
+
: CoreWallet.restoreWithCoinHashes(snapshot.publicKeys, snapshot.state, snapshot.coinHashes, progress, snapshot.protocolVersion, snapshot.networkId, snapshot.txHistory);
|
|
90
108
|
}));
|
|
91
109
|
},
|
|
92
110
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TransactionHistoryStorage } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
2
2
|
import type * as ledger from '@midnightntwrk/ledger-v9';
|
|
3
3
|
import { Duration, Effect, Schema } from 'effect';
|
|
4
|
-
import { TransactionHistoryError } from './WalletError.js';
|
|
4
|
+
import { BlocklessFinalizedEntryError, TransactionHistoryError } from './WalletError.js';
|
|
5
5
|
export declare const QualifiedShieldedCoinInfoSchema: Schema.Struct<{
|
|
6
6
|
type: typeof Schema.String;
|
|
7
7
|
nonce: typeof Schema.String;
|
|
@@ -39,11 +39,11 @@ export declare const ShieldedTransactionHistoryEntrySchema: Schema.Struct<Readon
|
|
|
39
39
|
submittedAt: typeof Schema.Date;
|
|
40
40
|
}>, Schema.Struct<{
|
|
41
41
|
status: Schema.Literal<["finalized"]>;
|
|
42
|
-
finalizedBlock: Schema.Struct<{
|
|
42
|
+
finalizedBlock: Schema.optional<Schema.Struct<{
|
|
43
43
|
hash: typeof Schema.String;
|
|
44
44
|
height: typeof Schema.Number;
|
|
45
45
|
timestamp: typeof Schema.Date;
|
|
46
|
-
}
|
|
46
|
+
}>>;
|
|
47
47
|
}>, Schema.Struct<{
|
|
48
48
|
status: Schema.Literal<["rejected"]>;
|
|
49
49
|
rejectedAt: typeof Schema.Date;
|
|
@@ -92,7 +92,7 @@ export type TransactionDetails = {
|
|
|
92
92
|
};
|
|
93
93
|
export type TransactionHistoryService = {
|
|
94
94
|
put(changes: ledger.ZswapStateChanges, metadata: TransactionDetails, protocolVersion: number): Effect.Effect<void, TransactionHistoryError>;
|
|
95
|
-
getTransactionDetails(hash: TransactionHistoryStorage.TransactionHash): Effect.Effect<TransactionDetails, TransactionHistoryError>;
|
|
95
|
+
getTransactionDetails(hash: TransactionHistoryStorage.TransactionHash): Effect.Effect<TransactionDetails, TransactionHistoryError | BlocklessFinalizedEntryError>;
|
|
96
96
|
};
|
|
97
97
|
export declare const mergeShieldedSections: (existing: ShieldedSection, incoming: ShieldedSection) => ShieldedSection;
|
|
98
98
|
export declare const makeDefaultTransactionHistoryService: (config: DefaultTransactionHistoryConfiguration, _getContext: () => unknown) => TransactionHistoryService;
|
|
@@ -14,7 +14,7 @@ import { TransactionHistoryStorage } from '@midnightntwrk/wallet-sdk-abstraction
|
|
|
14
14
|
import { Duration, Array as EArray, Effect, Schedule, Schema } from 'effect';
|
|
15
15
|
import { TransactionHistoryDetail } from '@midnightntwrk/wallet-sdk-indexer-client';
|
|
16
16
|
import { HttpQueryClient } from '@midnightntwrk/wallet-sdk-indexer-client/effect';
|
|
17
|
-
import { TransactionHistoryError } from './WalletError.js';
|
|
17
|
+
import { BlocklessFinalizedEntryError, TransactionHistoryError } from './WalletError.js';
|
|
18
18
|
export const QualifiedShieldedCoinInfoSchema = Schema.Struct({
|
|
19
19
|
type: Schema.String,
|
|
20
20
|
nonce: Schema.String,
|
|
@@ -116,17 +116,26 @@ export const makeSimulatorTransactionHistoryService = (config, _getContext) => {
|
|
|
116
116
|
getTransactionDetails: (hash) => Effect.tryPromise({
|
|
117
117
|
try: () => txHistoryStorage.get(hash),
|
|
118
118
|
catch: (e) => new TransactionHistoryError({ message: `Failed to get transaction details for ${hash}`, cause: e }),
|
|
119
|
-
}).pipe(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
119
|
+
}).pipe(
|
|
120
|
+
// Two distinct failures, reported distinctly. Storage may never have heard of the transaction; or it holds a
|
|
121
|
+
// finalized entry restored from a history written before the lifecycle field existed, which records no block.
|
|
122
|
+
// This service backs the simulator, where storage is the only source, so neither case can be repaired here.
|
|
123
|
+
Effect.flatMap((entry) => !isFinalized(entry)
|
|
124
|
+
? Effect.fail(new TransactionHistoryError({ message: `No transaction found in storage for hash: ${hash}` }))
|
|
125
|
+
: entry.lifecycle.finalizedBlock === undefined
|
|
126
|
+
? Effect.fail(new BlocklessFinalizedEntryError({
|
|
127
|
+
message: `Transaction ${hash} is finalized but its history entry records no block (restored from a pre-lifecycle history)`,
|
|
128
|
+
hash,
|
|
129
|
+
}))
|
|
130
|
+
: Effect.succeed({
|
|
131
|
+
hash: entry.hash,
|
|
132
|
+
block: {
|
|
133
|
+
hash: entry.lifecycle.finalizedBlock.hash,
|
|
134
|
+
height: entry.lifecycle.finalizedBlock.height,
|
|
135
|
+
timestamp: entry.lifecycle.finalizedBlock.timestamp.getTime(),
|
|
136
|
+
},
|
|
137
|
+
status: entry.status ?? 'SUCCESS',
|
|
138
|
+
identifiers: entry.identifiers,
|
|
139
|
+
}))),
|
|
131
140
|
};
|
|
132
141
|
};
|
package/dist/v2/V2Builder.js
CHANGED
|
@@ -203,6 +203,9 @@ export class V2Builder {
|
|
|
203
203
|
message: 'Failed to migrate shielded wallet state into this variant',
|
|
204
204
|
cause: error,
|
|
205
205
|
}))),
|
|
206
|
+
// The version the state was left at: where the chain was when a snapshot was written, or what the chain answered
|
|
207
|
+
// when a fresh state was stamped from it. The runtime starts at this version rather than the variant's lower bound.
|
|
208
|
+
protocolVersionOf: (state) => state.protocolVersion,
|
|
206
209
|
deserializeState: (serialized) => {
|
|
207
210
|
return v2Context.serializationCapability.deserialize(null, serialized);
|
|
208
211
|
},
|
package/dist/v2/WalletError.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { type SnapshotFormat } from '@midnightntwrk/wallet-sdk-abstractions';
|
|
1
2
|
import type * as ledger from '@midnightntwrk/ledger-v9';
|
|
2
3
|
import { type LedgerOps } from '@midnightntwrk/wallet-sdk-utilities';
|
|
3
4
|
export declare const WalletError: {
|
|
4
5
|
other(err: unknown): WalletError;
|
|
5
6
|
submission(err: unknown): WalletError;
|
|
6
7
|
};
|
|
7
|
-
export type WalletError = OtherWalletError | InsufficientFundsError | SubmissionError | AddressError | SyncWalletError | InvalidCoinHashesError | TransactingError | OutOfOrderSyncUpdateError | LedgerOps.LedgerError;
|
|
8
|
+
export type WalletError = SnapshotFormat.SnapshotRestoreError | OtherWalletError | InsufficientFundsError | SubmissionError | AddressError | SyncWalletError | InvalidCoinHashesError | TransactingError | OutOfOrderSyncUpdateError | LedgerOps.LedgerError;
|
|
8
9
|
declare const OtherWalletError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
9
10
|
readonly _tag: "Wallet.Other";
|
|
10
11
|
} & Readonly<A>;
|
|
@@ -71,6 +72,28 @@ export declare class TransactionHistoryError extends TransactionHistoryError_bas
|
|
|
71
72
|
cause?: unknown;
|
|
72
73
|
}> {
|
|
73
74
|
}
|
|
75
|
+
declare const BlocklessFinalizedEntryError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
76
|
+
readonly _tag: "Wallet.BlocklessFinalizedEntry";
|
|
77
|
+
} & Readonly<A>;
|
|
78
|
+
/**
|
|
79
|
+
* A finalized history entry that records no block, met where a block is needed.
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* Only an entry restored from a history written before the lifecycle field existed looks like this: it is known to have
|
|
83
|
+
* been finalized, but the block it landed in was never recorded, and none is invented. It is its own error rather
|
|
84
|
+
* than a message on {@link TransactionHistoryError} so that a caller which can fetch the block by hash matches on the
|
|
85
|
+
* tag.
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* if (error._tag === 'Wallet.BlocklessFinalizedEntry') fetchBlockFor(error.hash);
|
|
89
|
+
* ```;
|
|
90
|
+
*/
|
|
91
|
+
export declare class BlocklessFinalizedEntryError extends BlocklessFinalizedEntryError_base<{
|
|
92
|
+
readonly message: string;
|
|
93
|
+
/** The transaction whose history entry records no block. */
|
|
94
|
+
readonly hash: string;
|
|
95
|
+
}> {
|
|
96
|
+
}
|
|
74
97
|
declare const OutOfOrderSyncUpdateError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
75
98
|
readonly _tag: "Wallet.OutOfOrderSyncUpdate";
|
|
76
99
|
} & Readonly<A>;
|
package/dist/v2/WalletError.js
CHANGED
|
@@ -51,6 +51,21 @@ export class TransactingError extends Data.TaggedError('Wallet.Transacting') {
|
|
|
51
51
|
}
|
|
52
52
|
export class TransactionHistoryError extends Data.TaggedError('Wallet.TransactionHistory') {
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* A finalized history entry that records no block, met where a block is needed.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* Only an entry restored from a history written before the lifecycle field existed looks like this: it is known to have
|
|
59
|
+
* been finalized, but the block it landed in was never recorded, and none is invented. It is its own error rather
|
|
60
|
+
* than a message on {@link TransactionHistoryError} so that a caller which can fetch the block by hash matches on the
|
|
61
|
+
* tag.
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* if (error._tag === 'Wallet.BlocklessFinalizedEntry') fetchBlockFor(error.hash);
|
|
65
|
+
* ```;
|
|
66
|
+
*/
|
|
67
|
+
export class BlocklessFinalizedEntryError extends Data.TaggedError('Wallet.BlocklessFinalizedEntry') {
|
|
68
|
+
}
|
|
54
69
|
/**
|
|
55
70
|
* A batch of zswap ledger events was not in ascending id order: an event arrived at or below the one before it, or at
|
|
56
71
|
* or below the applied cursor.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midnightntwrk/wallet-sdk-shielded",
|
|
3
|
-
"version": "4.0.0-rc.
|
|
3
|
+
"version": "4.0.0-rc.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@midnight-ntwrk/ledger-v8": "^8.1.0",
|
|
38
38
|
"@midnightntwrk/ledger-v9": "1.0.0-rc.5",
|
|
39
|
-
"@midnightntwrk/wallet-sdk-abstractions": "3.0.0-rc.
|
|
39
|
+
"@midnightntwrk/wallet-sdk-abstractions": "3.0.0-rc.1",
|
|
40
40
|
"@midnightntwrk/wallet-sdk-address-format": "4.0.0-rc.0",
|
|
41
|
-
"@midnightntwrk/wallet-sdk-capabilities": "4.0.0-rc.
|
|
42
|
-
"@midnightntwrk/wallet-sdk-indexer-client": "2.0.0-rc.
|
|
43
|
-
"@midnightntwrk/wallet-sdk-runtime": "
|
|
41
|
+
"@midnightntwrk/wallet-sdk-capabilities": "4.0.0-rc.1",
|
|
42
|
+
"@midnightntwrk/wallet-sdk-indexer-client": "2.0.0-rc.1",
|
|
43
|
+
"@midnightntwrk/wallet-sdk-runtime": "2.0.0-rc.1",
|
|
44
44
|
"@midnightntwrk/wallet-sdk-utilities": "1.2.2-rc.0",
|
|
45
45
|
"effect": "^3.19.19",
|
|
46
46
|
"rxjs": "^7.8.2"
|