@ckb-ccc/joy-id 0.0.5-alpha.0 → 0.0.5-alpha.2
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/advancedBarrel.d.ts +1 -0
- package/dist/advancedBarrel.d.ts.map +1 -1
- package/dist/advancedBarrel.js +1 -0
- package/dist/barrel.d.ts +1 -0
- package/dist/barrel.d.ts.map +1 -1
- package/dist/barrel.js +1 -0
- package/dist/btc/index.d.ts +6 -3
- package/dist/btc/index.d.ts.map +1 -1
- package/dist/btc/index.js +28 -17
- package/dist/ckb/index.d.ts +9 -3
- package/dist/ckb/index.d.ts.map +1 -1
- package/dist/ckb/index.js +58 -30
- package/dist/common/index.d.ts +24 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +50 -0
- package/dist/evm/index.d.ts +20 -0
- package/dist/evm/index.d.ts.map +1 -0
- package/dist/evm/index.js +78 -0
- package/dist/signerFactory/index.d.ts +1 -1
- package/dist/signerFactory/index.d.ts.map +1 -1
- package/dist/signerFactory/index.js +10 -10
- package/dist.commonjs/advancedBarrel.d.ts +1 -0
- package/dist.commonjs/advancedBarrel.d.ts.map +1 -1
- package/dist.commonjs/advancedBarrel.js +1 -0
- package/dist.commonjs/barrel.d.ts +1 -0
- package/dist.commonjs/barrel.d.ts.map +1 -1
- package/dist.commonjs/barrel.js +1 -0
- package/dist.commonjs/btc/index.d.ts +6 -3
- package/dist.commonjs/btc/index.d.ts.map +1 -1
- package/dist.commonjs/btc/index.js +27 -16
- package/dist.commonjs/ckb/index.d.ts +9 -3
- package/dist.commonjs/ckb/index.d.ts.map +1 -1
- package/dist.commonjs/ckb/index.js +57 -29
- package/dist.commonjs/common/index.d.ts +24 -0
- package/dist.commonjs/common/index.d.ts.map +1 -0
- package/dist.commonjs/common/index.js +54 -0
- package/dist.commonjs/evm/index.d.ts +20 -0
- package/dist.commonjs/evm/index.d.ts.map +1 -0
- package/dist.commonjs/evm/index.js +82 -0
- package/dist.commonjs/signerFactory/index.d.ts +1 -1
- package/dist.commonjs/signerFactory/index.d.ts.map +1 -1
- package/dist.commonjs/signerFactory/index.js +10 -10
- package/package.json +3 -3
- package/src/advancedBarrel.ts +1 -0
- package/src/barrel.ts +1 -0
- package/src/btc/index.ts +45 -19
- package/src/ckb/index.ts +89 -44
- package/src/common/index.ts +100 -0
- package/src/evm/index.ts +118 -0
- package/src/signerFactory/index.ts +14 -9
- package/dist.commonjs/tsconfig.commonjs.tsbuildinfo +0 -1
package/src/btc/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ccc } from "@ckb-ccc/core";
|
|
2
|
-
import {
|
|
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
|
|
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(
|
|
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
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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.
|
|
84
|
+
{ uri: this.appUri, addressType: `btc-${res.btcAddressType}` },
|
|
65
85
|
this.connection,
|
|
66
86
|
),
|
|
67
87
|
this.connectionsRepo.set(
|
|
68
|
-
{ uri: this.
|
|
88
|
+
{ uri: this.appUri, addressType: "btc-auto" },
|
|
69
89
|
this.connection,
|
|
70
90
|
),
|
|
71
91
|
]);
|
|
@@ -77,26 +97,32 @@ export class BitcoinSigner extends ccc.SignerBtc {
|
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
this.connection = await this.connectionsRepo.get({
|
|
80
|
-
uri: this.
|
|
100
|
+
uri: this.appUri,
|
|
81
101
|
addressType: `btc-${this.addressType}`,
|
|
82
102
|
});
|
|
83
103
|
return this.connection !== undefined;
|
|
84
104
|
}
|
|
85
105
|
|
|
86
|
-
async
|
|
106
|
+
async signMessageRaw(message: string | ccc.BytesLike): Promise<string> {
|
|
87
107
|
const { address } = this.assertConnection();
|
|
88
108
|
|
|
89
109
|
const challenge =
|
|
90
110
|
typeof message === "string" ? message : ccc.hexFrom(message).slice(2);
|
|
91
111
|
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -15,6 +9,14 @@ import {
|
|
|
15
9
|
} from "../connectionsStorage";
|
|
16
10
|
|
|
17
11
|
export class CkbSigner extends ccc.Signer {
|
|
12
|
+
get type(): ccc.SignerType {
|
|
13
|
+
return ccc.SignerType.CKB;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get signType(): ccc.SignerSignType {
|
|
17
|
+
return ccc.SignerSignType.JoyId;
|
|
18
|
+
}
|
|
19
|
+
|
|
18
20
|
private connection?: Connection;
|
|
19
21
|
|
|
20
22
|
private async assertConnection(): Promise<Connection> {
|
|
@@ -27,7 +29,9 @@ export class CkbSigner extends ccc.Signer {
|
|
|
27
29
|
|
|
28
30
|
constructor(
|
|
29
31
|
client: ccc.Client,
|
|
30
|
-
private readonly
|
|
32
|
+
private readonly name: string,
|
|
33
|
+
private readonly icon: string,
|
|
34
|
+
private readonly _appUri?: string,
|
|
31
35
|
private readonly _aggregatorUri?: string,
|
|
32
36
|
private readonly connectionsRepo: ConnectionsRepo = new ConnectionsRepoLocalStorage(),
|
|
33
37
|
) {
|
|
@@ -35,34 +39,44 @@ export class CkbSigner extends ccc.Signer {
|
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
async replaceClient(client: ccc.Client): Promise<CkbSigner> {
|
|
38
|
-
return new CkbSigner(
|
|
42
|
+
return new CkbSigner(
|
|
43
|
+
client,
|
|
44
|
+
this.name,
|
|
45
|
+
this.icon,
|
|
46
|
+
this._appUri,
|
|
47
|
+
this._aggregatorUri,
|
|
48
|
+
this.connectionsRepo,
|
|
49
|
+
);
|
|
39
50
|
}
|
|
40
51
|
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
:
|
|
52
|
+
private getConfig() {
|
|
53
|
+
return {
|
|
54
|
+
redirectURL: location.href,
|
|
55
|
+
joyidAppURL:
|
|
56
|
+
this._appUri ?? this.client.addressPrefix === "ckb"
|
|
57
|
+
? "https://app.joy.id"
|
|
58
|
+
: "https://testnet.joyid.dev",
|
|
59
|
+
name: this.name,
|
|
60
|
+
logo: this.icon,
|
|
61
|
+
};
|
|
49
62
|
}
|
|
50
63
|
|
|
51
|
-
private
|
|
64
|
+
private getAggregatorUri(): string {
|
|
52
65
|
if (this._aggregatorUri) {
|
|
53
66
|
return this._aggregatorUri;
|
|
54
67
|
}
|
|
55
68
|
|
|
56
|
-
return
|
|
69
|
+
return this.client.addressPrefix === "ckb"
|
|
57
70
|
? "https://cota.nervina.dev/mainnet-aggregator"
|
|
58
71
|
: "https://cota.nervina.dev/aggregator";
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
async connect(): Promise<void> {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
const config = this.getConfig();
|
|
76
|
+
|
|
77
|
+
const res = await createPopup(buildJoyIDURL(config, "popup", "/auth"), {
|
|
78
|
+
...config,
|
|
79
|
+
type: DappRequestType.Auth,
|
|
66
80
|
});
|
|
67
81
|
|
|
68
82
|
this.connection = {
|
|
@@ -90,6 +104,14 @@ export class CkbSigner extends ccc.Signer {
|
|
|
90
104
|
return (await this.assertConnection()).address;
|
|
91
105
|
}
|
|
92
106
|
|
|
107
|
+
async getIdentity(): Promise<string> {
|
|
108
|
+
const connection = await this.assertConnection();
|
|
109
|
+
return JSON.stringify({
|
|
110
|
+
keyType: connection.keyType,
|
|
111
|
+
publicKey: connection.publicKey.slice(2),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
93
115
|
async getAddressObj(): Promise<ccc.Address> {
|
|
94
116
|
return await ccc.Address.fromString(
|
|
95
117
|
await this.getInternalAddress(),
|
|
@@ -161,38 +183,61 @@ export class CkbSigner extends ccc.Signer {
|
|
|
161
183
|
async signOnlyTransaction(
|
|
162
184
|
txLike: ccc.TransactionLike,
|
|
163
185
|
): Promise<ccc.Transaction> {
|
|
164
|
-
const popup = openPopup("");
|
|
165
|
-
if (!popup) {
|
|
166
|
-
return createBlockDialog(async () => this.signOnlyTransaction(txLike));
|
|
167
|
-
}
|
|
168
186
|
const tx = ccc.Transaction.from(txLike);
|
|
169
187
|
const { script } = await this.getAddressObj();
|
|
170
188
|
|
|
171
|
-
|
|
189
|
+
const config = this.getConfig();
|
|
190
|
+
const res = await createPopup(
|
|
191
|
+
buildJoyIDURL(
|
|
192
|
+
{
|
|
193
|
+
...config,
|
|
194
|
+
tx: JSON.parse(tx.stringify()),
|
|
195
|
+
signerAddress: (await this.assertConnection()).address,
|
|
196
|
+
witnessIndex: await tx.findInputIndexByLock(script, this.client),
|
|
197
|
+
},
|
|
198
|
+
"popup",
|
|
199
|
+
"/sign-ckb-raw-tx",
|
|
200
|
+
),
|
|
172
201
|
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
signerAddress: (await this.assertConnection()).address,
|
|
176
|
-
redirectURL: location.href,
|
|
177
|
-
witnessIndex: await tx.findInputIndexByLock(script, this.client),
|
|
202
|
+
...config,
|
|
203
|
+
type: DappRequestType.SignCkbRawTx,
|
|
178
204
|
},
|
|
179
|
-
"popup",
|
|
180
|
-
"/sign-ckb-raw-tx",
|
|
181
205
|
);
|
|
182
206
|
|
|
183
|
-
const res = await runPopup({
|
|
184
|
-
timeoutInSeconds: 3600,
|
|
185
|
-
popup,
|
|
186
|
-
type: DappRequestType.SignCkbRawTx,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
207
|
return ccc.Transaction.from(res.tx);
|
|
190
208
|
}
|
|
191
209
|
|
|
210
|
+
async signMessageRaw(message: string | ccc.BytesLike): Promise<string> {
|
|
211
|
+
const { address } = await this.assertConnection();
|
|
212
|
+
|
|
213
|
+
const challenge =
|
|
214
|
+
typeof message === "string" ? message : ccc.hexFrom(message).slice(2);
|
|
215
|
+
|
|
216
|
+
const config = this.getConfig();
|
|
217
|
+
const res = await createPopup(
|
|
218
|
+
buildJoyIDURL(
|
|
219
|
+
{
|
|
220
|
+
...config,
|
|
221
|
+
challenge,
|
|
222
|
+
isData: typeof message !== "string",
|
|
223
|
+
address,
|
|
224
|
+
},
|
|
225
|
+
"popup",
|
|
226
|
+
"/sign-message",
|
|
227
|
+
),
|
|
228
|
+
{ ...config, type: DappRequestType.SignMessage },
|
|
229
|
+
);
|
|
230
|
+
return JSON.stringify({
|
|
231
|
+
signature: res.signature,
|
|
232
|
+
alg: res.alg,
|
|
233
|
+
message: res.message,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
192
237
|
private async saveConnection() {
|
|
193
238
|
return this.connectionsRepo.set(
|
|
194
239
|
{
|
|
195
|
-
uri:
|
|
240
|
+
uri: this.getConfig().joyidAppURL,
|
|
196
241
|
addressType: "ckb",
|
|
197
242
|
},
|
|
198
243
|
this.connection,
|
|
@@ -201,7 +246,7 @@ export class CkbSigner extends ccc.Signer {
|
|
|
201
246
|
|
|
202
247
|
private async restoreConnection() {
|
|
203
248
|
this.connection = await this.connectionsRepo.get({
|
|
204
|
-
uri:
|
|
249
|
+
uri: this.getConfig().joyidAppURL,
|
|
205
250
|
addressType: "ckb",
|
|
206
251
|
});
|
|
207
252
|
}
|
|
@@ -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
|
+
}
|
package/src/evm/index.ts
ADDED
|
@@ -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 signMessageRaw(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,33 @@
|
|
|
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(
|
|
6
|
+
export function getJoyIdSigners(
|
|
7
|
+
client: ccc.Client,
|
|
8
|
+
name: string,
|
|
9
|
+
icon: string,
|
|
10
|
+
): ccc.SignerInfo[] {
|
|
6
11
|
return [
|
|
7
12
|
{
|
|
8
|
-
type: ccc.SignerType.CKB,
|
|
9
13
|
name: "CKB",
|
|
10
|
-
signer: new CkbSigner(client),
|
|
14
|
+
signer: new CkbSigner(client, name, icon),
|
|
11
15
|
},
|
|
12
16
|
{
|
|
13
|
-
type: ccc.SignerType.BTC,
|
|
14
17
|
name: "BTC",
|
|
15
|
-
signer: new BitcoinSigner(client),
|
|
18
|
+
signer: new BitcoinSigner(client, name, icon),
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "EVM",
|
|
22
|
+
signer: new EvmSigner(client, name, icon),
|
|
16
23
|
},
|
|
17
24
|
{
|
|
18
|
-
type: ccc.SignerType.BTC,
|
|
19
25
|
name: "BTC (P2WPKH)",
|
|
20
|
-
signer: new BitcoinSigner(client, "p2wpkh"),
|
|
26
|
+
signer: new BitcoinSigner(client, name, icon, "p2wpkh"),
|
|
21
27
|
},
|
|
22
28
|
{
|
|
23
|
-
type: ccc.SignerType.BTC,
|
|
24
29
|
name: "BTC (P2TR)",
|
|
25
|
-
signer: new BitcoinSigner(client, "p2tr"),
|
|
30
|
+
signer: new BitcoinSigner(client, name, icon, "p2tr"),
|
|
26
31
|
},
|
|
27
32
|
];
|
|
28
33
|
}
|