@midnight-ntwrk/wallet-sdk-node-client 1.0.0-beta.9 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # @midnight-ntwrk/wallet-sdk-node-client
2
+
3
+ Client for communicating with the Midnight blockchain node.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @midnight-ntwrk/wallet-sdk-node-client
9
+ ```
10
+
11
+ ## Overview
12
+
13
+ This package provides a client for interacting with the Midnight blockchain node using Polkadot.js APIs. It handles:
14
+
15
+ - RPC communication with the node
16
+ - Transaction submission and tracking
17
+ - Blockchain state queries
18
+ - Type-safe interactions via generated types
19
+
20
+ ## Usage
21
+
22
+ ### Basic Usage
23
+
24
+ ```typescript
25
+ import { PolkadotNodeClient, makeConfig } from '@midnight-ntwrk/wallet-sdk-node-client';
26
+
27
+ // Initialize the client
28
+ const config = makeConfig({ endpoint: 'ws://localhost:9944' });
29
+ const client = await PolkadotNodeClient.init(config);
30
+
31
+ // Submit a transaction and wait for finalization
32
+ const result = await client.sendMidnightTransactionAndWait(serializedTransaction, 'Finalized');
33
+
34
+ // Clean up
35
+ await client.close();
36
+ ```
37
+
38
+ ### Tracking Submission Events
39
+
40
+ ```typescript
41
+ // Get an observable of submission events
42
+ const events$ = client.sendMidnightTransaction(serializedTransaction);
43
+
44
+ events$.subscribe({
45
+ next: (event) => {
46
+ switch (event._tag) {
47
+ case 'Submitted':
48
+ console.log('Transaction submitted');
49
+ break;
50
+ case 'InBlock':
51
+ console.log('Transaction in block:', event.blockHash);
52
+ break;
53
+ case 'Finalized':
54
+ console.log('Transaction finalized');
55
+ break;
56
+ }
57
+ },
58
+ });
59
+ ```
60
+
61
+ ## Exports
62
+
63
+ ### Default Export
64
+
65
+ - `PolkadotNodeClient` - Main client class for node communication
66
+ - `Config` - Configuration type
67
+ - `makeConfig` - Configuration factory function
68
+ - `DEFAULT_CONFIG` - Default configuration values
69
+
70
+ ### Effect Submodule (`/effect`)
71
+
72
+ Effect.ts-based implementation for functional programming patterns:
73
+
74
+ ```typescript
75
+ import { NodeClient, PolkadotNodeClient } from '@midnight-ntwrk/wallet-sdk-node-client/effect';
76
+ ```
77
+
78
+ ### Testing Submodule (`/testing`)
79
+
80
+ Testing utilities and mocks:
81
+
82
+ ```typescript
83
+ import { ... } from '@midnight-ntwrk/wallet-sdk-node-client/testing';
84
+ ```
85
+
86
+ ## License
87
+
88
+ Apache-2.0
@@ -1,21 +1,21 @@
1
1
  import { Context, Effect, Stream } from 'effect';
2
2
  import * as SubmissionEvent from './SubmissionEvent.js';
3
3
  import * as NodeClientError from './NodeClientError.js';
4
- export type SerializedMnTransaction = Uint8Array;
4
+ import { type SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
5
5
  export type Genesis = {
6
- readonly transactions: readonly SerializedMnTransaction[];
6
+ readonly transactions: readonly SerializedTransaction.SerializedTransaction[];
7
7
  };
8
8
  export interface Service {
9
- sendMidnightTransaction(serializedTransaction: SerializedMnTransaction): Stream.Stream<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError>;
9
+ sendMidnightTransaction(serializedTransaction: SerializedTransaction.SerializedTransaction): Stream.Stream<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError>;
10
10
  getGenesis(): Effect.Effect<Genesis, NodeClientError.NodeClientError>;
11
11
  }
12
12
  declare const NodeClient_base: Context.TagClass<NodeClient, "@midnight-ntwrk/wallet-node-client#NodeClient", Service>;
13
13
  export declare class NodeClient extends NodeClient_base {
14
14
  }
15
15
  export declare const getGenesisTransactions: () => Effect.Effect<Genesis, NodeClientError.NodeClientError, NodeClient>;
16
- export declare const sendMidnightTransaction: (serializedTransaction: SerializedMnTransaction) => Stream.Stream<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError, NodeClient>;
17
- export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedMnTransaction, waitFor: SubmissionEvent.Cases.Submitted['_tag']): Effect.Effect<SubmissionEvent.Cases.Submitted, NodeClientError.NodeClientError, NodeClient>;
18
- export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedMnTransaction, waitFor: SubmissionEvent.Cases.InBlock['_tag']): Effect.Effect<SubmissionEvent.Cases.InBlock, NodeClientError.NodeClientError, NodeClient>;
19
- export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedMnTransaction, waitFor: SubmissionEvent.Cases.Finalized['_tag']): Effect.Effect<SubmissionEvent.Cases.Finalized, NodeClientError.NodeClientError, NodeClient>;
20
- export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedMnTransaction, waitFor: SubmissionEvent.SubmissionEvent['_tag']): Effect.Effect<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError, NodeClient>;
16
+ export declare const sendMidnightTransaction: (serializedTransaction: SerializedTransaction.SerializedTransaction) => Stream.Stream<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError, NodeClient>;
17
+ export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedTransaction.SerializedTransaction, waitFor: SubmissionEvent.Cases.Submitted['_tag']): Effect.Effect<SubmissionEvent.Cases.Submitted, NodeClientError.NodeClientError, NodeClient>;
18
+ export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedTransaction.SerializedTransaction, waitFor: SubmissionEvent.Cases.InBlock['_tag']): Effect.Effect<SubmissionEvent.Cases.InBlock, NodeClientError.NodeClientError, NodeClient>;
19
+ export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedTransaction.SerializedTransaction, waitFor: SubmissionEvent.Cases.Finalized['_tag']): Effect.Effect<SubmissionEvent.Cases.Finalized, NodeClientError.NodeClientError, NodeClient>;
20
+ export declare function sendMidnightTransactionAndWait(serializedTransaction: SerializedTransaction.SerializedTransaction, waitFor: SubmissionEvent.SubmissionEvent['_tag']): Effect.Effect<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError, NodeClient>;
21
21
  export {};
@@ -1,3 +1,15 @@
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.
1
13
  import { Context, Effect, Option, Stream } from 'effect';
2
14
  import * as SubmissionEvent from './SubmissionEvent.js';
3
15
  import * as NodeClientError from './NodeClientError.js';
@@ -1,10 +1,11 @@
1
- import { SubmissionEvent } from './SubmissionEvent.js';
1
+ import { type SubmissionEvent } from './SubmissionEvent.js';
2
+ import { type SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
2
3
  declare const SubmissionError_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 & {
3
4
  readonly _tag: "SubmissionError";
4
5
  } & Readonly<A>;
5
6
  export declare class SubmissionError extends SubmissionError_base<{
6
7
  message: string;
7
- txData: Uint8Array;
8
+ txData: SerializedTransaction.SerializedTransaction;
8
9
  cause?: unknown;
9
10
  }> {
10
11
  }
@@ -21,7 +22,7 @@ declare const TransactionProgressError_base: new <A extends Record<string, any>
21
22
  } & Readonly<A>;
22
23
  export declare class TransactionProgressError extends TransactionProgressError_base<{
23
24
  message: string;
24
- txData: Uint8Array;
25
+ txData: SerializedTransaction.SerializedTransaction;
25
26
  desiredStage: SubmissionEvent['_tag'];
26
27
  }> {
27
28
  }
@@ -1,3 +1,15 @@
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.
1
13
  import { Data } from 'effect';
2
14
  export class SubmissionError extends Data.TaggedError('SubmissionError') {
3
15
  }
@@ -1,9 +1,10 @@
1
1
  import '../gen/augment-api.js';
2
2
  import { ApiPromise } from '@polkadot/api';
3
- import { Duration, Effect, Layer, Scope, Stream } from 'effect';
3
+ import { Duration, Effect, Layer, type Scope, Stream } from 'effect';
4
4
  import * as NodeClient from './NodeClient.js';
5
5
  import * as SubmissionEvent from './SubmissionEvent.js';
6
6
  import * as NodeClientError from './NodeClientError.js';
7
+ import { SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
7
8
  export type Config = {
8
9
  nodeURL: URL;
9
10
  reconnectionTimeout: Duration.Duration;
@@ -22,8 +23,8 @@ export declare class PolkadotNodeClient implements NodeClient.Service {
22
23
  readonly api: ApiPromise;
23
24
  constructor(config: Config, api: ApiPromise);
24
25
  ensureConnection(): Effect.Effect<void, NodeClientError.NodeClientError>;
25
- sendMidnightTransaction(serializedTransaction: NodeClient.SerializedMnTransaction): Stream.Stream<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError>;
26
+ sendMidnightTransaction(serializedTransaction: SerializedTransaction.SerializedTransaction): Stream.Stream<SubmissionEvent.SubmissionEvent, NodeClientError.NodeClientError>;
26
27
  getGenesis(): Effect.Effect<{
27
- readonly transactions: readonly NodeClient.SerializedMnTransaction[];
28
+ readonly transactions: readonly SerializedTransaction.SerializedTransaction[];
28
29
  }, NodeClientError.NodeClientError>;
29
30
  }
@@ -1,3 +1,15 @@
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.
1
13
  import '../gen/augment-api.js';
2
14
  import { ApiPromise, WsProvider } from '@polkadot/api';
3
15
  import { Duration, Effect, Either, Layer, pipe, Schedule, Schema, Stream, } from 'effect';
@@ -6,6 +18,7 @@ import * as SubmissionEvent from './SubmissionEvent.js';
6
18
  import * as NodeClientError from './NodeClientError.js';
7
19
  import BN from 'bn.js';
8
20
  import { u8aToHex } from '@polkadot/util';
21
+ import { SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
9
22
  export const DEFAULT_CONFIG = {
10
23
  reconnectionTimeout: Duration.infinity,
11
24
  reconnectionDelay: Duration.seconds(1),
@@ -17,14 +30,22 @@ export const makeConfig = (input) => ({
17
30
  export class PolkadotNodeClient {
18
31
  static make(configInput) {
19
32
  const config = makeConfig(configInput);
20
- return Effect.acquireRelease(Effect.promise(() => ApiPromise.create({
21
- // @ts-expect-error -- exactOptionalPropertyTypes cause an incompatibility here
22
- provider: new WsProvider(config.nodeURL.toString()),
23
- throwOnConnect: false,
24
- })), (api) => Effect.promise(() => api.disconnect())).pipe(Effect.map((api) => new PolkadotNodeClient(config, api)));
33
+ return Effect.acquireRelease(Effect.promise(async () => {
34
+ const api = await ApiPromise.create({
35
+ // @ts-expect-error -- exactOptionalPropertyTypes cause an incompatibility here
36
+ provider: new WsProvider(config.nodeURL.toString()),
37
+ throwOnConnect: false,
38
+ noInitWarn: true,
39
+ });
40
+ // Disconnect immediately after loading metadata to avoid keeping the WebSocket open.
41
+ // The health-check timer (10s interval) and timeout handler (5s interval) are cleared on disconnect.
42
+ // Metadata and type registry remain cached in memory for subsequent on-demand connections.
43
+ await api.disconnect();
44
+ return api;
45
+ }), (api) => Effect.promise(() => api.disconnect())).pipe(Effect.map((api) => new PolkadotNodeClient(config, api)));
25
46
  }
26
47
  static layer(configInput) {
27
- return Layer.effect(NodeClient.NodeClient, PolkadotNodeClient.make(configInput));
48
+ return Layer.scoped(NodeClient.NodeClient, PolkadotNodeClient.make(configInput));
28
49
  }
29
50
  config;
30
51
  api;
@@ -35,7 +56,16 @@ export class PolkadotNodeClient {
35
56
  ensureConnection() {
36
57
  return pipe(Effect.promise(async () => {
37
58
  if (!this.api.isConnected) {
38
- await this.api.connect();
59
+ try {
60
+ await this.api.connect();
61
+ }
62
+ catch (error) {
63
+ // WsProvider.connect() rejects if a WebSocket already exists (connection in progress).
64
+ // This is expected when the repeat loop re-enters before the 'open' event fires.
65
+ if (!(error instanceof Error && error.message === 'WebSocket is already connected')) {
66
+ throw error;
67
+ }
68
+ }
39
69
  }
40
70
  }), Effect.andThen(Effect.sync(() => this.api.isConnected)), Effect.repeat({
41
71
  until: (value) => value,
@@ -62,20 +92,20 @@ export class PolkadotNodeClient {
62
92
  });
63
93
  return Effect.promise(callUnsubscribe);
64
94
  });
65
- return pipe(Stream.fromEffect(this.ensureConnection()), Stream.flatMap(() => outputStream));
95
+ return pipe(Stream.fromEffect(this.ensureConnection()), Stream.flatMap(() => outputStream), Stream.ensuring(Effect.promise(() => this.api.disconnect())));
66
96
  }
67
97
  getGenesis() {
68
- return Effect.promise(() => this.api.rpc.chain.getBlock(this.api.genesisHash)).pipe(Effect.map((block) => {
69
- // https://polkadot.js.org/docs/api/cookbook/blocks/#how-do-i-view-extrinsic-information
70
- return {
71
- transactions: block.block.extrinsics
72
- .filter((extrinsic) => extrinsic.method.section === 'midnight' && extrinsic.method.method === 'sendMnTransaction')
73
- .map((extrinsic) => extrinsic.method.args[0].toU8a()),
74
- };
75
- }), Effect.mapError((error) => new NodeClientError.ConnectionError({
98
+ return pipe(this.ensureConnection(), Effect.andThen(() => Effect.promise(() => this.api.rpc.chain.getBlock(this.api.genesisHash))),
99
+ // https://polkadot.js.org/docs/api/cookbook/blocks/#how-do-i-view-extrinsic-information
100
+ Effect.map(({ block }) => ({
101
+ transactions: block.extrinsics
102
+ .filter(({ method }) => method.section === 'midnight' && method.method === 'sendMnTransaction')
103
+ .map(({ method }) => method.args[0].toU8a())
104
+ .map(SerializedTransaction.of),
105
+ })), Effect.mapError((error) => new NodeClientError.ConnectionError({
76
106
  message: 'Failed to retrieve genesis transactions',
77
107
  cause: error,
78
- })));
108
+ })), Effect.ensuring(Effect.promise(() => this.api.disconnect())));
79
109
  }
80
110
  #handleSubmissionResult = (serializedTransaction, emit, unsubscribe) => {
81
111
  const WithBNBlockNumber = Schema.Struct({
@@ -1,5 +1,5 @@
1
1
  import { Data } from 'effect';
2
- import { SerializedMnTransaction } from './NodeClient.js';
2
+ import { type SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
3
  export type HexString = string;
4
4
  export type SubmissionEvent = Cases.Submitted | Cases.InBlock | Cases.Finalized;
5
5
  export declare const Submitted: Data.Case.Constructor<Cases.Submitted, "_tag">, InBlock: Data.Case.Constructor<Cases.InBlock, "_tag">, Finalized: Data.Case.Constructor<Cases.Finalized, "_tag">, match: {
@@ -23,21 +23,21 @@ export declare const Submitted: Data.Case.Constructor<Cases.Submitted, "_tag">,
23
23
  export declare namespace Cases {
24
24
  type Submitted = {
25
25
  _tag: 'Submitted';
26
- tx: SerializedMnTransaction;
26
+ tx: SerializedTransaction.SerializedTransaction;
27
27
  txHash: HexString;
28
28
  };
29
29
  type InBlock = {
30
30
  _tag: 'InBlock';
31
31
  blockHash: HexString;
32
32
  blockHeight: bigint;
33
- tx: SerializedMnTransaction;
33
+ tx: SerializedTransaction.SerializedTransaction;
34
34
  txHash: HexString;
35
35
  };
36
36
  type Finalized = {
37
37
  _tag: 'Finalized';
38
38
  blockHash: HexString;
39
39
  blockHeight: bigint;
40
- tx: SerializedMnTransaction;
40
+ tx: SerializedTransaction.SerializedTransaction;
41
41
  txHash: HexString;
42
42
  };
43
43
  }
@@ -1,2 +1,14 @@
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.
1
13
  import { Data } from 'effect';
2
14
  export const { Submitted, InBlock, Finalized, $match: match, $is: is } = Data.taggedEnum();
@@ -1,3 +1,15 @@
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.
1
13
  export * as NodeClient from './NodeClient.js';
2
14
  export * from './PolkadotNodeClient.js';
3
15
  export * as SubmissionEvent from './SubmissionEvent.js';
@@ -1,3 +1,15 @@
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.
1
13
  /* eslint-disable */
2
14
  /**
3
15
  * Auto-generated with scripts/generate-types.ts
@@ -1,3 +1,15 @@
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.
1
13
  /* eslint-disable */
2
14
  /**
3
15
  * Auto-generated with scripts/generate-types.ts
@@ -1,3 +1,15 @@
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.
1
13
  /* eslint-disable */
2
14
  /**
3
15
  * Auto-generated with scripts/generate-types.ts
@@ -1,3 +1,15 @@
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.
1
13
  /* eslint-disable */
2
14
  /**
3
15
  * Auto-generated with scripts/generate-types.ts
package/dist/index.d.ts CHANGED
@@ -1,13 +1,14 @@
1
- import { NodeClient, SubmissionEvent, Config } from './effect/index.js';
2
- import { Observable } from '@polkadot/types/types';
1
+ import { type SubmissionEvent, type Config } from './effect/index.js';
2
+ import { type Observable } from '@polkadot/types/types';
3
+ import { type SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
3
4
  export { Config, makeConfig, DEFAULT_CONFIG } from './effect/PolkadotNodeClient.js';
4
5
  export declare class PolkadotNodeClient {
5
6
  #private;
6
7
  static init(config: Config): Promise<PolkadotNodeClient>;
7
8
  private constructor();
8
- sendMidnightTransaction(serializedTransaction: NodeClient.SerializedMnTransaction): Observable<SubmissionEvent.SubmissionEvent>;
9
- sendMidnightTransactionAndWait(serializedTransaction: NodeClient.SerializedMnTransaction, waitFor: SubmissionEvent.Cases.Submitted['_tag']): Promise<SubmissionEvent.Cases.Submitted>;
10
- sendMidnightTransactionAndWait(serializedTransaction: NodeClient.SerializedMnTransaction, waitFor: SubmissionEvent.Cases.InBlock['_tag']): Promise<SubmissionEvent.Cases.InBlock>;
11
- sendMidnightTransactionAndWait(serializedTransaction: NodeClient.SerializedMnTransaction, waitFor: SubmissionEvent.Cases.Finalized['_tag']): Promise<SubmissionEvent.Cases.Finalized>;
9
+ sendMidnightTransaction(serializedTransaction: SerializedTransaction.SerializedTransaction): Observable<SubmissionEvent.SubmissionEvent>;
10
+ sendMidnightTransactionAndWait(serializedTransaction: SerializedTransaction.SerializedTransaction, waitFor: SubmissionEvent.Cases.Submitted['_tag']): Promise<SubmissionEvent.Cases.Submitted>;
11
+ sendMidnightTransactionAndWait(serializedTransaction: SerializedTransaction.SerializedTransaction, waitFor: SubmissionEvent.Cases.InBlock['_tag']): Promise<SubmissionEvent.Cases.InBlock>;
12
+ sendMidnightTransactionAndWait(serializedTransaction: SerializedTransaction.SerializedTransaction, waitFor: SubmissionEvent.Cases.Finalized['_tag']): Promise<SubmissionEvent.Cases.Finalized>;
12
13
  close(): Promise<void>;
13
14
  }
package/dist/index.js CHANGED
@@ -1,3 +1,15 @@
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.
1
13
  import { NodeClient, PolkadotNodeClient as EffectNodeClient, } from './effect/index.js';
2
14
  import { Effect, Exit, pipe, Scope } from 'effect';
3
15
  import { ObservableOps } from '@midnight-ntwrk/wallet-sdk-utilities';
@@ -1 +1,13 @@
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.
1
13
  export * as TestTransactions from './test-transactions.js';
@@ -1,3 +1,15 @@
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.
1
13
  import { Encoding } from 'effect';
2
14
  export function normalizeTxs(tx) {
3
15
  const normalizedTxs = {
@@ -1,11 +1,17 @@
1
- import { Error, FileSystem } from '@effect/platform';
2
- import * as ledger from '@midnight-ntwrk/ledger-v6';
1
+ import { type Error, FileSystem } from '@effect/platform';
2
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
3
3
  import { SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
4
4
  import { ProverClient } from '@midnight-ntwrk/wallet-sdk-prover-client/effect';
5
- import { ClientError, ServerError } from '@midnight-ntwrk/wallet-sdk-utilities/networking';
6
- import { Effect, ParseResult, Schema, Stream } from 'effect';
7
- import { Scope } from 'effect/Scope';
8
- import { StartedNetwork } from 'testcontainers';
5
+ import { type ClientError, type ServerError } from '@midnight-ntwrk/wallet-sdk-utilities/networking';
6
+ import { Effect, DateTime, ParseResult, Schema, Stream, Option } from 'effect';
7
+ import { type Scope } from 'effect/Scope';
8
+ import { type StartedNetwork, type StartedTestContainer } from 'testcontainers';
9
+ export type Paths = {
10
+ readonly outputPath: string;
11
+ readonly fileName: string;
12
+ readonly fullPath: string;
13
+ };
14
+ export declare const defaultPaths: Paths;
9
15
  export type FinalizedTransaction = ledger.Transaction<ledger.SignatureEnabled, ledger.Proof, ledger.Binding>;
10
16
  declare const TestTransactionsSchema: Schema.Struct<{
11
17
  initial_tx: Schema.Schema<FinalizedTransaction, string, never>;
@@ -15,6 +21,13 @@ declare const TestTransactionsSchema: Schema.Struct<{
15
21
  export type TestTransactions = Schema.Schema.Type<typeof TestTransactionsSchema>;
16
22
  export declare const load: (file: string) => Effect.Effect<TestTransactions, ParseResult.ParseError | Error.PlatformError, FileSystem.FileSystem>;
17
23
  export declare const streamAllValid: (txs: TestTransactions) => Stream.Stream<FinalizedTransaction>;
18
- export declare const genUnbalancedTx: () => Effect.Effect<SerializedTransaction, ClientError | ServerError, ProverClient.ProverClient>;
19
- export declare const generateTestTransactions: (nodeUrl: string, proofServerUrl: string, network: StartedNetwork, outputPath: string, fileName: string) => Effect.Effect<void, Error | Error.PlatformError, FileSystem.FileSystem | Scope>;
24
+ export declare const getTTL: (txs: TestTransactions) => Effect.Effect<Option.Option<DateTime.Utc>, never, never>;
25
+ export declare const genUnbalancedTx: () => Effect.Effect<SerializedTransaction.SerializedTransaction, ClientError | ServerError, ProverClient.ProverClient>;
26
+ type TestTransactionsEnvironment = {
27
+ nodeContainer: StartedTestContainer;
28
+ hostProofServerContainer: StartedTestContainer;
29
+ networkProofServerContainer: StartedTestContainer;
30
+ network: StartedNetwork;
31
+ };
32
+ export declare const generateTestTransactions: (environment: TestTransactionsEnvironment, paths: Paths) => Effect.Effect<void, Error | Error.PlatformError, FileSystem.FileSystem | Scope>;
20
33
  export {};
@@ -1,10 +1,35 @@
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.
1
13
  import { FileSystem } from '@effect/platform';
2
- import * as ledger from '@midnight-ntwrk/ledger-v6';
14
+ import * as ledger from '@midnight-ntwrk/ledger-v7';
3
15
  import { SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
4
16
  import { HttpProverClient, ProverClient } from '@midnight-ntwrk/wallet-sdk-prover-client/effect';
5
17
  import { TestContainers } from '@midnight-ntwrk/wallet-sdk-utilities/testing';
6
- import { Effect, Encoding, ParseResult, pipe, Random, Schema, Stream } from 'effect';
18
+ import { Duration, Effect, Encoding, DateTime, ParseResult, pipe, Random, Schema, Stream, Option } from 'effect';
19
+ import { Wait } from 'testcontainers';
7
20
  import { normalizeTxs } from './normalize-txs.js';
21
+ import * as tar from 'tar-stream';
22
+ import * as path from 'node:path';
23
+ const Paths = {
24
+ make: (outputPath, fileName) => {
25
+ return {
26
+ outputPath,
27
+ fileName,
28
+ fullPath: path.resolve(outputPath, fileName),
29
+ };
30
+ },
31
+ };
32
+ export const defaultPaths = pipe(path.dirname(new URL(import.meta.url).pathname), (currentDir) => path.resolve(currentDir, '..', '..', 'temp-resources'), (outputPath) => Paths.make(outputPath, 'test-txs.json'));
8
33
  const TxSchema = Schema.declare((input) => input instanceof ledger.Transaction).annotations({
9
34
  identifier: 'ledger.Transaction',
10
35
  });
@@ -30,6 +55,12 @@ export const streamAllValid = (txs) => {
30
55
  const batches = Stream.fromIterable(txs.batches);
31
56
  return Stream.concat(initial, batches);
32
57
  };
58
+ export const getTTL = (txs) => {
59
+ return streamAllValid(txs).pipe(Stream.mapConcat((tx) => tx.intents ?? []), Stream.map(([_, intent]) => intent.ttl), Stream.mapConcat((ttl) => pipe(ttl, DateTime.make, Option.toArray)), Stream.runFold(Option.none(), (acc, ttl) => Option.match(acc, {
60
+ onNone: () => Option.some(ttl),
61
+ onSome: (accValue) => Option.some(DateTime.min(accValue, ttl)),
62
+ })));
63
+ };
33
64
  export const genUnbalancedTx = () => Effect.Do.pipe(Effect.bind('value', () => Random.nextIntBetween(1, 100_000_000).pipe(Effect.map((nr) => BigInt(nr)))), Effect.bind('shieldedTokenType', () => Effect.succeed(ledger.shieldedToken())), Effect.let('unprovenTx', ({ value, shieldedTokenType }) => {
34
65
  const recipient = ledger.ZswapSecretKeys.fromSeed(new Uint8Array(32).fill(0));
35
66
  const coin = ledger.createShieldedCoinInfo(shieldedTokenType.raw, value);
@@ -38,8 +69,8 @@ export const genUnbalancedTx = () => Effect.Do.pipe(Effect.bind('value', () => R
38
69
  return ledger.Transaction.fromParts('undeployed', unprovenOffer);
39
70
  }), Effect.flatMap(({ unprovenTx }) => Effect.gen(function* () {
40
71
  const proverClient = yield* ProverClient.ProverClient;
41
- const provedTx = yield* proverClient.proveTransaction(unprovenTx, ledger.CostModel.initialCostModel());
42
- return SerializedTransaction(provedTx.bind().serialize());
72
+ const provenTx = yield* proverClient.proveTransaction(unprovenTx, ledger.CostModel.initialCostModel());
73
+ return SerializedTransaction.from(provenTx.bind());
43
74
  })));
44
75
  const normalizeAndSaveUnbalancedTx = (txsPath, tx) => {
45
76
  /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */
@@ -61,16 +92,31 @@ const generateUnbalancedTransaction = (proofServerUrl) => {
61
92
  url: new URL(proofServerUrl),
62
93
  })));
63
94
  };
64
- export const generateTestTransactions = (nodeUrl, proofServerUrl, network, outputPath, fileName) => Effect.gen(function* () {
65
- const [, unbalancedTx] = yield* Effect.all([
95
+ export const generateTestTransactions = (environment, paths) => Effect.gen(function* () {
96
+ const fs = yield* FileSystem.FileSystem;
97
+ const [startedContainer, unbalancedTx] = yield* Effect.all([
66
98
  TestContainers.runTxGenerator({
67
- nodeUrl: nodeUrl,
68
- destPath: outputPath,
69
- fileName: fileName,
99
+ nodeUrl: `ws://${environment.nodeContainer.getHostname()}:9944`,
100
+ proofServerUrl: `http://${environment.networkProofServerContainer.getHostname()}:6300`,
101
+ destPath: paths.outputPath,
102
+ fileName: paths.fileName,
70
103
  txsPerBatch: 1,
