@ckb-ccc/joy-id 0.0.5-alpha.0 → 0.0.5-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/advancedBarrel.d.ts +1 -0
  2. package/dist/advancedBarrel.d.ts.map +1 -1
  3. package/dist/advancedBarrel.js +1 -0
  4. package/dist/barrel.d.ts +1 -0
  5. package/dist/barrel.d.ts.map +1 -1
  6. package/dist/barrel.js +1 -0
  7. package/dist/btc/index.d.ts +5 -2
  8. package/dist/btc/index.d.ts.map +1 -1
  9. package/dist/btc/index.js +27 -16
  10. package/dist/ckb/index.d.ts +5 -3
  11. package/dist/ckb/index.d.ts.map +1 -1
  12. package/dist/ckb/index.js +28 -28
  13. package/dist/common/index.d.ts +24 -0
  14. package/dist/common/index.d.ts.map +1 -0
  15. package/dist/common/index.js +50 -0
  16. package/dist/evm/index.d.ts +20 -0
  17. package/dist/evm/index.d.ts.map +1 -0
  18. package/dist/evm/index.js +78 -0
  19. package/dist/signerFactory/index.d.ts +1 -1
  20. package/dist/signerFactory/index.d.ts.map +1 -1
  21. package/dist/signerFactory/index.js +11 -5
  22. package/dist.commonjs/advancedBarrel.d.ts +1 -0
  23. package/dist.commonjs/advancedBarrel.d.ts.map +1 -1
  24. package/dist.commonjs/advancedBarrel.js +1 -0
  25. package/dist.commonjs/barrel.d.ts +1 -0
  26. package/dist.commonjs/barrel.d.ts.map +1 -1
  27. package/dist.commonjs/barrel.js +1 -0
  28. package/dist.commonjs/btc/index.d.ts +5 -2
  29. package/dist.commonjs/btc/index.d.ts.map +1 -1
  30. package/dist.commonjs/btc/index.js +26 -15
  31. package/dist.commonjs/ckb/index.d.ts +5 -3
  32. package/dist.commonjs/ckb/index.d.ts.map +1 -1
  33. package/dist.commonjs/ckb/index.js +27 -27
  34. package/dist.commonjs/common/index.d.ts +24 -0
  35. package/dist.commonjs/common/index.d.ts.map +1 -0
  36. package/dist.commonjs/common/index.js +54 -0
  37. package/dist.commonjs/evm/index.d.ts +20 -0
  38. package/dist.commonjs/evm/index.d.ts.map +1 -0
  39. package/dist.commonjs/evm/index.js +82 -0
  40. package/dist.commonjs/signerFactory/index.d.ts +1 -1
  41. package/dist.commonjs/signerFactory/index.d.ts.map +1 -1
  42. package/dist.commonjs/signerFactory/index.js +11 -5
  43. package/dist.commonjs/tsconfig.commonjs.tsbuildinfo +1 -1
  44. package/package.json +3 -3
  45. package/src/advancedBarrel.ts +1 -0
  46. package/src/barrel.ts +1 -0
  47. package/src/btc/index.ts +44 -18
  48. package/src/ckb/index.ts +45 -42
  49. package/src/common/index.ts +100 -0
  50. package/src/evm/index.ts +118 -0
  51. package/src/signerFactory/index.ts +15 -5
