@midnight-ntwrk/wallet-sdk-dust-wallet 1.0.0-beta.10 → 1.0.0-beta.11

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.
@@ -52,6 +52,7 @@ export class DustCoreWallet {
52
52
  applyEvents(secretKey, events, currentTime) {
53
53
  if (!events.length)
54
54
  return this;
55
+ // TODO: replace currentTime with `updatedState.syncTime` introduced in ledger-6.2.0-rc.1
55
56
  const updatedState = this.state.replayEvents(secretKey, events).processTtls(currentTime);
56
57
  let updatedPending = this.pendingDustTokens;
57
58
  if (updatedPending.length) {
@@ -35,10 +35,10 @@ export declare class DustWalletState {
35
35
  export interface DustWallet extends WalletLike.WalletLike<[Variant.VersionedVariant<DefaultV1Variant>]> {
36
36
  readonly state: rx.Observable<DustWalletState>;
37
37
  start(secretKey: DustSecretKey): Promise<void>;
38
- createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: Array<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Promise<UnprovenTransaction>;
38
+ createDustGenerationTransaction(currentTime: Date | undefined, ttl: Date, nightUtxos: Array<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Promise<UnprovenTransaction>;
39
39
  addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Promise<ProvingRecipe.ProvingRecipe<FinalizedTransaction>>;
40
40
  calculateFee(transaction: AnyTransaction): Promise<bigint>;
41
- addFeePayment(secretKey: DustSecretKey, transaction: UnprovenTransaction, currentTime: Date, ttl: Date): Promise<ProvingRecipe.ProvingRecipe<FinalizedTransaction>>;
41
+ addFeePayment(secretKey: DustSecretKey, transaction: UnprovenTransaction, ttl: Date, currentTime?: Date): Promise<ProvingRecipe.ProvingRecipe<FinalizedTransaction>>;
42
42
  finalizeTransaction(recipe: ProvingRecipe.ProvingRecipe<FinalizedTransaction>): Promise<FinalizedTransaction>;
43
43
  readonly submitTransaction: SubmitTransactionMethod<FinalizedTransaction>;
44
44
  serializeState(): Promise<string>;
@@ -110,10 +110,10 @@ export function DustWallet(configuration) {
110
110
  })
111
111
  .pipe(Effect.runPromise);
112
112
  }
113
- addFeePayment(secretKey, transaction, currentTime, ttl) {
113
+ addFeePayment(secretKey, transaction, ttl, currentTime) {
114
114
  return this.runtime
115
115
  .dispatch({
116
- [V1Tag]: (v1) => v1.addFeePayment(secretKey, transaction, currentTime, ttl),
116
+ [V1Tag]: (v1) => v1.addFeePayment(secretKey, transaction, ttl, currentTime),
117
117
  })
118
118
  .pipe(Effect.runPromise);
119
119
  }
@@ -35,10 +35,10 @@ export declare class RunningV1Variant<TSerialized, TSyncUpdate, TTransaction, TS
35
35
  constructor(scope: Scope.Scope, context: Variant.VariantContext<DustCoreWallet>, v1Context: RunningV1Variant.Context<TSerialized, TSyncUpdate, TTransaction, TStartAux>);
36
36
  startSyncInBackground(startAux: TStartAux): Effect.Effect<void>;
37
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>;
38
+ createDustGenerationTransaction(currentTime: Date | undefined, ttl: Date, nightUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Effect.Effect<UnprovenTransaction, WalletError.WalletError>;
39
39
  addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Effect.Effect<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
40
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>;
41
+ addFeePayment(secretKey: DustSecretKey, transaction: UnprovenTransaction, ttl: Date, currentTime?: Date): Effect.Effect<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
42
42
  finalizeTransaction(recipe: ProvingRecipe.ProvingRecipe<TTransaction>): Effect.Effect<TTransaction, WalletError.WalletError>;
43
43
  submitTransaction: SubmitTransactionMethod<TTransaction>;
44
44
  }
@@ -81,7 +81,7 @@ export class RunningV1Variant {
81
81
  if (nightUtxos.some((utxo) => utxo.type !== nativeToken().raw)) {
82
82
  return Effect.fail(WalletError.WalletError.other('Token of a non-Night type received'));
83
83
  }
84
- return Effect.Do.pipe(Effect.bind('currentState', () => SubscriptionRef.get(this.#context.stateRef)), Effect.bind('utxosWithDustValue', ({ currentState }) => LedgerOps.ledgerTry(() => {
84
+ return Effect.Do.pipe(Effect.bind('currentState', () => SubscriptionRef.get(this.#context.stateRef)), Effect.bind('blockData', () => this.#v1Context.syncService.blockData()), Effect.bind('utxosWithDustValue', ({ currentState, blockData }) => LedgerOps.ledgerTry(() => {
85
85
  const dustPublicKey = this.#v1Context.keysCapability.getDustPublicKey(currentState);
86
86
  return nightUtxos.map((utxo) => {
87
87
  const genInfo = {
@@ -90,12 +90,12 @@ export class RunningV1Variant {
90
90
  nonce: LedgerOps.randomNonce(),
91
91
  dtime: undefined,
92
92
  };
93
- const dustValue = updatedValue(utxo.ctime, 0n, genInfo, currentTime, currentState.state.params);
93
+ const dustValue = updatedValue(utxo.ctime, 0n, genInfo, currentTime ?? blockData.timestamp, currentState.state.params);
94
94
  return { token: utxo, value: dustValue };
95
95
  });
96
- })), Effect.flatMap(({ utxosWithDustValue }) => {
96
+ })), Effect.flatMap(({ utxosWithDustValue, blockData }) => {
97
97
  return this.#v1Context.transactingCapability
98
- .createDustGenerationTransaction(currentTime, ttl, utxosWithDustValue, nightVerifyingKey, dustReceiverAddress)
98
+ .createDustGenerationTransaction(currentTime ?? blockData.timestamp, ttl, utxosWithDustValue, nightVerifyingKey, dustReceiverAddress)
99
99
  .pipe(EitherOps.toEffect);
100
100
  }));
101
101
  }
@@ -105,11 +105,11 @@ export class RunningV1Variant {
105
105
  .pipe(EitherOps.toEffect);
106
106
  }
107
107
  calculateFee(transaction) {
108
- return pipe(this.#v1Context.syncService.ledgerParameters(), Effect.map((params) => this.#v1Context.transactingCapability.calculateFee(transaction, params)));
108
+ return pipe(this.#v1Context.syncService.blockData(), Effect.map((blockData) => this.#v1Context.transactingCapability.calculateFee(transaction, blockData.ledgerParameters)));
109
109
  }
110
- addFeePayment(secretKey, transaction, currentTime, ttl) {
110
+ addFeePayment(secretKey, transaction, ttl, currentTime) {
111
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]));
112
+ return pipe(this.#v1Context.syncService.blockData(), Effect.flatMap((blockData) => this.#v1Context.transactingCapability.addFeePayment(secretKey, state, transaction, ttl, currentTime ?? blockData.timestamp, blockData.ledgerParameters)), Effect.map(({ recipe, newState }) => [recipe, newState]));
113
113
  });
114
114
  }
115
115
  finalizeTransaction(recipe) {
@@ -11,6 +11,7 @@ export type SimulatorState = Readonly<{
11
11
  }>;
12
12
  export declare class Simulator {
13
13
  #private;
14
+ static blockHash: (blockTime: Date) => Effect.Effect<string>;
14
15
  static nextBlockContext: (blockTime: Date) => Effect.Effect<BlockContext>;
15
16
  static init(networkId: NetworkId): Effect.Effect<Simulator, never, Scope.Scope>;
16
17
  static apply(simulatorState: SimulatorState, tx: ProofErasedTransaction, strictness: WellFormedStrictness, blockContext: BlockContext, blockFullness?: SyntheticCost): Either.Either<[{
package/dist/Simulator.js CHANGED
@@ -18,7 +18,8 @@ const simpleHash = (input) => {
18
18
  return Encoding.decodeHex(input).pipe(EitherOps.toEffect, Effect.andThen((parsed) => Effect.promise(() => crypto.subtle.digest('SHA-256', parsed))), Effect.andThen((out) => Encoding.encodeHex(new Uint8Array(out))), Effect.orDie);
19
19
  };
20
20
  export class Simulator {
21
- static nextBlockContext = (blockTime) => pipe(DateOps.dateToSeconds(blockTime).toString(16), (str) => (str.length % 2 == 0 ? str : str.padStart(str.length + 1, '0')), simpleHash, Effect.map((hash) => ({
21
+ static blockHash = (blockTime) => pipe(DateOps.dateToSeconds(blockTime).toString(16), (str) => (str.length % 2 == 0 ? str : str.padStart(str.length + 1, '0')), simpleHash);
22
+ static nextBlockContext = (blockTime) => pipe(Simulator.blockHash(blockTime), Effect.map((hash) => ({
22
23
  parentBlockHash: hash,
23
24
  secondsSinceEpoch: DateOps.dateToSeconds(blockTime),
24
25
  secondsSinceEpochErr: 1,
package/dist/Sync.d.ts CHANGED
@@ -7,7 +7,13 @@ import { DustCoreWallet } from './DustCoreWallet.js';
7
7
  import { NetworkId } from './types/ledger.js';
8
8
  export interface SyncService<TState, TStartAux, TUpdate> {
9
9
  updates: (state: TState, auxData: TStartAux) => Stream.Stream<TUpdate, WalletError.WalletError, Scope.Scope>;
10
- ledgerParameters: () => Effect.Effect<LedgerParameters, WalletError.WalletError>;
10
+ blockData: () => Effect.Effect<BlockData, WalletError.WalletError>;
11
+ }
12
+ export interface BlockData {
13
+ hash: string;
14
+ height: number;
15
+ ledgerParameters: LedgerParameters;
16
+ timestamp: Date;
11
17
  }
12
18
  export interface SyncCapability<TState, TUpdate> {
13
19
  applyUpdate: (state: TState, update: TUpdate) => TState;
package/dist/Sync.js CHANGED
@@ -17,6 +17,7 @@ import { WsSubscriptionClient, HttpQueryClient, ConnectionHelper, } from '@midni
17
17
  import { DateOps, EitherOps, LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
18
18
  import { WsURL } from '@midnight-ntwrk/wallet-sdk-utilities/networking';
19
19
  import { WalletError } from '@midnight-ntwrk/wallet-sdk-shielded/v1';
20
+ import { Simulator } from './Simulator.js';
20
21
  import { Uint8ArraySchema } from './Serialization.js';
21
22
  export const SecretKeysResource = {
22
23
  create: (secretKey) => {
@@ -70,16 +71,22 @@ export const makeDefaultSyncService = (config) => {
70
71
  updates: (state, secretKey) => {
71
72
  return pipe(indexerSyncService.subscribeWallet(state), Stream.map((data) => WalletSyncUpdate.create(data, secretKey)), Stream.provideSomeLayer(indexerSyncService.connectionLayer()));
72
73
  },
73
- ledgerParameters: () => {
74
+ blockData: () => {
74
75
  return Effect.gen(function* () {
75
76
  const query = yield* BlockHash;
76
77
  const result = yield* query({ offset: null });
77
- return result.block?.ledgerParameters;
78
- }).pipe(Effect.provide(indexerSyncService.queryClient()), Effect.scoped, Effect.catchAll((err) => Effect.fail(WalletError.WalletError.other(`Encountered unexpected error: ${err.message}`))), Effect.flatMap((ledgerParameters) => {
79
- if (ledgerParameters === undefined) {
80
- return Effect.fail(WalletError.WalletError.other('Unable to fetch ledger parameters'));
78
+ return result.block;
79
+ }).pipe(Effect.provide(indexerSyncService.queryClient()), Effect.scoped, Effect.catchAll((err) => Effect.fail(WalletError.WalletError.other(`Encountered unexpected error: ${err.message}`))), Effect.flatMap((blockData) => {
80
+ if (!blockData) {
81
+ return Effect.fail(WalletError.WalletError.other('Unable to fetch block data'));
81
82
  }
82
- return LedgerOps.ledgerTry(() => LedgerParameters.deserialize(Buffer.from(ledgerParameters, 'hex')));
83
+ // TODO: convert to schema
84
+ return LedgerOps.ledgerTry(() => ({
85
+ hash: blockData.hash,
86
+ height: blockData.height,
87
+ ledgerParameters: LedgerParameters.deserialize(Buffer.from(blockData.ledgerParameters, 'hex')),
88
+ timestamp: new Date(blockData.timestamp),
89
+ }));
83
90
  }));
84
91
  },
85
92
  };
@@ -125,7 +132,18 @@ export const makeDefaultSyncCapability = () => {
125
132
  export const makeSimulatorSyncService = (config) => {
126
133
  return {
127
134
  updates: (_state, secretKey) => config.simulator.state$.pipe(Stream.map((state) => ({ update: state, secretKey }))),
128
- ledgerParameters: () => pipe(config.simulator.getLatestState(), Effect.map((state) => state.ledger.parameters)),
135
+ blockData: () => {
136
+ return Effect.gen(function* () {
137
+ const state = yield* config.simulator.getLatestState();
138
+ const timestamp = DateOps.secondsToDate(state.lastTxNumber);
139
+ return {
140
+ hash: yield* Simulator.blockHash(timestamp),
141
+ height: Number(state.lastTxNumber),
142
+ ledgerParameters: state.ledger.parameters,
143
+ timestamp,
144
+ };
145
+ });
146
+ },
129
147
  };
130
148
  };
131
149
  export const makeSimulatorSyncCapability = () => ({
@@ -11,7 +11,7 @@ export interface TransactingCapability<TSecrets, TState, TTransaction> {
11
11
  createDustGenerationTransaction(currentTime: Date, ttl: Date, nightUtxos: ReadonlyArray<CoinWithValue<Utxo>>, nightVerifyingKey: SignatureVerifyingKey, dustReceiverAddress: string | undefined): Either.Either<UnprovenTransaction, WalletError.WalletError>;
12
12
  addDustGenerationSignature(transaction: UnprovenTransaction, signature: Signature): Either.Either<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
13
13
  calculateFee(transaction: AnyTransaction, ledgerParams: LedgerParameters): bigint;
14
- addFeePayment(secretKey: TSecrets, state: TState, transaction: UnprovenTransaction, currentTime: Date, ttl: Date, ledgerParams: LedgerParameters): Either.Either<{
14
+ addFeePayment(secretKey: TSecrets, state: TState, transaction: UnprovenTransaction, ttl: Date, currentTime: Date, ledgerParams: LedgerParameters): Either.Either<{
15
15
  recipe: ProvingRecipe.ProvingRecipe<FinalizedTransaction>;
16
16
  newState: TState;
17
17
  }, WalletError.WalletError>;
@@ -41,7 +41,7 @@ export declare class TransactingCapabilityImplementation<TTransaction extends An
41
41
  addDustGenerationSignature(transaction: UnprovenTransaction, signatureData: Signature): Either.Either<ProvingRecipe.ProvingRecipe<FinalizedTransaction>, WalletError.WalletError>;
42
42
  calculateFee(transaction: AnyTransaction, ledgerParams: LedgerParameters): bigint;
43
43
  static feeImbalance(transaction: AnyTransaction, totalFee: bigint): bigint;
44
- addFeePayment(secretKey: DustSecretKey, state: DustCoreWallet, transaction: UnprovenTransaction, currentTime: Date, ttl: Date, ledgerParams: LedgerParameters): Either.Either<{
44
+ addFeePayment(secretKey: DustSecretKey, state: DustCoreWallet, transaction: UnprovenTransaction, ttl: Date, currentTime: Date, ledgerParams: LedgerParameters): Either.Either<{
45
45
  recipe: ProvingRecipe.ProvingRecipe<FinalizedTransaction>;
46
46
  newState: DustCoreWallet;
47
47
  }, WalletError.WalletError>;
@@ -108,7 +108,7 @@ export class TransactingCapabilityImplementation {
108
108
  .find(([tt, _]) => tt.tag === 'dust');
109
109
  return dustImbalance ? -dustImbalance[1] : totalFee;
110
110
  }
111
- addFeePayment(secretKey, state, transaction, currentTime, ttl, ledgerParams) {
111
+ addFeePayment(secretKey, state, transaction, ttl, currentTime, ledgerParams) {
112
112
  const network = this.networkId;
113
113
  const feeLeft = TransactingCapabilityImplementation.feeImbalance(transaction, this.calculateFee(transaction, ledgerParams));
114
114
  const dustTokens = this.getCoins().getAvailableCoinsWithGeneratedDust(state, currentTime);
@@ -119,8 +119,7 @@ export class TransactingCapabilityImplementation {
119
119
  const totalFeeInSelected = selectedTokens.reduce((total, { value }) => total + value, 0n);
120
120
  const feeDiff = totalFeeInSelected - feeLeft;
121
121
  if (feeDiff < 0n) {
122
- // A sanity-check, should never happen
123
- return Either.left(new WalletError.TransactingError({ message: 'Error in tokens selection algorithm' }));
122
+ return Either.left(new WalletError.TransactingError({ message: 'Not enough Dust generated to pay the fee' }));
124
123
  }
125
124
  // reduce the largest token's value by `feeDiff`
126
125
  const tokensWithFeeToTake = selectedTokens.toSorted((a, b) => Number(b.value - a.value));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midnight-ntwrk/wallet-sdk-dust-wallet",
3
- "version": "1.0.0-beta.10",
3
+ "version": "1.0.0-beta.11",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -28,10 +28,10 @@
28
28
  "@midnight-ntwrk/wallet-sdk-address-format": "3.0.0-beta.9",
29
29
  "@midnight-ntwrk/wallet-sdk-capabilities": "3.0.0-beta.9",
30
30
  "@midnight-ntwrk/wallet-sdk-hd": "3.0.0-beta.7",
31
- "@midnight-ntwrk/wallet-sdk-indexer-client": "1.0.0-beta.12",
31
+ "@midnight-ntwrk/wallet-sdk-indexer-client": "1.0.0-beta.13",
32
32
  "@midnight-ntwrk/wallet-sdk-node-client": "1.0.0-beta.10",
33
33
  "@midnight-ntwrk/wallet-sdk-prover-client": "1.0.0-beta.10",
34
- "@midnight-ntwrk/wallet-sdk-shielded": "1.0.0-beta.11",
34
+ "@midnight-ntwrk/wallet-sdk-shielded": "1.0.0-beta.12",
35
35
  "@midnight-ntwrk/wallet-sdk-utilities": "1.0.0-beta.7",
36
36
  "effect": "^3.17.3",
37
37
  "rxjs": "^7.5"
@@ -40,8 +40,8 @@
40
40
  "typecheck": "tsc -b ./tsconfig.json --noEmit",
41
41
  "test": "vitest run",
42
42
  "lint": "eslint --max-warnings 0",
43
- "format": "prettier --write \"**/*.{ts,js,json,yaml,yml}\"",
44
- "format:check": "prettier --check \"**/*.{ts,js,json,yaml,yml}\"",
43
+ "format": "prettier --write \"**/*.{ts,js,json,yaml,yml,md}\"",
44
+ "format:check": "prettier --check \"**/*.{ts,js,json,yaml,yml,md}\"",
45
45
  "dist": "tsc -b ./tsconfig.build.json",
46
46
  "dist:publish": "tsc -b ./tsconfig.publish.json",
47
47
  "clean": "rimraf --glob dist 'tsconfig.*.tsbuildinfo' && date +%s > .clean-timestamp",