@midnight-ntwrk/wallet-sdk-unshielded-wallet 1.0.0-beta.13 → 1.0.0-beta.14
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 +3 -7
- package/dist/KeyStore.js +2 -2
- package/dist/UnshieldedWallet.d.ts +57 -0
- package/dist/UnshieldedWallet.js +120 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -2
- package/dist/{tx-history-storage → storage}/InMemoryTransactionHistoryStorage.d.ts +3 -7
- package/dist/{tx-history-storage → storage}/TransactionHistoryStorage.d.ts +3 -7
- package/dist/{tx-history-storage → storage}/TransactionHistoryStorage.js +3 -7
- package/dist/{tx-history-storage → storage}/index.d.ts +1 -0
- package/dist/{tx-history-storage → storage}/index.js +1 -0
- package/dist/v1/CoinsAndBalances.d.ts +13 -0
- package/dist/v1/CoinsAndBalances.js +36 -0
- package/dist/v1/CoreWallet.d.ts +24 -0
- package/dist/v1/CoreWallet.js +60 -0
- package/dist/v1/Keys.d.ts +8 -0
- package/dist/v1/Keys.js +23 -0
- package/dist/v1/RunningV1Variant.d.ts +41 -0
- package/dist/v1/RunningV1Variant.js +91 -0
- package/dist/v1/Serialization.d.ts +12 -0
- package/dist/v1/Serialization.js +64 -0
- package/dist/v1/Simulator.d.ts +22 -0
- package/dist/v1/Simulator.js +102 -0
- package/dist/v1/Sync.d.ts +32 -0
- package/dist/v1/Sync.js +85 -0
- package/dist/v1/SyncProgress.d.ts +18 -0
- package/dist/v1/SyncProgress.js +23 -0
- package/dist/v1/SyncSchema.d.ts +449 -0
- package/dist/v1/SyncSchema.js +123 -0
- package/dist/v1/Transacting.d.ts +45 -0
- package/dist/v1/Transacting.js +252 -0
- package/dist/v1/Transaction.d.ts +25 -0
- package/dist/v1/Transaction.js +155 -0
- package/dist/v1/TransactionHistory.d.ts +12 -0
- package/dist/v1/TransactionHistory.js +29 -0
- package/dist/v1/TransactionImbalances.d.ts +8 -0
- package/dist/v1/TransactionImbalances.js +21 -0
- package/dist/v1/UnshieldedState.d.ts +37 -0
- package/dist/v1/UnshieldedState.js +67 -0
- package/dist/v1/V1Builder.d.ts +97 -0
- package/dist/v1/V1Builder.js +160 -0
- package/dist/v1/WalletError.d.ts +89 -0
- package/dist/v1/WalletError.js +53 -0
- package/dist/v1/index.d.ts +15 -0
- package/dist/v1/index.js +27 -0
- package/package.json +4 -4
- package/dist/State.d.ts +0 -21
- package/dist/State.js +0 -43
- package/dist/SyncService.d.ts +0 -55
- package/dist/SyncService.js +0 -88
- package/dist/TransactionHistoryService.d.ts +0 -31
- package/dist/TransactionHistoryService.js +0 -49
- package/dist/TransactionService.d.ts +0 -43
- package/dist/TransactionService.js +0 -291
- package/dist/WalletBuilder.d.ts +0 -37
- package/dist/WalletBuilder.js +0 -137
- /package/dist/{tx-history-storage → storage}/InMemoryTransactionHistoryStorage.js +0 -0
- /package/dist/{tx-history-storage → storage}/NoOpTransactionHistoryStorage.d.ts +0 -0
- /package/dist/{tx-history-storage → storage}/NoOpTransactionHistoryStorage.js +0 -0
package/dist/SyncService.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
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, Layer, Context, Stream, pipe, Schema, Data } from 'effect';
|
|
14
|
-
import { UnshieldedTransactions } from '@midnight-ntwrk/wallet-sdk-indexer-client';
|
|
15
|
-
import { UnshieldedTransactionSchema } from '@midnight-ntwrk/wallet-sdk-unshielded-state';
|
|
16
|
-
import { WsSubscriptionClient } from '@midnight-ntwrk/wallet-sdk-indexer-client/effect';
|
|
17
|
-
const TransactionSchema = Schema.Struct({
|
|
18
|
-
type: Schema.Literal('UnshieldedTransaction'),
|
|
19
|
-
transaction: UnshieldedTransactionSchema,
|
|
20
|
-
});
|
|
21
|
-
const ProgressSchema = Schema.Struct({
|
|
22
|
-
type: Schema.Literal('UnshieldedTransactionsProgress'),
|
|
23
|
-
highestTransactionId: Schema.Number,
|
|
24
|
-
});
|
|
25
|
-
export const UnshieldedUpdateSchema = Schema.Union(TransactionSchema, ProgressSchema);
|
|
26
|
-
const UnshieldedUpdateDecoder = Schema.decodeUnknown(UnshieldedUpdateSchema);
|
|
27
|
-
export class SyncServiceError extends Data.TaggedError('SyncServiceError') {
|
|
28
|
-
}
|
|
29
|
-
export class SyncService extends Context.Tag('@midnight-ntwrk/wallet-sdk-unshielded-wallet/SyncService')() {
|
|
30
|
-
static LiveWithIndexer = (indexerUrl) => {
|
|
31
|
-
const make = Effect.gen(function* () {
|
|
32
|
-
const indexerClient = yield* UnshieldedTransactions;
|
|
33
|
-
const startSync = (address, transactionId) => pipe(indexerClient({ address, transactionId }), Stream.provideLayer(WsSubscriptionClient.layer({ url: indexerUrl })), Stream.mapEffect((message) => {
|
|
34
|
-
const { type } = message.unshieldedTransactions;
|
|
35
|
-
if (type === 'UnshieldedTransactionsProgress') {
|
|
36
|
-
return UnshieldedUpdateDecoder({
|
|
37
|
-
type,
|
|
38
|
-
highestTransactionId: message.unshieldedTransactions.highestTransactionId,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
const { transaction, createdUtxos, spentUtxos } = message.unshieldedTransactions;
|
|
43
|
-
const isRegularTransaction = transaction.type === 'RegularTransaction';
|
|
44
|
-
const transactionResult = isRegularTransaction
|
|
45
|
-
? {
|
|
46
|
-
status: transaction.transactionResult.status,
|
|
47
|
-
segments: transaction.transactionResult.segments?.map((segment) => ({
|
|
48
|
-
id: segment.id.toString(),
|
|
49
|
-
success: segment.success,
|
|
50
|
-
})) ?? null,
|
|
51
|
-
}
|
|
52
|
-
: null;
|
|
53
|
-
return UnshieldedUpdateDecoder({
|
|
54
|
-
type,
|
|
55
|
-
transaction: {
|
|
56
|
-
type: transaction.type,
|
|
57
|
-
id: transaction.id,
|
|
58
|
-
hash: transaction.hash,
|
|
59
|
-
identifiers: isRegularTransaction ? transaction.identifiers : [],
|
|
60
|
-
protocolVersion: transaction.protocolVersion,
|
|
61
|
-
transactionResult,
|
|
62
|
-
createdUtxos: createdUtxos.map((utxo) => ({
|
|
63
|
-
value: utxo.value,
|
|
64
|
-
owner: utxo.owner,
|
|
65
|
-
type: utxo.tokenType,
|
|
66
|
-
intentHash: utxo.intentHash,
|
|
67
|
-
outputNo: utxo.outputIndex,
|
|
68
|
-
registeredForDustGeneration: utxo.registeredForDustGeneration,
|
|
69
|
-
ctime: utxo.ctime ? utxo.ctime * 1000 : undefined,
|
|
70
|
-
})),
|
|
71
|
-
spentUtxos: spentUtxos.map((utxo) => ({
|
|
72
|
-
value: utxo.value,
|
|
73
|
-
owner: utxo.owner,
|
|
74
|
-
type: utxo.tokenType,
|
|
75
|
-
intentHash: utxo.intentHash,
|
|
76
|
-
outputNo: utxo.outputIndex,
|
|
77
|
-
registeredForDustGeneration: utxo.registeredForDustGeneration,
|
|
78
|
-
ctime: utxo.ctime ? utxo.ctime * 1000 : undefined,
|
|
79
|
-
})),
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}), Stream.mapError((error) => new SyncServiceError({ error })));
|
|
84
|
-
return SyncService.of({ startSync });
|
|
85
|
-
});
|
|
86
|
-
return Layer.effect(SyncService, make);
|
|
87
|
-
};
|
|
88
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Effect, Layer, Context, Stream } from 'effect';
|
|
2
|
-
import { TransactionHash, TransactionHistoryEntry, TransactionHistoryStorage } from './tx-history-storage/index.js';
|
|
3
|
-
declare const TransactionHistoryServiceError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
4
|
-
readonly _tag: "TransactionHistoryServiceError";
|
|
5
|
-
} & Readonly<A>;
|
|
6
|
-
export declare class TransactionHistoryServiceError extends TransactionHistoryServiceError_base<{
|
|
7
|
-
readonly error?: unknown;
|
|
8
|
-
}> {
|
|
9
|
-
toString(): string;
|
|
10
|
-
}
|
|
11
|
-
export type TransactionHistoryChange = {
|
|
12
|
-
type: 'created' | 'updated' | 'deleted';
|
|
13
|
-
entry: TransactionHistoryEntry;
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* TransactionHistoryService API
|
|
17
|
-
*
|
|
18
|
-
* Extend with tx lifecycle methods when needed in the future.
|
|
19
|
-
*/
|
|
20
|
-
export interface TransactionHistoryServiceAPI {
|
|
21
|
-
create: (item: TransactionHistoryEntry) => Effect.Effect<void, TransactionHistoryServiceError>;
|
|
22
|
-
delete: (hash: TransactionHash) => Effect.Effect<void, TransactionHistoryServiceError>;
|
|
23
|
-
getAll: () => Stream.Stream<TransactionHistoryEntry, TransactionHistoryServiceError>;
|
|
24
|
-
get: (hash: TransactionHash) => Effect.Effect<TransactionHistoryEntry | undefined, TransactionHistoryServiceError>;
|
|
25
|
-
changes: Stream.Stream<TransactionHistoryChange | undefined>;
|
|
26
|
-
}
|
|
27
|
-
declare const TransactionHistoryService_base: Context.TagClass<TransactionHistoryService, "@midnight-ntwrk/wallet-sdk-unshielded-wallet/TransactionHistoryService", TransactionHistoryServiceAPI>;
|
|
28
|
-
export declare class TransactionHistoryService extends TransactionHistoryService_base {
|
|
29
|
-
static readonly Live: (storage: TransactionHistoryStorage) => Layer.Layer<TransactionHistoryService>;
|
|
30
|
-
}
|
|
31
|
-
export {};
|
|
@@ -1,49 +0,0 @@
|
|
|
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, Layer, Context, Data, SubscriptionRef, Stream } from 'effect';
|
|
14
|
-
export class TransactionHistoryServiceError extends Data.TaggedError('TransactionHistoryServiceError') {
|
|
15
|
-
toString() {
|
|
16
|
-
return `TransactionHistoryServiceError: ${this.error instanceof Error ? this.error.toString() : 'Unknown error'}`;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export class TransactionHistoryService extends Context.Tag('@midnight-ntwrk/wallet-sdk-unshielded-wallet/TransactionHistoryService')() {
|
|
20
|
-
static Live = (storage) => Layer.effect(TransactionHistoryService, Effect.gen(function* () {
|
|
21
|
-
const txHistoryRef = yield* SubscriptionRef.make(undefined);
|
|
22
|
-
return {
|
|
23
|
-
create: (entry) => Effect.tryPromise({
|
|
24
|
-
try: async () => storage.create(entry),
|
|
25
|
-
catch: (error) => new TransactionHistoryServiceError({ error }),
|
|
26
|
-
}).pipe(Effect.tap(() => SubscriptionRef.set(txHistoryRef, {
|
|
27
|
-
type: 'created',
|
|
28
|
-
entry,
|
|
29
|
-
}))),
|
|
30
|
-
delete: (hash) => Effect.tryPromise({
|
|
31
|
-
try: async () => {
|
|
32
|
-
const deletedEntry = await storage.get(hash);
|
|
33
|
-
await storage.delete(hash);
|
|
34
|
-
SubscriptionRef.set(txHistoryRef, {
|
|
35
|
-
type: 'deleted',
|
|
36
|
-
entry: deletedEntry,
|
|
37
|
-
});
|
|
38
|
-
},
|
|
39
|
-
catch: (error) => new TransactionHistoryServiceError({ error }),
|
|
40
|
-
}),
|
|
41
|
-
getAll: () => Stream.fromAsyncIterable(storage.getAll(), () => new TransactionHistoryServiceError({ error: 'Failed to get all transactions' })),
|
|
42
|
-
get: (hash) => Effect.tryPromise({
|
|
43
|
-
try: async () => await storage.get(hash),
|
|
44
|
-
catch: (error) => new TransactionHistoryServiceError({ error }),
|
|
45
|
-
}),
|
|
46
|
-
changes: txHistoryRef.changes,
|
|
47
|
-
};
|
|
48
|
-
}));
|
|
49
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Effect, Layer, Context } from 'effect';
|
|
2
|
-
import { ParseError } from 'effect/ParseResult';
|
|
3
|
-
import { UnshieldedStateAPI, UtxoNotFoundError } from '@midnight-ntwrk/wallet-sdk-unshielded-state';
|
|
4
|
-
import { Binding, PreBinding, type Bindingish, type PreProof, type Proofish, type SignatureEnabled, type Signaturish, Transaction, type RawTokenType, type UserAddress } from '@midnight-ntwrk/ledger-v6';
|
|
5
|
-
import { SignatureVerifyingKey } from '@midnight-ntwrk/ledger-v6';
|
|
6
|
-
import { NetworkId } from '@midnight-ntwrk/wallet-sdk-abstractions';
|
|
7
|
-
export type TokenTransfer = {
|
|
8
|
-
readonly amount: bigint;
|
|
9
|
-
readonly type: string;
|
|
10
|
-
readonly receiverAddress: string;
|
|
11
|
-
};
|
|
12
|
-
declare const DeserializationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
13
|
-
readonly _tag: "DeserializationError";
|
|
14
|
-
} & Readonly<A>;
|
|
15
|
-
export declare class DeserializationError extends DeserializationError_base<{
|
|
16
|
-
readonly message: string;
|
|
17
|
-
readonly internal?: unknown;
|
|
18
|
-
}> {
|
|
19
|
-
}
|
|
20
|
-
declare const TransactionServiceError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
21
|
-
readonly _tag: "TransactionServiceError";
|
|
22
|
-
} & Readonly<A>;
|
|
23
|
-
export declare class TransactionServiceError extends TransactionServiceError_base<{
|
|
24
|
-
readonly message: string;
|
|
25
|
-
readonly cause?: unknown;
|
|
26
|
-
}> {
|
|
27
|
-
}
|
|
28
|
-
export interface TransactionServiceLive {
|
|
29
|
-
readonly transferTransaction: (outputs: TokenTransfer[], ttl: Date, networkId: NetworkId.NetworkId) => Effect.Effect<Transaction<SignatureEnabled, PreProof, PreBinding>, TransactionServiceError>;
|
|
30
|
-
readonly initSwap: (desiredInputs: Record<RawTokenType, bigint>, desiredOutputs: TokenTransfer[], ttl: Date, networkId: NetworkId.NetworkId, state: UnshieldedStateAPI, myAddress: UserAddress, publicKey: SignatureVerifyingKey) => Effect.Effect<Transaction<SignatureEnabled, PreProof, PreBinding>, TransactionServiceError | ParseError | UtxoNotFoundError>;
|
|
31
|
-
readonly deserializeTransaction: <S extends Signaturish, P extends Proofish, B extends Bindingish>(markerS: S['instance'], markerP: P['instance'], markerB: B['instance'], tx: string) => Effect.Effect<Transaction<S, P, B>, DeserializationError>;
|
|
32
|
-
readonly serializeTransaction: (transaction: Transaction<Signaturish, Proofish, Bindingish>) => Effect.Effect<string, TransactionServiceError>;
|
|
33
|
-
readonly balanceTransaction: (transaction: Transaction<SignatureEnabled, Proofish, Bindingish>, state: UnshieldedStateAPI, myAddress: UserAddress, publicKey: SignatureVerifyingKey) => Effect.Effect<Transaction<SignatureEnabled, Proofish, Bindingish>, TransactionServiceError | ParseError | UtxoNotFoundError>;
|
|
34
|
-
readonly getOfferSignatureData: (transaction: Transaction<Signaturish, Proofish, Bindingish>, segment: number) => Effect.Effect<Uint8Array, TransactionServiceError>;
|
|
35
|
-
readonly addOfferSignature: <S extends Signaturish, P extends Proofish, B extends Bindingish>(transaction: Transaction<S, P, B>, signature: string, segment: number) => Effect.Effect<Transaction<S, P, B>, TransactionServiceError>;
|
|
36
|
-
readonly bindTransaction: <S extends Signaturish, P extends Proofish, B extends Bindingish>(transaction: Transaction<S, P, B>) => Effect.Effect<Transaction<S, P, Binding>, TransactionServiceError>;
|
|
37
|
-
readonly getSegments: (transaction: Transaction<Signaturish, Proofish, Bindingish>) => number[];
|
|
38
|
-
}
|
|
39
|
-
declare const TransactionService_base: Context.TagClass<TransactionService, "@midnight-ntwrk/wallet-sdk-unshielded-wallet/TransactionService", TransactionServiceLive>;
|
|
40
|
-
export declare class TransactionService extends TransactionService_base {
|
|
41
|
-
static readonly Live: Layer.Layer<TransactionService>;
|
|
42
|
-
}
|
|
43
|
-
export {};
|
|
@@ -1,291 +0,0 @@
|
|
|
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
|
-
/* temporarily disable eslint until we upgrade to ledger 6 */
|
|
14
|
-
import { Effect, Layer, Context, Data, HashSet, pipe, Option, Either } from 'effect';
|
|
15
|
-
import { getBalanceRecipe, Imbalances } from '@midnight-ntwrk/wallet-sdk-capabilities';
|
|
16
|
-
import { Binding, Transaction, Intent, UnshieldedOffer, } from '@midnight-ntwrk/ledger-v6';
|
|
17
|
-
export class DeserializationError extends Data.TaggedError('DeserializationError') {
|
|
18
|
-
}
|
|
19
|
-
export class TransactionServiceError extends Data.TaggedError('TransactionServiceError') {
|
|
20
|
-
}
|
|
21
|
-
const GUARANTEED_SEGMENT = 0;
|
|
22
|
-
const ledgerTry = (fn) => {
|
|
23
|
-
return Either.try({
|
|
24
|
-
try: fn,
|
|
25
|
-
catch: (error) => {
|
|
26
|
-
// eslint-disable-next-line no-console
|
|
27
|
-
console.log('Error from ledger', error);
|
|
28
|
-
const message = error instanceof Error ? error.message : `${error?.toString()}`;
|
|
29
|
-
return new TransactionServiceError({ message: `Error from ledger: ${message}`, cause: error });
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
const isIntentBound = (intent) => {
|
|
34
|
-
return ledgerTry(() => intent.binding instanceof Binding);
|
|
35
|
-
};
|
|
36
|
-
const mergeCounterOffer = (counterOffer, currentOffer) => pipe(Option.fromNullable(currentOffer), Option.match({
|
|
37
|
-
onNone: () => Either.right(counterOffer),
|
|
38
|
-
onSome: (currentOffer) => ledgerTry(() => UnshieldedOffer.new([...currentOffer.inputs, ...counterOffer.inputs], [...currentOffer.outputs, ...counterOffer.outputs], [...currentOffer.signatures, ...counterOffer.signatures])),
|
|
39
|
-
}));
|
|
40
|
-
export class TransactionService extends Context.Tag('@midnight-ntwrk/wallet-sdk-unshielded-wallet/TransactionService')() {
|
|
41
|
-
static Live = Layer.succeed(TransactionService, (() => {
|
|
42
|
-
const transferTransaction = (desiredOutputs, ttl, networkId) => Effect.gen(function* () {
|
|
43
|
-
const isValid = desiredOutputs.every((output) => output.amount > 0n);
|
|
44
|
-
if (!isValid) {
|
|
45
|
-
return yield* Effect.fail(new TransactionServiceError({ message: 'The amount needs to be positive' }));
|
|
46
|
-
}
|
|
47
|
-
const ledgerOutputs = desiredOutputs.map((output) => {
|
|
48
|
-
return {
|
|
49
|
-
value: output.amount,
|
|
50
|
-
owner: output.receiverAddress,
|
|
51
|
-
type: output.type,
|
|
52
|
-
};
|
|
53
|
-
});
|
|
54
|
-
return yield* ledgerTry(() => {
|
|
55
|
-
const intent = Intent.new(ttl);
|
|
56
|
-
intent.guaranteedUnshieldedOffer = UnshieldedOffer.new([], ledgerOutputs, []);
|
|
57
|
-
return Transaction.fromParts(networkId, undefined, undefined, intent);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
const initSwap = (desiredInputs, desiredOutputs, ttl, networkId, state, myAddress, publicKey) => Effect.gen(function* () {
|
|
61
|
-
const outputsValid = desiredOutputs.every((output) => output.amount > 0n);
|
|
62
|
-
if (!outputsValid) {
|
|
63
|
-
return yield* Effect.fail(new TransactionServiceError({ message: 'The amount needs to be positive' }));
|
|
64
|
-
}
|
|
65
|
-
const inputsValid = Object.entries(desiredInputs).every(([, amount]) => amount > 0n);
|
|
66
|
-
if (!inputsValid) {
|
|
67
|
-
return yield* Effect.fail(new TransactionServiceError({ message: 'The input amounts need to be positive' }));
|
|
68
|
-
}
|
|
69
|
-
const ledgerOutputs = desiredOutputs.map((output) => ({
|
|
70
|
-
value: output.amount,
|
|
71
|
-
owner: output.receiverAddress,
|
|
72
|
-
type: output.type,
|
|
73
|
-
}));
|
|
74
|
-
const targetImbalances = Imbalances.fromEntries(Object.entries(desiredInputs));
|
|
75
|
-
const latestState = yield* state.getLatestState();
|
|
76
|
-
const availableCoins = HashSet.toValues(latestState.utxos);
|
|
77
|
-
const { inputs, outputs: changeOutputs } = yield* Effect.try({
|
|
78
|
-
try: () => getBalanceRecipe({
|
|
79
|
-
coins: availableCoins,
|
|
80
|
-
initialImbalances: Imbalances.empty(),
|
|
81
|
-
feeTokenType: '',
|
|
82
|
-
transactionCostModel: {
|
|
83
|
-
inputFeeOverhead: 0n,
|
|
84
|
-
outputFeeOverhead: 0n,
|
|
85
|
-
},
|
|
86
|
-
createOutput: (coin) => ({
|
|
87
|
-
...coin,
|
|
88
|
-
owner: myAddress,
|
|
89
|
-
}),
|
|
90
|
-
isCoinEqual: (a, b) => a.intentHash === b.intentHash && a.outputNo === b.outputNo,
|
|
91
|
-
targetImbalances,
|
|
92
|
-
}),
|
|
93
|
-
catch: (error) => {
|
|
94
|
-
const message = error instanceof Error ? error.message : error?.toString() || '';
|
|
95
|
-
return new TransactionServiceError({ message });
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
for (const input of inputs) {
|
|
99
|
-
yield* state.spend(input);
|
|
100
|
-
}
|
|
101
|
-
const ledgerInputs = inputs.map((input) => ({
|
|
102
|
-
...input,
|
|
103
|
-
owner: publicKey,
|
|
104
|
-
}));
|
|
105
|
-
const offer = yield* ledgerTry(() => UnshieldedOffer.new(ledgerInputs, [...changeOutputs, ...ledgerOutputs], []));
|
|
106
|
-
const intent = Intent.new(ttl);
|
|
107
|
-
intent.guaranteedUnshieldedOffer = offer;
|
|
108
|
-
return yield* ledgerTry(() => Transaction.fromParts(networkId, undefined, undefined, intent));
|
|
109
|
-
});
|
|
110
|
-
const deserializeTransaction = (markerS, markerP, markerB, tx) =>
|
|
111
|
-
// NOTE: ledger's deserialization error is too of a low-level and doesn't tell us what exactly was wrong
|
|
112
|
-
Effect.mapError(ledgerTry(() => {
|
|
113
|
-
const data = Buffer.from(tx, 'hex');
|
|
114
|
-
return Transaction.deserialize(markerS, markerP, markerB, data);
|
|
115
|
-
}), (e) => new DeserializationError({ message: 'Unable to deserialize transaction', internal: e.message }));
|
|
116
|
-
const serializeTransaction = (transaction) => Effect.map(ledgerTry(() => transaction.serialize()), (res) => Buffer.from(res).toString('hex'));
|
|
117
|
-
const balanceTransaction = (transaction, state, myAddress, publicKey) => Effect.gen(function* () {
|
|
118
|
-
const segments = getSegments(transaction);
|
|
119
|
-
if (!transaction.intents || !transaction.intents.size || !segments.length) {
|
|
120
|
-
return transaction;
|
|
121
|
-
}
|
|
122
|
-
for (const segment of [...segments, GUARANTEED_SEGMENT]) {
|
|
123
|
-
const allIntentImbalances = yield* ledgerTry(() => transaction.imbalances(segment));
|
|
124
|
-
const imbalances = allIntentImbalances
|
|
125
|
-
.entries()
|
|
126
|
-
.filter(([token, value]) => token.tag === 'unshielded' && value !== 0n)
|
|
127
|
-
.map(([token, value]) => {
|
|
128
|
-
return [token.raw.toString(), value];
|
|
129
|
-
})
|
|
130
|
-
.toArray();
|
|
131
|
-
// intent is balanced
|
|
132
|
-
if (!imbalances.length)
|
|
133
|
-
continue;
|
|
134
|
-
const latestState = yield* state.getLatestState();
|
|
135
|
-
const availableCoins = HashSet.toValues(latestState.utxos);
|
|
136
|
-
// select inputs, receive the change outputs
|
|
137
|
-
const { inputs, outputs: changeOutputs } = yield* Effect.try({
|
|
138
|
-
try: () => getBalanceRecipe({
|
|
139
|
-
coins: availableCoins,
|
|
140
|
-
initialImbalances: Imbalances.fromEntries(imbalances),
|
|
141
|
-
feeTokenType: '',
|
|
142
|
-
transactionCostModel: {
|
|
143
|
-
inputFeeOverhead: 0n,
|
|
144
|
-
outputFeeOverhead: 0n,
|
|
145
|
-
},
|
|
146
|
-
createOutput: (coin) => ({
|
|
147
|
-
...coin,
|
|
148
|
-
owner: myAddress,
|
|
149
|
-
}),
|
|
150
|
-
isCoinEqual: (a, b) => a.intentHash === b.intentHash && a.outputNo === b.outputNo,
|
|
151
|
-
}),
|
|
152
|
-
catch: (error) => {
|
|
153
|
-
const message = error instanceof Error ? error.message : error?.toString() || '';
|
|
154
|
-
return new TransactionServiceError({ message });
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
if (!inputs.length) {
|
|
158
|
-
return yield* Effect.fail(new TransactionServiceError({ message: 'No coins found to spend' }));
|
|
159
|
-
}
|
|
160
|
-
// mark the coins as spent
|
|
161
|
-
for (const input of inputs) {
|
|
162
|
-
yield* state.spend(input);
|
|
163
|
-
}
|
|
164
|
-
const ledgerInputs = inputs.map((input) => ({
|
|
165
|
-
...input,
|
|
166
|
-
intentHash: input.intentHash,
|
|
167
|
-
owner: publicKey,
|
|
168
|
-
}));
|
|
169
|
-
const counterOffer = yield* ledgerTry(() => UnshieldedOffer.new(ledgerInputs, changeOutputs, []));
|
|
170
|
-
// NOTE: for the segment === 0 we insert the counter-offer into any intent's guaranteed section
|
|
171
|
-
if (segment !== GUARANTEED_SEGMENT) {
|
|
172
|
-
const intent = transaction.intents.get(segment);
|
|
173
|
-
const isBound = yield* isIntentBound(intent);
|
|
174
|
-
if (!isBound && intent.fallibleUnshieldedOffer) {
|
|
175
|
-
const mergedOffer = yield* mergeCounterOffer(counterOffer, intent.fallibleUnshieldedOffer);
|
|
176
|
-
yield* ledgerTry(() => {
|
|
177
|
-
intent.fallibleUnshieldedOffer = mergedOffer;
|
|
178
|
-
transaction.intents = transaction.intents.set(segment, intent);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
// create a new offer if the intent is bound
|
|
183
|
-
yield* ledgerTry(() => {
|
|
184
|
-
const nextSegment = Math.max(...getSegments(transaction)) + 1;
|
|
185
|
-
const newIntent = Intent.new(intent.ttl);
|
|
186
|
-
newIntent.fallibleUnshieldedOffer = counterOffer;
|
|
187
|
-
transaction.intents = transaction.intents.set(nextSegment, newIntent);
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
let ttl;
|
|
193
|
-
let updated = false;
|
|
194
|
-
// try to find and modify any unbound intent first
|
|
195
|
-
const segments = getSegments(transaction);
|
|
196
|
-
for (const segment of segments) {
|
|
197
|
-
const intent = transaction.intents.get(segment);
|
|
198
|
-
ttl = intent.ttl;
|
|
199
|
-
const isBound = yield* isIntentBound(intent);
|
|
200
|
-
if (!isBound) {
|
|
201
|
-
const mergedOffer = yield* mergeCounterOffer(counterOffer, intent.guaranteedUnshieldedOffer);
|
|
202
|
-
yield* ledgerTry(() => {
|
|
203
|
-
intent.guaranteedUnshieldedOffer = mergedOffer;
|
|
204
|
-
transaction.intents = transaction.intents.set(segment, intent);
|
|
205
|
-
});
|
|
206
|
-
updated = true;
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// no unbound intents found, insert a new one
|
|
211
|
-
if (!updated) {
|
|
212
|
-
yield* ledgerTry(() => {
|
|
213
|
-
const nextSegment = Math.max(...segments) + 1;
|
|
214
|
-
const newIntent = Intent.new(ttl);
|
|
215
|
-
newIntent.guaranteedUnshieldedOffer = counterOffer;
|
|
216
|
-
transaction.intents = transaction.intents.set(nextSegment, newIntent);
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return transaction;
|
|
222
|
-
});
|
|
223
|
-
const getOfferSignatureData = (transaction, segment = 1) => {
|
|
224
|
-
if (!transaction.intents) {
|
|
225
|
-
return Effect.fail(new TransactionServiceError({ message: 'No intents found in the provided transaction' }));
|
|
226
|
-
}
|
|
227
|
-
const intent = transaction.intents.get(segment);
|
|
228
|
-
if (!intent) {
|
|
229
|
-
return Effect.fail(new TransactionServiceError({ message: 'Intent with a given segment was not found' }));
|
|
230
|
-
}
|
|
231
|
-
return pipe(ledgerTry(() => (isIntentBound(intent) ? intent : intent.bind(segment))), Effect.andThen((boundIntent) => ledgerTry(() => boundIntent.signatureData(segment))));
|
|
232
|
-
};
|
|
233
|
-
const addOfferSignature = (transaction, signature, segment = 1) => Effect.gen(function* () {
|
|
234
|
-
if (!transaction.intents || !transaction.intents.size) {
|
|
235
|
-
return yield* Effect.fail(new TransactionServiceError({ message: 'No intents found in the provided transaction' }));
|
|
236
|
-
}
|
|
237
|
-
const intent = transaction.intents.get(segment);
|
|
238
|
-
if (!intent) {
|
|
239
|
-
return yield* Effect.fail(new TransactionServiceError({ message: 'Intent with a given segment was not found' }));
|
|
240
|
-
}
|
|
241
|
-
// skip if it's locked
|
|
242
|
-
const isBound = yield* isIntentBound(intent);
|
|
243
|
-
if (isBound)
|
|
244
|
-
return transaction;
|
|
245
|
-
let updatedIntent = intent;
|
|
246
|
-
if (intent.guaranteedUnshieldedOffer) {
|
|
247
|
-
const offer = intent.guaranteedUnshieldedOffer;
|
|
248
|
-
const inputsLen = offer.inputs.length;
|
|
249
|
-
const signatures = [];
|
|
250
|
-
for (let i = 0; i < inputsLen; ++i) {
|
|
251
|
-
signatures.push(offer.signatures.at(i) ?? signature);
|
|
252
|
-
}
|
|
253
|
-
const updatedOffer = yield* ledgerTry(() => offer.addSignatures(signatures));
|
|
254
|
-
updatedIntent = yield* ledgerTry(() => {
|
|
255
|
-
updatedIntent.guaranteedUnshieldedOffer = updatedOffer;
|
|
256
|
-
return updatedIntent;
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
if (intent.fallibleUnshieldedOffer) {
|
|
260
|
-
const offer = intent.fallibleUnshieldedOffer;
|
|
261
|
-
const inputsLen = offer.inputs.length;
|
|
262
|
-
const signatures = [];
|
|
263
|
-
for (let i = 0; i < inputsLen; ++i) {
|
|
264
|
-
signatures.push(offer.signatures.at(i) ?? signature);
|
|
265
|
-
}
|
|
266
|
-
const updatedOffer = yield* ledgerTry(() => offer.addSignatures(signatures));
|
|
267
|
-
updatedIntent = yield* ledgerTry(() => {
|
|
268
|
-
updatedIntent.fallibleUnshieldedOffer = updatedOffer;
|
|
269
|
-
return updatedIntent;
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
transaction.intents = yield* ledgerTry(() => transaction.intents.set(segment, updatedIntent));
|
|
273
|
-
return transaction;
|
|
274
|
-
});
|
|
275
|
-
const bindTransaction = (transaction) => ledgerTry(() => transaction.bind());
|
|
276
|
-
const getSegments = (transaction) => {
|
|
277
|
-
return transaction.intents ? [...transaction.intents.keys()] : [];
|
|
278
|
-
};
|
|
279
|
-
return TransactionService.of({
|
|
280
|
-
transferTransaction,
|
|
281
|
-
initSwap,
|
|
282
|
-
deserializeTransaction,
|
|
283
|
-
serializeTransaction,
|
|
284
|
-
balanceTransaction,
|
|
285
|
-
getOfferSignatureData,
|
|
286
|
-
addOfferSignature,
|
|
287
|
-
bindTransaction,
|
|
288
|
-
getSegments,
|
|
289
|
-
});
|
|
290
|
-
})());
|
|
291
|
-
}
|
package/dist/WalletBuilder.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import * as ledger from '@midnight-ntwrk/ledger-v6';
|
|
2
|
-
import { NetworkId } from '@midnight-ntwrk/wallet-sdk-abstractions';
|
|
3
|
-
import { Observable } from 'rxjs';
|
|
4
|
-
import { PublicKey } from './KeyStore.js';
|
|
5
|
-
import { State } from './State.js';
|
|
6
|
-
import { TransactionHistoryChange } from './TransactionHistoryService.js';
|
|
7
|
-
import { TokenTransfer } from './TransactionService.js';
|
|
8
|
-
import { TransactionHash, TransactionHistoryEntry, TransactionHistoryStorage } from './tx-history-storage/index.js';
|
|
9
|
-
interface WalletConfig {
|
|
10
|
-
publicKey: PublicKey;
|
|
11
|
-
networkId: NetworkId.NetworkId;
|
|
12
|
-
indexerUrl: string;
|
|
13
|
-
txHistoryStorage?: TransactionHistoryStorage | undefined;
|
|
14
|
-
}
|
|
15
|
-
export interface UnshieldedWallet {
|
|
16
|
-
start(): Promise<void>;
|
|
17
|
-
stop(): Promise<void>;
|
|
18
|
-
serializeState(): Promise<string>;
|
|
19
|
-
state: () => Observable<State>;
|
|
20
|
-
transferTransaction(outputs: TokenTransfer[], ttl: Date): Promise<ledger.UnprovenTransaction>;
|
|
21
|
-
initSwap(desiredInputs: Record<string, bigint>, desiredOutputs: TokenTransfer[], ttl: Date): Promise<ledger.UnprovenTransaction>;
|
|
22
|
-
balanceTransaction(tx: ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.Bindingish>): Promise<ledger.Transaction<ledger.SignatureEnabled, ledger.Proofish, ledger.Bindingish>>;
|
|
23
|
-
signTransaction(tx: ledger.UnprovenTransaction, signSegment: (data: Uint8Array) => ledger.Signature): Promise<ledger.UnprovenTransaction>;
|
|
24
|
-
transactionHistory: undefined | {
|
|
25
|
-
get: (item: TransactionHash) => Promise<TransactionHistoryEntry | undefined>;
|
|
26
|
-
getAll: () => Observable<TransactionHistoryEntry>;
|
|
27
|
-
changes: () => Observable<TransactionHistoryChange | undefined>;
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
interface RestorableWalletConfig extends WalletConfig {
|
|
31
|
-
serializedState: string;
|
|
32
|
-
}
|
|
33
|
-
export declare class WalletBuilder {
|
|
34
|
-
static build({ publicKey, networkId, indexerUrl, txHistoryStorage }: WalletConfig): Promise<UnshieldedWallet>;
|
|
35
|
-
static restore({ publicKey, networkId, indexerUrl, serializedState, txHistoryStorage, }: RestorableWalletConfig): Promise<UnshieldedWallet>;
|
|
36
|
-
}
|
|
37
|
-
export {};
|