@midnight-ntwrk/wallet-sdk-unshielded-wallet 3.0.0 → 3.1.0

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.
@@ -46,6 +46,13 @@ export type UnshieldedWalletAPI<TSerialized = string> = {
46
46
  balanceUnboundTransaction(tx: UnboundTransaction): Promise<UnboundTransactionBalanceResult>;
47
47
  balanceUnprovenTransaction(tx: ledger.UnprovenTransaction): Promise<UnprovenTransactionBalanceResult>;
48
48
  transferTransaction(outputs: readonly TokenTransfer[], ttl: Date): Promise<ledger.UnprovenTransaction>;
49
+ /**
50
+ * Books a caller-supplied set of Night UTxOs and returns an unproven transaction that moves them back to the same
51
+ * owner, split between the guaranteed (segment 0) and fallible (segment 1) sections of a single intent. Booking moves
52
+ * the UTxOs from available to pending so a concurrent build call cannot reuse them. The fallible section is available
53
+ * for callers that want to attach further actions (e.g. a Dust registration) at segment 1.
54
+ */
55
+ rotateUtxos(guaranteedUtxos: readonly UtxoWithMeta[], fallibleUtxos: readonly UtxoWithMeta[], nightVerifyingKey: ledger.SignatureVerifyingKey, ttl: Date): Promise<ledger.UnprovenTransaction>;
49
56
  initSwap(desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: readonly TokenTransfer[], ttl: Date): Promise<ledger.UnprovenTransaction>;
50
57
  signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Promise<ledger.UnprovenTransaction>;
51
58
  signUnboundTransaction(transaction: UnboundTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Promise<UnboundTransaction>;
@@ -106,6 +106,13 @@ export function CustomUnshieldedWallet(configuration, builder) {
106
106
  })
107
107
  .pipe(Effect.runPromise);
108
108
  }
