@midnight-ntwrk/wallet-sdk-dust-wallet 1.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/CoinsAndBalances.d.ts +19 -0
- package/dist/CoinsAndBalances.js +90 -0
- package/dist/DustCoreWallet.d.ts +31 -0
- package/dist/DustCoreWallet.js +108 -0
- package/dist/DustWallet.d.ts +52 -0
- package/dist/DustWallet.js +143 -0
- package/dist/Keys.d.ts +8 -0
- package/dist/Keys.js +11 -0
- package/dist/RunningV1Variant.d.ts +44 -0
- package/dist/RunningV1Variant.js +125 -0
- package/dist/Serialization.d.ts +9 -0
- package/dist/Serialization.js +76 -0
- package/dist/Simulator.d.ts +32 -0
- package/dist/Simulator.js +110 -0
- package/dist/Submission.d.ts +33 -0
- package/dist/Submission.js +69 -0
- package/dist/Sync.d.ts +58 -0
- package/dist/Sync.js +135 -0
- package/dist/Transacting.d.ts +50 -0
- package/dist/Transacting.js +195 -0
- package/dist/Utils.d.ts +14 -0
- package/dist/Utils.js +26 -0
- package/dist/V1Builder.d.ts +100 -0
- package/dist/V1Builder.js +181 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +21 -0
- package/dist/types/Dust.d.ts +30 -0
- package/dist/types/Dust.js +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +15 -0
- package/dist/types/ledger.d.ts +4 -0
- package/dist/types/ledger.js +1 -0
- package/dist/types/transaction.d.ts +4 -0
- package/dist/types/transaction.js +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DustCoreWallet } from './DustCoreWallet.js';
|
|
2
|
+
import { DustGenerationInfo, DustToken, DustTokenFullInfo } from './types/Dust.js';
|
|
3
|
+
export type Balance = bigint;
|
|
4
|
+
export type CoinWithValue<TToken> = {
|
|
5
|
+
token: TToken;
|
|
6
|
+
value: Balance;
|
|
7
|
+
};
|
|
8
|
+
export type CoinSelection<TInput> = (coins: readonly CoinWithValue<TInput>[], amountNeeded: Balance) => CoinWithValue<TInput>[];
|
|
9
|
+
export declare const chooseCoin: <TInput>(coins: readonly CoinWithValue<TInput>[], amountNeeded: Balance) => CoinWithValue<TInput>[];
|
|
10
|
+
export type CoinsAndBalancesCapability<TState> = {
|
|
11
|
+
getWalletBalance(state: TState, time: Date): Balance;
|
|
12
|
+
getAvailableCoins(state: TState): readonly DustToken[];
|
|
13
|
+
getPendingCoins(state: TState): readonly DustToken[];
|
|
14
|
+
getTotalCoins(state: TState): ReadonlyArray<DustToken>;
|
|
15
|
+
getAvailableCoinsWithGeneratedDust(state: TState, currentTime: Date): ReadonlyArray<CoinWithValue<DustToken>>;
|
|
16
|
+
getAvailableCoinsWithFullInfo(state: TState, blockTime: Date): readonly DustTokenFullInfo[];
|
|
17
|
+
getGenerationInfo(state: TState, token: DustToken): DustGenerationInfo | undefined;
|
|
18
|
+
};
|
|
19
|
+
export declare const makeDefaultCoinsAndBalancesCapability: () => CoinsAndBalancesCapability<DustCoreWallet>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// This file is part of MIDNIGHT-WALLET-SDK.
|
|
2
|
+
// Copyright (C) 2025 Midnight Foundation
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// You may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { Array, pipe } from 'effect';
|
|
14
|
+
import { updatedValue } from '@midnight-ntwrk/ledger-v6';
|
|
15
|
+
import { DateOps } from '@midnight-ntwrk/wallet-sdk-utilities';
|
|
16
|
+
export const chooseCoin = (coins, amountNeeded) => {
|
|
17
|
+
let sum = 0n;
|
|
18
|
+
const sorted = coins.toSorted((a, b) => Number(a.value - b.value));
|
|
19
|
+
const result = [];
|
|
20
|
+
for (const coin of sorted) {
|
|
21
|
+
sum += coin.value;
|
|
22
|
+
result.push(coin);
|
|
23
|
+
if (sum >= amountNeeded)
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
28
|
+
export const makeDefaultCoinsAndBalancesCapability = () => {
|
|
29
|
+
const getWalletBalance = (state, time) => {
|
|
30
|
+
return state.state.walletBalance(time);
|
|
31
|
+
};
|
|
32
|
+
const getAvailableCoins = (state) => {
|
|
33
|
+
const pendingSpends = new Set([...state.pendingDustTokens.values()].map((coin) => coin.nonce));
|
|
34
|
+
return pipe(state.state.utxos, Array.filter((coin) => !pendingSpends.has(coin.nonce)));
|
|
35
|
+
};
|
|
36
|
+
const getPendingCoins = (state) => state.pendingDustTokens;
|
|
37
|
+
const getTotalCoins = (state) => [
|
|
38
|
+
...getAvailableCoins(state),
|
|
39
|
+
...getPendingCoins(state),
|
|
40
|
+
];
|
|
41
|
+
const getGenerationInfo = (state, token) => {
|
|
42
|
+
const info = state.state.generationInfo(token);
|
|
43
|
+
return info && info.dtime
|
|
44
|
+
? {
|
|
45
|
+
...info,
|
|
46
|
+
dtime: new Date(+info.dtime), // TODO: remove when the ledger start to return a date instead of the number
|
|
47
|
+
}
|
|
48
|
+
: info;
|
|
49
|
+
};
|
|
50
|
+
const getAvailableCoinsWithGeneratedDust = (state, currentTime) => {
|
|
51
|
+
const result = [];
|
|
52
|
+
const available = getAvailableCoins(state);
|
|
53
|
+
for (const coin of available) {
|
|
54
|
+
const genInfo = getGenerationInfo(state, coin);
|
|
55
|
+
if (genInfo) {
|
|
56
|
+
const generatedValue = updatedValue(coin.ctime, coin.initialValue, genInfo, currentTime, state.state.params);
|
|
57
|
+
result.push({ token: coin, value: generatedValue });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
};
|
|
62
|
+
const getAvailableCoinsWithFullInfo = (state, blockTime) => {
|
|
63
|
+
const result = [];
|
|
64
|
+
const available = getAvailableCoins(state);
|
|
65
|
+
for (const coin of available) {
|
|
66
|
+
const genInfo = getGenerationInfo(state, coin);
|
|
67
|
+
if (genInfo) {
|
|
68
|
+
const generatedValue = updatedValue(coin.ctime, coin.initialValue, genInfo, blockTime, state.state.params);
|
|
69
|
+
result.push({
|
|
70
|
+
token: coin,
|
|
71
|
+
dtime: genInfo.dtime,
|
|
72
|
+
maxCap: genInfo.value * state.state.params.nightDustRatio,
|
|
73
|
+
maxCapReachedAt: DateOps.addSeconds(coin.ctime, state.state.params.timeToCapSeconds),
|
|
74
|
+
generatedNow: generatedValue,
|
|
75
|
+
rate: genInfo.value * state.state.params.generationDecayRate,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
getWalletBalance,
|
|
83
|
+
getAvailableCoins,
|
|
84
|
+
getPendingCoins,
|
|
85
|
+
getTotalCoins,
|
|
86
|
+
getAvailableCoinsWithGeneratedDust,
|
|
87
|
+
getAvailableCoinsWithFullInfo,
|
|
88
|
+
getGenerationInfo,
|
|
89
|
+
};
|
|
90
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Bindingish, DustLocalState, DustNullifier, DustParameters, DustPublicKey, DustSecretKey, Proofish, Signaturish, Transaction, Event } from '@midnight-ntwrk/ledger-v6';
|
|
2
|
+
import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
|
|
3
|
+
import { SyncProgress } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
|
|
4
|
+
import { DustToken, DustTokenWithNullifier } from './types/Dust.js';
|
|
5
|
+
import { CoinWithValue } from './CoinsAndBalances.js';
|
|
6
|
+
import { NetworkId, UnprovenDustSpend } from './types/ledger.js';
|
|
7
|
+
export type PublicKey = {
|
|
8
|
+
publicKey: DustPublicKey;
|
|
9
|
+
};
|
|
10
|
+
export declare const PublicKey: {
|
|
11
|
+
fromSecretKey: (secretKey: DustSecretKey) => PublicKey;
|
|
12
|
+
};
|
|
13
|
+
export declare class DustCoreWallet {
|
|
14
|
+
readonly state: DustLocalState;
|
|
15
|
+
readonly publicKey: PublicKey;
|
|
16
|
+
readonly protocolVersion: ProtocolVersion.ProtocolVersion;
|
|
17
|
+
readonly progress: SyncProgress.SyncProgress;
|
|
18
|
+
readonly networkId: NetworkId;
|
|
19
|
+
readonly pendingDustTokens: Array<DustTokenWithNullifier>;
|
|
20
|
+
constructor(state: DustLocalState, publicKey: PublicKey, networkId: NetworkId, pendingDustTokens?: Array<DustTokenWithNullifier>, syncProgress?: Omit<SyncProgress.SyncProgressData, 'isConnected'>, protocolVersion?: ProtocolVersion.ProtocolVersion);
|
|
21
|
+
static init(localState: DustLocalState, secretKey: DustSecretKey, networkId: NetworkId): DustCoreWallet;
|
|
22
|
+
static readonly initEmpty: (dustParameters: DustParameters, secretKey: DustSecretKey, networkId: NetworkId) => DustCoreWallet;
|
|
23
|
+
static empty(localState: DustLocalState, publicKey: PublicKey, networkId: NetworkId): DustCoreWallet;
|
|
24
|
+
static restore(localState: DustLocalState, publicKey: PublicKey, pendingTokens: Array<DustTokenWithNullifier>, syncProgress: SyncProgress.SyncProgressData, protocolVersion: bigint, networkId: NetworkId): DustCoreWallet;
|
|
25
|
+
applyEvents(secretKey: DustSecretKey, events: Event[], currentTime: Date): DustCoreWallet;
|
|
26
|
+
applyFailed(tx: Transaction<Signaturish, Proofish, Bindingish>): DustCoreWallet;
|
|
27
|
+
revertTransaction<TTransaction extends Transaction<Signaturish, Proofish, Bindingish>>(tx: TTransaction): DustCoreWallet;
|
|
28
|
+
updateProgress({ appliedIndex, highestRelevantWalletIndex, highestIndex, highestRelevantIndex, isConnected, }: Partial<SyncProgress.SyncProgressData>): DustCoreWallet;
|
|
29
|
+
spendCoins(secretKey: DustSecretKey, coins: ReadonlyArray<CoinWithValue<DustToken>>, currentTime: Date): [ReadonlyArray<UnprovenDustSpend>, DustCoreWallet];
|
|
30
|
+
static pendingDustTokensToMap(tokens: Array<DustTokenWithNullifier>): Map<DustNullifier, DustToken>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// This file is part of MIDNIGHT-WALLET-SDK.
|
|
2
|
+
// Copyright (C) 2025 Midnight Foundation
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// You may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { DustLocalState, } from '@midnight-ntwrk/ledger-v6';
|
|
14
|
+
import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
|
|
15
|
+
import { SyncProgress } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
|
|
16
|
+
import { DateOps } from '@midnight-ntwrk/wallet-sdk-utilities';
|
|
17
|
+
import { Array as Arr, pipe } from 'effect';
|
|
18
|
+
export const PublicKey = {
|
|
19
|
+
fromSecretKey: (secretKey) => {
|
|
20
|
+
return {
|
|
21
|
+
publicKey: secretKey.publicKey,
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export class DustCoreWallet {
|
|
26
|
+
state;
|
|
27
|
+
publicKey;
|
|
28
|
+
protocolVersion;
|
|
29
|
+
progress;
|
|
30
|
+
networkId;
|
|
31
|
+
pendingDustTokens;
|
|
32
|
+
constructor(state, publicKey, networkId, pendingDustTokens = [], syncProgress, protocolVersion = ProtocolVersion.MinSupportedVersion) {
|
|
33
|
+
this.state = state;
|
|
34
|
+
this.publicKey = publicKey;
|
|
35
|
+
this.networkId = networkId;
|
|
36
|
+
this.pendingDustTokens = pendingDustTokens;
|
|
37
|
+
this.protocolVersion = protocolVersion;
|
|
38
|
+
this.progress = syncProgress ? SyncProgress.createSyncProgress(syncProgress) : SyncProgress.createSyncProgress();
|
|
39
|
+
}
|
|
40
|
+
static init(localState, secretKey, networkId) {
|
|
41
|
+
return new DustCoreWallet(localState, PublicKey.fromSecretKey(secretKey), networkId);
|
|
42
|
+
}
|
|
43
|
+
static initEmpty = (dustParameters, secretKey, networkId) => {
|
|
44
|
+
return DustCoreWallet.empty(new DustLocalState(dustParameters), PublicKey.fromSecretKey(secretKey), networkId);
|
|
45
|
+
};
|
|
46
|
+
static empty(localState, publicKey, networkId) {
|
|
47
|
+
return new DustCoreWallet(localState, publicKey, networkId);
|
|
48
|
+
}
|
|
49
|
+
static restore(localState, publicKey, pendingTokens, syncProgress, protocolVersion, networkId) {
|
|
50
|
+
return new DustCoreWallet(localState, publicKey, networkId, pendingTokens, syncProgress, ProtocolVersion.ProtocolVersion(protocolVersion));
|
|
51
|
+
}
|
|
52
|
+
applyEvents(secretKey, events, currentTime) {
|
|
53
|
+
if (!events.length)
|
|
54
|
+
return this;
|
|
55
|
+
const updatedState = this.state.replayEvents(secretKey, events).processTtls(currentTime);
|
|
56
|
+
let updatedPending = this.pendingDustTokens;
|
|
57
|
+
if (updatedPending.length) {
|
|
58
|
+
const newAvailable = updatedState.utxos.map((utxo) => utxo.nonce);
|
|
59
|
+
updatedPending = updatedPending.filter((pendingToken) => newAvailable.includes(pendingToken.nonce));
|
|
60
|
+
}
|
|
61
|
+
return new DustCoreWallet(updatedState, this.publicKey, this.networkId, updatedPending, this.progress);
|
|
62
|
+
}
|
|
63
|
+
applyFailed(tx) {
|
|
64
|
+
const removedPending = [];
|
|
65
|
+
let updatedState = this.state;
|
|
66
|
+
if (tx.intents) {
|
|
67
|
+
const pendingTokensMap = DustCoreWallet.pendingDustTokensToMap(this.pendingDustTokens);
|
|
68
|
+
for (const intent of tx.intents.values()) {
|
|
69
|
+
if (intent.dustActions && intent.dustActions.spends) {
|
|
70
|
+
for (const spend of intent.dustActions.spends) {
|
|
71
|
+
const pending = pendingTokensMap.get(spend.oldNullifier);
|
|
72
|
+
if (pending === undefined)
|
|
73
|
+
continue;
|
|
74
|
+
removedPending.push(spend.oldNullifier);
|
|
75
|
+
updatedState = updatedState.processTtls(DateOps.addSeconds(pending.ctime, this.state.params.dustGracePeriodSeconds));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const pendingLeft = this.pendingDustTokens.filter((token) => !removedPending.includes(token.nullifier));
|
|
81
|
+
return new DustCoreWallet(updatedState, this.publicKey, this.networkId, pendingLeft, this.progress);
|
|
82
|
+
}
|
|
83
|
+
revertTransaction(tx) {
|
|
84
|
+
return this.applyFailed(tx);
|
|
85
|
+
}
|
|
86
|
+
updateProgress({ appliedIndex, highestRelevantWalletIndex, highestIndex, highestRelevantIndex, isConnected, }) {
|
|
87
|
+
const updatedProgress = SyncProgress.createSyncProgress({
|
|
88
|
+
appliedIndex: appliedIndex ?? this.progress.appliedIndex,
|
|
89
|
+
highestRelevantWalletIndex: highestRelevantWalletIndex ?? this.progress.highestRelevantWalletIndex,
|
|
90
|
+
highestIndex: highestIndex ?? this.progress.highestIndex,
|
|
91
|
+
highestRelevantIndex: highestRelevantIndex ?? this.progress.highestRelevantIndex,
|
|
92
|
+
isConnected: isConnected ?? this.progress.isConnected,
|
|
93
|
+
});
|
|
94
|
+
return new DustCoreWallet(this.state, this.publicKey, this.networkId, this.pendingDustTokens, updatedProgress);
|
|
95
|
+
}
|
|
96
|
+
spendCoins(secretKey, coins, currentTime) {
|
|
97
|
+
const [output, newState, newPending] = pipe(coins, Arr.reduce([[], this.state, this.pendingDustTokens], ([spends, localState], { token: coinToSpend, value: takeFee }) => {
|
|
98
|
+
const [newState, dustSpend] = localState.spend(secretKey, coinToSpend, takeFee, currentTime);
|
|
99
|
+
const newPending = [...this.pendingDustTokens, { ...coinToSpend, nullifier: dustSpend.oldNullifier }];
|
|
100
|
+
return [Arr.append(spends, dustSpend), newState, newPending];
|
|
101
|
+
}));
|
|
102
|
+
const updatedState = new DustCoreWallet(newState, this.publicKey, this.networkId, newPending, this.progress);
|
|
103
|
+
return [output, updatedState];
|
|
104
|
+
}
|
|
105
|
+
static pendingDustTokensToMap(tokens) {
|
|
106
|
+
return new Map(tokens.map(({ nullifier, ...token }) => [nullifier, token]));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { DustParameters, DustPublicKey, DustSecretKey, FinalizedTransaction, Signature, SignatureVerifyingKey, UnprovenTransaction } from '@midnight-ntwrk/ledger-v6';
|
|
2
|
+
import { ProtocolState, ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
|
|
3
|
+
import { Variant, WalletLike } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
|
|
4
|
+
import { ProvingRecipe, TransactionHistory } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
|
|
5
|
+
import * as rx from 'rxjs';
|
|
6
|
+
import { Balance, CoinsAndBalancesCapability } from './CoinsAndBalances.js';
|
|
7
|
+
import { DustCoreWallet } from './DustCoreWallet.js';
|
|
8
|
+
import { KeysCapability } from './Keys.js';
|
|
9
|
+
import { SerializationCapability } from './Serialization.js';
|
|
10
|
+
import { SubmitTransactionMethod } from './Submission.js';
|
|
11
|
+
import { DustToken, DustTokenFullInfo, UtxoWithMeta } from './types/Dust.js';
|
|
12
|
+
import { AnyTransaction } from './types/ledger.js';
|
|
13
|
+
import { DefaultV1Configuration, DefaultV1Variant } from './V1Builder.js';
|
|
14
|
+
export type DustWalletCapabilities = {
|
|
15
|
+
serialization: SerializationCapability<DustCoreWallet, null, string>;
|
|
16
|
+
coinsAndBalances: CoinsAndBalancesCapability<DustCoreWallet>;
|
|
17
|
+
keys: KeysCapability<DustCoreWallet>;
|
|
18
|
+
};
|
|
19
|
+
export declare class DustWalletState {
|
|
20
|
+
static readonly mapState: (capabilities: DustWalletCapabilities) => (state: ProtocolState.ProtocolState<DustCoreWallet>) => DustWalletState;
|
|
21
|
+
readonly protocolVersion: ProtocolVersion.ProtocolVersion;
|
|
22
|
+
readonly state: DustCoreWallet;
|
|
23
|
+
readonly capabilities: DustWalletCapabilities;
|
|
24
|
+
get totalCoins(): readonly DustToken[];
|
|
25
|
+
get availableCoins(): readonly DustToken[];
|
|
26
|
+
get pendingCoins(): readonly DustToken[];
|
|
27
|
+
get dustPublicKey(): DustPublicKey;
|
|
28
|
+
get dustAddress(): string;
|
|
29
|
+
get progress(): TransactionHistory.ProgressUpdate;
|
|
30
|
+
constructor(state: ProtocolState.ProtocolState<DustCoreWallet>, capabilities: DustWalletCapabilities);
|
|
31
|
+
walletBalance(time: Date): Balance;
|
|
32
|
+
availableCoinsWithFullInfo(time: Date): readonly DustTokenFullInfo[];
|
|
33
|
+
serialize(): string;
|
|
34
|
+
}
|
|
35
|
+
export interface DustWallet extends WalletLike.WalletLike<[Variant.VersionedVariant<DefaultV1Variant>]> {
|
|
36
|
+
readonly state: rx.Observable<DustWalletState>;
|
|
37
|
+
start(secretKey: DustSecretKey): Promise<void>;
|
|
38
|
+
createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: Array<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Promise<UnprovenTransaction>;
|
|
39
|
+
addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Promise<ProvingRecipe.ProvingRecipe<FinalizedTransaction>>;
|
|
40
|
+
calculateFee(transaction: AnyTransaction): Promise<bigint>;
|
|
41
|
+
addFeePayment(secretKey: DustSecretKey, transaction: UnprovenTransaction, currentTime: Date, ttl: Date): Promise<ProvingRecipe.ProvingRecipe<FinalizedTransaction>>;
|
|
42
|
+
finalizeTransaction(recipe: ProvingRecipe.ProvingRecipe<FinalizedTransaction>): Promise<FinalizedTransaction>;
|
|
43
|
+
readonly submitTransaction: SubmitTransactionMethod<FinalizedTransaction>;
|
|
44
|
+
serializeState(): Promise<string>;
|
|
45
|
+
waitForSyncedState(allowedGap?: bigint): Promise<DustWalletState>;
|
|
46
|
+
}
|
|
47
|
+
export interface DustWalletClass extends WalletLike.BaseWalletClass<[Variant.VersionedVariant<DefaultV1Variant>]> {
|
|
48
|
+
startWithSeed(seed: Uint8Array, dustParameters: DustParameters): DustWallet;
|
|
49
|
+
startWithSecretKey(secretKey: DustSecretKey, dustParameters: DustParameters): DustWallet;
|
|
50
|
+
restore(serializedState: string): DustWallet;
|
|
51
|
+
}
|
|
52
|
+
export declare function DustWallet(configuration: DefaultV1Configuration): DustWalletClass;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// This file is part of MIDNIGHT-WALLET-SDK.
|
|
2
|
+
// Copyright (C) 2025 Midnight Foundation
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// You may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { DustSecretKey, } from '@midnight-ntwrk/ledger-v6';
|
|
14
|
+
import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
|
|
15
|
+
import { DustAddress } from '@midnight-ntwrk/wallet-sdk-address-format';
|
|
16
|
+
import { WalletBuilder } from '@midnight-ntwrk/wallet-sdk-runtime';
|
|
17
|
+
import { Effect, Either } from 'effect';
|
|
18
|
+
import * as rx from 'rxjs';
|
|
19
|
+
import { DustCoreWallet } from './DustCoreWallet.js';
|
|
20
|
+
import { V1Tag } from './RunningV1Variant.js';
|
|
21
|
+
import { V1Builder } from './V1Builder.js';
|
|
22
|
+
export class DustWalletState {
|
|
23
|
+
static mapState = (capabilities) => (state) => {
|
|
24
|
+
return new DustWalletState(state, capabilities);
|
|
25
|
+
};
|
|
26
|
+
protocolVersion;
|
|
27
|
+
state;
|
|
28
|
+
capabilities;
|
|
29
|
+
get totalCoins() {
|
|
30
|
+
return this.capabilities.coinsAndBalances.getTotalCoins(this.state);
|
|
31
|
+
}
|
|
32
|
+
get availableCoins() {
|
|
33
|
+
return this.capabilities.coinsAndBalances.getAvailableCoins(this.state);
|
|
34
|
+
}
|
|
35
|
+
get pendingCoins() {
|
|
36
|
+
return this.capabilities.coinsAndBalances.getPendingCoins(this.state);
|
|
37
|
+
}
|
|
38
|
+
get dustPublicKey() {
|
|
39
|
+
return this.capabilities.keys.getDustPublicKey(this.state);
|
|
40
|
+
}
|
|
41
|
+
get dustAddress() {
|
|
42
|
+
return DustAddress.encodePublicKey(this.state.networkId, this.dustPublicKey);
|
|
43
|
+
}
|
|
44
|
+
get progress() {
|
|
45
|
+
return {
|
|
46
|
+
appliedIndex: this.state.progress.appliedIndex,
|
|
47
|
+
highestRelevantWalletIndex: this.state.progress.highestRelevantWalletIndex,
|
|
48
|
+
highestIndex: this.state.progress.highestIndex,
|
|
49
|
+
highestRelevantIndex: this.state.progress.highestRelevantIndex,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
constructor(state, capabilities) {
|
|
53
|
+
this.protocolVersion = state.version;
|
|
54
|
+
this.state = state.state;
|
|
55
|
+
this.capabilities = capabilities;
|
|
56
|
+
}
|
|
57
|
+
walletBalance(time) {
|
|
58
|
+
return this.capabilities.coinsAndBalances.getWalletBalance(this.state, time);
|
|
59
|
+
}
|
|
60
|
+
availableCoinsWithFullInfo(time) {
|
|
61
|
+
return this.capabilities.coinsAndBalances.getAvailableCoinsWithFullInfo(this.state, time);
|
|
62
|
+
}
|
|
63
|
+
serialize() {
|
|
64
|
+
return this.capabilities.serialization.serialize(this.state);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function DustWallet(configuration) {
|
|
68
|
+
const BaseWallet = WalletBuilder.init()
|
|
69
|
+
.withVariant(ProtocolVersion.MinSupportedVersion, new V1Builder().withDefaults())
|
|
70
|
+
.build(configuration);
|
|
71
|
+
return class DustWalletImplementation extends BaseWallet {
|
|
72
|
+
static startWithSeed(seed, dustParameters) {
|
|
73
|
+
const dustSecretKey = DustSecretKey.fromSeed(seed);
|
|
74
|
+
return DustWalletImplementation.startFirst(DustWalletImplementation, DustCoreWallet.initEmpty(dustParameters, dustSecretKey, configuration.networkId));
|
|
75
|
+
}
|
|
76
|
+
static startWithSecretKey(secretKey, dustParameters) {
|
|
77
|
+
return DustWalletImplementation.startFirst(DustWalletImplementation, DustCoreWallet.initEmpty(dustParameters, secretKey, configuration.networkId));
|
|
78
|
+
}
|
|
79
|
+
static restore(serializedState) {
|
|
80
|
+
const deserialized = DustWalletImplementation.allVariantsRecord()[V1Tag].variant.deserializeState(serializedState)
|
|
81
|
+
.pipe(Either.getOrThrow);
|
|
82
|
+
return DustWalletImplementation.startFirst(DustWalletImplementation, deserialized);
|
|
83
|
+
}
|
|
84
|
+
state;
|
|
85
|
+
constructor(runtime, scope) {
|
|
86
|
+
super(runtime, scope);
|
|
87
|
+
this.state = this.rawState.pipe(rx.map(DustWalletState.mapState(DustWalletImplementation.allVariantsRecord()[V1Tag].variant)), rx.shareReplay({ refCount: true, bufferSize: 1 }));
|
|
88
|
+
}
|
|
89
|
+
start(secretKey) {
|
|
90
|
+
return this.runtime.dispatch({ [V1Tag]: (v1) => v1.startSyncInBackground(secretKey) }).pipe(Effect.runPromise);
|
|
91
|
+
}
|
|
92
|
+
createDustGenerationTransaction(currentTime, ttl, nightUtxos, nightVerifyingKey, dustReceiverAddress) {
|
|
93
|
+
return this.runtime
|
|
94
|
+
.dispatch({
|
|
95
|
+
[V1Tag]: (v1) => v1.createDustGenerationTransaction(currentTime, ttl, nightUtxos, nightVerifyingKey, dustReceiverAddress),
|
|
96
|
+
})
|
|
97
|
+
.pipe(Effect.runPromise);
|
|
98
|
+
}
|
|
99
|
+
addDustGenerationSignature(transaction, signature) {
|
|
100
|
+
return this.runtime
|
|
101
|
+
.dispatch({
|
|
102
|
+
[V1Tag]: (v1) => v1.addDustGenerationSignature(transaction, signature),
|
|
103
|
+
})
|
|
104
|
+
.pipe(Effect.runPromise);
|
|
105
|
+
}
|
|
106
|
+
calculateFee(transaction) {
|
|
107
|
+
return this.runtime
|
|
108
|
+
.dispatch({
|
|
109
|
+
[V1Tag]: (v1) => v1.calculateFee(transaction),
|
|
110
|
+
})
|
|
111
|
+
.pipe(Effect.runPromise);
|
|
112
|
+
}
|
|
113
|
+
addFeePayment(secretKey, transaction, currentTime, ttl) {
|
|
114
|
+
return this.runtime
|
|
115
|
+
.dispatch({
|
|
116
|
+
[V1Tag]: (v1) => v1.addFeePayment(secretKey, transaction, currentTime, ttl),
|
|
117
|
+
})
|
|
118
|
+
.pipe(Effect.runPromise);
|
|
119
|
+
}
|
|
120
|
+
finalizeTransaction(recipe) {
|
|
121
|
+
return this.runtime
|
|
122
|
+
.dispatch({
|
|
123
|
+
[V1Tag]: (v1) => v1.finalizeTransaction(recipe),
|
|
124
|
+
})
|
|
125
|
+
.pipe(Effect.runPromise);
|
|
126
|
+
}
|
|
127
|
+
submitTransaction = ((tx, waitForStatus = 'InBlock') => {
|
|
128
|
+
return this.runtime
|
|
129
|
+
.dispatch({ [V1Tag]: (v1) => v1.submitTransaction(tx, waitForStatus) })
|
|
130
|
+
.pipe(Effect.runPromise);
|
|
131
|
+
});
|
|
132
|
+
waitForSyncedState(allowedGap = 0n) {
|
|
133
|
+
return rx.firstValueFrom(this.state.pipe(rx.filter((state) => state.state.progress.isCompleteWithin(allowedGap))));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Serializes the most recent state
|
|
137
|
+
* It's preferable to use [[DustWalletState.serialize]] instead, to know exactly, which state is serialized
|
|
138
|
+
*/
|
|
139
|
+
serializeState() {
|
|
140
|
+
return rx.firstValueFrom(this.state).then((state) => state.serialize());
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
package/dist/Keys.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DustPublicKey } from '@midnight-ntwrk/ledger-v6';
|
|
2
|
+
import { DustAddress } from '@midnight-ntwrk/wallet-sdk-address-format';
|
|
3
|
+
import { DustCoreWallet } from './DustCoreWallet.js';
|
|
4
|
+
export type KeysCapability<TState> = {
|
|
5
|
+
getDustPublicKey(state: TState): DustPublicKey;
|
|
6
|
+
getDustAddress(state: TState): DustAddress;
|
|
7
|
+
};
|
|
8
|
+
export declare const makeDefaultKeysCapability: () => KeysCapability<DustCoreWallet>;
|
package/dist/Keys.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DustAddress } from '@midnight-ntwrk/wallet-sdk-address-format';
|
|
2
|
+
export const makeDefaultKeysCapability = () => {
|
|
3
|
+
return {
|
|
4
|
+
getDustPublicKey: (state) => {
|
|
5
|
+
return state.publicKey.publicKey;
|
|
6
|
+
},
|
|
7
|
+
getDustAddress: (state) => {
|
|
8
|
+
return new DustAddress(state.publicKey.publicKey);
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Effect, Stream, Scope } from 'effect';
|
|
2
|
+
import { DustSecretKey, Signature, SignatureVerifyingKey, FinalizedTransaction, UnprovenTransaction } from '@midnight-ntwrk/ledger-v6';
|
|
3
|
+
import { Proving, ProvingRecipe, WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
|
|
4
|
+
import { WalletRuntimeError, Variant, StateChange } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
|
|
5
|
+
import { DustToken, UtxoWithMeta } from './types/Dust.js';
|
|
6
|
+
import { KeysCapability } from './Keys.js';
|
|
7
|
+
import { SyncCapability, SyncService } from './Sync.js';
|
|
8
|
+
import { SimulatorState } from './Simulator.js';
|
|
9
|
+
import { CoinsAndBalancesCapability, CoinSelection } from './CoinsAndBalances.js';
|
|
10
|
+
import { TransactingCapability } from './Transacting.js';
|
|
11
|
+
import { SubmissionService, SubmitTransactionMethod } from './Submission.js';
|
|
12
|
+
import { DustCoreWallet } from './DustCoreWallet.js';
|
|
13
|
+
import { SerializationCapability } from './Serialization.js';
|
|
14
|
+
import { AnyTransaction } from './types/ledger.js';
|
|
15
|
+
export declare namespace RunningV1Variant {
|
|
16
|
+
type Context<TSerialized, TSyncUpdate, TTransaction, TStartAux> = {
|
|
17
|
+
serializationCapability: SerializationCapability<DustCoreWallet, null, TSerialized>;
|
|
18
|
+
syncService: SyncService<DustCoreWallet, TStartAux, TSyncUpdate>;
|
|
19
|
+
syncCapability: SyncCapability<DustCoreWallet, TSyncUpdate>;
|
|
20
|
+
transactingCapability: TransactingCapability<DustSecretKey, DustCoreWallet, TTransaction>;
|
|
21
|
+
provingService: Proving.ProvingService<TTransaction>;
|
|
22
|
+
coinsAndBalancesCapability: CoinsAndBalancesCapability<DustCoreWallet>;
|
|
23
|
+
keysCapability: KeysCapability<DustCoreWallet>;
|
|
24
|
+
submissionService: SubmissionService<TTransaction>;
|
|
25
|
+
coinSelection: CoinSelection<DustToken>;
|
|
26
|
+
};
|
|
27
|
+
type AnyContext = Context<any, any, any, any>;
|
|
28
|
+
}
|
|
29
|
+
export declare const V1Tag: unique symbol;
|
|
30
|
+
export type DefaultRunningV1 = RunningV1Variant<string, SimulatorState, FinalizedTransaction, DustSecretKey>;
|
|
31
|
+
export declare class RunningV1Variant<TSerialized, TSyncUpdate, TTransaction, TStartAux> implements Variant.RunningVariant<typeof V1Tag, DustCoreWallet> {
|
|
32
|
+
#private;
|
|
33
|
+
__polyTag__: typeof V1Tag;
|
|
34
|
+
readonly state: Stream.Stream<StateChange.StateChange<DustCoreWallet>, WalletRuntimeError>;
|
|
35
|
+
constructor(scope: Scope.Scope, context: Variant.VariantContext<DustCoreWallet>, v1Context: RunningV1Variant.Context<TSerialized, TSyncUpdate, TTransaction, TStartAux>);
|
|
36
|
+
startSyncInBackground(startAux: TStartAux): Effect.Effect<void>;
|
|
37
|
+
startSync(startAux: TStartAux): Stream.Stream<void, WalletError.WalletError, Scope.Scope>;
|
|
38
|
+
createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Effect.Effect<UnprovenTransaction, WalletError.WalletError>;
|
|
39
|
+
addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Effect.Effect<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
|
|
40
|
+
calculateFee(transaction: AnyTransaction): Effect.Effect<bigint, WalletError.WalletError>;
|
|
41
|
+
addFeePayment(secretKey: DustSecretKey, transaction: UnprovenTransaction, currentTime: Date, ttl: Date): Effect.Effect<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
|
|
42
|
+
finalizeTransaction(recipe: ProvingRecipe.ProvingRecipe<TTransaction>): Effect.Effect<TTransaction, WalletError.WalletError>;
|
|
43
|
+
submitTransaction: SubmitTransactionMethod<TTransaction>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// This file is part of MIDNIGHT-WALLET-SDK.
|
|
2
|
+
// Copyright (C) 2025 Midnight Foundation
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// You may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { Effect, SubscriptionRef, Stream, pipe, Scope, Sink, Console, Duration, Schedule } from 'effect';
|
|
14
|
+
import { nativeToken, updatedValue, } from '@midnight-ntwrk/ledger-v6';
|
|
15
|
+
import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
|
|
16
|
+
import { WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
|
|
17
|
+
import { EitherOps, LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
|
|
18
|
+
import { StateChange, VersionChangeType, } from '@midnight-ntwrk/wallet-sdk-runtime/abstractions';
|
|
19
|
+
const progress = (state) => {
|
|
20
|
+
const appliedIndex = state.progress?.appliedIndex ?? 0n;
|
|
21
|
+
const highestRelevantWalletIndex = state.progress?.highestRelevantWalletIndex ?? 0n;
|
|
22
|
+
const highestIndex = state.progress?.highestIndex ?? 0n;
|
|
23
|
+
const highestRelevantIndex = state.progress?.highestRelevantIndex ?? 0n;
|
|
24
|
+
const sourceGap = highestIndex - highestRelevantIndex;
|
|
25
|
+
const applyGap = highestRelevantWalletIndex - appliedIndex;
|
|
26
|
+
return [StateChange.ProgressUpdate({ sourceGap, applyGap })];
|
|
27
|
+
};
|
|
28
|
+
const protocolVersionChange = (previous, current) => {
|
|
29
|
+
return previous.protocolVersion != current.protocolVersion
|
|
30
|
+
? [
|
|
31
|
+
StateChange.VersionChange({
|
|
32
|
+
change: VersionChangeType.Version({
|
|
33
|
+
version: ProtocolVersion.ProtocolVersion(current.protocolVersion),
|
|
34
|
+
}),
|
|
35
|
+
}),
|
|
36
|
+
]
|
|
37
|
+
: [];
|
|
38
|
+
};
|
|
39
|
+
export const V1Tag = Symbol('V1');
|
|
40
|
+
export class RunningV1Variant {
|
|
41
|
+
__polyTag__ = V1Tag;
|
|
42
|
+
#scope;
|
|
43
|
+
#context;
|
|
44
|
+
#v1Context;
|
|
45
|
+
state;
|
|
46
|
+
constructor(scope, context, v1Context) {
|
|
47
|
+
this.#scope = scope;
|
|
48
|
+
this.#context = context;
|
|
49
|
+
this.#v1Context = v1Context;
|
|
50
|
+
this.state = Stream.fromEffect(context.stateRef.get).pipe(Stream.flatMap((initialState) => context.stateRef.changes.pipe(Stream.mapAccum(initialState, (previous, current) => {
|
|
51
|
+
return [current, [previous, current]];
|
|
52
|
+
}))), Stream.mapConcat(([previous, current]) => {
|
|
53
|
+
// TODO: emit progress only upon actual change
|
|
54
|
+
return [
|
|
55
|
+
StateChange.State({ state: current }),
|
|
56
|
+
...progress(current),
|
|
57
|
+
...protocolVersionChange(previous, current),
|
|
58
|
+
];
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
startSyncInBackground(startAux) {
|
|
62
|
+
return this.startSync(startAux).pipe(Stream.runScoped(Sink.drain), Effect.forkScoped, Effect.provideService(Scope.Scope, this.#scope));
|
|
63
|
+
}
|
|
64
|
+
startSync(startAux) {
|
|
65
|
+
return pipe(SubscriptionRef.get(this.#context.stateRef), Stream.fromEffect, Stream.flatMap((state) => this.#v1Context.syncService.updates(state, startAux)), Stream.mapEffect((update) => {
|
|
66
|
+
return SubscriptionRef.updateEffect(this.#context.stateRef, (state) => Effect.try({
|
|
67
|
+
try: () => this.#v1Context.syncCapability.applyUpdate(state, update),
|
|
68
|
+
catch: (err) => new WalletError.OtherWalletError({
|
|
69
|
+
message: 'Error while applying sync update',
|
|
70
|
+
cause: err,
|
|
71
|
+
}),
|
|
72
|
+
}));
|
|
73
|
+
}), Stream.tapError((error) => Console.error(error)), Stream.retry(pipe(Schedule.exponential(Duration.seconds(1), 2), Schedule.map((delay) => {
|
|
74
|
+
const maxDelay = Duration.minutes(2);
|
|
75
|
+
const jitter = Duration.millis(Math.floor(Math.random() * 1000));
|
|
76
|
+
const delayWithJitter = Duration.toMillis(delay) + Duration.toMillis(jitter);
|
|
77
|
+
return Duration.millis(Math.min(delayWithJitter, Duration.toMillis(maxDelay)));
|
|
78
|
+
}))));
|
|
79
|
+
}
|
|
80
|
+
createDustGenerationTransaction(currentTime, ttl, nightUtxos, nightVerifyingKey, dustReceiverAddress) {
|
|
81
|
+
if (nightUtxos.some((utxo) => utxo.type !== nativeToken().raw)) {
|
|
82
|
+
return Effect.fail(WalletError.WalletError.other('Token of a non-Night type received'));
|
|
83
|
+
}
|
|
84
|
+
return Effect.Do.pipe(Effect.bind('currentState', () => SubscriptionRef.get(this.#context.stateRef)), Effect.bind('utxosWithDustValue', ({ currentState }) => LedgerOps.ledgerTry(() => {
|
|
85
|
+
const dustPublicKey = this.#v1Context.keysCapability.getDustPublicKey(currentState);
|
|
86
|
+
return nightUtxos.map((utxo) => {
|
|
87
|
+
const genInfo = {
|
|
88
|
+
value: utxo.value,
|
|
89
|
+
owner: dustPublicKey,
|
|
90
|
+
nonce: LedgerOps.randomNonce(),
|
|
91
|
+
dtime: undefined,
|
|
92
|
+
};
|
|
93
|
+
const dustValue = updatedValue(utxo.ctime, 0n, genInfo, currentTime, currentState.state.params);
|
|
94
|
+
return { token: utxo, value: dustValue };
|
|
95
|
+
});
|
|
96
|
+
})), Effect.flatMap(({ utxosWithDustValue }) => {
|
|
97
|
+
return this.#v1Context.transactingCapability
|
|
98
|
+
.createDustGenerationTransaction(currentTime, ttl, utxosWithDustValue, nightVerifyingKey, dustReceiverAddress)
|
|
99
|
+
.pipe(EitherOps.toEffect);
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
addDustGenerationSignature(transaction, signature) {
|
|
103
|
+
return this.#v1Context.transactingCapability
|
|
104
|
+
.addDustGenerationSignature(transaction, signature)
|
|
105
|
+
.pipe(EitherOps.toEffect);
|
|
106
|
+
}
|
|
107
|
+
calculateFee(transaction) {
|
|
108
|
+
return pipe(this.#v1Context.syncService.ledgerParameters(), Effect.map((params) => this.#v1Context.transactingCapability.calculateFee(transaction, params)));
|
|
109
|
+
}
|
|
110
|
+
addFeePayment(secretKey, transaction, currentTime, ttl) {
|
|
111
|
+
return SubscriptionRef.modifyEffect(this.#context.stateRef, (state) => {
|
|
112
|
+
return pipe(this.#v1Context.syncService.ledgerParameters(), Effect.flatMap((params) => this.#v1Context.transactingCapability.addFeePayment(secretKey, state, transaction, currentTime, ttl, params)), Effect.map(({ recipe, newState }) => [recipe, newState]));
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
finalizeTransaction(recipe) {
|
|
116
|
+
return this.#v1Context.provingService
|
|
117
|
+
.prove(recipe)
|
|
118
|
+
.pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revertRecipe(state, recipe)))));
|
|
119
|
+
}
|
|
120
|
+
submitTransaction = ((transaction, waitForStatus = 'InBlock') => {
|
|
121
|
+
return this.#v1Context.submissionService
|
|
122
|
+
.submitTransaction(transaction, waitForStatus)
|
|
123
|
+
.pipe(Effect.tapError(() => SubscriptionRef.updateEffect(this.#context.stateRef, (state) => EitherOps.toEffect(this.#v1Context.transactingCapability.revert(state, transaction)))));
|
|
124
|
+
});
|
|
125
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Either, Schema } from 'effect';
|
|
2
|
+
import { WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
|
|
3
|
+
import { DustCoreWallet } from './DustCoreWallet.js';
|
|
4
|
+
export type SerializationCapability<TWallet, TAux, TSerialized> = {
|
|
5
|
+
serialize(wallet: TWallet): TSerialized;
|
|
6
|
+
deserialize(aux: TAux, data: TSerialized): Either.Either<TWallet, WalletError.WalletError>;
|
|
7
|
+
};
|
|
8
|
+
export declare const Uint8ArraySchema: Schema.declare<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, readonly [], never>;
|
|
9
|
+
export declare const makeDefaultV1SerializationCapability: () => SerializationCapability<DustCoreWallet, null, string>;
|