@midnightntwrk/wallet-sdk-facade 5.0.0-beta.0 → 5.0.0-beta.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/index.d.ts +37 -10
- package/dist/index.js +85 -25
- package/dist/transaction.d.ts +18 -0
- package/dist/transaction.js +24 -0
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -14,10 +14,33 @@ import { type DefaultPendingTransactionsServiceConfiguration, PendingTransaction
|
|
|
14
14
|
import { type BlockData, type BlockDataFetcher, type ValidateTxOptions, ValidationFetchError, type ValidationService, WellFormedError, type WellFormedStrictnessFlags } from '@midnightntwrk/wallet-sdk-capabilities/validation';
|
|
15
15
|
import { type DustAddress, type ShieldedAddress, type UnshieldedAddress } from '@midnightntwrk/wallet-sdk-address-format';
|
|
16
16
|
/**
|
|
17
|
-
* Full entry schema for transaction history
|
|
18
|
-
* `
|
|
17
|
+
* Full entry schema for transaction history. The common entry data and wallet-specific sections (`shielded`,
|
|
18
|
+
* `unshielded`, `dust`) live on every entry regardless of lifecycle; the `lifecycle` field is the only discriminator.
|
|
19
|
+
* Pass this to `InMemoryTransactionHistoryStorage` to enable serialize/restore.
|
|
19
20
|
*/
|
|
20
|
-
export declare const WalletEntrySchema: Schema.Struct<{
|
|
21
|
+
export declare const WalletEntrySchema: Schema.Struct<Readonly<{
|
|
22
|
+
hash: typeof Schema.String;
|
|
23
|
+
identifiers: Schema.Array$<typeof Schema.String>;
|
|
24
|
+
protocolVersion: Schema.optional<typeof Schema.Number>;
|
|
25
|
+
status: Schema.optional<Schema.Literal<["SUCCESS", "FAILURE", "PARTIAL_SUCCESS"]>>;
|
|
26
|
+
timestamp: Schema.optional<typeof Schema.Date>;
|
|
27
|
+
fees: Schema.optional<Schema.NullOr<typeof Schema.BigInt>>;
|
|
28
|
+
lifecycle: Schema.Union<[Schema.Struct<{
|
|
29
|
+
status: Schema.Literal<["pending"]>;
|
|
30
|
+
submittedAt: typeof Schema.Date;
|
|
31
|
+
}>, Schema.Struct<{
|
|
32
|
+
status: Schema.Literal<["finalized"]>;
|
|
33
|
+
finalizedBlock: Schema.Struct<{
|
|
34
|
+
hash: typeof Schema.String;
|
|
35
|
+
height: typeof Schema.Number;
|
|
36
|
+
timestamp: typeof Schema.Date;
|
|
37
|
+
}>;
|
|
38
|
+
}>, Schema.Struct<{
|
|
39
|
+
status: Schema.Literal<["rejected"]>;
|
|
40
|
+
rejectedAt: typeof Schema.Date;
|
|
41
|
+
reason: Schema.optional<typeof Schema.String>;
|
|
42
|
+
}>]>;
|
|
43
|
+
}> & {
|
|
21
44
|
shielded: Schema.optional<Schema.Struct<{
|
|
22
45
|
receivedCoins: Schema.Array$<Schema.Struct<{
|
|
23
46
|
type: typeof Schema.String;
|
|
@@ -65,15 +88,19 @@ export declare const WalletEntrySchema: Schema.Struct<{
|
|
|
65
88
|
mtIndex: typeof Schema.BigInt;
|
|
66
89
|
}>>;
|
|
67
90
|
}>>;
|
|
68
|
-
hash: typeof Schema.String;
|
|
69
|
-
protocolVersion: typeof Schema.Number;
|
|
70
|
-
status: Schema.Literal<["SUCCESS", "FAILURE", "PARTIAL_SUCCESS"]>;
|
|
71
|
-
identifiers: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
72
|
-
timestamp: Schema.optional<typeof Schema.Date>;
|
|
73
|
-
fees: Schema.optional<Schema.NullOr<typeof Schema.BigInt>>;
|
|
74
91
|
}>;
|
|
75
92
|
export type WalletEntry = Schema.Schema.Type<typeof WalletEntrySchema>;
|
|
76
|
-
|
|
93
|
+
/** A `WalletEntry` whose lifecycle is `pending`. */
|
|
94
|
+
export type PendingWalletEntry = WalletEntry & {
|
|
95
|
+
readonly lifecycle: TransactionHistoryStorage.PendingLifecycle;
|
|
96
|
+
};
|
|
97
|
+
/** A `WalletEntry` whose lifecycle is `finalized`. */
|
|
98
|
+
export type FinalizedWalletEntry = WalletEntry & {
|
|
99
|
+
readonly lifecycle: TransactionHistoryStorage.FinalizedLifecycle;
|
|
100
|
+
};
|
|
101
|
+
export declare const isPendingWalletEntry: (entry: WalletEntry) => entry is PendingWalletEntry;
|
|
102
|
+
export declare const isFinalizedWalletEntry: (entry: WalletEntry) => entry is FinalizedWalletEntry;
|
|
103
|
+
export declare function mergeWalletEntries(existing: WalletEntry, incoming: WalletEntry): WalletEntry;
|
|
77
104
|
type TokenKind = 'dust' | 'shielded' | 'unshielded';
|
|
78
105
|
type TokenKindsToBalance = 'all' | TokenKind[];
|
|
79
106
|
declare const TokenKindsToBalance: {
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import * as ledger from '@midnightntwrk/ledger-v9';
|
|
|
14
14
|
import { makeDefaultSubmissionService, } from '@midnightntwrk/wallet-sdk-capabilities';
|
|
15
15
|
import { makeDefaultProvingService, } from '@midnightntwrk/wallet-sdk-capabilities/proving';
|
|
16
16
|
import { ShieldedSectionSchema, mergeShieldedSections, } from '@midnightntwrk/wallet-sdk-shielded';
|
|
17
|
-
import { UnshieldedSectionSchema } from '@midnightntwrk/wallet-sdk-unshielded-wallet';
|
|
17
|
+
import { UnshieldedSectionSchema, mergeUnshieldedSections, } from '@midnightntwrk/wallet-sdk-unshielded-wallet';
|
|
18
18
|
import { DustSectionSchema, mergeDustSections } from '@midnightntwrk/wallet-sdk-dust-wallet';
|
|
19
19
|
import { Clock } from '@midnightntwrk/wallet-sdk-utilities';
|
|
20
20
|
import { FetchTermsAndConditions as FetchTermsAndConditionsQuery } from '@midnightntwrk/wallet-sdk-indexer-client';
|
|
@@ -24,31 +24,81 @@ import { TransactionHistoryStorage } from '@midnightntwrk/wallet-sdk-abstraction
|
|
|
24
24
|
import { combineLatest, map, firstValueFrom, concatMap } from 'rxjs';
|
|
25
25
|
import { PendingTransactions, PendingTransactionsServiceImpl, } from '@midnightntwrk/wallet-sdk-capabilities';
|
|
26
26
|
import { makeDefaultBlockDataFetcher, makeDefaultValidationService, ValidationFetchError, WellFormedError, } from '@midnightntwrk/wallet-sdk-capabilities/validation';
|
|
27
|
-
import { finalizedTransactionTrait } from './transaction.js';
|
|
27
|
+
import { finalizedTransactionTrait, txHistoryHash } from './transaction.js';
|
|
28
28
|
/**
|
|
29
|
-
* Full entry schema for transaction history
|
|
30
|
-
* `
|
|
29
|
+
* Full entry schema for transaction history. The common entry data and wallet-specific sections (`shielded`,
|
|
30
|
+
* `unshielded`, `dust`) live on every entry regardless of lifecycle; the `lifecycle` field is the only discriminator.
|
|
31
|
+
* Pass this to `InMemoryTransactionHistoryStorage` to enable serialize/restore.
|
|
31
32
|
*/
|
|
32
|
-
export const WalletEntrySchema =
|
|
33
|
-
...TransactionHistoryStorage.TransactionHistoryCommonSchema.fields,
|
|
33
|
+
export const WalletEntrySchema = TransactionHistoryStorage.extendEntrySchema({
|
|
34
34
|
shielded: Schema.optional(ShieldedSectionSchema),
|
|
35
35
|
unshielded: Schema.optional(UnshieldedSectionSchema),
|
|
36
36
|
dust: Schema.optional(DustSectionSchema),
|
|
37
37
|
});
|
|
38
|
-
export const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
export const isPendingWalletEntry = (entry) => entry.lifecycle.status === 'pending';
|
|
39
|
+
export const isFinalizedWalletEntry = (entry) => entry.lifecycle.status === 'finalized';
|
|
40
|
+
/**
|
|
41
|
+
* Merge two wallet entries arriving under the same hash. Treats the entry as `T × lifecycle` per the storage model:
|
|
42
|
+
*
|
|
43
|
+
* - **Shared scalar facts about the tx** (`protocolVersion`, `status`, `timestamp`, `fees`) — first writer wins. Once any
|
|
44
|
+
* wallet has set the value, later writes are no-ops for these fields. This is correct because the value is the same
|
|
45
|
+
* across all wallets (it's a property of the on-chain tx, not the wallet's view of it).
|
|
46
|
+
* - **`identifiers`** — unioned (each wallet may surface a different identifier subset).
|
|
47
|
+
* - **`lifecycle`** — incoming wins (this is how `pending → finalized` transitions are recorded).
|
|
48
|
+
* - **Wallet sections** (`shielded`, `unshielded`, `dust`) — combined via per-section merge when both sides have them;
|
|
49
|
+
* otherwise whichever side is present is used.
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* Combine two optional values under a merge function: if both sides have it, delegate to `merge`; otherwise return
|
|
53
|
+
* whichever side is present (or `undefined` if neither). Encapsulates the four-way pattern used for every wallet
|
|
54
|
+
* section in {@link mergeWalletEntries}.
|
|
55
|
+
*/
|
|
56
|
+
const mergeOptionalSection = (existing, incoming, merge) => {
|
|
57
|
+
if (existing !== undefined && incoming !== undefined)
|
|
58
|
+
return merge(existing, incoming);
|
|
59
|
+
return existing ?? incoming;
|
|
60
|
+
};
|
|
61
|
+
export function mergeWalletEntries(existing, incoming) {
|
|
62
|
+
// identifiers: each wallet may surface a different subset, so union them
|
|
63
|
+
const identifiers = Array.from(new Set([...existing.identifiers, ...incoming.identifiers]));
|
|
64
|
+
// wallet sections: per-section merge when both sides have it; whichever side is present otherwise
|
|
65
|
+
const shielded = mergeOptionalSection(existing.shielded, incoming.shielded, mergeShieldedSections);
|
|
66
|
+
const unshielded = mergeOptionalSection(existing.unshielded, incoming.unshielded, mergeUnshieldedSections);
|
|
67
|
+
const dust = mergeOptionalSection(existing.dust, incoming.dust, mergeDustSections);
|
|
68
|
+
return {
|
|
69
|
+
hash: existing.hash,
|
|
70
|
+
identifiers,
|
|
71
|
+
// shared scalar facts about the on-chain tx — first writer wins (same value across all wallets)
|
|
72
|
+
protocolVersion: existing.protocolVersion ?? incoming.protocolVersion,
|
|
73
|
+
status: existing.status ?? incoming.status,
|
|
74
|
+
timestamp: existing.timestamp ?? incoming.timestamp,
|
|
75
|
+
fees: existing.fees ?? incoming.fees,
|
|
76
|
+
// lifecycle: incoming wins — this is how pending → finalized/rejected transitions are recorded
|
|
77
|
+
lifecycle: incoming.lifecycle,
|
|
78
|
+
...(shielded !== undefined ? { shielded } : {}),
|
|
79
|
+
...(unshielded !== undefined ? { unshielded } : {}),
|
|
80
|
+
...(dust !== undefined ? { dust } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Storage key for a tx we're about to submit (record as pending). The hash comes from {@link txHistoryHash}, which the
|
|
85
|
+
* revert side uses too — so a tx keyed here while pending resolves to the same key when later confirmed or reverted.
|
|
86
|
+
*/
|
|
87
|
+
const submitTxHistoryKey = (tx) => ({
|
|
88
|
+
hash: txHistoryHash(tx),
|
|
89
|
+
identifiers: tx.identifiers(),
|
|
50
90
|
});
|
|
51
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Storage key for a tx we're about to revert (record as rejected). Shares {@link txHistoryHash} with the submit side so
|
|
93
|
+
* the rejected entry lands on the pending entry in place. Returns `undefined` only when the tx has no identifiers at
|
|
94
|
+
* all (nothing to revert).
|
|
95
|
+
*/
|
|
96
|
+
const revertTxHistoryKey = (tx) => {
|
|
97
|
+
const identifiers = tx.identifiers();
|
|
98
|
+
if (identifiers.length === 0)
|
|
99
|
+
return undefined;
|
|
100
|
+
return { hash: txHistoryHash(tx), identifiers };
|
|
101
|
+
};
|
|
52
102
|
const TokenKindsToBalance = new (class {
|
|
53
103
|
allTokenKinds = ['shielded', 'unshielded', 'dust'];
|
|
54
104
|
toFlags = (tokenKinds) => {
|
|
@@ -391,10 +441,15 @@ export class WalletFacade {
|
|
|
391
441
|
* @throws {@link WellFormedError} — call {@link validateTransaction} first to get this error early.
|
|
392
442
|
*/
|
|
393
443
|
async submitTransaction(tx) {
|
|
444
|
+
const identifiers = tx.identifiers();
|
|
394
445
|
try {
|
|
395
446
|
await this.pendingTransactionsService.addPendingTransaction(tx);
|
|
447
|
+
// Insert before awaiting submission so the entry exists while the tx is in flight — the per-wallet sync
|
|
448
|
+
// handlers' gotFinalized call clears the pending entry on confirmation.
|
|
449
|
+
const key = submitTxHistoryKey(tx);
|
|
450
|
+
await this.#txHistoryStorage.gotPending({ ...key, submittedAt: this.clock.now() });
|
|
396
451
|
await this.submissionService.submitTransaction(tx, 'Finalized');
|
|
397
|
-
return
|
|
452
|
+
return identifiers.at(-1);
|
|
398
453
|
}
|
|
399
454
|
catch (error) {
|
|
400
455
|
await this.revert(tx);
|
|
@@ -774,7 +829,13 @@ export class WalletFacade {
|
|
|
774
829
|
this.shielded.revertTransaction(tx),
|
|
775
830
|
this.unshielded.revertTransaction(tx),
|
|
776
831
|
this.dust.revertTransaction(tx),
|
|
777
|
-
]).then(() =>
|
|
832
|
+
]).then(async () => {
|
|
833
|
+
await this.pendingTransactionsService.clear(tx);
|
|
834
|
+
const key = revertTxHistoryKey(tx);
|
|
835
|
+
if (key !== undefined) {
|
|
836
|
+
await this.#txHistoryStorage.gotRejected({ ...key, rejectedAt: this.clock.now() });
|
|
837
|
+
}
|
|
838
|
+
});
|
|
778
839
|
}
|
|
779
840
|
async start(shieldedSecretKeys, dustSecretKey) {
|
|
780
841
|
await Promise.all([
|
|
@@ -795,11 +856,10 @@ export class WalletFacade {
|
|
|
795
856
|
]);
|
|
796
857
|
}
|
|
797
858
|
async queryTxHistoryByHash(hash) {
|
|
798
|
-
|
|
799
|
-
return raw && isWalletEntry(raw) ? raw : undefined;
|
|
859
|
+
return this.#txHistoryStorage.get(hash);
|
|
800
860
|
}
|
|
801
861
|
async getAllFromTxHistory() {
|
|
802
|
-
const
|
|
803
|
-
return [...
|
|
862
|
+
const all = await this.#txHistoryStorage.getAll();
|
|
863
|
+
return [...all];
|
|
804
864
|
}
|
|
805
865
|
}
|
package/dist/transaction.d.ts
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
1
|
import { type PendingTransactions } from '@midnightntwrk/wallet-sdk-capabilities';
|
|
2
2
|
import * as ledger from '@midnightntwrk/ledger-v9';
|
|
3
|
+
import { type AnyTransaction } from '@midnightntwrk/wallet-sdk-dust-wallet/v1';
|
|
4
|
+
/**
|
|
5
|
+
* The key under which a transaction's history entry is stored.
|
|
6
|
+
*
|
|
7
|
+
* Prefer the ledger transaction hash — it's the canonical chain identifier and the value the indexer reports a
|
|
8
|
+
* confirmed tx under. `transactionHash()` is only defined for proven + signed + bound transactions, though; it throws
|
|
9
|
+
* for the other variants, notably the proof-erased transactions the simulator produces. In that case fall back to the
|
|
10
|
+
* hex of the tx's serialized bytes: `serialize()` is total over every variant (it's the same encoding used to submit
|
|
11
|
+
* the tx), so a key is always available — unlike `identifiers[0]`, which is an identifier, not a hash of the
|
|
12
|
+
* transaction.
|
|
13
|
+
*
|
|
14
|
+
* Both the submit (pending) and revert (rejected) sides route through this one function so they can never disagree on
|
|
15
|
+
* the key. The fallback is deterministic: the same transaction object yields the same bytes every time, and the
|
|
16
|
+
* auto-revert path reverts the very object it submitted, so the rejected entry lands on the pending entry in place.
|
|
17
|
+
* (Serialization differs across lifecycle states, so this is only stable for a fixed tx — which is exactly the
|
|
18
|
+
* submit→revert flow.)
|
|
19
|
+
*/
|
|
20
|
+
export declare const txHistoryHash: (tx: AnyTransaction) => string;
|
|
3
21
|
export declare const finalizedTransactionTrait: PendingTransactions.TransactionTrait<ledger.FinalizedTransaction>;
|
package/dist/transaction.js
CHANGED
|
@@ -14,6 +14,30 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { Array as Arr, DateTime, Duration, HashSet, Option, Order, pipe } from 'effect';
|
|
16
16
|
import * as ledger from '@midnightntwrk/ledger-v9';
|
|
17
|
+
/**
|
|
18
|
+
* The key under which a transaction's history entry is stored.
|
|
19
|
+
*
|
|
20
|
+
* Prefer the ledger transaction hash — it's the canonical chain identifier and the value the indexer reports a
|
|
21
|
+
* confirmed tx under. `transactionHash()` is only defined for proven + signed + bound transactions, though; it throws
|
|
22
|
+
* for the other variants, notably the proof-erased transactions the simulator produces. In that case fall back to the
|
|
23
|
+
* hex of the tx's serialized bytes: `serialize()` is total over every variant (it's the same encoding used to submit
|
|
24
|
+
* the tx), so a key is always available — unlike `identifiers[0]`, which is an identifier, not a hash of the
|
|
25
|
+
* transaction.
|
|
26
|
+
*
|
|
27
|
+
* Both the submit (pending) and revert (rejected) sides route through this one function so they can never disagree on
|
|
28
|
+
* the key. The fallback is deterministic: the same transaction object yields the same bytes every time, and the
|
|
29
|
+
* auto-revert path reverts the very object it submitted, so the rejected entry lands on the pending entry in place.
|
|
30
|
+
* (Serialization differs across lifecycle states, so this is only stable for a fixed tx — which is exactly the
|
|
31
|
+
* submit→revert flow.)
|
|
32
|
+
*/
|
|
33
|
+
export const txHistoryHash = (tx) => {
|
|
34
|
+
try {
|
|
35
|
+
return tx.transactionHash().toString();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return Buffer.from(tx.serialize()).toString('hex');
|
|
39
|
+
}
|
|
40
|
+
};
|
|
17
41
|
export const finalizedTransactionTrait = {
|
|
18
42
|
areAllTxIdsIncluded(tx, txIds) {
|
|
19
43
|
const txIdsSet = HashSet.fromIterable(tx.identifiers());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midnightntwrk/wallet-sdk-facade",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -27,18 +27,18 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@midnightntwrk/ledger-v9": "1.0.0-rc.2",
|
|
30
|
-
"@midnightntwrk/wallet-sdk-abstractions": "
|
|
31
|
-
"@midnightntwrk/wallet-sdk-address-format": "
|
|
32
|
-
"@midnightntwrk/wallet-sdk-capabilities": "
|
|
33
|
-
"@midnightntwrk/wallet-sdk-dust-wallet": "
|
|
34
|
-
"@midnightntwrk/wallet-sdk-indexer-client": "
|
|
35
|
-
"@midnightntwrk/wallet-sdk-shielded": "
|
|
36
|
-
"@midnightntwrk/wallet-sdk-unshielded-wallet": "
|
|
30
|
+
"@midnightntwrk/wallet-sdk-abstractions": "3.0.0-beta.0",
|
|
31
|
+
"@midnightntwrk/wallet-sdk-address-format": "4.0.0-beta.1",
|
|
32
|
+
"@midnightntwrk/wallet-sdk-capabilities": "4.0.0-beta.1",
|
|
33
|
+
"@midnightntwrk/wallet-sdk-dust-wallet": "5.0.0-beta.1",
|
|
34
|
+
"@midnightntwrk/wallet-sdk-indexer-client": "1.3.0-beta.1",
|
|
35
|
+
"@midnightntwrk/wallet-sdk-shielded": "4.0.0-beta.1",
|
|
36
|
+
"@midnightntwrk/wallet-sdk-unshielded-wallet": "4.0.0-beta.1",
|
|
37
37
|
"effect": "^3.19.19",
|
|
38
38
|
"rxjs": "^7.8.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@midnightntwrk/wallet-sdk-hd": "^3.1.0-beta.
|
|
41
|
+
"@midnightntwrk/wallet-sdk-hd": "^3.1.0-beta.1",
|
|
42
42
|
"@midnightntwrk/wallet-sdk-utilities": "^1.2.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|