@ckb-ccc/joy-id 0.0.5-alpha.8 → 0.0.7-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/btc/index.d.ts +46 -1
- package/dist/btc/index.d.ts.map +1 -1
- package/dist/btc/index.js +46 -3
- package/dist/ckb/index.d.ts +94 -2
- package/dist/ckb/index.d.ts.map +1 -1
- package/dist/ckb/index.js +115 -14
- package/dist/common/index.d.ts +13 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +9 -0
- package/dist/connectionsStorage/index.d.ts +58 -0
- package/dist/connectionsStorage/index.d.ts.map +1 -1
- package/dist/connectionsStorage/index.js +30 -0
- package/dist/evm/index.d.ts +51 -1
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +52 -4
- package/dist/nostr/index.d.ts +51 -0
- package/dist/nostr/index.d.ts.map +1 -0
- package/dist/nostr/index.js +106 -0
- package/dist/signerFactory/index.d.ts +9 -0
- package/dist/signerFactory/index.d.ts.map +1 -1
- package/dist/signerFactory/index.js +14 -0
- package/dist.commonjs/advanced.d.ts +1 -1
- package/dist.commonjs/advanced.js +40 -19
- package/dist.commonjs/advancedBarrel.d.ts +1 -1
- package/dist.commonjs/advancedBarrel.js +30 -14
- package/dist.commonjs/barrel.d.ts +1 -1
- package/dist.commonjs/barrel.js +30 -14
- package/dist.commonjs/btc/index.d.ts +68 -16
- package/dist.commonjs/btc/index.d.ts.map +1 -1
- package/dist.commonjs/btc/index.js +145 -76
- package/dist.commonjs/ckb/index.d.ts +126 -27
- package/dist.commonjs/ckb/index.d.ts.map +1 -1
- package/dist.commonjs/ckb/index.js +312 -154
- package/dist.commonjs/common/index.d.ts +47 -21
- package/dist.commonjs/common/index.d.ts.map +1 -1
- package/dist.commonjs/common/index.js +59 -45
- package/dist.commonjs/connectionsStorage/index.d.ts +81 -14
- package/dist.commonjs/connectionsStorage/index.d.ts.map +1 -1
- package/dist.commonjs/connectionsStorage/index.js +58 -25
- package/dist.commonjs/evm/index.d.ts +72 -16
- package/dist.commonjs/evm/index.d.ts.map +1 -1
- package/dist.commonjs/evm/index.js +140 -70
- package/dist.commonjs/index.d.ts +1 -1
- package/dist.commonjs/index.js +40 -19
- package/dist.commonjs/nostr/index.d.ts +57 -0
- package/dist.commonjs/nostr/index.d.ts.map +1 -0
- package/dist.commonjs/nostr/index.js +129 -0
- package/dist.commonjs/signerFactory/index.d.ts +15 -2
- package/dist.commonjs/signerFactory/index.d.ts.map +1 -1
- package/dist.commonjs/signerFactory/index.js +52 -27
- package/package.json +5 -5
- package/src/btc/index.ts +47 -12
- package/src/ckb/index.ts +127 -25
- package/src/common/index.ts +13 -0
- package/src/connectionsStorage/index.ts +64 -2
- package/src/evm/index.ts +56 -15
- package/src/nostr/index.ts +135 -0
- package/src/signerFactory/index.ts +14 -0
package/src/ckb/index.ts
CHANGED
|
@@ -8,17 +8,36 @@ import {
|
|
|
8
8
|
ConnectionsRepoLocalStorage,
|
|
9
9
|
} from "../connectionsStorage";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Class representing a CKB signer that extends Signer from @ckb-ccc/core.
|
|
13
|
+
* @class
|
|
14
|
+
* @extends {ccc.Signer}
|
|
15
|
+
*/
|
|
11
16
|
export class CkbSigner extends ccc.Signer {
|
|
17
|
+
/**
|
|
18
|
+
* Gets the signer type.
|
|
19
|
+
* @returns {ccc.SignerType} The type of the signer.
|
|
20
|
+
*/
|
|
12
21
|
get type(): ccc.SignerType {
|
|
13
22
|
return ccc.SignerType.CKB;
|
|
14
23
|
}
|
|
15
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Gets the sign type.
|
|
27
|
+
* @returns {ccc.SignerSignType} The sign type.
|
|
28
|
+
*/
|
|
16
29
|
get signType(): ccc.SignerSignType {
|
|
17
30
|
return ccc.SignerSignType.JoyId;
|
|
18
31
|
}
|
|
19
32
|
|
|
20
33
|
private connection?: Connection;
|
|
21
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Ensures that the signer is connected and returns the connection.
|
|
37
|
+
* @private
|
|
38
|
+
* @throws Will throw an error if not connected.
|
|
39
|
+
* @returns {Promise<Connection>} A promise that resolves to the current connection.
|
|
40
|
+
*/
|
|
22
41
|
private async assertConnection(): Promise<Connection> {
|
|
23
42
|
if (!(await this.isConnected()) || !this.connection) {
|
|
24
43
|
throw new Error("Not connected");
|
|
@@ -27,6 +46,15 @@ export class CkbSigner extends ccc.Signer {
|
|
|
27
46
|
return this.connection;
|
|
28
47
|
}
|
|
29
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Creates an instance of CkbSigner.
|
|
51
|
+
* @param {ccc.Client} client - The client instance.
|
|
52
|
+
* @param {string} name - The name of the signer.
|
|
53
|
+
* @param {string} icon - The icon URL of the signer.
|
|
54
|
+
* @param {string} [_appUri] - The application URI.
|
|
55
|
+
* @param {string} [_aggregatorUri] - The aggregator URI.
|
|
56
|
+
* @param {ConnectionsRepo} [connectionsRepo=new ConnectionsRepoLocalStorage()] - The connections repository.
|
|
57
|
+
*/
|
|
30
58
|
constructor(
|
|
31
59
|
client: ccc.Client,
|
|
32
60
|
private readonly name: string,
|
|
@@ -38,17 +66,11 @@ export class CkbSigner extends ccc.Signer {
|
|
|
38
66
|
super(client);
|
|
39
67
|
}
|
|
40
68
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
this._appUri,
|
|
47
|
-
this._aggregatorUri,
|
|
48
|
-
this.connectionsRepo,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Gets the configuration for JoyID.
|
|
71
|
+
* @private
|
|
72
|
+
* @returns {object} The configuration object.
|
|
73
|
+
*/
|
|
52
74
|
private getConfig() {
|
|
53
75
|
return {
|
|
54
76
|
redirectURL: location.href,
|
|
@@ -61,6 +83,11 @@ export class CkbSigner extends ccc.Signer {
|
|
|
61
83
|
};
|
|
62
84
|
}
|
|
63
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Gets the aggregator URI.
|
|
88
|
+
* @private
|
|
89
|
+
* @returns {string} The aggregator URI.
|
|
90
|
+
*/
|
|
64
91
|
private getAggregatorUri(): string {
|
|
65
92
|
if (this._aggregatorUri) {
|
|
66
93
|
return this._aggregatorUri;
|
|
@@ -71,6 +98,10 @@ export class CkbSigner extends ccc.Signer {
|
|
|
71
98
|
: "https://cota.nervina.dev/aggregator";
|
|
72
99
|
}
|
|
73
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Connects to the provider by requesting authentication.
|
|
103
|
+
* @returns {Promise<void>} A promise that resolves when the connection is established.
|
|
104
|
+
*/
|
|
74
105
|
async connect(): Promise<void> {
|
|
75
106
|
const config = this.getConfig();
|
|
76
107
|
|
|
@@ -87,11 +118,10 @@ export class CkbSigner extends ccc.Signer {
|
|
|
87
118
|
await this.saveConnection();
|
|
88
119
|
}
|
|
89
120
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Checks if the signer is connected.
|
|
123
|
+
* @returns {Promise<boolean>} A promise that resolves to true if connected, false otherwise.
|
|
124
|
+
*/
|
|
95
125
|
async isConnected(): Promise<boolean> {
|
|
96
126
|
if (this.connection) {
|
|
97
127
|
return true;
|
|
@@ -100,10 +130,18 @@ export class CkbSigner extends ccc.Signer {
|
|
|
100
130
|
return this.connection !== undefined;
|
|
101
131
|
}
|
|
102
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Gets the internal address.
|
|
135
|
+
* @returns {Promise<string>} A promise that resolves to the internal address.
|
|
136
|
+
*/
|
|
103
137
|
async getInternalAddress(): Promise<string> {
|
|
104
138
|
return (await this.assertConnection()).address;
|
|
105
139
|
}
|
|
106
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Gets the identity of the signer.
|
|
143
|
+
* @returns {Promise<string>} A promise that resolves to the identity.
|
|
144
|
+
*/
|
|
107
145
|
async getIdentity(): Promise<string> {
|
|
108
146
|
const connection = await this.assertConnection();
|
|
109
147
|
return JSON.stringify({
|
|
@@ -112,6 +150,10 @@ export class CkbSigner extends ccc.Signer {
|
|
|
112
150
|
});
|
|
113
151
|
}
|
|
114
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Gets the address object.
|
|
155
|
+
* @returns {Promise<ccc.Address>} A promise that resolves to the address object.
|
|
156
|
+
*/
|
|
115
157
|
async getAddressObj(): Promise<ccc.Address> {
|
|
116
158
|
return await ccc.Address.fromString(
|
|
117
159
|
await this.getInternalAddress(),
|
|
@@ -119,14 +161,24 @@ export class CkbSigner extends ccc.Signer {
|
|
|
119
161
|
);
|
|
120
162
|
}
|
|
121
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Gets the address objects.
|
|
166
|
+
* @returns {Promise<ccc.Address[]>} A promise that resolves to an array of address objects.
|
|
167
|
+
*/
|
|
122
168
|
async getAddressObjs(): Promise<ccc.Address[]> {
|
|
123
169
|
return [await this.getAddressObj()];
|
|
124
170
|
}
|
|
125
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Prepares a transaction.
|
|
174
|
+
* @param {ccc.TransactionLike} txLike - The transaction-like object.
|
|
175
|
+
* @returns {Promise<ccc.Transaction>} A promise that resolves to the prepared transaction.
|
|
176
|
+
*/
|
|
126
177
|
async prepareTransaction(
|
|
127
178
|
txLike: ccc.TransactionLike,
|
|
128
179
|
): Promise<ccc.Transaction> {
|
|
129
180
|
const tx = ccc.Transaction.from(txLike);
|
|
181
|
+
await tx.addCellDepsOfKnownScripts(this.client, ccc.KnownScript.JoyId);
|
|
130
182
|
const position = await tx.findInputIndexByLock(
|
|
131
183
|
(await this.getAddressObj()).script,
|
|
132
184
|
this.client,
|
|
@@ -136,11 +188,20 @@ export class CkbSigner extends ccc.Signer {
|
|
|
136
188
|
}
|
|
137
189
|
|
|
138
190
|
const witness = tx.getWitnessArgsAt(position) ?? ccc.WitnessArgs.from({});
|
|
139
|
-
witness.lock = "
|
|
191
|
+
witness.lock = ccc.hexFrom("00".repeat(1000));
|
|
140
192
|
await this.prepareTransactionForSubKey(tx, witness);
|
|
141
|
-
|
|
193
|
+
tx.setWitnessArgsAt(position, witness);
|
|
194
|
+
|
|
195
|
+
return tx;
|
|
142
196
|
}
|
|
143
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Prepares a transaction for a sub key.
|
|
200
|
+
* @private
|
|
201
|
+
* @param tx - The transaction object.
|
|
202
|
+
* @param witness - The witness arguments.
|
|
203
|
+
* @throws Will throw an error if no COTA cells are found for the sub key wallet.
|
|
204
|
+
*/
|
|
144
205
|
private async prepareTransactionForSubKey(
|
|
145
206
|
tx: ccc.Transaction,
|
|
146
207
|
witness: ccc.WitnessArgs,
|
|
@@ -161,10 +222,10 @@ export class CkbSigner extends ccc.Signer {
|
|
|
161
222
|
witness.outputType = ccc.hexFrom(unlockEntry);
|
|
162
223
|
|
|
163
224
|
const cotaDeps: ccc.CellDep[] = [];
|
|
164
|
-
for await (const cell of this.client.findCellsByLockAndType(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
225
|
+
for await (const cell of this.client.findCellsByLockAndType(
|
|
226
|
+
lock,
|
|
227
|
+
await ccc.Script.fromKnownScript(this.client, ccc.KnownScript.COTA, "0x"),
|
|
228
|
+
)) {
|
|
168
229
|
cotaDeps.push(
|
|
169
230
|
ccc.CellDep.from({
|
|
170
231
|
depType: "code",
|
|
@@ -180,11 +241,37 @@ export class CkbSigner extends ccc.Signer {
|
|
|
180
241
|
tx.cellDeps.unshift(...cotaDeps);
|
|
181
242
|
}
|
|
182
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Signs a transaction.
|
|
246
|
+
* @param {ccc.TransactionLike} txLike - The transaction-like object.
|
|
247
|
+
* @returns {Promise<ccc.Transaction>} A promise that resolves to the signed transaction.
|
|
248
|
+
*/
|
|
183
249
|
async signOnlyTransaction(
|
|
184
250
|
txLike: ccc.TransactionLike,
|
|
185
251
|
): Promise<ccc.Transaction> {
|
|
186
252
|
const tx = ccc.Transaction.from(txLike);
|
|
187
253
|
const { script } = await this.getAddressObj();
|
|
254
|
+
const witnessIndexes = await ccc.reduceAsync(
|
|
255
|
+
tx.inputs,
|
|
256
|
+
async (acc, input, i) => {
|
|
257
|
+
await input.completeExtraInfos(this.client);
|
|
258
|
+
if (!input.cellOutput) {
|
|
259
|
+
throw new Error("Unable to complete input");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (input.cellOutput.lock.eq(script)) {
|
|
263
|
+
acc.push(i);
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
[] as number[],
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
// Trim unnecessary fields to reduce tx size
|
|
270
|
+
await tx.prepareSighashAllWitness(script, 0, this.client);
|
|
271
|
+
tx.inputs.forEach((i) => {
|
|
272
|
+
i.cellOutput = undefined;
|
|
273
|
+
i.outputData = undefined;
|
|
274
|
+
});
|
|
188
275
|
|
|
189
276
|
const config = this.getConfig();
|
|
190
277
|
const res = await createPopup(
|
|
@@ -193,7 +280,7 @@ export class CkbSigner extends ccc.Signer {
|
|
|
193
280
|
...config,
|
|
194
281
|
tx: JSON.parse(tx.stringify()),
|
|
195
282
|
signerAddress: (await this.assertConnection()).address,
|
|
196
|
-
|
|
283
|
+
witnessIndexes,
|
|
197
284
|
},
|
|
198
285
|
"popup",
|
|
199
286
|
"/sign-ckb-raw-tx",
|
|
@@ -207,6 +294,11 @@ export class CkbSigner extends ccc.Signer {
|
|
|
207
294
|
return ccc.Transaction.from(res.tx);
|
|
208
295
|
}
|
|
209
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Signs a raw message with the account.
|
|
299
|
+
* @param {string | ccc.BytesLike} message - The message to sign.
|
|
300
|
+
* @returns {Promise<string>} A promise that resolves to the signed message.
|
|
301
|
+
*/
|
|
210
302
|
async signMessageRaw(message: string | ccc.BytesLike): Promise<string> {
|
|
211
303
|
const { address } = await this.assertConnection();
|
|
212
304
|
|
|
@@ -234,7 +326,12 @@ export class CkbSigner extends ccc.Signer {
|
|
|
234
326
|
});
|
|
235
327
|
}
|
|
236
328
|
|
|
237
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Saves the current connection.
|
|
331
|
+
* @private
|
|
332
|
+
* @returns {Promise<void>}
|
|
333
|
+
*/
|
|
334
|
+
private async saveConnection(): Promise<void> {
|
|
238
335
|
return this.connectionsRepo.set(
|
|
239
336
|
{
|
|
240
337
|
uri: this.getConfig().joyidAppURL,
|
|
@@ -244,7 +341,12 @@ export class CkbSigner extends ccc.Signer {
|
|
|
244
341
|
);
|
|
245
342
|
}
|
|
246
343
|
|
|
247
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Restores the previous connection.
|
|
346
|
+
* @private
|
|
347
|
+
* @returns {Promise<void>}
|
|
348
|
+
*/
|
|
349
|
+
private async restoreConnection(): Promise<void> {
|
|
248
350
|
this.connection = await this.connectionsRepo.get({
|
|
249
351
|
uri: this.getConfig().joyidAppURL,
|
|
250
352
|
addressType: "ckb",
|
package/src/common/index.ts
CHANGED
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
openPopup,
|
|
17
17
|
} from "@joyid/common";
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Interface representing the return type for various Dapp request types.
|
|
21
|
+
* @interface
|
|
22
|
+
*/
|
|
19
23
|
export interface PopupReturnType {
|
|
20
24
|
[DappRequestType.Auth]: AuthResponseData;
|
|
21
25
|
[DappRequestType.SignMessage]: SignMessageResponseData;
|
|
@@ -36,6 +40,15 @@ export interface PopupReturnType {
|
|
|
36
40
|
[DappRequestType.EvmWeb2Login]: EvmWeb2LoginResponse;
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Creates a popup window for JoyID Dapp requests.
|
|
45
|
+
* @param {string} url - The URL to open in the popup.
|
|
46
|
+
* @param {PopupConfigOptions<T> & { joyidAppURL: string }} config - The popup configuration options.
|
|
47
|
+
* @returns {Promise<PopupReturnType[T]>} A promise that resolves to the response data of the requested type.
|
|
48
|
+
* @throws {PopupNotSupportedError} If popups are not supported in the current browser.
|
|
49
|
+
* @throws {PopupCancelledError} If the popup is closed by the user.
|
|
50
|
+
* @throws {PopupTimeoutError} If the popup operation times out.
|
|
51
|
+
*/
|
|
39
52
|
export async function createPopup<T extends DappRequestType>(
|
|
40
53
|
url: string,
|
|
41
54
|
config: PopupConfigOptions<T> & { joyidAppURL: string },
|
|
@@ -1,42 +1,104 @@
|
|
|
1
1
|
import { ccc } from "@ckb-ccc/core";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Type representing an account selector with a URI and address type.
|
|
5
|
+
* @typedef {Object} AccountSelector
|
|
6
|
+
* @property {string} uri - The URI of the account.
|
|
7
|
+
* @property {string} addressType - The address type of the account.
|
|
8
|
+
*/
|
|
3
9
|
export type AccountSelector = {
|
|
4
10
|
uri: string;
|
|
5
11
|
addressType: string;
|
|
6
12
|
};
|
|
7
13
|
|
|
8
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Checks if two AccountSelectors are equal.
|
|
16
|
+
* @param {AccountSelector} a - The first account selector.
|
|
17
|
+
* @param {AccountSelector} b - The second account selector.
|
|
18
|
+
* @returns {boolean} True if the selectors are equal, false otherwise.
|
|
19
|
+
*/
|
|
20
|
+
export function isSelectorEq(a: AccountSelector, b: AccountSelector): boolean {
|
|
9
21
|
return a.uri === b.uri && a.addressType === b.addressType;
|
|
10
22
|
}
|
|
11
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Type representing a connection with an address, public key, and key type.
|
|
26
|
+
* @typedef {Object} Connection
|
|
27
|
+
* @property {string} address - The address of the connection.
|
|
28
|
+
* @property {ccc.Hex} publicKey - The public key of the connection.
|
|
29
|
+
* @property {string} keyType - The key type of the connection.
|
|
30
|
+
*/
|
|
12
31
|
export type Connection = {
|
|
13
32
|
readonly address: string;
|
|
14
33
|
readonly publicKey: ccc.Hex;
|
|
15
34
|
readonly keyType: string;
|
|
16
35
|
};
|
|
17
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Interface representing a repository for managing connections.
|
|
39
|
+
* @interface
|
|
40
|
+
*/
|
|
18
41
|
export interface ConnectionsRepo {
|
|
42
|
+
/**
|
|
43
|
+
* Gets a connection for the given selector.
|
|
44
|
+
* @param {AccountSelector} selector - The account selector.
|
|
45
|
+
* @returns {Promise<Connection | undefined>} A promise that resolves to the connection, if found.
|
|
46
|
+
*/
|
|
19
47
|
get(selector: AccountSelector): Promise<Connection | undefined>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Sets a connection for the given selector.
|
|
51
|
+
* @param {AccountSelector} selector - The account selector.
|
|
52
|
+
* @param {Connection | undefined} connection - The connection to set.
|
|
53
|
+
* @returns {Promise<void>} A promise that resolves when the connection is set.
|
|
54
|
+
*/
|
|
20
55
|
set(
|
|
21
56
|
selector: AccountSelector,
|
|
22
57
|
connection: Connection | undefined,
|
|
23
58
|
): Promise<void>;
|
|
24
59
|
}
|
|
25
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Class representing a local storage-based repository for managing connections.
|
|
63
|
+
* @class
|
|
64
|
+
* @implements {ConnectionsRepo}
|
|
65
|
+
*/
|
|
26
66
|
export class ConnectionsRepoLocalStorage implements ConnectionsRepo {
|
|
67
|
+
/**
|
|
68
|
+
* Creates an instance of ConnectionsRepoLocalStorage.
|
|
69
|
+
* @param {string} [storageKey="ccc-joy-id-signer"] - The local storage key.
|
|
70
|
+
*/
|
|
27
71
|
constructor(private readonly storageKey = "ccc-joy-id-signer") {}
|
|
28
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Reads all connections from local storage.
|
|
75
|
+
* @returns {Promise<[AccountSelector, Connection][]>} A promise that resolves to an array of selectors and connections.
|
|
76
|
+
*/
|
|
29
77
|
async readConnections(): Promise<[AccountSelector, Connection][]> {
|
|
30
78
|
return JSON.parse(window.localStorage.getItem(this.storageKey) ?? "[]");
|
|
31
79
|
}
|
|
32
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Gets a connection for the given selector.
|
|
83
|
+
* @param {AccountSelector} selector - The account selector.
|
|
84
|
+
* @returns {Promise<Connection | undefined>} A promise that resolves to the connection, if found.
|
|
85
|
+
*/
|
|
33
86
|
async get(selector: AccountSelector): Promise<Connection | undefined> {
|
|
34
87
|
return (await this.readConnections()).find(([s]) =>
|
|
35
88
|
isSelectorEq(selector, s),
|
|
36
89
|
)?.[1];
|
|
37
90
|
}
|
|
38
91
|
|
|
39
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Sets a connection for the given selector.
|
|
94
|
+
* @param {AccountSelector} selector - The account selector.
|
|
95
|
+
* @param {Connection | undefined} connection - The connection to set.
|
|
96
|
+
* @returns {Promise<void>}
|
|
97
|
+
*/
|
|
98
|
+
async set(
|
|
99
|
+
selector: AccountSelector,
|
|
100
|
+
connection: Connection | undefined,
|
|
101
|
+
): Promise<void> {
|
|
40
102
|
const connections = await this.readConnections();
|
|
41
103
|
|
|
42
104
|
if (connection) {
|
package/src/evm/index.ts
CHANGED
|
@@ -7,10 +7,21 @@ import {
|
|
|
7
7
|
ConnectionsRepoLocalStorage,
|
|
8
8
|
} from "../connectionsStorage";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Class representing an EVM signer that extends SignerEvm from @ckb-ccc/core.
|
|
12
|
+
* @class
|
|
13
|
+
* @extends {ccc.SignerEvm}
|
|
14
|
+
*/
|
|
10
15
|
export class EvmSigner extends ccc.SignerEvm {
|
|
11
16
|
private connection?: Connection;
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Ensures that the signer is connected and returns the connection.
|
|
20
|
+
* @private
|
|
21
|
+
* @throws Will throw an error if not connected.
|
|
22
|
+
* @returns {Connection} The current connection.
|
|
23
|
+
*/
|
|
24
|
+
private assertConnection(): Connection {
|
|
14
25
|
if (!this.isConnected() || !this.connection) {
|
|
15
26
|
throw new Error("Not connected");
|
|
16
27
|
}
|
|
@@ -18,6 +29,14 @@ export class EvmSigner extends ccc.SignerEvm {
|
|
|
18
29
|
return this.connection;
|
|
19
30
|
}
|
|
20
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Creates an instance of EvmSigner.
|
|
34
|
+
* @param {ccc.Client} client - The client instance.
|
|
35
|
+
* @param {string} name - The name of the signer.
|
|
36
|
+
* @param {string} icon - The icon URL of the signer.
|
|
37
|
+
* @param {string} [appUri="https://app.joy.id"] - The application URI.
|
|
38
|
+
* @param {ConnectionsRepo} [connectionsRepo=new ConnectionsRepoLocalStorage()] - The connections repository.
|
|
39
|
+
*/
|
|
21
40
|
constructor(
|
|
22
41
|
client: ccc.Client,
|
|
23
42
|
private readonly name: string,
|
|
@@ -28,16 +47,11 @@ export class EvmSigner extends ccc.SignerEvm {
|
|
|
28
47
|
super(client);
|
|
29
48
|
}
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
this.appUri,
|
|
37
|
-
this.connectionsRepo,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Gets the configuration for JoyID.
|
|
52
|
+
* @private
|
|
53
|
+
* @returns {object} The configuration object.
|
|
54
|
+
*/
|
|
41
55
|
private getConfig() {
|
|
42
56
|
return {
|
|
43
57
|
redirectURL: location.href,
|
|
@@ -48,12 +62,20 @@ export class EvmSigner extends ccc.SignerEvm {
|
|
|
48
62
|
};
|
|
49
63
|
}
|
|
50
64
|
|
|
51
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Gets the EVM account address.
|
|
67
|
+
* @returns {Promise<string>} A promise that resolves to the EVM account address.
|
|
68
|
+
*/
|
|
69
|
+
async getEvmAccount(): Promise<string> {
|
|
52
70
|
return this.assertConnection().address;
|
|
53
71
|
}
|
|
54
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Connects to the provider by requesting authentication.
|
|
75
|
+
* @returns {Promise<void>} A promise that resolves when the connection is established.
|
|
76
|
+
*/
|
|
55
77
|
async connect(): Promise<void> {
|
|
56
|
-
const config =
|
|
78
|
+
const config = this.getConfig();
|
|
57
79
|
|
|
58
80
|
const res = await createPopup(buildJoyIDURL(config, "popup", "/auth"), {
|
|
59
81
|
...config,
|
|
@@ -68,6 +90,10 @@ export class EvmSigner extends ccc.SignerEvm {
|
|
|
68
90
|
await this.saveConnection();
|
|
69
91
|
}
|
|
70
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Checks if the signer is connected.
|
|
95
|
+
* @returns {Promise<boolean>} A promise that resolves to true if connected, false otherwise.
|
|
96
|
+
*/
|
|
71
97
|
async isConnected(): Promise<boolean> {
|
|
72
98
|
if (this.connection) {
|
|
73
99
|
return true;
|
|
@@ -76,6 +102,11 @@ export class EvmSigner extends ccc.SignerEvm {
|
|
|
76
102
|
return this.connection !== undefined;
|
|
77
103
|
}
|
|
78
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Signs a raw message with the EVM account.
|
|
107
|
+
* @param {string | ccc.BytesLike} message - The message to sign.
|
|
108
|
+
* @returns {Promise<ccc.Hex>} A promise that resolves to the signed message.
|
|
109
|
+
*/
|
|
79
110
|
async signMessageRaw(message: string | ccc.BytesLike): Promise<ccc.Hex> {
|
|
80
111
|
const { address } = this.assertConnection();
|
|
81
112
|
|
|
@@ -99,7 +130,12 @@ export class EvmSigner extends ccc.SignerEvm {
|
|
|
99
130
|
return ccc.hexFrom(signature);
|
|
100
131
|
}
|
|
101
132
|
|
|
102
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Saves the current connection.
|
|
135
|
+
* @private
|
|
136
|
+
* @returns {Promise<void>}
|
|
137
|
+
*/
|
|
138
|
+
private async saveConnection(): Promise<void> {
|
|
103
139
|
return this.connectionsRepo.set(
|
|
104
140
|
{
|
|
105
141
|
uri: this.getConfig().joyidAppURL,
|
|
@@ -109,7 +145,12 @@ export class EvmSigner extends ccc.SignerEvm {
|
|
|
109
145
|
);
|
|
110
146
|
}
|
|
111
147
|
|
|
112
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Restores the previous connection.
|
|
150
|
+
* @private
|
|
151
|
+
* @returns {Promise<void>}
|
|
152
|
+
*/
|
|
153
|
+
private async restoreConnection(): Promise<void> {
|
|
113
154
|
this.connection = await this.connectionsRepo.get({
|
|
114
155
|
uri: this.getConfig().joyidAppURL,
|
|
115
156
|
addressType: "ethereum",
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { ccc } from "@ckb-ccc/core";
|
|
2
|
+
import { DappRequestType, buildJoyIDURL } from "@joyid/common";
|
|
3
|
+
import { createPopup } from "../common";
|
|
4
|
+
import {
|
|
5
|
+
Connection,
|
|
6
|
+
ConnectionsRepo,
|
|
7
|
+
ConnectionsRepoLocalStorage,
|
|
8
|
+
} from "../connectionsStorage";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Class representing a Nostr signer that extends SignerNostr from @ckb-ccc/core.
|
|
12
|
+
* @class
|
|
13
|
+
* @extends {ccc.SignerNostr}
|
|
14
|
+
*/
|
|
15
|
+
export class NostrSigner extends ccc.SignerNostr {
|
|
16
|
+
private connection?: Connection;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Ensures that the signer is connected and returns the connection.
|
|
20
|
+
* @private
|
|
21
|
+
* @throws Will throw an error if not connected.
|
|
22
|
+
* @returns {Connection} The current connection.
|
|
23
|
+
*/
|
|
24
|
+
private assertConnection(): Connection {
|
|
25
|
+
if (!this.isConnected() || !this.connection) {
|
|
26
|
+
throw new Error("Not connected");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return this.connection;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Creates an instance of NostrSigner.
|
|
34
|
+
* @param {ccc.Client} client - The client instance.
|
|
35
|
+
* @param {string} name - The name of the signer.
|
|
36
|
+
* @param {string} icon - The icon URL of the signer.
|
|
37
|
+
* @param {string} [appUri="https://app.joy.id"] - The application URI.
|
|
38
|
+
* @param {ConnectionsRepo} [connectionsRepo=new ConnectionsRepoLocalStorage()] - The connections repository.
|
|
39
|
+
*/
|
|
40
|
+
constructor(
|
|
41
|
+
client: ccc.Client,
|
|
42
|
+
private readonly name: string,
|
|
43
|
+
private readonly icon: string,
|
|
44
|
+
private readonly appUri = "https://app.joy.id",
|
|
45
|
+
private readonly connectionsRepo: ConnectionsRepo = new ConnectionsRepoLocalStorage(),
|
|
46
|
+
) {
|
|
47
|
+
super(client);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static isValidClient(client: ccc.Client): boolean {
|
|
51
|
+
return client.addressPrefix === "ckt";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async replaceClient(client: ccc.Client): Promise<boolean> {
|
|
55
|
+
if (!NostrSigner.isValidClient(client)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return super.replaceClient(client);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Gets the configuration for JoyID.
|
|
63
|
+
* @private
|
|
64
|
+
* @returns {object} The configuration object.
|
|
65
|
+
*/
|
|
66
|
+
private getConfig() {
|
|
67
|
+
return {
|
|
68
|
+
redirectURL: location.href,
|
|
69
|
+
joyidAppURL: this.appUri,
|
|
70
|
+
requestNetwork: "nostr",
|
|
71
|
+
name: this.name,
|
|
72
|
+
logo: this.icon,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Connects to the provider by requesting authentication.
|
|
78
|
+
* @returns {Promise<void>} A promise that resolves when the connection is established.
|
|
79
|
+
*/
|
|
80
|
+
async connect(): Promise<void> {
|
|
81
|
+
const config = this.getConfig();
|
|
82
|
+
const res = await createPopup(buildJoyIDURL(config, "popup", "/auth"), {
|
|
83
|
+
...config,
|
|
84
|
+
type: DappRequestType.Auth,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
this.connection = {
|
|
88
|
+
address: "",
|
|
89
|
+
publicKey: ccc.hexFrom(res.nostrPubkey),
|
|
90
|
+
keyType: res.keyType,
|
|
91
|
+
};
|
|
92
|
+
await this.connectionsRepo.set(
|
|
93
|
+
{ uri: this.appUri, addressType: "nostr" },
|
|
94
|
+
this.connection,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Checks if the signer is connected.
|
|
100
|
+
* @returns {Promise<boolean>} A promise that resolves to true if connected, false otherwise.
|
|
101
|
+
*/
|
|
102
|
+
async isConnected(): Promise<boolean> {
|
|
103
|
+
if (this.connection) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.connection = await this.connectionsRepo.get({
|
|
108
|
+
uri: this.appUri,
|
|
109
|
+
addressType: "nostr",
|
|
110
|
+
});
|
|
111
|
+
return this.connection !== undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async getNostrPublicKey(): Promise<ccc.Hex> {
|
|
115
|
+
if (!this.connection) {
|
|
116
|
+
throw new Error("Not connected");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return this.connection.publicKey;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async signNostrEvent(
|
|
123
|
+
event: ccc.NostrEvent,
|
|
124
|
+
): Promise<Required<ccc.NostrEvent>> {
|
|
125
|
+
const config = this.getConfig();
|
|
126
|
+
const res = await createPopup(
|
|
127
|
+
buildJoyIDURL({ ...config, event }, "popup", "/sign-nostr-event"),
|
|
128
|
+
{
|
|
129
|
+
...config,
|
|
130
|
+
type: DappRequestType.SignNostrEvent,
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
return res.event;
|
|
134
|
+
}
|
|
135
|
+
}
|