@midnightntwrk/wallet-sdk-unshielded-wallet 4.0.0-beta.1 → 4.0.0-beta.2
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/KeyStore.d.ts +8 -0
- package/dist/KeyStore.js +1 -0
- package/dist/UnshieldedWallet.d.ts +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/v1/RunningV1Variant.d.ts +4 -2
- package/dist/v1/RunningV1Variant.js +2 -2
- package/dist/v1/Signing.d.ts +25 -0
- package/dist/v1/Signing.js +40 -0
- package/dist/v1/Transacting.d.ts +0 -4
- package/dist/v1/Transacting.js +0 -42
- package/dist/v1/TransactionOps.d.ts +12 -0
- package/dist/v1/TransactionOps.js +27 -0
- package/dist/v1/V1Builder.d.ts +7 -1
- package/dist/v1/V1Builder.js +14 -1
- package/dist/v1/index.d.ts +1 -0
- package/dist/v1/index.js +1 -0
- package/package.json +4 -4
package/dist/KeyStore.d.ts
CHANGED
|
@@ -18,6 +18,14 @@ export interface UnshieldedKeystore {
|
|
|
18
18
|
getBech32Address(): MidnightBech32m;
|
|
19
19
|
getPublicKey(): SignatureVerifyingKey;
|
|
20
20
|
getAddress(): UserAddress;
|
|
21
|
+
/** The synchronous in-process signing primitive. */
|
|
21
22
|
signData(data: Uint8Array): Signature;
|
|
23
|
+
/**
|
|
24
|
+
* Async counterpart of {@link signData} that conforms to the SDK's signer callback shape (`(data) =>
|
|
25
|
+
* Promise<Signature>`), so the keystore can be passed directly to `signRecipe`/`signUnprovenTransaction`/… without
|
|
26
|
+
* wrapping each call site. It simply resolves the synchronous {@link signData}; out-of-process backends (MPC, HSM)
|
|
27
|
+
* supply their own async signer.
|
|
28
|
+
*/
|
|
29
|
+
signDataAsync: (data: Uint8Array) => Promise<Signature>;
|
|
22
30
|
}
|
|
23
31
|
export declare const createKeystore: (secretKey: UnshieldedSecretKey, networkId: NetworkId.NetworkId) => UnshieldedKeystore;
|
package/dist/KeyStore.js
CHANGED
|
@@ -36,6 +36,7 @@ export const createKeystore = (secretKey, networkId) => {
|
|
|
36
36
|
getPublicKey: () => signatureVerifyingKey(ledgerSigningKey),
|
|
37
37
|
getAddress: () => addressFromKey(keystore.getPublicKey()),
|
|
38
38
|
signData: (data) => signData(ledgerSigningKey, data),
|
|
39
|
+
signDataAsync: (data) => Promise.resolve(keystore.signData(data)),
|
|
39
40
|
};
|
|
40
41
|
return keystore;
|
|
41
42
|
};
|
|
@@ -8,6 +8,7 @@ import { type CoinsAndBalancesCapability } from './v1/CoinsAndBalances.js';
|
|
|
8
8
|
import { type KeysCapability } from './v1/Keys.js';
|
|
9
9
|
import { type TokenTransfer, type FinalizedTransactionBalanceResult, type UnboundTransactionBalanceResult, type UnprovenTransactionBalanceResult } from './v1/Transacting.js';
|
|
10
10
|
import { type WalletSyncUpdate } from './v1/SyncSchema.js';
|
|
11
|
+
import { type SignSegment } from './v1/Signing.js';
|
|
11
12
|
import { type UtxoWithMeta } from './v1/UnshieldedState.js';
|
|
12
13
|
import { type Variant, type VariantBuilder, type WalletLike } from '@midnightntwrk/wallet-sdk-runtime/abstractions';
|
|
13
14
|
import { type PublicKey } from './KeyStore.js';
|
|
@@ -54,8 +55,8 @@ export type UnshieldedWalletAPI<TSerialized = string> = {
|
|
|
54
55
|
*/
|
|
55
56
|
rotateUtxos(guaranteedUtxos: readonly UtxoWithMeta[], fallibleUtxos: readonly UtxoWithMeta[], nightVerifyingKey: ledger.SignatureVerifyingKey, ttl: Date): Promise<ledger.UnprovenTransaction>;
|
|
56
57
|
initSwap(desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: readonly TokenTransfer[], ttl: Date): Promise<ledger.UnprovenTransaction>;
|
|
57
|
-
signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment:
|
|
58
|
-
signUnboundTransaction(transaction: UnboundTransaction, signSegment:
|
|
58
|
+
signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment: SignSegment): Promise<ledger.UnprovenTransaction>;
|
|
59
|
+
signUnboundTransaction(transaction: UnboundTransaction, signSegment: SignSegment): Promise<UnboundTransaction>;
|
|
59
60
|
serializeState(): Promise<TSerialized>;
|
|
60
61
|
waitForSyncedState(allowedGap?: bigint): Promise<UnshieldedWalletState<TSerialized>>;
|
|
61
62
|
revertTransaction(transaction: ledger.Transaction<ledger.Signaturish, ledger.Proofish, ledger.Bindingish>): Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { type WalletSyncUpdate } from './SyncSchema.js';
|
|
|
6
6
|
import { type TransactingCapability, type TokenTransfer, type FinalizedTransactionBalanceResult, type UnboundTransactionBalanceResult, type UnprovenTransactionBalanceResult } from './Transacting.js';
|
|
7
7
|
import { type UtxoWithMeta } from './UnshieldedState.js';
|
|
8
8
|
import { type UnboundTransaction } from './TransactionOps.js';
|
|
9
|
+
import { type SignSegment, type SigningService } from './Signing.js';
|
|
9
10
|
import { type WalletError } from './WalletError.js';
|
|
10
11
|
import { type CoinsAndBalancesCapability } from './CoinsAndBalances.js';
|
|
11
12
|
import { type KeysCapability } from './Keys.js';
|
|
@@ -19,6 +20,7 @@ export declare namespace RunningV1Variant {
|
|
|
19
20
|
syncService: SyncService<CoreWallet, TSyncUpdate>;
|
|
20
21
|
syncCapability: SyncCapability<CoreWallet, TSyncUpdate>;
|
|
21
22
|
transactingCapability: TransactingCapability<CoreWallet>;
|
|
23
|
+
signingService: SigningService;
|
|
22
24
|
coinsAndBalancesCapability: CoinsAndBalancesCapability<CoreWallet>;
|
|
23
25
|
keysCapability: KeysCapability<CoreWallet>;
|
|
24
26
|
coinSelection: CoinSelection<ledger.Utxo>;
|
|
@@ -41,8 +43,8 @@ export declare class RunningV1Variant<TSerialized, TSyncUpdate> implements Varia
|
|
|
41
43
|
transferTransaction(outputs: ReadonlyArray<TokenTransfer>, ttl: Date): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
|
|
42
44
|
rotateUtxos(guaranteedUtxos: ReadonlyArray<UtxoWithMeta>, fallibleUtxos: ReadonlyArray<UtxoWithMeta>, nightVerifyingKey: ledger.SignatureVerifyingKey, ttl: Date): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
|
|
43
45
|
initSwap(desiredInputs: Record<string, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>, ttl: Date): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
|
|
44
|
-
signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment:
|
|
45
|
-
signUnboundTransaction(transaction: UnboundTransaction, signSegment:
|
|
46
|
+
signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment: SignSegment): Effect.Effect<ledger.UnprovenTransaction, WalletError>;
|
|
47
|
+
signUnboundTransaction(transaction: UnboundTransaction, signSegment: SignSegment): Effect.Effect<UnboundTransaction, WalletError>;
|
|
46
48
|
revertTransaction(transaction: ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.Bindingish>): Effect.Effect<void, WalletError>;
|
|
47
49
|
serializeState(state: CoreWallet): TSerialized;
|
|
48
50
|
}
|
|
@@ -98,10 +98,10 @@ export class RunningV1Variant {
|
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
signUnprovenTransaction(transaction, signSegment) {
|
|
101
|
-
return this.#v1Context.
|
|
101
|
+
return this.#v1Context.signingService.sign(transaction, signSegment);
|
|
102
102
|
}
|
|
103
103
|
signUnboundTransaction(transaction, signSegment) {
|
|
104
|
-
return this.#v1Context.
|
|
104
|
+
return this.#v1Context.signingService.sign(transaction, signSegment);
|
|
105
105
|
}
|
|
106
106
|
revertTransaction(transaction) {
|
|
107
107
|
return SubscriptionRef.updateEffect(this.#context.stateRef, (state) => {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import type * as ledger from '@midnightntwrk/ledger-v9';
|
|
3
|
+
import { type UnboundTransaction } from './TransactionOps.js';
|
|
4
|
+
import { type WalletError } from './WalletError.js';
|
|
5
|
+
/**
|
|
6
|
+
* Produces a {@link ledger.Signature} over the supplied bytes. Asynchronous so that out-of-process signers (MPC, HSM) —
|
|
7
|
+
* whose whole purpose is that the secret never materializes in-process — can be plugged in directly. A synchronous
|
|
8
|
+
* in-process keystore satisfies this by resolving immediately: `keystore.signDataAsync`.
|
|
9
|
+
*/
|
|
10
|
+
export type SignSegment = (data: Uint8Array) => Promise<ledger.Signature>;
|
|
11
|
+
/**
|
|
12
|
+
* Authorizes a transaction by signing each of its signable segments with the supplied async {@link SignSegment}. The
|
|
13
|
+
* service is the imperative shell: it drives the async signer and maps its failures into the typed error channel; the
|
|
14
|
+
* pure work is delegated to {@link TransactionOps.collectSignableData} and {@link TransactionOps.attachSignatures}.
|
|
15
|
+
*/
|
|
16
|
+
export interface SigningService {
|
|
17
|
+
sign<TTransaction extends ledger.UnprovenTransaction | UnboundTransaction>(transaction: TTransaction, signSegment: SignSegment): Effect.Effect<TTransaction, WalletError>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The default signing service: collect each segment's signable data (pure), invoke the async signer once per segment
|
|
21
|
+
* (sequentially — segment counts are tiny), then attach the signatures (pure, with scheme validation). A signer
|
|
22
|
+
* rejection or throw is wrapped in a {@link SignError}; a scheme mismatch short-circuits inside `attachSignatures`
|
|
23
|
+
* before anything is attached, so no partially-signed transaction can escape.
|
|
24
|
+
*/
|
|
25
|
+
export declare const makeDefaultSigningService: () => SigningService;
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
// Signing as a service (#504). Authorizing a transaction means producing a `Signature` over each signable segment.
|
|
15
|
+
// For an in-process keystore that is instantaneous, but MPC (threshold protocols with network round-trips) and HSM
|
|
16
|
+
// (on-device PKCS#11) signers are inherently asynchronous. The signer is therefore an async callback, and the
|
|
17
|
+
// orchestration that invokes it lives here — in the Effect (imperative-shell) layer — while the pure transformations
|
|
18
|
+
// (which segments to sign, scheme validation, signature attachment) stay in `TransactionOps`.
|
|
19
|
+
import { EitherOps } from '@midnightntwrk/wallet-sdk-utilities';
|
|
20
|
+
import { Effect, pipe } from 'effect';
|
|
21
|
+
import { TransactionOps } from './TransactionOps.js';
|
|
22
|
+
import { SignError } from './WalletError.js';
|
|
23
|
+
/**
|
|
24
|
+
* The default signing service: collect each segment's signable data (pure), invoke the async signer once per segment
|
|
25
|
+
* (sequentially — segment counts are tiny), then attach the signatures (pure, with scheme validation). A signer
|
|
26
|
+
* rejection or throw is wrapped in a {@link SignError}; a scheme mismatch short-circuits inside `attachSignatures`
|
|
27
|
+
* before anything is attached, so no partially-signed transaction can escape.
|
|
28
|
+
*/
|
|
29
|
+
export const makeDefaultSigningService = () => ({
|
|
30
|
+
sign(transaction, signSegment) {
|
|
31
|
+
return Effect.gen(function* () {
|
|
32
|
+
const segments = yield* EitherOps.toEffect(TransactionOps.collectSignableData(transaction));
|
|
33
|
+
const signatures = yield* Effect.forEach(segments, (segment) => pipe(Effect.tryPromise({
|
|
34
|
+
try: () => signSegment(segment.data),
|
|
35
|
+
catch: (cause) => new SignError({ message: 'Signer callback failed', cause }),
|
|
36
|
+
}), Effect.map((signature) => ({ segment: segment.segment, signature }))));
|
|
37
|
+
return yield* EitherOps.toEffect(TransactionOps.attachSignatures(transaction, signatures));
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
});
|
package/dist/v1/Transacting.d.ts
CHANGED
|
@@ -44,9 +44,7 @@ export interface TransactingCapability<TState> {
|
|
|
44
44
|
balanceFinalizedTransaction(wallet: CoreWallet, transaction: ledger.FinalizedTransaction): Either.Either<[FinalizedTransactionBalanceResult, CoreWallet], WalletError>;
|
|
45
45
|
balanceUnboundTransaction(wallet: CoreWallet, transaction: UnboundTransaction): Either.Either<[UnboundTransactionBalanceResult, CoreWallet], WalletError>;
|
|
46
46
|
balanceUnprovenTransaction(wallet: CoreWallet, transaction: ledger.UnprovenTransaction): Either.Either<[UnprovenTransactionBalanceResult, CoreWallet], WalletError>;
|
|
47
|
-
signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Either.Either<ledger.UnprovenTransaction, WalletError>;
|
|
48
47
|
revertTransaction(wallet: CoreWallet, transaction: ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.Bindingish>): Either.Either<CoreWallet, WalletError>;
|
|
49
|
-
signUnboundTransaction(transaction: UnboundTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Either.Either<UnboundTransaction, WalletError>;
|
|
50
48
|
}
|
|
51
49
|
export type DefaultTransactingConfiguration = {
|
|
52
50
|
networkId: NetworkId.NetworkId;
|
|
@@ -111,8 +109,6 @@ export declare class TransactingCapabilityImplementation implements TransactingC
|
|
|
111
109
|
* @returns The initialized swap transaction and the new wallet state if successful, otherwise an error
|
|
112
110
|
*/
|
|
113
111
|
initSwap(wallet: CoreWallet, desiredInputs: Record<ledger.RawTokenType, bigint>, desiredOutputs: ReadonlyArray<TokenTransfer>, ttl: Date): Either.Either<TransactingResult<ledger.UnprovenTransaction, CoreWallet>, WalletError>;
|
|
114
|
-
signUnprovenTransaction(transaction: ledger.UnprovenTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Either.Either<ledger.UnprovenTransaction, WalletError>;
|
|
115
|
-
signUnboundTransaction(transaction: UnboundTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Either.Either<UnboundTransaction, WalletError>;
|
|
116
112
|
/**
|
|
117
113
|
* Reverts a transaction by rolling back all inputs owned by this wallet
|
|
118
114
|
*
|
package/dist/v1/Transacting.js
CHANGED
|
@@ -16,7 +16,6 @@ import { CoreWallet } from './CoreWallet.js';
|
|
|
16
16
|
import { InsufficientFundsError, OtherWalletError, TransactingError } from './WalletError.js';
|
|
17
17
|
import { getBalanceRecipe, Imbalances, InsufficientFundsError as BalancingInsufficientFundsError, } from '@midnightntwrk/wallet-sdk-capabilities';
|
|
18
18
|
import { TransactionOps } from './TransactionOps.js';
|
|
19
|
-
import { assertSignatureMatchesKey } from '../SchemeConsistency.js';
|
|
20
19
|
const GUARANTEED_SEGMENT = 0;
|
|
21
20
|
export const makeDefaultTransactingCapability = (config, getContext) => {
|
|
22
21
|
return new TransactingCapabilityImplementation(config.networkId, () => getContext().coinSelection, () => getContext().coinsAndBalancesCapability, () => getContext().keysCapability, TransactionOps);
|
|
@@ -221,47 +220,6 @@ export class TransactingCapabilityImplementation {
|
|
|
221
220
|
};
|
|
222
221
|
});
|
|
223
222
|
}
|
|
224
|
-
signUnprovenTransaction(transaction, signSegment) {
|
|
225
|
-
return this.#signTransactionInternal(transaction, signSegment);
|
|
226
|
-
}
|
|
227
|
-
signUnboundTransaction(transaction, signSegment) {
|
|
228
|
-
return this.#signTransactionInternal(transaction, signSegment);
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Internal method to sign either an unproven or unbound transaction
|
|
232
|
-
*
|
|
233
|
-
* @param transaction - The transaction to sign
|
|
234
|
-
* @param signSegment - The signing function
|
|
235
|
-
* @returns The signed transaction if successful, otherwise an error
|
|
236
|
-
*/
|
|
237
|
-
#signTransactionInternal(transaction, signSegment) {
|
|
238
|
-
return Either.gen(this, function* () {
|
|
239
|
-
const segments = this.txOps.getSegments(transaction);
|
|
240
|
-
for (const segment of segments) {
|
|
241
|
-
const signedData = yield* this.txOps.getSignatureData(transaction, segment);
|
|
242
|
-
const signature = signSegment(signedData);
|
|
243
|
-
// Reject a wrong-scheme signature before it is attached, so a mismatch
|
|
244
|
-
// never reaches the network (no partially-signed transaction escapes).
|
|
245
|
-
yield* this.#assertSignatureMatchesSegmentOwners(transaction, segment, signature);
|
|
246
|
-
transaction = yield* this.txOps.addSignature(transaction, signature, segment);
|
|
247
|
-
}
|
|
248
|
-
return transaction;
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Asserts that a freshly produced signature shares the scheme (`schnorr` vs `ecdsa`) of every input owner it will
|
|
253
|
-
* authorize in the given segment. Pure and synchronous: a mismatch short-circuits signing with a typed
|
|
254
|
-
* `SchemeMismatchError` before the signature is attached.
|
|
255
|
-
*/
|
|
256
|
-
#assertSignatureMatchesSegmentOwners(transaction, segment, signature) {
|
|
257
|
-
const intent = transaction.intents?.get(segment);
|
|
258
|
-
const owners = [
|
|
259
|
-
...(intent?.guaranteedUnshieldedOffer?.inputs ?? []),
|
|
260
|
-
...(intent?.fallibleUnshieldedOffer?.inputs ?? []),
|
|
261
|
-
].map((input) => input.owner);
|
|
262
|
-
const ok = Either.right(signature);
|
|
263
|
-
return pipe(owners, Arr.reduce(ok, (acc, owner) => Either.flatMap(acc, () => assertSignatureMatchesKey(owner, signature))));
|
|
264
|
-
}
|
|
265
223
|
/**
|
|
266
224
|
* Reverts a transaction by rolling back all inputs owned by this wallet
|
|
267
225
|
*
|
|
@@ -6,11 +6,23 @@ import { type WalletError } from './WalletError.js';
|
|
|
6
6
|
export type UnboundTransaction = ledger.Transaction<ledger.SignatureEnabled, ledger.Proof, ledger.PreBinding>;
|
|
7
7
|
/** Utility type to extract the Intent type from a Transaction type. Maps Transaction<S, P, B> to Intent<S, P, B>. */
|
|
8
8
|
export type IntentOf<T> = T extends ledger.Transaction<infer S, infer P, infer B> ? ledger.Intent<S, P, B> : never;
|
|
9
|
+
/** A transaction segment paired with the bytes that must be signed to authorize it. */
|
|
10
|
+
export type SignableSegment = {
|
|
11
|
+
readonly segment: number;
|
|
12
|
+
readonly data: Uint8Array;
|
|
13
|
+
};
|
|
14
|
+
/** A signature produced for a specific transaction segment, ready to be attached. */
|
|
15
|
+
export type SegmentSignature = {
|
|
16
|
+
readonly segment: number;
|
|
17
|
+
readonly signature: ledger.Signature;
|
|
18
|
+
};
|
|
9
19
|
export type TransactionOps = {
|
|
10
20
|
getSignatureData: (transaction: ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.PreBinding>, segment: number) => Either.Either<Uint8Array, WalletError>;
|
|
11
21
|
getSegments(transaction: ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.Bindingish>): number[];
|
|
12
22
|
findAvailableSegmentId(transaction: ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.Bindingish>): Option.Option<number>;
|
|
13
23
|
addSignature<TTransaction extends ledger.UnprovenTransaction | UnboundTransaction>(transaction: TTransaction, signature: ledger.Signature, segment: number): Either.Either<TTransaction, WalletError>;
|
|
24
|
+
collectSignableData(transaction: ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.PreBinding>): Either.Either<readonly SignableSegment[], WalletError>;
|
|
25
|
+
attachSignatures<TTransaction extends ledger.UnprovenTransaction | UnboundTransaction>(transaction: TTransaction, signatures: readonly SegmentSignature[]): Either.Either<TTransaction, WalletError>;
|
|
14
26
|
getImbalances(transaction: ledger.FinalizedTransaction | UnboundTransaction | ledger.UnprovenTransaction, segment: number): Imbalances;
|
|
15
27
|
addSignaturesToOffer(offer: ledger.UnshieldedOffer<ledger.SignatureEnabled>, signature: ledger.Signature, segment: number, offerType: 'guaranteed' | 'fallible'): Either.Either<ledger.UnshieldedOffer<ledger.SignatureEnabled>, WalletError>;
|
|
16
28
|
isIntentBound(intent: ledger.Intent<ledger.SignatureEnabled, ledger.Proofish, ledger.Bindingish>): boolean;
|
|
@@ -13,7 +13,21 @@
|
|
|
13
13
|
import { Either, pipe, Array as Arr, Iterable as IterableOps } from 'effect';
|
|
14
14
|
import { Imbalances } from '@midnightntwrk/wallet-sdk-capabilities';
|
|
15
15
|
import { addressFromKey, SignatureEnabled } from '@midnightntwrk/ledger-v9';
|
|
16
|
+
import { assertSignatureMatchesKey } from '../SchemeConsistency.js';
|
|
16
17
|
import { TransactingError } from './WalletError.js';
|
|
18
|
+
/**
|
|
19
|
+
* Asserts that `signature` shares the scheme of every input owner authorized in `segment`. Pure and synchronous: a
|
|
20
|
+
* mismatch short-circuits with a typed `SchemeMismatchError` so a wrong-scheme signature is never attached.
|
|
21
|
+
*/
|
|
22
|
+
const assertSignatureMatchesSegmentOwners = (transaction, segment, signature) => {
|
|
23
|
+
const intent = transaction.intents?.get(segment);
|
|
24
|
+
const owners = [
|
|
25
|
+
...(intent?.guaranteedUnshieldedOffer?.inputs ?? []),
|
|
26
|
+
...(intent?.fallibleUnshieldedOffer?.inputs ?? []),
|
|
27
|
+
].map((input) => input.owner);
|
|
28
|
+
const seed = Either.right(signature);
|
|
29
|
+
return pipe(owners, Arr.reduce(seed, (acc, owner) => Either.flatMap(acc, () => assertSignatureMatchesKey(owner, signature))));
|
|
30
|
+
};
|
|
17
31
|
export const TransactionOps = {
|
|
18
32
|
getSignatureData(tx, segment) {
|
|
19
33
|
if (!tx.intents) {
|
|
@@ -58,6 +72,19 @@ export const TransactionOps = {
|
|
|
58
72
|
return transaction;
|
|
59
73
|
});
|
|
60
74
|
},
|
|
75
|
+
collectSignableData(transaction) {
|
|
76
|
+
// A transaction with no intents has no signable segments — yields an empty list, never an error.
|
|
77
|
+
return Either.all(TransactionOps.getSegments(transaction).map((segment) => Either.map(TransactionOps.getSignatureData(transaction, segment), (data) => ({ segment, data }))));
|
|
78
|
+
},
|
|
79
|
+
attachSignatures(transaction, signatures) {
|
|
80
|
+
return Either.gen(function* () {
|
|
81
|
+
// Validate every signature's scheme against its segment's owners BEFORE attaching any of them, so a
|
|
82
|
+
// mismatch leaves the transaction untouched (no partially-signed transaction can escape toward the network).
|
|
83
|
+
yield* Either.all(signatures.map(({ segment, signature }) => assertSignatureMatchesSegmentOwners(transaction, segment, signature)));
|
|
84
|
+
const seed = Either.right(transaction);
|
|
85
|
+
return yield* pipe(signatures, Arr.reduce(seed, (acc, { segment, signature }) => Either.flatMap(acc, (tx) => TransactionOps.addSignature(tx, signature, segment))));
|
|
86
|
+
});
|
|
87
|
+
},
|
|
61
88
|
getImbalances(transaction, segment) {
|
|
62
89
|
const imbalances = transaction
|
|
63
90
|
.imbalances(segment)
|
package/dist/v1/V1Builder.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { type DefaultSyncContext, type DefaultSyncConfiguration, type SyncCapabi
|
|
|
8
8
|
import { type WalletSyncUpdate } from './SyncSchema.js';
|
|
9
9
|
import { type DefaultTransactingConfiguration, type DefaultTransactingContext, type TransactingCapability } from './Transacting.js';
|
|
10
10
|
import { type WalletError } from './WalletError.js';
|
|
11
|
+
import { type SigningService } from './Signing.js';
|
|
11
12
|
import { type CoinsAndBalancesCapability } from './CoinsAndBalances.js';
|
|
12
13
|
import { type KeysCapability } from './Keys.js';
|
|
13
14
|
import { type CoinSelection } from '@midnightntwrk/wallet-sdk-capabilities';
|
|
@@ -42,6 +43,8 @@ export declare class V1Builder<TConfig extends BaseV1Configuration = BaseV1Confi
|
|
|
42
43
|
withSerialization<TSerializationConfig, TSerializationContext extends Partial<RunningV1Variant.AnyContext>, TSerialized>(serializationCapability: (configuration: TSerializationConfig, getContext: () => TSerializationContext) => SerializationCapability<CoreWallet, TSerialized>): V1Builder<TConfig & TSerializationConfig, TContext & TSerializationContext, TSerialized, TSyncUpdate>;
|
|
43
44
|
withTransactingDefaults(this: V1Builder<TConfig, TContext, TSerialized, TSyncUpdate>): V1Builder<TConfig & DefaultTransactingConfiguration, TContext & DefaultTransactingContext, TSerialized, TSyncUpdate>;
|
|
44
45
|
withTransacting<TTransactingConfig, TTransactingContext extends Partial<RunningV1Variant.AnyContext>>(transactingCapability: (config: TTransactingConfig, getContext: () => TTransactingContext) => TransactingCapability<CoreWallet>): V1Builder<TConfig & TTransactingConfig, TContext & TTransactingContext, TSerialized, TSyncUpdate>;
|
|
46
|
+
withSigningDefaults(): V1Builder<TConfig, TContext, TSerialized, TSyncUpdate>;
|
|
47
|
+
withSigning<TSigningConfig, TSigningContext extends Partial<RunningV1Variant.AnyContext>>(signingService: (configuration: TSigningConfig, getContext: () => TSigningContext) => SigningService): V1Builder<TConfig & TSigningConfig, TContext & TSigningContext, TSerialized, TSyncUpdate>;
|
|
45
48
|
withCoinSelection<TCoinSelectionConfig, TCoinSelectionContext extends Partial<RunningV1Variant.AnyContext>>(coinSelection: (config: TCoinSelectionConfig, getContext: () => TCoinSelectionContext) => CoinSelection<ledger.Utxo>): V1Builder<TConfig & TCoinSelectionConfig, TContext & TCoinSelectionContext, TSerialized, TSyncUpdate>;
|
|
46
49
|
withCoinSelectionDefaults(): V1Builder<TConfig, TContext, TSerialized, TSyncUpdate>;
|
|
47
50
|
withCoinsAndBalancesDefaults(): V1Builder<TConfig, TContext, TSerialized, TSyncUpdate>;
|
|
@@ -61,6 +64,9 @@ declare namespace V1Builder {
|
|
|
61
64
|
type HasTransacting<TConfig, TContext> = {
|
|
62
65
|
readonly transactingCapability: (configuration: TConfig, getContext: () => TContext) => TransactingCapability<CoreWallet>;
|
|
63
66
|
};
|
|
67
|
+
type HasSigning<TConfig, TContext> = {
|
|
68
|
+
readonly signingService: (configuration: TConfig, getContext: () => TContext) => SigningService;
|
|
69
|
+
};
|
|
64
70
|
type HasCoinSelection<TConfig, TContext> = {
|
|
65
71
|
readonly coinSelection: (configuration: TConfig, getContext: () => TContext) => CoinSelection<ledger.Utxo>;
|
|
66
72
|
};
|
|
@@ -77,7 +83,7 @@ declare namespace V1Builder {
|
|
|
77
83
|
readonly keysCapability: (configuration: TConfig, getContext: () => TContext) => KeysCapability<CoreWallet>;
|
|
78
84
|
};
|
|
79
85
|
/** The internal build state of {@link V1Builder}. */
|
|
80
|
-
type FullBuildState<TConfig, TContext, TSerialized, TSyncUpdate> = Types.Simplify<HasSync<TConfig, TContext, TSyncUpdate> & HasSerialization<TConfig, TContext, TSerialized> & HasTransacting<TConfig, TContext> & HasCoinSelection<TConfig, TContext> & HasCoinsAndBalances<TConfig, TContext> & HasKeys<TConfig, TContext> & HasTransactionHistory<TConfig, TContext>>;
|
|
86
|
+
type FullBuildState<TConfig, TContext, TSerialized, TSyncUpdate> = Types.Simplify<HasSync<TConfig, TContext, TSyncUpdate> & HasSerialization<TConfig, TContext, TSerialized> & HasTransacting<TConfig, TContext> & HasSigning<TConfig, TContext> & HasCoinSelection<TConfig, TContext> & HasCoinsAndBalances<TConfig, TContext> & HasKeys<TConfig, TContext> & HasTransactionHistory<TConfig, TContext>>;
|
|
81
87
|
type PartialBuildState<TConfig = object, TContext = object, TSerialized = never, TSyncUpdate = never> = {
|
|
82
88
|
[K in keyof FullBuildState<never, never, never, never>]?: FullBuildState<TConfig, TContext, TSerialized, TSyncUpdate>[K] | undefined;
|
|
83
89
|
};
|
package/dist/v1/V1Builder.js
CHANGED
|
@@ -4,6 +4,7 @@ import { RunningV1Variant, V1Tag } from './RunningV1Variant.js';
|
|
|
4
4
|
import { makeDefaultV1SerializationCapability } from './Serialization.js';
|
|
5
5
|
import { makeDefaultSyncService, makeDefaultSyncCapability, } from './Sync.js';
|
|
6
6
|
import { makeDefaultTransactingCapability, } from './Transacting.js';
|
|
7
|
+
import { makeDefaultSigningService } from './Signing.js';
|
|
7
8
|
import { makeDefaultCoinsAndBalancesCapability } from './CoinsAndBalances.js';
|
|
8
9
|
import { makeDefaultKeysCapability } from './Keys.js';
|
|
9
10
|
import { chooseCoin } from '@midnightntwrk/wallet-sdk-capabilities';
|
|
@@ -22,6 +23,7 @@ export class V1Builder {
|
|
|
22
23
|
return this.withSyncDefaults()
|
|
23
24
|
.withSerializationDefaults()
|
|
24
25
|
.withTransactingDefaults()
|
|
26
|
+
.withSigningDefaults()
|
|
25
27
|
.withCoinsAndBalancesDefaults()
|
|
26
28
|
.withTransactionHistoryDefaults()
|
|
27
29
|
.withKeysDefaults()
|
|
@@ -55,6 +57,15 @@ export class V1Builder {
|
|
|
55
57
|
transactingCapability,
|
|
56
58
|
});
|
|
57
59
|
}
|
|
60
|
+
withSigningDefaults() {
|
|
61
|
+
return this.withSigning(makeDefaultSigningService);
|
|
62
|
+
}
|
|
63
|
+
withSigning(signingService) {
|
|
64
|
+
return new V1Builder({
|
|
65
|
+
...this.#buildState,
|
|
66
|
+
signingService,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
58
69
|
withCoinSelection(coinSelection) {
|
|
59
70
|
return new V1Builder({
|
|
60
71
|
...this.#buildState,
|
|
@@ -119,13 +130,14 @@ export class V1Builder {
|
|
|
119
130
|
if (!isBuildStateFull(this.#buildState)) {
|
|
120
131
|
throw new Error('Not all components are configured in V1 Builder');
|
|
121
132
|
}
|
|
122
|
-
const { syncCapability, syncService, transactingCapability, serializationCapability, coinSelection, coinsAndBalancesCapability, keysCapability, transactionHistoryService, } = this.#buildState;
|
|
133
|
+
const { syncCapability, syncService, transactingCapability, signingService, serializationCapability, coinSelection, coinsAndBalancesCapability, keysCapability, transactionHistoryService, } = this.#buildState;
|
|
123
134
|
const getContext = () => context;
|
|
124
135
|
const context = {
|
|
125
136
|
serializationCapability: serializationCapability(configuration, getContext),
|
|
126
137
|
syncCapability: syncCapability(configuration, getContext),
|
|
127
138
|
syncService: syncService(configuration, getContext),
|
|
128
139
|
transactingCapability: transactingCapability(configuration, getContext),
|
|
140
|
+
signingService: signingService(configuration, getContext),
|
|
129
141
|
coinsAndBalancesCapability: coinsAndBalancesCapability(configuration, getContext),
|
|
130
142
|
keysCapability: keysCapability(configuration, getContext),
|
|
131
143
|
coinSelection: coinSelection(configuration, getContext),
|
|
@@ -139,6 +151,7 @@ const isBuildStateFull = (buildState) => {
|
|
|
139
151
|
'syncService',
|
|
140
152
|
'syncCapability',
|
|
141
153
|
'transactingCapability',
|
|
154
|
+
'signingService',
|
|
142
155
|
'coinSelection',
|
|
143
156
|
'serializationCapability',
|
|
144
157
|
'coinsAndBalancesCapability',
|
package/dist/v1/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './V1Builder.js';
|
|
|
2
2
|
export * as Sync from './Sync.js';
|
|
3
3
|
export * as SyncProgress from './SyncProgress.js';
|
|
4
4
|
export * as Transacting from './Transacting.js';
|
|
5
|
+
export * as Signing from './Signing.js';
|
|
5
6
|
export * as TransactionHistory from './TransactionHistory.js';
|
|
6
7
|
export * as Serialization from './Serialization.js';
|
|
7
8
|
export * as CoinsAndBalances from './CoinsAndBalances.js';
|
package/dist/v1/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './V1Builder.js';
|
|
|
14
14
|
export * as Sync from './Sync.js';
|
|
15
15
|
export * as SyncProgress from './SyncProgress.js';
|
|
16
16
|
export * as Transacting from './Transacting.js';
|
|
17
|
+
export * as Signing from './Signing.js';
|
|
17
18
|
export * as TransactionHistory from './TransactionHistory.js';
|
|
18
19
|
export * as Serialization from './Serialization.js';
|
|
19
20
|
export * as CoinsAndBalances from './CoinsAndBalances.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midnightntwrk/wallet-sdk-unshielded-wallet",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@midnightntwrk/ledger-v9": "1.0.0-rc.
|
|
33
|
+
"@midnightntwrk/ledger-v9": "1.0.0-rc.3",
|
|
34
34
|
"@midnightntwrk/wallet-sdk-abstractions": "3.0.0-beta.0",
|
|
35
|
-
"@midnightntwrk/wallet-sdk-address-format": "4.0.0-beta.
|
|
36
|
-
"@midnightntwrk/wallet-sdk-capabilities": "4.0.0-beta.
|
|
35
|
+
"@midnightntwrk/wallet-sdk-address-format": "4.0.0-beta.2",
|
|
36
|
+
"@midnightntwrk/wallet-sdk-capabilities": "4.0.0-beta.2",
|
|
37
37
|
"@midnightntwrk/wallet-sdk-indexer-client": "1.3.0-beta.1",
|
|
38
38
|
"@midnightntwrk/wallet-sdk-runtime": "1.0.6-beta.0",
|
|
39
39
|
"@midnightntwrk/wallet-sdk-utilities": "1.2.0",
|