package/src/btc/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ccc } from "@ckb-ccc/core";
2
- import { authWithPopup, signMessageWithPopup } from "@joyid/common";
2
+ import { DappRequestType, buildJoyIDURL } from "@joyid/common";
3
+ import { createPopup } from "../common";
3
4
  import {
4
5
  Connection,
5
6
  ConnectionsRepo,
@@ -19,15 +20,34 @@ export class BitcoinSigner extends ccc.SignerBtc {
19
20
 
20
21
  constructor(
21
22
  client: ccc.Client,
23
+ private readonly name: string,
24
+ private readonly icon: string,
22
25
  private readonly addressType: "auto" | "p2wpkh" | "p2tr" = "auto",
23
- private readonly uri = "https://app.joy.id",
26
+ private readonly appUri = "https://app.joy.id",
24
27
  private readonly connectionsRepo: ConnectionsRepo = new ConnectionsRepoLocalStorage(),
25
28
  ) {
26
29
  super(client);
27
30
  }
28
31
 
29
32
  async replaceClient(client: ccc.Client): Promise<BitcoinSigner> {
30
- return new BitcoinSigner(client, this.addressType, this.uri);
33
+ return new BitcoinSigner(
34
+ client,
35
+ this.name,
36
+ this.icon,
37
+ this.addressType,
38
+ this.appUri,
39
+ this.connectionsRepo,
40
+ );
41
+ }
42
+
43
+ private getConfig() {
44
+ return {
45
+ redirectURL: location.href,
46
+ joyidAppURL: this.appUri,
47
+ requestNetwork: `btc-${this.addressType}`,
48
+ name: this.name,
49
+ logo: this.icon,
50
+ };
31
51
  }
32
52
 
33
53
  async getBtcAccount(): Promise<string> {
@@ -41,10 +61,10 @@ export class BitcoinSigner extends ccc.SignerBtc {
41
61
  }
42
62
 
43
63
  async connect(): Promise<void> {
44
- const res = await authWithPopup({
45
- joyidAppURL: this.uri,
46
- redirectURL: location.href,
47
- requestNetwork: `btc-${this.addressType}`,
64
+ const config = this.getConfig();
65
+ const res = await createPopup(buildJoyIDURL(config, "popup", "/auth"), {
66
+ ...config,
67
+ type: DappRequestType.Auth,
48
68
  });
49
69
 
50
70
  const { address, pubkey } = (() => {
@@ -61,11 +81,11 @@ export class BitcoinSigner extends ccc.SignerBtc {
61
81
  };
62
82
  await Promise.all([
63
83
  this.connectionsRepo.set(
64
- { uri: this.uri, addressType: `btc-${res.btcAddressType}` },
84
+ { uri: this.appUri, addressType: `btc-${res.btcAddressType}` },
65
85
  this.connection,
66
86
  ),
67
87
  this.connectionsRepo.set(
68
- { uri: this.uri, addressType: "btc-auto" },
88
+ { uri: this.appUri, addressType: "btc-auto" },
69
89
  this.connection,
70
90
  ),
71
91
  ]);
@@ -77,7 +97,7 @@ export class BitcoinSigner extends ccc.SignerBtc {
77
97
  }
78
98
 
79
99
  this.connection = await this.connectionsRepo.get({
80
- uri: this.uri,
100
+ uri: this.appUri,
81
101
  addressType: `btc-${this.addressType}`,
82
102
  });
83
103
  return this.connection !== undefined;
@@ -89,14 +109,20 @@ export class BitcoinSigner extends ccc.SignerBtc {
89
109
  const challenge =
90
110
  typeof message === "string" ? message : ccc.hexFrom(message).slice(2);
91
111
 
92
- const { signature } = await signMessageWithPopup({
93
- joyidAppURL: this.uri,
94
- requestNetwork: `btc-${this.addressType}`,
95
- challenge,
96
- address,
97
- signMessageType: "ecdsa",
98
- redirectURL: location.href,
99
- });
112
+ const config = this.getConfig();
113
+ const { signature } = await createPopup(
114
+ buildJoyIDURL(
115
+ {
116
+ ...config,
117
+ challenge,
118
+ address,
119
+ signMessageType: "ecdsa",
120
+ },
121
+ "popup",
122
+ "/sign-message",
123
+ ),
124
+ { ...config, type: DappRequestType.SignMessage },
125
+ );
100
126
  return signature;
101
127
  }
102
128
  }
package/src/ckb/index.ts CHANGED
@@ -1,13 +1,7 @@
1
1
  import { ccc } from "@ckb-ccc/core";
2
2
  import { Aggregator } from "@joyid/ckb";
3
- import {
4
- DappRequestType,
5
- authWithPopup,
6
- buildJoyIDURL,
7
- createBlockDialog,
8
- openPopup,
9
- runPopup,
10
- } from "@joyid/common";
3
+ import { DappRequestType, buildJoyIDURL } from "@joyid/common";
4
+ import { createPopup } from "../common";
11
5
  import {
12
6
  Connection,
13
7
  ConnectionsRepo,
@@ -27,7 +21,9 @@ export class CkbSigner extends ccc.Signer {
27
21
 
28
22
  constructor(
29
23
  client: ccc.Client,
30
- private readonly _uri?: string,
24
+ private readonly name: string,
25
+ private readonly icon: string,
26
+ private readonly _appUri?: string,
31
27
  private readonly _aggregatorUri?: string,
32
28
  private readonly connectionsRepo: ConnectionsRepo = new ConnectionsRepoLocalStorage(),
33
29
  ) {
@@ -35,17 +31,27 @@ export class CkbSigner extends ccc.Signer {
35
31
  }
36
32
 
37
33
  async replaceClient(client: ccc.Client): Promise<CkbSigner> {
38
- return new CkbSigner(client, this._uri);
34
+ return new CkbSigner(
35
+ client,
36
+ this.name,
37
+ this.icon,
38
+ this._appUri,
39
+ this._aggregatorUri,
40
+ this.connectionsRepo,
41
+ );
39
42
  }
40
43
 
41
- private async getUri(): Promise<string> {
42
- if (this._uri) {
43
- return this._uri;
44
- }
45
-
46
- return (await this.client.getAddressPrefix()) === "ckb"
47
- ? "https://app.joy.id"
48
- : "https://testnet.joyid.dev";
44
+ private async getConfig() {
45
+ return {
46
+ redirectURL: location.href,
47
+ joyidAppURL:
48
+ this._appUri ??
49
+ ((await this.client.getAddressPrefix()) === "ckb"
50
+ ? "https://app.joy.id"
51
+ : "https://testnet.joyid.dev"),
52
+ name: this.name,
53
+ logo: this.icon,
54
+ };
49
55
  }
50
56
 
51
57
  private async getAggregatorUri(): Promise<string> {
@@ -59,10 +65,11 @@ export class CkbSigner extends ccc.Signer {
59
65
  }
60
66
 
61
67
  async connect(): Promise<void> {
62
- const uri = await this.getUri();
63
- const res = await authWithPopup({
64
- joyidAppURL: uri,
65
- redirectURL: location.href,
68
+ const config = await this.getConfig();
69
+
70
+ const res = await createPopup(buildJoyIDURL(config, "popup", "/auth"), {
71
+ ...config,
72
+ type: DappRequestType.Auth,
66
73
  });
67
74
 
68
75
  this.connection = {
@@ -161,38 +168,34 @@ export class CkbSigner extends ccc.Signer {
161
168
  async signOnlyTransaction(
162
169
  txLike: ccc.TransactionLike,
163
170
  ): Promise<ccc.Transaction> {
164
- const popup = openPopup("");
165
- if (!popup) {
166
- return createBlockDialog(async () => this.signOnlyTransaction(txLike));
167
- }
168
171
  const tx = ccc.Transaction.from(txLike);
169
172
  const { script } = await this.getAddressObj();
170
173
 
171
- popup.location.href = buildJoyIDURL(
174
+ const config = await this.getConfig();
175
+ const res = await createPopup(
176
+ buildJoyIDURL(
177
+ {
178
+ ...config,
179
+ tx: JSON.parse(tx.stringify()),
180
+ signerAddress: (await this.assertConnection()).address,
181
+ witnessIndex: await tx.findInputIndexByLock(script, this.client),
182
+ },
183
+ "popup",
184
+ "/sign-ckb-raw-tx",
185
+ ),
172
186
  {
173
- joyidAppURL: await this.getUri(),
174
- tx: JSON.parse(tx.stringify()),
175
- signerAddress: (await this.assertConnection()).address,
176
- redirectURL: location.href,
177
- witnessIndex: await tx.findInputIndexByLock(script, this.client),
187
+ ...config,
188
+ type: DappRequestType.SignCkbRawTx,
178
189
  },
179
- "popup",
180
- "/sign-ckb-raw-tx",
181
190
  );
182
191
 
183
- const res = await runPopup({
184
- timeoutInSeconds: 3600,
185
- popup,
186
- type: DappRequestType.SignCkbRawTx,
187
- });
188
-
189
192
  return ccc.Transaction.from(res.tx);
190
193
  }
191
194
 
192
195
  private async saveConnection() {
193
196
  return this.connectionsRepo.set(
194
197
  {
195
- uri: await this.getUri(),
198
+ uri: (await this.getConfig()).joyidAppURL,
196
199
  addressType: "ckb",
197
200
  },
198
201
  this.connection,
@@ -201,7 +204,7 @@ export class CkbSigner extends ccc.Signer {
201
204
 
202
205
  private async restoreConnection() {
203
206
  this.connection = await this.connectionsRepo.get({
204
- uri: await this.getUri(),
207
+ uri: (await this.getConfig()).joyidAppURL,
205
208
  addressType: "ckb",
206
209
  });
207
210
  }
@@ -0,0 +1,100 @@
1
+ import {
2
+ AuthResponseData,
3
+ DappRequestType,
4
+ EvmWeb2LoginResponse,
5
+ PopupCancelledError,
6
+ PopupConfigOptions,
7
+ PopupNotSupportedError,
8
+ PopupTimeoutError,
9
+ SignCkbTxResponseData,
10
+ SignCotaNFTResponseData,
11
+ SignEvmTxResponseData,
12
+ SignMessageResponseData,
13
+ SignNostrEventData,
14
+ createBlockDialog,
15
+ isStandaloneBrowser,
16
+ openPopup,
17
+ } from "@joyid/common";
18
+
19
+ export interface PopupReturnType {
20
+ [DappRequestType.Auth]: AuthResponseData;
21
+ [DappRequestType.SignMessage]: SignMessageResponseData;
22
+ [DappRequestType.SignEvm]: SignEvmTxResponseData;
23
+ [DappRequestType.SignPsbt]: SignEvmTxResponseData;
24
+ [DappRequestType.BatchSignPsbt]: {
25
+ psbts: string[];
26
+ };
27
+ [DappRequestType.SignCkbTx]: SignCkbTxResponseData;
28
+ [DappRequestType.SignCotaNFT]: SignCotaNFTResponseData;
29
+ [DappRequestType.SignCkbRawTx]: SignCkbTxResponseData;
30
+ [DappRequestType.SignNostrEvent]: SignNostrEventData;
31
+ [DappRequestType.EncryptNostrMessage]: any;
32
+ [DappRequestType.DecryptNostrMessage]: any;
33
+ [DappRequestType.AuthMiniApp]: any;
34
+ [DappRequestType.SignMiniAppEvm]: any;
35
+ [DappRequestType.SignMiniAppMessage]: any;
36
+ [DappRequestType.EvmWeb2Login]: EvmWeb2LoginResponse;
37
+ }
38
+
39
+ export async function createPopup<T extends DappRequestType>(
40
+ url: string,
41
+ config: PopupConfigOptions<T> & { joyidAppURL: string },
42
+ ): Promise<PopupReturnType[T]> {
43
+ if (config.popup == null) {
44
+ config.popup = openPopup("");
45
+
46
+ if (config.popup == null) {
47
+ return createBlockDialog(async () => createPopup(url, config));
48
+ }
49
+ }
50
+
51
+ config.popup.location.href = url;
52
+
53
+ return new Promise((resolve, reject) => {
54
+ if (isStandaloneBrowser()) {
55
+ reject(new PopupNotSupportedError(config.popup));
56
+ }
57
+ let popupEventListener: (e: MessageEvent) => void;
58
+ let timeoutId: undefined | ReturnType<typeof setTimeout>;
59
+ // Check each second if the popup is closed triggering a PopupCancelledError
60
+ const popupTimer = setInterval(() => {
61
+ if (config.popup?.closed) {
62
+ clearInterval(popupTimer);
63
+ clearTimeout(timeoutId);
64
+ window.removeEventListener("message", popupEventListener, false);
65
+ reject(new PopupCancelledError(config.popup));
66
+ }
67
+ }, 1000);
68
+
69
+ timeoutId = setTimeout(
70
+ () => {
71
+ clearInterval(popupTimer);
72
+ reject(new PopupTimeoutError(config.popup));
73
+ window.removeEventListener("message", popupEventListener, false);
74
+ },
75
+ (config.timeoutInSeconds ?? 3000) * 1000,
76
+ );
77
+
78
+ popupEventListener = (e: MessageEvent) => {
79
+ const { joyidAppURL } = config;
80
+ const appURL = new URL(joyidAppURL);
81
+ if (e.origin !== appURL.origin) {
82
+ return;
83
+ }
84
+ if (!e.data || e.data?.type !== config.type) {
85
+ return;
86
+ }
87
+
88
+ clearTimeout(timeoutId);
89
+ clearInterval(popupTimer);
90
+ window.removeEventListener("message", popupEventListener, false);
91
+ config.popup.close();
92
+ if (e.data.error) {
93
+ reject(new Error(e.data.error));
94
+ }
95
+ resolve(e.data.data);
96
+ };
97
+
98
+ window.addEventListener("message", popupEventListener);
99
+ });
100
+ }
@@ -0,0 +1,118 @@
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
+ export class EvmSigner extends ccc.SignerEvm {
11
+ private connection?: Connection;
12
+
13
+ private assertConnection() {
14
+ if (!this.isConnected() || !this.connection) {
15
+ throw new Error("Not connected");
16
+ }
17
+
18
+ return this.connection;
19
+ }
20
+
21
+ constructor(
22
+ client: ccc.Client,
23
+ private readonly name: string,
24
+ private readonly icon: string,
25
+ private readonly appUri = "https://app.joy.id",
26
+ private readonly connectionsRepo: ConnectionsRepo = new ConnectionsRepoLocalStorage(),
27
+ ) {
28
+ super(client);
29
+ }
30
+
31
+ async replaceClient(client: ccc.Client): Promise<EvmSigner> {
32
+ return new EvmSigner(
33
+ client,
34
+ this.name,
35
+ this.icon,
36
+ this.appUri,
37
+ this.connectionsRepo,
38
+ );
39
+ }
40
+
41
+ private getConfig() {
42
+ return {
43
+ redirectURL: location.href,
44
+ joyidAppURL: this.appUri,
45
+ requestNetwork: `ethereum`,
46
+ name: this.name,
47
+ logo: this.icon,
48
+ };
49
+ }
50
+
51
+ async getEvmAccount() {
52
+ return this.assertConnection().address;
53
+ }
54
+
55
+ async connect(): Promise<void> {
56
+ const config = await this.getConfig();
57
+
58
+ const res = await createPopup(buildJoyIDURL(config, "popup", "/auth"), {
59
+ ...config,
60
+ type: DappRequestType.Auth,
61
+ });
62
+
63
+ this.connection = {
64
+ address: res.ethAddress,
65
+ publicKey: ccc.hexFrom(res.pubkey),
66
+ keyType: res.keyType,
67
+ };
68
+ await this.saveConnection();
69
+ }
70
+
71
+ async isConnected(): Promise<boolean> {
72
+ if (this.connection) {
73
+ return true;
74
+ }
75
+ await this.restoreConnection();
76
+ return this.connection !== undefined;
77
+ }
78
+
79
+ async signMessage(message: string | ccc.BytesLike): Promise<ccc.Hex> {
80
+ const { address } = this.assertConnection();
81
+
82
+ const challenge =
83
+ typeof message === "string" ? message : ccc.hexFrom(message).slice(2);
84
+
85
+ const config = this.getConfig();
86
+ const { signature } = await createPopup(
87
+ buildJoyIDURL(
88
+ {
89
+ ...config,
90
+ challenge,
91
+ isData: typeof message !== "string",
92
+ address,
93
+ },
94
+ "popup",
95
+ "/sign-message",
96
+ ),
97
+ { ...config, type: DappRequestType.SignMessage },
98
+ );
99
+ return ccc.hexFrom(signature);
100
+ }
101
+
102
+ private async saveConnection() {
103
+ return this.connectionsRepo.set(
104
+ {
105
+ uri: this.getConfig().joyidAppURL,
106
+ addressType: "ethereum",
107
+ },
108
+ this.connection,
109
+ );
110
+ }
111
+
112
+ private async restoreConnection() {
113
+ this.connection = await this.connectionsRepo.get({
114
+ uri: this.getConfig().joyidAppURL,
115
+ addressType: "ethereum",
116
+ });
117
+ }
118
+ }
@@ -1,28 +1,38 @@
1
1
  import { ccc } from "@ckb-ccc/core";
2
2
  import { BitcoinSigner } from "../btc";
3
3
  import { CkbSigner } from "../ckb";
4
+ import { EvmSigner } from "../evm";
4
5
 
5
- export function getJoyIdSigners(client: ccc.Client): ccc.SignerInfo[] {
6
+ export function getJoyIdSigners(
7
+ client: ccc.Client,
8
+ name: string,
9
+ icon: string,
10
+ ): ccc.SignerInfo[] {
6
11
  return [
7
12
  {
8
13
  type: ccc.SignerType.CKB,
9
14
  name: "CKB",
10
- signer: new CkbSigner(client),
15
+ signer: new CkbSigner(client, name, icon),
11
16
  },
12
17
  {
13
18
  type: ccc.SignerType.BTC,
14
19
  name: "BTC",
15
- signer: new BitcoinSigner(client),
20
+ signer: new BitcoinSigner(client, name, icon),
21
+ },
22
+ {
23
+ type: ccc.SignerType.EVM,
24
+ name: "EVM",
25
+ signer: new EvmSigner(client, name, icon),
16
26
  },
17
27
  {
18
28
  type: ccc.SignerType.BTC,
19
29
  name: "BTC (P2WPKH)",
20
- signer: new BitcoinSigner(client, "p2wpkh"),
30
+ signer: new BitcoinSigner(client, name, icon, "p2wpkh"),
21
31
  },
22
32
  {
23
33
  type: ccc.SignerType.BTC,
24
34
  name: "BTC (P2TR)",
25
- signer: new BitcoinSigner(client, "p2tr"),
35
+ signer: new BitcoinSigner(client, name, icon, "p2tr"),
26
36
  },
27
37
  ];
28
38
  }