71
104
  batches: 1,
72
- }, (c) => c.withNetwork(network)),
73
- generateUnbalancedTransaction(proofServerUrl),
74
- ]);
75
- yield* normalizeAndSaveUnbalancedTx(`${outputPath}/${fileName}`, unbalancedTx);
105
+ }, (c) => c.withNetwork(environment.network).withWaitStrategy(Wait.forLogMessage('generated transactions'))),
106
+ generateUnbalancedTransaction(`http://localhost:${environment.hostProofServerContainer.getMappedPort(6300)}`),
107
+ ], { concurrency: 'unbounded' });
108
+ yield* Effect.sleep(Duration.seconds(1));
109
+ const stoppedContainer = yield* Effect.promise(() => startedContainer.stop({ remove: false }));
110
+ yield* Effect.log('copying archive from container');
111
+ yield* Effect.promise(() => stoppedContainer.copyArchiveFromContainer(`/tmp/${paths.fileName}`)).pipe(Effect.flatMap((stream) => pipe(stream, (s) => s.pipe(tar.extract()), (s) => Stream.fromAsyncIterable(s, (error) => error), Stream.tapBoth({
112
+ onSuccess: (entry) => Effect.log('entry after extract', entry),
113
+ onFailure: (error) => Effect.log(error),
114
+ }), Stream.tapBoth({
115
+ onSuccess: (entry) => Effect.log('entry', entry),
116
+ onFailure: (error) => Effect.log(error),
117
+ }), Stream.mapEffect((entry) => Stream.fromAsyncIterable(entry, (error) => error).pipe(Stream.tapBoth({
118
+ onSuccess: (chunk) => Effect.log('chunk', chunk),
119
+ onFailure: (error) => Effect.log(error),
120
+ }), Stream.run(fs.sink(paths.fullPath)))), Stream.runDrain, Effect.andThen(Effect.log('done')))));
121
+ yield* normalizeAndSaveUnbalancedTx(paths.fullPath, unbalancedTx);
76
122
  });
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@midnight-ntwrk/wallet-sdk-node-client",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
- "author": "IOHK",
7
+ "author": "Midnight Foundation",
8
8
  "license": "Apache-2.0",
