@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 +21 -0
- package/README.md +51 -0
- package/dist/index.d.mts +123 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.js +228 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +226 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -0
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
|
+
[](https://www.npmjs.com/package/@partylayer/adapter-nightly)
|
|
8
|
+
[](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
|
package/dist/index.d.mts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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":"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","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
|
+
}
|