109
+ rotateUtxos(guaranteedUtxos, fallibleUtxos, nightVerifyingKey, ttl) {
110
+ return this.runtime
111
+ .dispatch({
112
+ [V1Tag]: (v1) => v1.rotateUtxos(guaranteedUtxos, fallibleUtxos, nightVerifyingKey, ttl),
113
+ })
114
+ .pipe(Effect.runPromise);
115
+ }
109
116
  initSwap(desiredInputs, desiredOutputs, ttl) {
110
117
  return this.runtime
111
118
  .dispatch({ [V1Tag]: (v1) => v1.initSwap(desiredInputs, desiredOutputs, ttl) })
@@ -4,6 +4,7 @@ import { type SerializationCapability } from './Serialization.js';
4
4
  import { type SyncCapability, type SyncService } from './Sync.js';
5
5
  import { type WalletSyncUpdate } from './SyncSchema.js';
6
6
  import { type TransactingCapability, type TokenTransfer, type FinalizedTransactionBalanceResult, type UnboundTransactionBalanceResult, type UnprovenTransactionBalanceResult } from './Transacting.js';
7
+ import { type UtxoWithMeta } from './UnshieldedState.js';
7
8
  import { type UnboundTransaction } from './TransactionOps.js';
8
9
  import { type WalletError } from './WalletError.js';
9
10
  import { type CoinsAndBalancesCapability } from './CoinsAndBalances.js';
@@ -38,6 +39,7 @@ export declare class RunningV1Variant<TSerialized, TSyncUpdate> implements Varia
38
39
  balanceUnboundTransaction(tx: UnboundTransaction): Effect.Effect<UnboundTransactionBalanceResult, WalletError>;
39
40
  balanceUnprovenTransaction(tx: ledger.UnprovenTransaction): Effect.Effect<UnprovenTransactionBalanceResult, WalletError>;
40
41
  transferTransaction(outputs: ReadonlyArray<TokenTransfer>, ttl: Date): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
42
+ rotateUtxos(guaranteedUtxos: ReadonlyArray<UtxoWithMeta>, fallibleUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: ledger.SignatureVerifyingKey, ttl: Date): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
41
43
  initSwap(desiredInputs: Record<string, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>, ttl: Date): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
42
44
  signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
43
45
  signUnboundTransaction(transaction: UnboundTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Effect.Effect<UnboundTransaction, WalletError>;
@@ -87,6 +87,11 @@ export class RunningV1Variant {
87
87
  return pipe(this.#v1Context.transactingCapability.makeTransfer(state, outputs, ttl), EitherOps.toEffect, Effect.map(({ transaction, newState }) => [transaction, newState]));
88
88
  });
89
89
  }
90
+ rotateUtxos(guaranteedUtxos, fallibleUtxos, nightVerifyingKey, ttl) {
91
+ return SubscriptionRef.modifyEffect(this.#context.stateRef, (state) => {
92
+ return pipe(this.#v1Context.transactingCapability.rotateUtxos(state, guaranteedUtxos, fallibleUtxos, nightVerifyingKey, ttl), EitherOps.toEffect, Effect.map(({ transaction, newState }) => [transaction, newState]));
93
+ });
94
+ }
90
95
  initSwap(desiredInputs, desiredOutputs, ttl) {
91
96
  return SubscriptionRef.modifyEffect(this.#context.stateRef, (state) => {
92
97
  return pipe(this.#v1Context.transactingCapability.initSwap(state, desiredInputs, desiredOutputs, ttl), Effect.map(({ transaction, newState }) => [transaction, newState]));
@@ -3,6 +3,7 @@ import { type NetworkId } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
3
  import { Either } from 'effect';
4
4
  import { CoreWallet } from './CoreWallet.js';
5
5
  import { type WalletError } from './WalletError.js';
6
+ import { type UtxoWithMeta } from './UnshieldedState.js';
6
7
  import { type CoinSelection } from '@midnight-ntwrk/wallet-sdk-capabilities';
7
8
  import { TransactionOps, type UnboundTransaction } from './TransactionOps.js';
8
9
  import { type CoinsAndBalancesCapability } from './CoinsAndBalances.js';
@@ -23,6 +24,23 @@ export type TransactingResult<TTransaction, TState> = {
23
24
  export interface TransactingCapability<TState> {
24
25
  makeTransfer(wallet: CoreWallet, outputs: ReadonlyArray<TokenTransfer>, ttl: Date): Either.Either<TransactingResult<ledger.UnprovenTransaction, TState>, WalletError>;
25
26
  initSwap(wallet: CoreWallet, desiredInputs: Record<string, bigint>, outputs: ReadonlyArray<TokenTransfer>, ttl: Date): Either.Either<TransactingResult<ledger.UnprovenTransaction, TState>, WalletError>;
27
+ /**
28
+ * Builds an unproven transaction that moves a caller-supplied set of Night UTxOs back to their current owner,
29
+ * splitting them between the guaranteed and fallible sections of a single intent. The provided UTxOs are booked in
30
+ * the wallet state (moved from available to pending) so that no subsequent build call can pick them.
31
+ *
32
+ * Used by the Dust wallet's registration/deregistration flow, where the Dust wallet picks the guaranteed slot (based
33
+ * on dust generation) and hands both sets here for booking and intent construction. The Dust wallet then attaches its
34
+ * DustActions onto the returned intent.
35
+ *
36
+ * @param wallet - The wallet whose UTxOs are being passed through
37
+ * @param guaranteedUtxos - UTxOs to place in the guaranteed offer (segment 0)
38
+ * @param fallibleUtxos - UTxOs to place in the fallible offer (segment 1+)
39
+ * @param nightVerifyingKey - The verifying key used as the input owner and the address for the consolidating output
40
+ * @param ttl - The TTL for the transaction
41
+ * @returns The new wallet state (with all provided UTxOs booked) and the unproven transaction
42
+ */
43
+ rotateUtxos(wallet: CoreWallet, guaranteedUtxos: ReadonlyArray<UtxoWithMeta>, fallibleUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: ledger.SignatureVerifyingKey, ttl: Date): Either.Either<TransactingResult<ledger.UnprovenTransaction, TState>, WalletError>;
26
44
  balanceFinalizedTransaction(wallet: CoreWallet, transaction: ledger.FinalizedTransaction): Either.Either<[FinalizedTransactionBalanceResult, CoreWallet], WalletError>;
27
45
  balanceUnboundTransaction(wallet: CoreWallet, transaction: UnboundTransaction): Either.Either<[UnboundTransactionBalanceResult, CoreWallet], WalletError>;
28
46
  balanceUnprovenTransaction(wallet: CoreWallet, transaction: ledger.UnprovenTransaction): Either.Either<[UnprovenTransactionBalanceResult, CoreWallet], WalletError>;
@@ -82,6 +100,7 @@ export declare class TransactingCapabilityImplementation implements TransactingC
82
100
  * @returns The balanced transfer transaction and the new wallet state if successful, otherwise an error
83
101
  */
84
102
  makeTransfer(wallet: CoreWallet, outputs: ReadonlyArray<TokenTransfer>, ttl: Date): Either.Either<TransactingResult<ledger.UnprovenTransaction, CoreWallet>, WalletError>;
103
+ rotateUtxos(wallet: CoreWallet, guaranteedUtxos: ReadonlyArray<UtxoWithMeta>, fallibleUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: ledger.SignatureVerifyingKey, ttl: Date): Either.Either<TransactingResult<ledger.UnprovenTransaction, CoreWallet>, WalletError>;
85
104
  /**
86
105
  * Initializes a swap transaction
87
106
  *
@@ -85,9 +85,7 @@ export class TransactingCapabilityImplementation {
85
85
  const balancingIntent = ledger.Intent.new(intent.ttl);
86
86
  balancingIntent.guaranteedUnshieldedOffer = offer;
87
87
  const segmentId = Option.getOrElse(this.txOps.findAvailableSegmentId(transaction), () => 1);
88
- // @TODO in ledger 8.1.0 will be able to set the segment id when constructing the tx
89
- const balancingTx = ledger.Transaction.fromParts(this.networkId, undefined, undefined, undefined);
90
- balancingTx.intents = new Map([[segmentId, balancingIntent]]);
88
+ const balancingTx = ledger.Transaction.fromParts(this.networkId).addIntent({ tag: 'specific', value: segmentId }, balancingIntent);
91
89
  return [balancingTx, newState];
92
90
  });
93
91
  }
@@ -132,6 +130,56 @@ export class TransactingCapabilityImplementation {
132
130
  };
133
131
  });
134
132
  }
133
+ rotateUtxos(wallet, guaranteedUtxos, fallibleUtxos, nightVerifyingKey, ttl) {
134
+ return Either.gen(this, function* () {
135
+ const { networkId } = this;
136
+ if (guaranteedUtxos.length === 0 && fallibleUtxos.length === 0) {
137
+ return yield* Either.left(new TransactingError({ message: 'At least one UTxO must be provided to rotateUtxos' }));
138
+ }
139
+ const ownerAddress = ledger.addressFromKey(nightVerifyingKey);
140
+ const makeOffer = (utxos) => {
141
+ if (utxos.length === 0) {
142
+ return Option.none();
143
+ }
144
+ const inputs = utxos.map(({ utxo }) => ({
145
+ value: utxo.value,
146
+ type: utxo.type,
147
+ intentHash: utxo.intentHash,
148
+ outputNo: utxo.outputNo,
149
+ owner: nightVerifyingKey,
150
+ }));
151
+ const totalValue = pipe(utxos, Arr.map(({ utxo }) => utxo.value), Arr.reduce(0n, (a, b) => a + b));
152
+ const output = {
153
+ owner: ownerAddress,
154
+ type: ledger.nativeToken().raw,
155
+ value: totalValue,
156
+ };
157
+ return Option.some(ledger.UnshieldedOffer.new(inputs, [output], []));
158
+ };
159
+ const allUtxos = [...guaranteedUtxos, ...fallibleUtxos].map(({ utxo }) => utxo);
160
+ const [, walletAfterBooking] = yield* CoreWallet.spendUtxos(wallet, allUtxos);
161
+ const guaranteedOffer = makeOffer(guaranteedUtxos);
162
+ const fallibleOffer = makeOffer(fallibleUtxos);
163
+ const intent = pipe(ledger.Intent.new(ttl), (i) => Option.match(guaranteedOffer, {
164
+ onNone: () => i,
165
+ onSome: (offer) => {
166
+ i.guaranteedUnshieldedOffer = offer;
167
+ return i;
168
+ },
169
+ }), (i) => Option.match(fallibleOffer, {
170
+ onNone: () => i,
171
+ onSome: (offer) => {
172
+ i.fallibleUnshieldedOffer = offer;
173
+ return i;
174
+ },
175
+ }));
176
+ const transaction = ledger.Transaction.fromParts(networkId, undefined, undefined, intent);
177
+ return {
178
+ newState: walletAfterBooking,
179
+ transaction,
180
+ };
181
+ });
182
+ }
135
183
  /**
136
184
  * Initializes a swap transaction
137
185
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midnight-ntwrk/wallet-sdk-unshielded-wallet",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -28,13 +28,13 @@
28
28
  }
29
29
  },
30
30
  "dependencies": {
31
- "@midnight-ntwrk/ledger-v8": "^8.0.3",
32
- "@midnight-ntwrk/wallet-sdk-abstractions": "2.1.0",
33
- "@midnight-ntwrk/wallet-sdk-address-format": "3.1.1",
34
- "@midnight-ntwrk/wallet-sdk-capabilities": "3.3.0",
35
- "@midnight-ntwrk/wallet-sdk-indexer-client": "1.2.1",
36
- "@midnight-ntwrk/wallet-sdk-runtime": "1.0.3",
37
- "@midnight-ntwrk/wallet-sdk-utilities": "1.1.1",
31
+ "@midnight-ntwrk/ledger-v8": "^8.1.0",
32
+ "@midnight-ntwrk/wallet-sdk-abstractions": "^2.1.0",
33
+ "@midnight-ntwrk/wallet-sdk-address-format": "^3.1.2",
34
+ "@midnight-ntwrk/wallet-sdk-capabilities": "^3.3.1",
35
+ "@midnight-ntwrk/wallet-sdk-indexer-client": "^1.2.2",
36
+ "@midnight-ntwrk/wallet-sdk-runtime": "^1.0.4",
37
+ "@midnight-ntwrk/wallet-sdk-utilities": "^1.2.0",
38
38
  "effect": "^3.19.19",
39
39
  "rxjs": "^7.8.2"
40
40
  },
@@ -50,6 +50,6 @@
50
50
  "publint": "publint --strict"
51
51
  },
52
52
  "devDependencies": {
53
- "@midnight-ntwrk/wallet-sdk-hd": "3.0.2"
53
+ "@midnight-ntwrk/wallet-sdk-hd": "^3.0.2"
54
54
  }
55
55
  }