9
9
  "publishConfig": {
10
10
  "registry": "https://npm.pkg.github.com/"
@@ -31,51 +31,38 @@
31
31
  }
32
32
  },
33
33
  "dependencies": {
34
- "@polkadot/api": "^16.3.1",
35
- "@polkadot/api-augment": "^16.3.1",
36
- "@polkadot/api-base": "^16.3.1",
37
- "@polkadot/rpc-augment": "^16.3.1",
38
- "@polkadot/rpc-core": "^16.3.1",
39
- "@polkadot/types": "^16.3.1",
40
- "@polkadot/types-augment": "^16.3.1",
41
- "@polkadot/types-codec": "^16.3.1",
42
- "@polkadot/types-known": "^16.3.1",
43
- "@polkadot/types-support": "^16.3.1",
34
+ "@midnight-ntwrk/wallet-sdk-abstractions": "2.0.0",
35
+ "@midnight-ntwrk/wallet-sdk-utilities": "1.0.1",
36
+ "@polkadot/api": "^16.5.4",
37
+ "@polkadot/types": "^16.5.4",
38
+ "@polkadot/util": "^14.0.1",
44
39
  "@types/bn.js": "^5.2.0",
45
- "bn.js": "^5.2.2",
46
- "effect": "^3.17.3",
47
- "rxjs": "^7.5",
48
- "testcontainers": "^11.4.0"
40
+ "bn.js": "^5.2.3",
41
+ "effect": "^3.19.19"
49
42
  },
