@partylayer/adapter-nightly 0.2.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 PartyLayer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @partylayer/adapter-nightly
2
+
3
+ <div align="center">
4
+
5
+ **Nightly Wallet adapter for PartyLayer**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@partylayer/adapter-nightly.svg?style=flat-square)](https://www.npmjs.com/package/@partylayer/adapter-nightly)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
9
+
10
+ </div>
11
+
12
+ ---
13
+
14
+ ## Overview
15
+
16
+ Adapter for the [Nightly Wallet](https://nightly.app/), a multichain wallet with Canton Network support. The wallet injects at `window.nightly.canton` and uses a callback-based signing interface.
17
+
18
+ > **Note**: This adapter is included in `@partylayer/sdk` by default. You only need to install it separately if building a custom setup.
19
+
20
+ ---
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @partylayer/adapter-nightly
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Usage with SDK
31
+
32
+ ```typescript
33
+ import { createPartyLayer } from '@partylayer/sdk';
34
+
35
+ const client = createPartyLayer({ network: 'devnet' });
36
+ await client.connect({ walletId: 'nightly' });
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Links
42
+
43
+ - [GitHub Repository](https://github.com/PartyLayer/PartyLayer)
44
+ - [Nightly Wallet](https://nightly.app/)
45
+ - [Report Issues](https://github.com/PartyLayer/PartyLayer/issues)
46
+
47
+ ---
48
+
49
+ ## License
50
+
51
+ MIT
@@ -0,0 +1,123 @@
1
+ import * as _partylayer_core from '@partylayer/core';
2
+ import { WalletAdapter, CapabilityKey, AdapterDetectResult, AdapterContext, PartyId, AdapterConnectResult, Session, PersistedSession, SignMessageParams, SignedMessage, SignTransactionParams, SignedTransaction, SubmitTransactionParams, TxReceipt } from '@partylayer/core';
3
+
4
+ /** Sign request response types from Nightly wallet */
5
+ declare enum SignRequestResponseType {
6
+ SIGN_REQUEST_APPROVED = "sign_request_approved",
7
+ SIGN_REQUEST_REJECTED = "sign_request_rejected",
8
+ SIGN_REQUEST_ERROR = "sign_request_error"
9
+ }
10
+ interface SignRequestResponse {
11
+ type: SignRequestResponseType;
12
+ data: {
13
+ signature?: string;
14
+ updateId?: string;
15
+ } | {
16
+ reason: string;
17
+ } | {
18
+ error: string;
19
+ };
20
+ }
21
+ interface Instrument {
22
+ id: string;
23
+ admin: string;
24
+ }
25
+ interface TransactionCommand {
26
+ command: unknown;
27
+ disclosedContracts: unknown[];
28
+ }
29
+ interface CreateTransferCommandParams {
30
+ receiverPartyId: string;
31
+ amount: string;
32
+ instrument: Instrument;
33
+ memo?: string;
34
+ expiryDate?: string;
35
+ }
36
+ /** The wallet object returned after successful connection */
37
+ interface NightlyCantonWallet {
38
+ partyId: string;
39
+ publicKey: string;
40
+ signMessage: (message: string, onResponse: (response: SignRequestResponse) => void) => void;
41
+ createTransferCommand: (params: CreateTransferCommandParams) => Promise<TransactionCommand>;
42
+ submitTransactionCommand: (transactionCommand: TransactionCommand, onResponse: (response: SignRequestResponse) => void) => void;
43
+ getPendingTransactions: () => Promise<unknown[] | null>;
44
+ getHoldingUtxos: () => Promise<unknown[] | null>;
45
+ }
46
+ /** The injected provider at window.nightly.canton */
47
+ interface NightlyCantonProvider extends NightlyCantonWallet {
48
+ connect: () => Promise<{
49
+ partyId: string;
50
+ publicKey: string;
51
+ }>;
52
+ disconnect: () => Promise<void>;
53
+ isConnected: () => boolean;
54
+ }
55
+ declare global {
56
+ interface Window {
57
+ nightly?: {
58
+ canton?: NightlyCantonProvider;
59
+ };
60
+ }
61
+ }
62
+ /**
63
+ * Nightly Wallet adapter
64
+ *
65
+ * Implements WalletAdapter interface for Nightly Wallet's Canton support.
66
+ * The wallet injects at window.nightly.canton and provides:
67
+ * - connect/disconnect via Promise
68
+ * - signMessage via callback
69
+ * - transaction commands via callback
70
+ * - session restore via isConnected()
71
+ */
72
+ declare class NightlyAdapter implements WalletAdapter {
73
+ readonly walletId: _partylayer_core.WalletId;
74
+ readonly name = "Nightly";
75
+ private wallet;
76
+ getCapabilities(): CapabilityKey[];
77
+ /**
78
+ * Detect if Nightly wallet extension is installed.
79
+ * Checks for window.nightly.canton provider.
80
+ */
81
+ detectInstalled(): Promise<AdapterDetectResult>;
82
+ /**
83
+ * Connect to Nightly Wallet.
84
+ *
85
+ * Calls window.nightly.canton.connect() which opens the extension
86
+ * popup for user approval.
87
+ */
88
+ connect(ctx: AdapterContext, _opts?: {
89
+ timeoutMs?: number;
90
+ partyId?: PartyId;
91
+ }): Promise<AdapterConnectResult>;
92
+ /**
93
+ * Disconnect from Nightly Wallet.
94
+ */
95
+ disconnect(ctx: AdapterContext, _session: Session): Promise<void>;
96
+ /**
97
+ * Restore session — check if Nightly is still connected.
98
+ */
99
+ restore(ctx: AdapterContext, persisted: PersistedSession): Promise<Session | null>;
100
+ /**
101
+ * Sign a message.
102
+ *
103
+ * Nightly uses a callback-based signMessage API — we wrap it
104
+ * in a Promise for the WalletAdapter interface.
105
+ */
106
+ signMessage(ctx: AdapterContext, session: Session, params: SignMessageParams): Promise<SignedMessage>;
107
+ /**
108
+ * Sign a transaction — not supported standalone.
109
+ *
110
+ * Nightly combines signing and submission via submitTransactionCommand.
111
+ */
112
+ signTransaction(_ctx: AdapterContext, _session: Session, _params: SignTransactionParams): Promise<SignedTransaction>;
113
+ /**
114
+ * Submit a transaction.
115
+ *
116
+ * Nightly uses callback-based submitTransactionCommand.
117
+ * The signedTx should be a TransactionCommand object created via
118
+ * createTransferCommand or createTransactionChoiceCommand.
119
+ */
120
+ submitTransaction(ctx: AdapterContext, session: Session, params: SubmitTransactionParams): Promise<TxReceipt>;
121
+ }
122
+
123
+ export { NightlyAdapter };
@@ -0,0 +1,123 @@
1
+ import * as _partylayer_core from '@partylayer/core';
2
+ import { WalletAdapter, CapabilityKey, AdapterDetectResult, AdapterContext, PartyId, AdapterConnectResult, Session, PersistedSession, SignMessageParams, SignedMessage, SignTransactionParams, SignedTransaction, SubmitTransactionParams, TxReceipt } from '@partylayer/core';
3
+
4
+ /** Sign request response types from Nightly wallet */
5
+ declare enum SignRequestResponseType {
6
+ SIGN_REQUEST_APPROVED = "sign_request_approved",
7
+ SIGN_REQUEST_REJECTED = "sign_request_rejected",
8
+ SIGN_REQUEST_ERROR = "sign_request_error"
9
+ }
10
+ interface SignRequestResponse {
11
+ type: SignRequestResponseType;
12
+ data: {
13
+ signature?: string;
14
+ updateId?: string;
15
+ } | {
16
+ reason: string;
17
+ } | {
18
+ error: string;
19
+ };
20
+ }
21
+ interface Instrument {
22
+ id: string;
23
+ admin: string;
24
+ }
25
+ interface TransactionCommand {
26
+ command: unknown;
27
+ disclosedContracts: unknown[];
28
+ }
29
+ interface CreateTransferCommandParams {
30
+ receiverPartyId: string;
31
+ amount: string;
32
+ instrument: Instrument;
33
+ memo?: string;
34
+ expiryDate?: string;
35
+ }
36
+ /** The wallet object returned after successful connection */
37
+ interface NightlyCantonWallet {
38
+ partyId: string;
39
+ publicKey: string;
40
+ signMessage: (message: string, onResponse: (response: SignRequestResponse) => void) => void;
41
+ createTransferCommand: (params: CreateTransferCommandParams) => Promise<TransactionCommand>;
42
+ submitTransactionCommand: (transactionCommand: TransactionCommand, onResponse: (response: SignRequestResponse) => void) => void;
43
+ getPendingTransactions: () => Promise<unknown[] | null>;
44
+ getHoldingUtxos: () => Promise<unknown[] | null>;
45
+ }
46
+ /** The injected provider at window.nightly.canton */
47
+ interface NightlyCantonProvider extends NightlyCantonWallet {
48
+ connect: () => Promise<{
49
+ partyId: string;
50
+ publicKey: string;
51
+ }>;
52
+ disconnect: () => Promise<void>;
53
+ isConnected: () => boolean;
54
+ }
55
+ declare global {
56
+ interface Window {
57
+ nightly?: {
58
+ canton?: NightlyCantonProvider;
59
+ };
60
+ }
61
+ }
62
+ /**
63
+ * Nightly Wallet adapter
64
+ *
65
+ * Implements WalletAdapter interface for Nightly Wallet's Canton support.
66
+ * The wallet injects at window.nightly.canton and provides:
67
+ * - connect/disconnect via Promise
68
+ * - signMessage via callback
69
+ * - transaction commands via callback
70
+ * - session restore via isConnected()
71
+ */
72
+ declare class NightlyAdapter implements WalletAdapter {
73
+ readonly walletId: _partylayer_core.WalletId;
74
+ readonly name = "Nightly";
75
+ private wallet;
76
+ getCapabilities(): CapabilityKey[];
77
+ /**
78
+ * Detect if Nightly wallet extension is installed.
79
+ * Checks for window.nightly.canton provider.
80
+ */
81
+ detectInstalled(): Promise<AdapterDetectResult>;
82
+ /**
83
+ * Connect to Nightly Wallet.
84
+ *
85
+ * Calls window.nightly.canton.connect() which opens the extension
86
+ * popup for user approval.
87
+ */
88
+ connect(ctx: AdapterContext, _opts?: {
89
+ timeoutMs?: number;
90
+ partyId?: PartyId;
91
+ }): Promise<AdapterConnectResult>;
92
+ /**
93
+ * Disconnect from Nightly Wallet.
94
+ */
95
+ disconnect(ctx: AdapterContext, _session: Session): Promise<void>;
96
+ /**
97
+ * Restore session — check if Nightly is still connected.
98
+ */
99
+ restore(ctx: AdapterContext, persisted: PersistedSession): Promise<Session | null>;
100
+ /**
101
+ * Sign a message.
102
+ *
103
+ * Nightly uses a callback-based signMessage API — we wrap it
104
+ * in a Promise for the WalletAdapter interface.
105
+ */
106
+ signMessage(ctx: AdapterContext, session: Session, params: SignMessageParams): Promise<SignedMessage>;
107
+ /**
108
+ * Sign a transaction — not supported standalone.
109
+ *
110
+ * Nightly combines signing and submission via submitTransactionCommand.
111
+ */
112
+ signTransaction(_ctx: AdapterContext, _session: Session, _params: SignTransactionParams): Promise<SignedTransaction>;
113
+ /**
114
+ * Submit a transaction.
115
+ *
116
+ * Nightly uses callback-based submitTransactionCommand.
117
+ * The signedTx should be a TransactionCommand object created via
118
+ * createTransferCommand or createTransactionChoiceCommand.
119
+ */
120
+ submitTransaction(ctx: AdapterContext, session: Session, params: SubmitTransactionParams): Promise<TxReceipt>;
121
+ }
122
+
123
+ export { NightlyAdapter };
package/dist/index.js ADDED
@@ -0,0 +1,228 @@
1
+ 'use strict';
2
+
3
+ var core = require('@partylayer/core');
4
+
5
+ // src/nightly-adapter.ts
6
+ var NightlyAdapter = class {
7
+ walletId = core.toWalletId("nightly");
8
+ name = "Nightly";
9
+ wallet = null;
10
+ getCapabilities() {
11
+ return [
12
+ "connect",
13
+ "disconnect",
14
+ "restore",
15
+ "signMessage",
16
+ "submitTransaction",
17
+ "events",
18
+ "injected"
19
+ ];
20
+ }
21
+ /**
22
+ * Detect if Nightly wallet extension is installed.
23
+ * Checks for window.nightly.canton provider.
24
+ */
25
+ async detectInstalled() {
26
+ if (typeof window === "undefined") {
27
+ return { installed: false, reason: "Browser environment required" };
28
+ }
29
+ if (window.nightly?.canton) {
30
+ return {
31
+ installed: true,
32
+ reason: "Nightly wallet detected"
33
+ };
34
+ }
35
+ return {
36
+ installed: false,
37
+ reason: "Nightly wallet not detected. Install from https://nightly.app/download"
38
+ };
39
+ }
40
+ /**
41
+ * Connect to Nightly Wallet.
42
+ *
43
+ * Calls window.nightly.canton.connect() which opens the extension
44
+ * popup for user approval.
45
+ */
46
+ async connect(ctx, _opts) {
47
+ try {
48
+ const provider = window.nightly?.canton;
49
+ if (!provider) {
50
+ throw new core.WalletNotInstalledError(
51
+ this.walletId,
52
+ "Nightly wallet not detected. Install from https://nightly.app/download"
53
+ );
54
+ }
55
+ ctx.logger.debug("Connecting to Nightly Wallet", {
56
+ appName: ctx.appName,
57
+ network: ctx.network
58
+ });
59
+ await provider.connect();
60
+ this.wallet = provider;
61
+ const partyId = core.toPartyId(provider.partyId);
62
+ ctx.logger.info("Connected to Nightly Wallet", {
63
+ partyId: provider.partyId
64
+ });
65
+ return {
66
+ partyId,
67
+ session: {
68
+ walletId: this.walletId,
69
+ network: ctx.network,
70
+ createdAt: Date.now(),
71
+ metadata: {
72
+ publicKey: provider.publicKey
73
+ }
74
+ },
75
+ capabilities: this.getCapabilities()
76
+ };
77
+ } catch (err) {
78
+ throw core.mapUnknownErrorToPartyLayerError(err, {
79
+ walletId: this.walletId,
80
+ phase: "connect",
81
+ transport: "injected",
82
+ details: { origin: ctx.origin, network: ctx.network }
83
+ });
84
+ }
85
+ }
86
+ /**
87
+ * Disconnect from Nightly Wallet.
88
+ */
89
+ async disconnect(ctx, _session) {
90
+ try {
91
+ await window.nightly?.canton?.disconnect();
92
+ } catch (err) {
93
+ ctx.logger.warn("Error during Nightly wallet disconnect", err);
94
+ }
95
+ this.wallet = null;
96
+ }
97
+ /**
98
+ * Restore session — check if Nightly is still connected.
99
+ */
100
+ async restore(ctx, persisted) {
101
+ try {
102
+ if (typeof window === "undefined") return null;
103
+ if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {
104
+ return null;
105
+ }
106
+ const provider = window.nightly?.canton;
107
+ if (!provider) return null;
108
+ if (typeof provider.isConnected === "function" && provider.isConnected()) {
109
+ this.wallet = provider;
110
+ ctx.logger.debug("Restored Nightly Wallet session", {
111
+ partyId: provider.partyId
112
+ });
113
+ return { ...persisted, walletId: this.walletId };
114
+ }
115
+ return null;
116
+ } catch (err) {
117
+ ctx.logger.warn("Failed to restore Nightly wallet session", err);
118
+ return null;
119
+ }
120
+ }
121
+ /**
122
+ * Sign a message.
123
+ *
124
+ * Nightly uses a callback-based signMessage API — we wrap it
125
+ * in a Promise for the WalletAdapter interface.
126
+ */
127
+ async signMessage(ctx, session, params) {
128
+ try {
129
+ if (!this.wallet) {
130
+ throw new Error("Not connected to Nightly Wallet");
131
+ }
132
+ ctx.logger.debug("Signing message with Nightly Wallet", {
133
+ sessionId: session.sessionId,
134
+ messageLength: params.message.length
135
+ });
136
+ const signature = await new Promise((resolve, reject) => {
137
+ this.wallet.signMessage(params.message, (response) => {
138
+ if (response.type === "sign_request_approved" /* SIGN_REQUEST_APPROVED */) {
139
+ const data = response.data;
140
+ resolve(data.signature || "");
141
+ } else if (response.type === "sign_request_rejected" /* SIGN_REQUEST_REJECTED */) {
142
+ const data = response.data;
143
+ reject(new Error(`Sign rejected: ${data.reason}`));
144
+ } else {
145
+ const data = response.data;
146
+ reject(new Error(`Sign error: ${data.error}`));
147
+ }
148
+ });
149
+ });
150
+ return {
151
+ signature: core.toSignature(signature),
152
+ partyId: session.partyId,
153
+ message: params.message,
154
+ nonce: params.nonce,
155
+ domain: params.domain
156
+ };
157
+ } catch (err) {
158
+ throw core.mapUnknownErrorToPartyLayerError(err, {
159
+ walletId: this.walletId,
160
+ phase: "signMessage",
161
+ transport: "injected",
162
+ details: { sessionId: session.sessionId }
163
+ });
164
+ }
165
+ }
166
+ /**
167
+ * Sign a transaction — not supported standalone.
168
+ *
169
+ * Nightly combines signing and submission via submitTransactionCommand.
170
+ */
171
+ async signTransaction(_ctx, _session, _params) {
172
+ throw new core.CapabilityNotSupportedError(
173
+ this.walletId,
174
+ "signTransaction \u2014 Nightly combines signing and submission. Use submitTransaction instead."
175
+ );
176
+ }
177
+ /**
178
+ * Submit a transaction.
179
+ *
180
+ * Nightly uses callback-based submitTransactionCommand.
181
+ * The signedTx should be a TransactionCommand object created via
182
+ * createTransferCommand or createTransactionChoiceCommand.
183
+ */
184
+ async submitTransaction(ctx, session, params) {
185
+ try {
186
+ if (!this.wallet) {
187
+ throw new Error("Not connected to Nightly Wallet");
188
+ }
189
+ ctx.logger.debug("Submitting transaction with Nightly Wallet", {
190
+ sessionId: session.sessionId
191
+ });
192
+ const txCommand = params.signedTx;
193
+ const result = await new Promise(
194
+ (resolve, reject) => {
195
+ this.wallet.submitTransactionCommand(txCommand, (response) => {
196
+ if (response.type === "sign_request_approved" /* SIGN_REQUEST_APPROVED */) {
197
+ resolve(
198
+ response.data
199
+ );
200
+ } else if (response.type === "sign_request_rejected" /* SIGN_REQUEST_REJECTED */) {
201
+ const data = response.data;
202
+ reject(new Error(`Transaction rejected: ${data.reason}`));
203
+ } else {
204
+ const data = response.data;
205
+ reject(new Error(`Transaction error: ${data.error}`));
206
+ }
207
+ });
208
+ }
209
+ );
210
+ const hash = result.updateId || result.signature || `tx_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
211
+ return {
212
+ transactionHash: core.toTransactionHash(hash),
213
+ submittedAt: Date.now()
214
+ };
215
+ } catch (err) {
216
+ throw core.mapUnknownErrorToPartyLayerError(err, {
217
+ walletId: this.walletId,
218
+ phase: "submitTransaction",
219
+ transport: "injected",
220
+ details: { sessionId: session.sessionId }
221
+ });
222
+ }
223
+ }
224
+ };
225
+
226
+ exports.NightlyAdapter = NightlyAdapter;
227
+ //# sourceMappingURL=index.js.map
228
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/nightly-adapter.ts"],"names":["toWalletId","WalletNotInstalledError","toPartyId","mapUnknownErrorToPartyLayerError","toSignature","CapabilityNotSupportedError","toTransactionHash"],"mappings":";;;;;AAsHO,IAAM,iBAAN,MAA8C;AAAA,EAC1C,QAAA,GAAWA,gBAAW,SAAS,CAAA;AAAA,EAC/B,IAAA,GAAO,SAAA;AAAA,EAER,MAAA,GAAqC,IAAA;AAAA,EAE7C,eAAA,GAAmC;AACjC,IAAA,OAAO;AAAA,MACL,SAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,aAAA;AAAA,MACA,mBAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAA,GAAgD;AACpD,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,OAAO,EAAE,SAAA,EAAW,KAAA,EAAO,MAAA,EAAQ,8BAAA,EAA+B;AAAA,IACpE;AAEA,IAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAQ;AAC1B,MAAA,OAAO;AAAA,QACL,SAAA,EAAW,IAAA;AAAA,QACX,MAAA,EAAQ;AAAA,OACV;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,KAAA;AAAA,MACX,MAAA,EACE;AAAA,KACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAA,CACJ,GAAA,EACA,KAAA,EAC+B;AAC/B,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,OAAO,OAAA,EAAS,MAAA;AACjC,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,MAAM,IAAIC,4BAAA;AAAA,UACR,IAAA,CAAK,QAAA;AAAA,UACL;AAAA,SACF;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,MAAA,CAAO,MAAM,8BAAA,EAAgC;AAAA,QAC/C,SAAS,GAAA,CAAI,OAAA;AAAA,QACb,SAAS,GAAA,CAAI;AAAA,OACd,CAAA;AAGD,MAAA,MAAM,SAAS,OAAA,EAAQ;AAGvB,MAAA,IAAA,CAAK,MAAA,GAAS,QAAA;AACd,MAAA,MAAM,OAAA,GAAUC,cAAA,CAAU,QAAA,CAAS,OAAO,CAAA;AAE1C,MAAA,GAAA,CAAI,MAAA,CAAO,KAAK,6BAAA,EAA+B;AAAA,QAC7C,SAAS,QAAA,CAAS;AAAA,OACnB,CAAA;AAED,MAAA,OAAO;AAAA,QACL,OAAA;AAAA,QACA,OAAA,EAAS;AAAA,UACP,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,SAAS,GAAA,CAAI,OAAA;AAAA,UACb,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,UACpB,QAAA,EAAU;AAAA,YACR,WAAW,QAAA,CAAS;AAAA;AACtB,SACF;AAAA,QACA,YAAA,EAAc,KAAK,eAAA;AAAgB,OACrC;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMC,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,SAAA;AAAA,QACP,SAAA,EAAW,UAAA;AAAA,QACX,SAAS,EAAE,MAAA,EAAQ,IAAI,MAAA,EAAQ,OAAA,EAAS,IAAI,OAAA;AAAQ,OACrD,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAA,CAAW,GAAA,EAAqB,QAAA,EAAkC;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAW;AAAA,IAC3C,SAAS,GAAA,EAAK;AACZ,MAAA,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,wCAAA,EAA0C,GAAG,CAAA;AAAA,IAC/D;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAA,CACJ,GAAA,EACA,SAAA,EACyB;AACzB,IAAA,IAAI;AACF,MAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAE1C,MAAA,IAAI,UAAU,SAAA,IAAa,IAAA,CAAK,GAAA,EAAI,IAAK,UAAU,SAAA,EAAW;AAC5D,QAAA,OAAO,IAAA;AAAA,MACT;AAEA,MAAA,MAAM,QAAA,GAAW,OAAO,OAAA,EAAS,MAAA;AACjC,MAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAGtB,MAAA,IAAI,OAAO,QAAA,CAAS,WAAA,KAAgB,UAAA,IAAc,QAAA,CAAS,aAAY,EAAG;AACxE,QAAA,IAAA,CAAK,MAAA,GAAS,QAAA;AACd,QAAA,GAAA,CAAI,MAAA,CAAO,MAAM,iCAAA,EAAmC;AAAA,UAClD,SAAS,QAAA,CAAS;AAAA,SACnB,CAAA;AACD,QAAA,OAAO,EAAE,GAAG,SAAA,EAAW,QAAA,EAAU,KAAK,QAAA,EAAS;AAAA,MACjD;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,SAAS,GAAA,EAAK;AACZ,MAAA,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,0CAAA,EAA4C,GAAG,CAAA;AAC/D,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WAAA,CACJ,GAAA,EACA,OAAA,EACA,MAAA,EACwB;AACxB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,QAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,MACnD;AAEA,MAAA,GAAA,CAAI,MAAA,CAAO,MAAM,qCAAA,EAAuC;AAAA,QACtD,WAAW,OAAA,CAAQ,SAAA;AAAA,QACnB,aAAA,EAAe,OAAO,OAAA,CAAQ;AAAA,OAC/B,CAAA;AAED,MAAA,MAAM,YAAY,MAAM,IAAI,OAAA,CAAgB,CAAC,SAAS,MAAA,KAAW;AAC/D,QAAA,IAAA,CAAK,MAAA,CAAQ,WAAA,CAAY,MAAA,CAAO,OAAA,EAAS,CAAC,QAAA,KAAa;AACrD,UAAA,IAAI,QAAA,CAAS,SAAS,uBAAA,8BAA+C;AACnE,YAAA,MAAM,OAAO,QAAA,CAAS,IAAA;AACtB,YAAA,OAAA,CAAQ,IAAA,CAAK,aAAa,EAAE,CAAA;AAAA,UAC9B,CAAA,MAAA,IACE,QAAA,CAAS,IAAA,KAAS,uBAAA,8BAClB;AACA,YAAA,MAAM,OAAO,QAAA,CAAS,IAAA;AACtB,YAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAA,CAAK,MAAM,EAAE,CAAC,CAAA;AAAA,UACnD,CAAA,MAAO;AACL,YAAA,MAAM,OAAO,QAAA,CAAS,IAAA;AACtB,YAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,IAAA,CAAK,KAAK,EAAE,CAAC,CAAA;AAAA,UAC/C;AAAA,QACF,CAAC,CAAA;AAAA,MACH,CAAC,CAAA;AAED,MAAA,OAAO;AAAA,QACL,SAAA,EAAWC,iBAAY,SAAS,CAAA;AAAA,QAChC,SAAS,OAAA,CAAQ,OAAA;AAAA,QACjB,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,OAAO,MAAA,CAAO,KAAA;AAAA,QACd,QAAQ,MAAA,CAAO;AAAA,OACjB;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMD,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,aAAA;AAAA,QACP,SAAA,EAAW,UAAA;AAAA,QACX,OAAA,EAAS,EAAE,SAAA,EAAW,OAAA,CAAQ,SAAA;AAAU,OACzC,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eAAA,CACJ,IAAA,EACA,QAAA,EACA,OAAA,EAC4B;AAC5B,IAAA,MAAM,IAAIE,gCAAA;AAAA,MACR,IAAA,CAAK,QAAA;AAAA,MACL;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,iBAAA,CACJ,GAAA,EACA,OAAA,EACA,MAAA,EACoB;AACpB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,QAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,MACnD;AAEA,MAAA,GAAA,CAAI,MAAA,CAAO,MAAM,4CAAA,EAA8C;AAAA,QAC7D,WAAW,OAAA,CAAQ;AAAA,OACpB,CAAA;AAED,MAAA,MAAM,YAAY,MAAA,CAAO,QAAA;AAEzB,MAAA,MAAM,MAAA,GAAS,MAAM,IAAI,OAAA;AAAA,QACvB,CAAC,SAAS,MAAA,KAAW;AACnB,UAAA,IAAA,CAAK,MAAA,CAAQ,wBAAA,CAAyB,SAAA,EAAW,CAAC,QAAA,KAAa;AAC7D,YAAA,IACE,QAAA,CAAS,SAAS,uBAAA,8BAClB;AACA,cAAA,OAAA;AAAA,gBACE,QAAA,CAAS;AAAA,eACX;AAAA,YACF,CAAA,MAAA,IACE,QAAA,CAAS,IAAA,KAAS,uBAAA,8BAClB;AACA,cAAA,MAAM,OAAO,QAAA,CAAS,IAAA;AACtB,cAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,IAAA,CAAK,MAAM,EAAE,CAAC,CAAA;AAAA,YAC1D,CAAA,MAAO;AACL,cAAA,MAAM,OAAO,QAAA,CAAS,IAAA;AACtB,cAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,IAAA,CAAK,KAAK,EAAE,CAAC,CAAA;AAAA,YACtD;AAAA,UACF,CAAC,CAAA;AAAA,QACH;AAAA,OACF;AAEA,MAAA,MAAM,OACJ,MAAA,CAAO,QAAA,IACP,OAAO,SAAA,IACP,CAAA,GAAA,EAAM,KAAK,GAAA,EAAK,IAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,SAAA,CAAU,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AAEjE,MAAA,OAAO;AAAA,QACL,eAAA,EAAiBC,uBAAkB,IAAI,CAAA;AAAA,QACvC,WAAA,EAAa,KAAK,GAAA;AAAI,OACxB;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMH,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,mBAAA;AAAA,QACP,SAAA,EAAW,UAAA;AAAA,QACX,OAAA,EAAS,EAAE,SAAA,EAAW,OAAA,CAAQ,SAAA;AAAU,OACzC,CAAA;AAAA,IACH;AAAA,EACF;AACF","file":"index.js","sourcesContent":["/**\n * Nightly Wallet adapter implementation\n *\n * Nightly is a multichain wallet with Canton Network support.\n * The wallet injects at window.nightly.canton and uses a custom\n * (non-CIP-0103) interface with callback-based signing.\n *\n * Reference: https://docs.nightly.app/docs/canton/canton/connect/\n * Template: https://github.com/nightly-labs/canton-web3-template\n */\n\nimport type {\n WalletAdapter,\n AdapterContext,\n AdapterDetectResult,\n AdapterConnectResult,\n SignMessageParams,\n SignTransactionParams,\n SubmitTransactionParams,\n SignedMessage,\n SignedTransaction,\n TxReceipt,\n Session,\n PersistedSession,\n CapabilityKey,\n PartyId,\n} from '@partylayer/core';\nimport {\n toWalletId,\n toPartyId,\n toTransactionHash,\n toSignature,\n WalletNotInstalledError,\n CapabilityNotSupportedError,\n mapUnknownErrorToPartyLayerError,\n} from '@partylayer/core';\n\n// ─── Nightly Canton Types ───────────────────────────────────────────────────\n\n/** Sign request response types from Nightly wallet */\nenum SignRequestResponseType {\n SIGN_REQUEST_APPROVED = 'sign_request_approved',\n SIGN_REQUEST_REJECTED = 'sign_request_rejected',\n SIGN_REQUEST_ERROR = 'sign_request_error',\n}\n\ninterface SignRequestResponse {\n type: SignRequestResponseType;\n data:\n | { signature?: string; updateId?: string }\n | { reason: string }\n | { error: string };\n}\n\ninterface Instrument {\n id: string;\n admin: string;\n}\n\ninterface TransactionCommand {\n command: unknown;\n disclosedContracts: unknown[];\n}\n\ninterface CreateTransferCommandParams {\n receiverPartyId: string;\n amount: string;\n instrument: Instrument;\n memo?: string;\n expiryDate?: string;\n}\n\n/** The wallet object returned after successful connection */\ninterface NightlyCantonWallet {\n partyId: string;\n publicKey: string;\n signMessage: (\n message: string,\n onResponse: (response: SignRequestResponse) => void,\n ) => void;\n createTransferCommand: (\n params: CreateTransferCommandParams,\n ) => Promise<TransactionCommand>;\n submitTransactionCommand: (\n transactionCommand: TransactionCommand,\n onResponse: (response: SignRequestResponse) => void,\n ) => void;\n getPendingTransactions: () => Promise<unknown[] | null>;\n getHoldingUtxos: () => Promise<unknown[] | null>;\n}\n\n/** The injected provider at window.nightly.canton */\ninterface NightlyCantonProvider extends NightlyCantonWallet {\n connect: () => Promise<{ partyId: string; publicKey: string }>;\n disconnect: () => Promise<void>;\n isConnected: () => boolean;\n}\n\ndeclare global {\n interface Window {\n nightly?: {\n canton?: NightlyCantonProvider;\n };\n }\n}\n\n// ─── Adapter ────────────────────────────────────────────────────────────────\n\n/**\n * Nightly Wallet adapter\n *\n * Implements WalletAdapter interface for Nightly Wallet's Canton support.\n * The wallet injects at window.nightly.canton and provides:\n * - connect/disconnect via Promise\n * - signMessage via callback\n * - transaction commands via callback\n * - session restore via isConnected()\n */\nexport class NightlyAdapter implements WalletAdapter {\n readonly walletId = toWalletId('nightly');\n readonly name = 'Nightly';\n\n private wallet: NightlyCantonWallet | null = null;\n\n getCapabilities(): CapabilityKey[] {\n return [\n 'connect',\n 'disconnect',\n 'restore',\n 'signMessage',\n 'submitTransaction',\n 'events',\n 'injected',\n ];\n }\n\n /**\n * Detect if Nightly wallet extension is installed.\n * Checks for window.nightly.canton provider.\n */\n async detectInstalled(): Promise<AdapterDetectResult> {\n if (typeof window === 'undefined') {\n return { installed: false, reason: 'Browser environment required' };\n }\n\n if (window.nightly?.canton) {\n return {\n installed: true,\n reason: 'Nightly wallet detected',\n };\n }\n\n return {\n installed: false,\n reason:\n 'Nightly wallet not detected. Install from https://nightly.app/download',\n };\n }\n\n /**\n * Connect to Nightly Wallet.\n *\n * Calls window.nightly.canton.connect() which opens the extension\n * popup for user approval.\n */\n async connect(\n ctx: AdapterContext,\n _opts?: { timeoutMs?: number; partyId?: PartyId },\n ): Promise<AdapterConnectResult> {\n try {\n const provider = window.nightly?.canton;\n if (!provider) {\n throw new WalletNotInstalledError(\n this.walletId,\n 'Nightly wallet not detected. Install from https://nightly.app/download',\n );\n }\n\n ctx.logger.debug('Connecting to Nightly Wallet', {\n appName: ctx.appName,\n network: ctx.network,\n });\n\n // connect() opens the extension popup for approval\n await provider.connect();\n\n // After connect, the provider itself acts as the wallet\n this.wallet = provider;\n const partyId = toPartyId(provider.partyId);\n\n ctx.logger.info('Connected to Nightly Wallet', {\n partyId: provider.partyId,\n });\n\n return {\n partyId,\n session: {\n walletId: this.walletId,\n network: ctx.network,\n createdAt: Date.now(),\n metadata: {\n publicKey: provider.publicKey,\n },\n },\n capabilities: this.getCapabilities(),\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'connect',\n transport: 'injected',\n details: { origin: ctx.origin, network: ctx.network },\n });\n }\n }\n\n /**\n * Disconnect from Nightly Wallet.\n */\n async disconnect(ctx: AdapterContext, _session: Session): Promise<void> {\n try {\n await window.nightly?.canton?.disconnect();\n } catch (err) {\n ctx.logger.warn('Error during Nightly wallet disconnect', err);\n }\n this.wallet = null;\n }\n\n /**\n * Restore session — check if Nightly is still connected.\n */\n async restore(\n ctx: AdapterContext,\n persisted: PersistedSession,\n ): Promise<Session | null> {\n try {\n if (typeof window === 'undefined') return null;\n\n if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {\n return null;\n }\n\n const provider = window.nightly?.canton;\n if (!provider) return null;\n\n // Check if the wallet reports being connected\n if (typeof provider.isConnected === 'function' && provider.isConnected()) {\n this.wallet = provider;\n ctx.logger.debug('Restored Nightly Wallet session', {\n partyId: provider.partyId,\n });\n return { ...persisted, walletId: this.walletId };\n }\n\n return null;\n } catch (err) {\n ctx.logger.warn('Failed to restore Nightly wallet session', err);\n return null;\n }\n }\n\n /**\n * Sign a message.\n *\n * Nightly uses a callback-based signMessage API — we wrap it\n * in a Promise for the WalletAdapter interface.\n */\n async signMessage(\n ctx: AdapterContext,\n session: Session,\n params: SignMessageParams,\n ): Promise<SignedMessage> {\n try {\n if (!this.wallet) {\n throw new Error('Not connected to Nightly Wallet');\n }\n\n ctx.logger.debug('Signing message with Nightly Wallet', {\n sessionId: session.sessionId,\n messageLength: params.message.length,\n });\n\n const signature = await new Promise<string>((resolve, reject) => {\n this.wallet!.signMessage(params.message, (response) => {\n if (response.type === SignRequestResponseType.SIGN_REQUEST_APPROVED) {\n const data = response.data as { signature?: string };\n resolve(data.signature || '');\n } else if (\n response.type === SignRequestResponseType.SIGN_REQUEST_REJECTED\n ) {\n const data = response.data as { reason: string };\n reject(new Error(`Sign rejected: ${data.reason}`));\n } else {\n const data = response.data as { error: string };\n reject(new Error(`Sign error: ${data.error}`));\n }\n });\n });\n\n return {\n signature: toSignature(signature),\n partyId: session.partyId,\n message: params.message,\n nonce: params.nonce,\n domain: params.domain,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signMessage',\n transport: 'injected',\n details: { sessionId: session.sessionId },\n });\n }\n }\n\n /**\n * Sign a transaction — not supported standalone.\n *\n * Nightly combines signing and submission via submitTransactionCommand.\n */\n async signTransaction(\n _ctx: AdapterContext,\n _session: Session,\n _params: SignTransactionParams,\n ): Promise<SignedTransaction> {\n throw new CapabilityNotSupportedError(\n this.walletId,\n 'signTransaction — Nightly combines signing and submission. Use submitTransaction instead.',\n );\n }\n\n /**\n * Submit a transaction.\n *\n * Nightly uses callback-based submitTransactionCommand.\n * The signedTx should be a TransactionCommand object created via\n * createTransferCommand or createTransactionChoiceCommand.\n */\n async submitTransaction(\n ctx: AdapterContext,\n session: Session,\n params: SubmitTransactionParams,\n ): Promise<TxReceipt> {\n try {\n if (!this.wallet) {\n throw new Error('Not connected to Nightly Wallet');\n }\n\n ctx.logger.debug('Submitting transaction with Nightly Wallet', {\n sessionId: session.sessionId,\n });\n\n const txCommand = params.signedTx as TransactionCommand;\n\n const result = await new Promise<{ signature?: string; updateId?: string }>(\n (resolve, reject) => {\n this.wallet!.submitTransactionCommand(txCommand, (response) => {\n if (\n response.type === SignRequestResponseType.SIGN_REQUEST_APPROVED\n ) {\n resolve(\n response.data as { signature?: string; updateId?: string },\n );\n } else if (\n response.type === SignRequestResponseType.SIGN_REQUEST_REJECTED\n ) {\n const data = response.data as { reason: string };\n reject(new Error(`Transaction rejected: ${data.reason}`));\n } else {\n const data = response.data as { error: string };\n reject(new Error(`Transaction error: ${data.error}`));\n }\n });\n },\n );\n\n const hash =\n result.updateId ||\n result.signature ||\n `tx_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;\n\n return {\n transactionHash: toTransactionHash(hash),\n submittedAt: Date.now(),\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'submitTransaction',\n transport: 'injected',\n details: { sessionId: session.sessionId },\n });\n }\n }\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,226 @@
1
+ import { toWalletId, WalletNotInstalledError, toPartyId, mapUnknownErrorToPartyLayerError, toSignature, CapabilityNotSupportedError, toTransactionHash } from '@partylayer/core';
2
+
3
+ // src/nightly-adapter.ts
4
+ var NightlyAdapter = class {
5
+ walletId = toWalletId("nightly");
6
+ name = "Nightly";
7
+ wallet = null;
8
+ getCapabilities() {
9
+ return [
10
+ "connect",
11
+ "disconnect",
12
+ "restore",
13
+ "signMessage",
14
+ "submitTransaction",
15
+ "events",
16
+ "injected"
17
+ ];
18
+ }
19
+ /**
20
+ * Detect if Nightly wallet extension is installed.
21
+ * Checks for window.nightly.canton provider.
22
+ */
23
+ async detectInstalled() {
24
+ if (typeof window === "undefined") {
25
+ return { installed: false, reason: "Browser environment required" };
26
+ }
27
+ if (window.nightly?.canton) {
28
+ return {
29
+ installed: true,
30
+ reason: "Nightly wallet detected"
31
+ };
32
+ }
33
+ return {
34
+ installed: false,
35
+ reason: "Nightly wallet not detected. Install from https://nightly.app/download"
36
+ };
37
+ }
38
+ /**
39
+ * Connect to Nightly Wallet.
40
+ *
41
+ * Calls window.nightly.canton.connect() which opens the extension
42
+ * popup for user approval.
43
+ */
44
+ async connect(ctx, _opts) {
45
+ try {
46
+ const provider = window.nightly?.canton;
47
+ if (!provider) {
48
+ throw new WalletNotInstalledError(
49
+ this.walletId,
50
+ "Nightly wallet not detected. Install from https://nightly.app/download"
51
+ );
52
+ }
53
+ ctx.logger.debug("Connecting to Nightly Wallet", {
54
+ appName: ctx.appName,
55
+ network: ctx.network
56
+ });
57
+ await provider.connect();
58
+ this.wallet = provider;
59
+ const partyId = toPartyId(provider.partyId);
60
+ ctx.logger.info("Connected to Nightly Wallet", {
61
+ partyId: provider.partyId
62
+ });
63
+ return {
64
+ partyId,
65
+ session: {
66
+ walletId: this.walletId,
67
+ network: ctx.network,
68
+ createdAt: Date.now(),
69
+ metadata: {
70
+ publicKey: provider.publicKey
71
+ }
72
+ },
73
+ capabilities: this.getCapabilities()
74
+ };
75
+ } catch (err) {
76
+ throw mapUnknownErrorToPartyLayerError(err, {
77
+ walletId: this.walletId,
78
+ phase: "connect",
79
+ transport: "injected",
80
+ details: { origin: ctx.origin, network: ctx.network }
81
+ });
82
+ }
83
+ }
84
+ /**
85
+ * Disconnect from Nightly Wallet.
86
+ */
87
+ async disconnect(ctx, _session) {
88
+ try {
89
+ await window.nightly?.canton?.disconnect();
90
+ } catch (err) {
91
+ ctx.logger.warn("Error during Nightly wallet disconnect", err);
92
+ }
93
+ this.wallet = null;
94
+ }
95
+ /**
96
+ * Restore session — check if Nightly is still connected.
97
+ */
98
+ async restore(ctx, persisted) {
99
+ try {
100
+ if (typeof window === "undefined") return null;
101
+ if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {
102
+ return null;
103
+ }
104
+ const provider = window.nightly?.canton;
105
+ if (!provider) return null;
106
+ if (typeof provider.isConnected === "function" && provider.isConnected()) {
107
+ this.wallet = provider;
108
+ ctx.logger.debug("Restored Nightly Wallet session", {
109
+ partyId: provider.partyId
110
+ });
111
+ return { ...persisted, walletId: this.walletId };
112
+ }
113
+ return null;
114
+ } catch (err) {
115
+ ctx.logger.warn("Failed to restore Nightly wallet session", err);
116
+ return null;
117
+ }
118
+ }
119
+ /**
120
+ * Sign a message.
121
+ *
122
+ * Nightly uses a callback-based signMessage API — we wrap it
123
+ * in a Promise for the WalletAdapter interface.
124
+ */
125
+ async signMessage(ctx, session, params) {
126
+ try {
127
+ if (!this.wallet) {
128
+ throw new Error("Not connected to Nightly Wallet");
129
+ }
130
+ ctx.logger.debug("Signing message with Nightly Wallet", {
131
+ sessionId: session.sessionId,
132
+ messageLength: params.message.length
133
+ });
134
+ const signature = await new Promise((resolve, reject) => {
135
+ this.wallet.signMessage(params.message, (response) => {
136
+ if (response.type === "sign_request_approved" /* SIGN_REQUEST_APPROVED */) {
137
+ const data = response.data;
138
+ resolve(data.signature || "");
139
+ } else if (response.type === "sign_request_rejected" /* SIGN_REQUEST_REJECTED */) {
140
+ const data = response.data;
141
+ reject(new Error(`Sign rejected: ${data.reason}`));
142
+ } else {
143
+ const data = response.data;
144
+ reject(new Error(`Sign error: ${data.error}`));
145
+ }
146
+ });
147
+ });
148
+ return {
149
+ signature: toSignature(signature),
150
+ partyId: session.partyId,
151
+ message: params.message,
152
+ nonce: params.nonce,
153
+ domain: params.domain
154
+ };
155
+ } catch (err) {
156
+ throw mapUnknownErrorToPartyLayerError(err, {
157
+ walletId: this.walletId,
158
+ phase: "signMessage",
159
+ transport: "injected",
160
+ details: { sessionId: session.sessionId }
161
+ });
162
+ }
163
+ }
164
+ /**
165
+ * Sign a transaction — not supported standalone.
166
+ *
167
+ * Nightly combines signing and submission via submitTransactionCommand.
168
+ */
169
+ async signTransaction(_ctx, _session, _params) {
170
+ throw new CapabilityNotSupportedError(
171
+ this.walletId,
172
+ "signTransaction \u2014 Nightly combines signing and submission. Use submitTransaction instead."
173
+ );
174
+ }
175
+ /**
176
+ * Submit a transaction.
177
+ *
178
+ * Nightly uses callback-based submitTransactionCommand.
179
+ * The signedTx should be a TransactionCommand object created via
180
+ * createTransferCommand or createTransactionChoiceCommand.
181
+ */
182
+ async submitTransaction(ctx, session, params) {
183
+ try {
184
+ if (!this.wallet) {
185
+ throw new Error("Not connected to Nightly Wallet");
186
+ }
187
+ ctx.logger.debug("Submitting transaction with Nightly Wallet", {
188
+ sessionId: session.sessionId
189
+ });
190
+ const txCommand = params.signedTx;
191
+ const result = await new Promise(
192
+ (resolve, reject) => {
193
+ this.wallet.submitTransactionCommand(txCommand, (response) => {
194
+ if (response.type === "sign_request_approved" /* SIGN_REQUEST_APPROVED */) {
195
+ resolve(
196
+ response.data
197
+ );
198
+ } else if (response.type === "sign_request_rejected" /* SIGN_REQUEST_REJECTED */) {
199
+ const data = response.data;
200
+ reject(new Error(`Transaction rejected: ${data.reason}`));
201
+ } else {
202
+ const data = response.data;
203
+ reject(new Error(`Transaction error: ${data.error}`));
204
+ }
205
+ });
206
+ }
207
+ );
208
+ const hash = result.updateId || result.signature || `tx_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
209
+ return {
210
+ transactionHash: toTransactionHash(hash),
211
+ submittedAt: Date.now()
212
+ };
213
+ } catch (err) {
214
+ throw mapUnknownErrorToPartyLayerError(err, {
215
+ walletId: this.walletId,
216
+ phase: "submitTransaction",
217
+ transport: "injected",
218
+ details: { sessionId: session.sessionId }
219
+ });
220
+ }
221
+ }
222
+ };
223
+
224
+ export { NightlyAdapter };
225
+ //# sourceMappingURL=index.mjs.map
226
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/nightly-adapter.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Nightly Wallet adapter implementation\n *\n * Nightly is a multichain wallet with Canton Network support.\n * The wallet injects at window.nightly.canton and uses a custom\n * (non-CIP-0103) interface with callback-based signing.\n *\n * Reference: https://docs.nightly.app/docs/canton/canton/connect/\n * Template: https://github.com/nightly-labs/canton-web3-template\n */\n\nimport type {\n WalletAdapter,\n AdapterContext,\n AdapterDetectResult,\n AdapterConnectResult,\n SignMessageParams,\n SignTransactionParams,\n SubmitTransactionParams,\n SignedMessage,\n SignedTransaction,\n TxReceipt,\n Session,\n PersistedSession,\n CapabilityKey,\n PartyId,\n} from '@partylayer/core';\nimport {\n toWalletId,\n toPartyId,\n toTransactionHash,\n toSignature,\n WalletNotInstalledError,\n CapabilityNotSupportedError,\n mapUnknownErrorToPartyLayerError,\n} from '@partylayer/core';\n\n// ─── Nightly Canton Types ───────────────────────────────────────────────────\n\n/** Sign request response types from Nightly wallet */\nenum SignRequestResponseType {\n SIGN_REQUEST_APPROVED = 'sign_request_approved',\n SIGN_REQUEST_REJECTED = 'sign_request_rejected',\n SIGN_REQUEST_ERROR = 'sign_request_error',\n}\n\ninterface SignRequestResponse {\n type: SignRequestResponseType;\n data:\n | { signature?: string; updateId?: string }\n | { reason: string }\n | { error: string };\n}\n\ninterface Instrument {\n id: string;\n admin: string;\n}\n\ninterface TransactionCommand {\n command: unknown;\n disclosedContracts: unknown[];\n}\n\ninterface CreateTransferCommandParams {\n receiverPartyId: string;\n amount: string;\n instrument: Instrument;\n memo?: string;\n expiryDate?: string;\n}\n\n/** The wallet object returned after successful connection */\ninterface NightlyCantonWallet {\n partyId: string;\n publicKey: string;\n signMessage: (\n message: string,\n onResponse: (response: SignRequestResponse) => void,\n ) => void;\n createTransferCommand: (\n params: CreateTransferCommandParams,\n ) => Promise<TransactionCommand>;\n submitTransactionCommand: (\n transactionCommand: TransactionCommand,\n onResponse: (response: SignRequestResponse) => void,\n ) => void;\n getPendingTransactions: () => Promise<unknown[] | null>;\n getHoldingUtxos: () => Promise<unknown[] | null>;\n}\n\n/** The injected provider at window.nightly.canton */\ninterface NightlyCantonProvider extends NightlyCantonWallet {\n connect: () => Promise<{ partyId: string; publicKey: string }>;\n disconnect: () => Promise<void>;\n isConnected: () => boolean;\n}\n\ndeclare global {\n interface Window {\n nightly?: {\n canton?: NightlyCantonProvider;\n };\n }\n}\n\n// ─── Adapter ────────────────────────────────────────────────────────────────\n\n/**\n * Nightly Wallet adapter\n *\n * Implements WalletAdapter interface for Nightly Wallet's Canton support.\n * The wallet injects at window.nightly.canton and provides:\n * - connect/disconnect via Promise\n * - signMessage via callback\n * - transaction commands via callback\n * - session restore via isConnected()\n */\nexport class NightlyAdapter implements WalletAdapter {\n readonly walletId = toWalletId('nightly');\n readonly name = 'Nightly';\n\n private wallet: NightlyCantonWallet | null = null;\n\n getCapabilities(): CapabilityKey[] {\n return [\n 'connect',\n 'disconnect',\n 'restore',\n 'signMessage',\n 'submitTransaction',\n 'events',\n 'injected',\n ];\n }\n\n /**\n * Detect if Nightly wallet extension is installed.\n * Checks for window.nightly.canton provider.\n */\n async detectInstalled(): Promise<AdapterDetectResult> {\n if (typeof window === 'undefined') {\n return { installed: false, reason: 'Browser environment required' };\n }\n\n if (window.nightly?.canton) {\n return {\n installed: true,\n reason: 'Nightly wallet detected',\n };\n }\n\n return {\n installed: false,\n reason:\n 'Nightly wallet not detected. Install from https://nightly.app/download',\n };\n }\n\n /**\n * Connect to Nightly Wallet.\n *\n * Calls window.nightly.canton.connect() which opens the extension\n * popup for user approval.\n */\n async connect(\n ctx: AdapterContext,\n _opts?: { timeoutMs?: number; partyId?: PartyId },\n ): Promise<AdapterConnectResult> {\n try {\n const provider = window.nightly?.canton;\n if (!provider) {\n throw new WalletNotInstalledError(\n this.walletId,\n 'Nightly wallet not detected. Install from https://nightly.app/download',\n );\n }\n\n ctx.logger.debug('Connecting to Nightly Wallet', {\n appName: ctx.appName,\n network: ctx.network,\n });\n\n // connect() opens the extension popup for approval\n await provider.connect();\n\n // After connect, the provider itself acts as the wallet\n this.wallet = provider;\n const partyId = toPartyId(provider.partyId);\n\n ctx.logger.info('Connected to Nightly Wallet', {\n partyId: provider.partyId,\n });\n\n return {\n partyId,\n session: {\n walletId: this.walletId,\n network: ctx.network,\n createdAt: Date.now(),\n metadata: {\n publicKey: provider.publicKey,\n },\n },\n capabilities: this.getCapabilities(),\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'connect',\n transport: 'injected',\n details: { origin: ctx.origin, network: ctx.network },\n });\n }\n }\n\n /**\n * Disconnect from Nightly Wallet.\n */\n async disconnect(ctx: AdapterContext, _session: Session): Promise<void> {\n try {\n await window.nightly?.canton?.disconnect();\n } catch (err) {\n ctx.logger.warn('Error during Nightly wallet disconnect', err);\n }\n this.wallet = null;\n }\n\n /**\n * Restore session — check if Nightly is still connected.\n */\n async restore(\n ctx: AdapterContext,\n persisted: PersistedSession,\n ): Promise<Session | null> {\n try {\n if (typeof window === 'undefined') return null;\n\n if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {\n return null;\n }\n\n const provider = window.nightly?.canton;\n if (!provider) return null;\n\n // Check if the wallet reports being connected\n if (typeof provider.isConnected === 'function' && provider.isConnected()) {\n this.wallet = provider;\n ctx.logger.debug('Restored Nightly Wallet session', {\n partyId: provider.partyId,\n });\n return { ...persisted, walletId: this.walletId };\n }\n\n return null;\n } catch (err) {\n ctx.logger.warn('Failed to restore Nightly wallet session', err);\n return null;\n }\n }\n\n /**\n * Sign a message.\n *\n * Nightly uses a callback-based signMessage API — we wrap it\n * in a Promise for the WalletAdapter interface.\n */\n async signMessage(\n ctx: AdapterContext,\n session: Session,\n params: SignMessageParams,\n ): Promise<SignedMessage> {\n try {\n if (!this.wallet) {\n throw new Error('Not connected to Nightly Wallet');\n }\n\n ctx.logger.debug('Signing message with Nightly Wallet', {\n sessionId: session.sessionId,\n messageLength: params.message.length,\n });\n\n const signature = await new Promise<string>((resolve, reject) => {\n this.wallet!.signMessage(params.message, (response) => {\n if (response.type === SignRequestResponseType.SIGN_REQUEST_APPROVED) {\n const data = response.data as { signature?: string };\n resolve(data.signature || '');\n } else if (\n response.type === SignRequestResponseType.SIGN_REQUEST_REJECTED\n ) {\n const data = response.data as { reason: string };\n reject(new Error(`Sign rejected: ${data.reason}`));\n } else {\n const data = response.data as { error: string };\n reject(new Error(`Sign error: ${data.error}`));\n }\n });\n });\n\n return {\n signature: toSignature(signature),\n partyId: session.partyId,\n message: params.message,\n nonce: params.nonce,\n domain: params.domain,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signMessage',\n transport: 'injected',\n details: { sessionId: session.sessionId },\n });\n }\n }\n\n /**\n * Sign a transaction — not supported standalone.\n *\n * Nightly combines signing and submission via submitTransactionCommand.\n */\n async signTransaction(\n _ctx: AdapterContext,\n _session: Session,\n _params: SignTransactionParams,\n ): Promise<SignedTransaction> {\n throw new CapabilityNotSupportedError(\n this.walletId,\n 'signTransaction — Nightly combines signing and submission. Use submitTransaction instead.',\n );\n }\n\n /**\n * Submit a transaction.\n *\n * Nightly uses callback-based submitTransactionCommand.\n * The signedTx should be a TransactionCommand object created via\n * createTransferCommand or createTransactionChoiceCommand.\n */\n async submitTransaction(\n ctx: AdapterContext,\n session: Session,\n params: SubmitTransactionParams,\n ): Promise<TxReceipt> {\n try {\n if (!this.wallet) {\n throw new Error('Not connected to Nightly Wallet');\n }\n\n ctx.logger.debug('Submitting transaction with Nightly Wallet', {\n sessionId: session.sessionId,\n });\n\n const txCommand = params.signedTx as TransactionCommand;\n\n const result = await new Promise<{ signature?: string; updateId?: string }>(\n (resolve, reject) => {\n this.wallet!.submitTransactionCommand(txCommand, (response) => {\n if (\n response.type === SignRequestResponseType.SIGN_REQUEST_APPROVED\n ) {\n resolve(\n response.data as { signature?: string; updateId?: string },\n );\n } else if (\n response.type === SignRequestResponseType.SIGN_REQUEST_REJECTED\n ) {\n const data = response.data as { reason: string };\n reject(new Error(`Transaction rejected: ${data.reason}`));\n } else {\n const data = response.data as { error: string };\n reject(new Error(`Transaction error: ${data.error}`));\n }\n });\n },\n );\n\n const hash =\n result.updateId ||\n result.signature ||\n `tx_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;\n\n return {\n transactionHash: toTransactionHash(hash),\n submittedAt: Date.now(),\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'submitTransaction',\n transport: 'injected',\n details: { sessionId: session.sessionId },\n });\n }\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@partylayer/adapter-nightly",
3
+ "version": "0.2.4",
4
+ "description": "Nightly Wallet adapter for PartyLayer",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "keywords": [
19
+ "canton",
20
+ "wallet",
21
+ "nightly"
22
+ ],
23
+ "author": "PartyLayer Contributors",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/PartyLayer/PartyLayer.git",
28
+ "directory": "packages/adapters/nightly"
29
+ },
30
+ "homepage": "https://github.com/PartyLayer/PartyLayer#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/PartyLayer/PartyLayer/issues"
33
+ },
34
+ "dependencies": {
35
+ "@partylayer/core": "0.2.4"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.11.0",
39
+ "typescript": "^5.3.3",
40
+ "vitest": "^1.2.0"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "clean": "rm -rf dist",
45
+ "lint": "eslint src --ext .ts",
46
+ "typecheck": "tsc --noEmit",
47
+ "test": "vitest run"
48
+ }
49
+ }