50
43
  "devDependencies": {
51
- "@effect/cluster": "^0.46.2",
52
- "@effect/experimental": "^0.54.2",
53
- "@effect/platform": "^0.90.0",
54
- "@effect/platform-node": "^0.94.0",
55
- "@effect/rpc": "^0.68.0",
56
- "@effect/sql": "^0.44.0",
57
- "@effect/workflow": "^0.8.1",
58
- "@midnight-ntwrk/ledger-v6": "6.1.0-alpha.5",
59
- "@midnight-ntwrk/wallet-sdk-abstractions": "1.0.0-beta.8",
60
- "@midnight-ntwrk/wallet-sdk-prover-client": "1.0.0-beta.8",
61
- "@midnight-ntwrk/wallet-sdk-utilities": "1.0.0-beta.7",
62
- "@polkadot/typegen": "^16.3.1",
63
- "@types/yargs": "^17.0.33",
64
- "eslint": "^9.37.0",
65
- "publint": "~0.3.14",
66
- "rimraf": "^6.0.1",
67
- "tsx": "^4.20.4",
68
- "typescript": "^5.9.3",
69
- "vitest": "^3.2.4",
70
- "yargs": "^18.0.0"
44
+ "@effect/cluster": "^0.56.4",
45
+ "@effect/experimental": "^0.58.0",
46
+ "@effect/platform": "^0.94.5",
47
+ "@effect/platform-node": "^0.104.1",
48
+ "@effect/rpc": "^0.73.2",
49
+ "@effect/sql": "^0.49.0",
50
+ "@effect/workflow": "^0.16.0",
51
+ "@midnight-ntwrk/ledger-v7": "^7.0.2",
52
+ "@midnight-ntwrk/wallet-sdk-prover-client": "1.1.0",
53
+ "@types/tar-stream": "^3.1.4",
54
+ "tar-stream": "^3.1.7",
55
+ "tsx": "^4.21.0"
71
56
  },
72
57
  "scripts": {
73
58
  "typecheck-script": "tsc -b ./tsconfig.script.json --noEmit",
74
59
  "polkadot-typegen": "tsx ./scripts/generate-types.ts",
75
- "typecheck": "tsc -b ./tsconfig.json --noEmit",
76
- "test": "vitest run",
60
+ "gen-test-tx": "DEBUG='testcontainers:containers' tsx ./scripts/generate-test-tx.ts",
61
+ "typecheck": "tsc -b ./tsconfig.json --noEmit --force",
62
+ "test": "DEBUG='testcontainers:containers' vitest run",
77
63
  "lint": "eslint --max-warnings 0",
78
- "format": "prettier --write \"**/*.{ts,js,json,yaml,yml}\"",
64
+ "format": "prettier --write \"**/*.{ts,js,json,yaml,yml,md}\"",
65
+ "format:check": "prettier --check \"**/*.{ts,js,json,yaml,yml,md}\"",
79
66
  "dist": "tsc -b ./tsconfig.build.json",
80
67
  "dist:publish": "tsc -b ./tsconfig.publish.json",
81
68
  "clean": "rimraf --glob dist 'tsconfig.*.tsbuildinfo' && date +%s > .clean-timestamp",