@ckb-ccc/joy-id 0.0.5-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.
Files changed (59) hide show
  1. package/README.md +43 -0
  2. package/dist/advanced.d.ts +2 -0
  3. package/dist/advanced.d.ts.map +1 -0
  4. package/dist/advanced.js +1 -0
  5. package/dist/advancedBarrel.d.ts +2 -0
  6. package/dist/advancedBarrel.d.ts.map +1 -0
  7. package/dist/advancedBarrel.js +1 -0
  8. package/dist/barrel.d.ts +4 -0
  9. package/dist/barrel.d.ts.map +1 -0
  10. package/dist/barrel.js +3 -0
  11. package/dist/btc/index.d.ts +17 -0
  12. package/dist/btc/index.d.ts.map +1 -0
  13. package/dist/btc/index.js +73 -0
  14. package/dist/ckb/index.d.ts +25 -0
  15. package/dist/ckb/index.d.ts.map +1 -0
  16. package/dist/ckb/index.js +142 -0
  17. package/dist/connectionsStorage/index.d.ts +23 -0
  18. package/dist/connectionsStorage/index.d.ts.map +1 -0
  19. package/dist/connectionsStorage/index.js +30 -0
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +1 -0
  23. package/dist/signerFactory/index.d.ts +3 -0
  24. package/dist/signerFactory/index.d.ts.map +1 -0
  25. package/dist/signerFactory/index.js +27 -0
  26. package/dist.commonjs/advanced.d.ts +2 -0
  27. package/dist.commonjs/advanced.d.ts.map +1 -0
  28. package/dist.commonjs/advanced.js +27 -0
  29. package/dist.commonjs/advancedBarrel.d.ts +2 -0
  30. package/dist.commonjs/advancedBarrel.d.ts.map +1 -0
  31. package/dist.commonjs/advancedBarrel.js +17 -0
  32. package/dist.commonjs/barrel.d.ts +4 -0
  33. package/dist.commonjs/barrel.d.ts.map +1 -0
  34. package/dist.commonjs/barrel.js +19 -0
  35. package/dist.commonjs/btc/index.d.ts +17 -0
  36. package/dist.commonjs/btc/index.d.ts.map +1 -0
  37. package/dist.commonjs/btc/index.js +77 -0
  38. package/dist.commonjs/ckb/index.d.ts +25 -0
  39. package/dist.commonjs/ckb/index.d.ts.map +1 -0
  40. package/dist.commonjs/ckb/index.js +146 -0
  41. package/dist.commonjs/connectionsStorage/index.d.ts +23 -0
  42. package/dist.commonjs/connectionsStorage/index.d.ts.map +1 -0
  43. package/dist.commonjs/connectionsStorage/index.js +35 -0
  44. package/dist.commonjs/index.d.ts +2 -0
  45. package/dist.commonjs/index.d.ts.map +1 -0
  46. package/dist.commonjs/index.js +27 -0
  47. package/dist.commonjs/signerFactory/index.d.ts +3 -0
  48. package/dist.commonjs/signerFactory/index.d.ts.map +1 -0
  49. package/dist.commonjs/signerFactory/index.js +31 -0
  50. package/dist.commonjs/tsconfig.commonjs.tsbuildinfo +1 -0
  51. package/package.json +46 -0
  52. package/src/advanced.ts +1 -0
  53. package/src/advancedBarrel.ts +1 -0
  54. package/src/barrel.ts +3 -0
  55. package/src/btc/index.ts +102 -0
  56. package/src/ckb/index.ts +208 -0
  57. package/src/connectionsStorage/index.ts +57 -0
  58. package/src/index.ts +1 -0
  59. package/src/signerFactory/index.ts +28 -0
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ <p align="center">
2
+ <a href="https://ckbccc-demo.vercel.app/">
3
+ <img alt="Logo" src="https://raw.githubusercontent.com/ckb-ecofund/ccc/master/assets/logo.svg" width="20%" />
4
+ </a>
5
+ </p>
6
+
7
+ <h1 align="center" style="font-size: 48px;">
8
+ CCC's support for JoyID
9
+ </h1>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@ckb-ccc/joy-id"><img
13
+ alt="NPM Version" src="https://img.shields.io/npm/v/%40ckb-ccc%2Fjoy-id"
14
+ /></a>
15
+ <img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/ckb-ecofund/ccc" />
16
+ <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/ckb-ecofund/ccc/master" />
17
+ <img alt="GitHub deployments" src="https://img.shields.io/github/deployments/ckb-ecofund/ccc/production" />
18
+ <a href="https://ckbccc-demo.vercel.app/"><img
19
+ alt="Demo" src="https://img.shields.io/website?url=https%3A%2F%2Fckbccc-demo.vercel.app%2F&label=Demo"
20
+ /></a>
21
+ </p>
22
+
23
+ <p align="center">
24
+ "Common Chains Connector" is where CCC begins.
25
+ <br />
26
+ CCC helps you to interoperate wallets from different chain ecosystems with CKB,
27
+ <br />
28
+ fully enabling CKB's cryptographic freedom power.
29
+ </p>
30
+
31
+ ## Preview
32
+
33
+ <p align="center">
34
+ <a href="https://ckbccc-demo.vercel.app/">
35
+ <img src="https://raw.githubusercontent.com/ckb-ecofund/ccc/master/assets/preview.png" width="30%" />
36
+ </a>
37
+ </p>
38
+
39
+ This project is still under active development, and we are looking forward to your feedback. [Try its demo now here](https://ckbccc-demo.vercel.app/).
40
+
41
+ <h3 align="center">
42
+ Read more about CCC on its <a href="https://github.com/ckb-ecofund/ccc">GitHub Repo</a>.
43
+ </h3>
@@ -0,0 +1,2 @@
1
+ export * as JoyIdA from "./advancedBarrel";
2
+ //# sourceMappingURL=advanced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1 @@
1
+ export * as JoyIdA from "./advancedBarrel";
@@ -0,0 +1,2 @@
1
+ export * from "./connectionsStorage";
2
+ //# sourceMappingURL=advancedBarrel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advancedBarrel.d.ts","sourceRoot":"","sources":["../src/advancedBarrel.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "./connectionsStorage";
@@ -0,0 +1,4 @@
1
+ export * from "./btc";
2
+ export * from "./ckb";
3
+ export * from "./signerFactory";
4
+ //# sourceMappingURL=barrel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC"}
package/dist/barrel.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./btc";
2
+ export * from "./ckb";
3
+ export * from "./signerFactory";
@@ -0,0 +1,17 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { ConnectionsRepo } from "../connectionsStorage";
3
+ export declare class BitcoinSigner extends ccc.SignerBtc {
4
+ private readonly addressType;
5
+ private readonly uri;
6
+ private readonly connectionsRepo;
7
+ private connection?;
8
+ private assertConnection;
9
+ constructor(client: ccc.Client, addressType?: "auto" | "p2wpkh" | "p2tr", uri?: string, connectionsRepo?: ConnectionsRepo);
10
+ replaceClient(client: ccc.Client): Promise<BitcoinSigner>;
11
+ getBtcAccount(): Promise<string>;
12
+ getBtcPublicKey(): Promise<ccc.Hex>;
13
+ connect(): Promise<void>;
14
+ isConnected(): Promise<boolean>;
15
+ signMessage(message: string | ccc.BytesLike): Promise<string>;
16
+ }
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/btc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAE/B,qBAAa,aAAc,SAAQ,GAAG,CAAC,SAAS;IAa5C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAdlC,OAAO,CAAC,UAAU,CAAC,CAAa;IAEhC,OAAO,CAAC,gBAAgB;gBAStB,MAAM,EAAE,GAAG,CAAC,MAAM,EACD,WAAW,GAAE,MAAM,GAAG,QAAQ,GAAG,MAAe,EAChD,GAAG,SAAuB,EAC1B,eAAe,GAAE,eAAmD;IAKjF,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIzD,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAKhC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;IAKnC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BxB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAY/B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;CAgBpE"}
@@ -0,0 +1,73 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { authWithPopup, signMessageWithPopup } from "@joyid/common";
3
+ import { ConnectionsRepoLocalStorage, } from "../connectionsStorage";
4
+ export class BitcoinSigner extends ccc.SignerBtc {
5
+ assertConnection() {
6
+ if (!this.isConnected() || !this.connection) {
7
+ throw new Error("Not connected");
8
+ }
9
+ return this.connection;
10
+ }
11
+ constructor(client, addressType = "auto", uri = "https://app.joy.id", connectionsRepo = new ConnectionsRepoLocalStorage()) {
12
+ super(client);
13
+ this.addressType = addressType;
14
+ this.uri = uri;
15
+ this.connectionsRepo = connectionsRepo;
16
+ }
17
+ async replaceClient(client) {
18
+ return new BitcoinSigner(client, this.addressType, this.uri);
19
+ }
20
+ async getBtcAccount() {
21
+ const { address } = this.assertConnection();
22
+ return address;
23
+ }
24
+ async getBtcPublicKey() {
25
+ const { publicKey } = this.assertConnection();
26
+ return publicKey;
27
+ }
28
+ async connect() {
29
+ const res = await authWithPopup({
30
+ joyidAppURL: this.uri,
31
+ redirectURL: location.href,
32
+ requestNetwork: `btc-${this.addressType}`,
33
+ });
34
+ const { address, pubkey } = (() => {
35
+ if (this.addressType === "auto") {
36
+ return res.btcAddressType === "p2wpkh" ? res.nativeSegwit : res.taproot;
37
+ }
38
+ return res.btcAddressType === "p2wpkh" ? res.nativeSegwit : res.taproot;
39
+ })();
40
+ this.connection = {
41
+ address,
42
+ publicKey: ccc.hexFrom(pubkey),
43
+ keyType: res.keyType,
44
+ };
45
+ await Promise.all([
46
+ this.connectionsRepo.set({ uri: this.uri, addressType: `btc-${res.btcAddressType}` }, this.connection),
47
+ this.connectionsRepo.set({ uri: this.uri, addressType: "btc-auto" }, this.connection),
48
+ ]);
49
+ }
50
+ async isConnected() {
51
+ if (this.connection) {
52
+ return true;
53
+ }
54
+ this.connection = await this.connectionsRepo.get({
55
+ uri: this.uri,
56
+ addressType: `btc-${this.addressType}`,
57
+ });
58
+ return this.connection !== undefined;
59
+ }
60
+ async signMessage(message) {
61
+ const { address } = this.assertConnection();
62
+ const challenge = typeof message === "string" ? message : ccc.hexFrom(message).slice(2);
63
+ const { signature } = await signMessageWithPopup({
64
+ joyidAppURL: this.uri,
65
+ requestNetwork: `btc-${this.addressType}`,
66
+ challenge,
67
+ address,
68
+ signMessageType: "ecdsa",
69
+ redirectURL: location.href,
70
+ });
71
+ return signature;
72
+ }
73
+ }
@@ -0,0 +1,25 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { ConnectionsRepo } from "../connectionsStorage";
3
+ export declare class CkbSigner extends ccc.Signer {
4
+ private readonly _uri?;
5
+ private readonly _aggregatorUri?;
6
+ private readonly connectionsRepo;
7
+ private connection?;
8
+ private assertConnection;
9
+ constructor(client: ccc.Client, _uri?: string | undefined, _aggregatorUri?: string | undefined, connectionsRepo?: ConnectionsRepo);
10
+ replaceClient(client: ccc.Client): Promise<CkbSigner>;
11
+ private getUri;
12
+ private getAggregatorUri;
13
+ connect(): Promise<void>;
14
+ disconnect(): Promise<void>;
15
+ isConnected(): Promise<boolean>;
16
+ getInternalAddress(): Promise<string>;
17
+ getAddressObj(): Promise<ccc.Address>;
18
+ getAddressObjs(): Promise<ccc.Address[]>;
19
+ prepareTransaction(txLike: ccc.TransactionLike): Promise<ccc.Transaction>;
20
+ private prepareTransactionForSubKey;
21
+ signOnlyTransaction(txLike: ccc.TransactionLike): Promise<ccc.Transaction>;
22
+ private saveConnection;
23
+ private restoreConnection;
24
+ }
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ckb/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAUpC,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAE/B,qBAAa,SAAU,SAAQ,GAAG,CAAC,MAAM;IAarC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAdlC,OAAO,CAAC,UAAU,CAAC,CAAa;YAElB,gBAAgB;gBAS5B,MAAM,EAAE,GAAG,CAAC,MAAM,EACD,IAAI,CAAC,oBAAQ,EACb,cAAc,CAAC,oBAAQ,EACvB,eAAe,GAAE,eAAmD;IAKjF,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;YAI7C,MAAM;YAUN,gBAAgB;IAUxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAexB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAQ/B,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIrC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;IAOrC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAIxC,kBAAkB,CACtB,MAAM,EAAE,GAAG,CAAC,eAAe,GAC1B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YAgBb,2BAA2B;IAuCnC,mBAAmB,CACvB,MAAM,EAAE,GAAG,CAAC,eAAe,GAC1B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YA6Bb,cAAc;YAUd,iBAAiB;CAMhC"}
@@ -0,0 +1,142 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { Aggregator } from "@joyid/ckb";
3
+ import { DappRequestType, authWithPopup, buildJoyIDURL, createBlockDialog, openPopup, runPopup, } from "@joyid/common";
4
+ import { ConnectionsRepoLocalStorage, } from "../connectionsStorage";
5
+ export class CkbSigner extends ccc.Signer {
6
+ async assertConnection() {
7
+ if (!(await this.isConnected()) || !this.connection) {
8
+ throw new Error("Not connected");
9
+ }
10
+ return this.connection;
11
+ }
12
+ constructor(client, _uri, _aggregatorUri, connectionsRepo = new ConnectionsRepoLocalStorage()) {
13
+ super(client);
14
+ this._uri = _uri;
15
+ this._aggregatorUri = _aggregatorUri;
16
+ this.connectionsRepo = connectionsRepo;
17
+ }
18
+ async replaceClient(client) {
19
+ return new CkbSigner(client, this._uri);
20
+ }
21
+ async getUri() {
22
+ if (this._uri) {
23
+ return this._uri;
24
+ }
25
+ return (await this.client.getAddressPrefix()) === "ckb"
26
+ ? "https://app.joy.id"
27
+ : "https://testnet.joyid.dev";
28
+ }
29
+ async getAggregatorUri() {
30
+ if (this._aggregatorUri) {
31
+ return this._aggregatorUri;
32
+ }
33
+ return (await this.client.getAddressPrefix()) === "ckb"
34
+ ? "https://cota.nervina.dev/mainnet-aggregator"
35
+ : "https://cota.nervina.dev/aggregator";
36
+ }
37
+ async connect() {
38
+ const uri = await this.getUri();
39
+ const res = await authWithPopup({
40
+ joyidAppURL: uri,
41
+ redirectURL: location.href,
42
+ });
43
+ this.connection = {
44
+ address: res.address,
45
+ publicKey: ccc.hexFrom(res.pubkey),
46
+ keyType: res.keyType,
47
+ };
48
+ await this.saveConnection();
49
+ }
50
+ async disconnect() {
51
+ this.connection = undefined;
52
+ await this.saveConnection();
53
+ }
54
+ async isConnected() {
55
+ if (this.connection) {
56
+ return true;
57
+ }
58
+ await this.restoreConnection();
59
+ return this.connection !== undefined;
60
+ }
61
+ async getInternalAddress() {
62
+ return (await this.assertConnection()).address;
63
+ }
64
+ async getAddressObj() {
65
+ return await ccc.Address.fromString(await this.getInternalAddress(), this.client);
66
+ }
67
+ async getAddressObjs() {
68
+ return [await this.getAddressObj()];
69
+ }
70
+ async prepareTransaction(txLike) {
71
+ const tx = ccc.Transaction.from(txLike);
72
+ const position = await tx.findInputIndexByLock((await this.getAddressObj()).script, this.client);
73
+ if (position === undefined) {
74
+ return tx;
75
+ }
76
+ const witness = tx.getWitnessArgsAt(position) ?? ccc.WitnessArgs.from({});
77
+ witness.lock = "0x";
78
+ await this.prepareTransactionForSubKey(tx, witness);
79
+ return tx.setWitnessArgsAt(position, witness);
80
+ }
81
+ async prepareTransactionForSubKey(tx, witness) {
82
+ if (this.connection?.keyType !== "sub_key") {
83
+ return [];
84
+ }
85
+ const pubkeyHash = ccc.ckbHash(this.connection.publicKey).substring(0, 42);
86
+ const lock = (await this.getAddressObj()).script;
87
+ const aggregator = new Aggregator(await this.getAggregatorUri());
88
+ const { unlock_entry: unlockEntry } = await aggregator.generateSubkeyUnlockSmt({
89
+ alg_index: 1,
90
+ pubkey_hash: pubkeyHash,
91
+ lock_script: ccc.hexFrom(lock.toBytes()),
92
+ });
93
+ witness.outputType = ccc.hexFrom(unlockEntry);
94
+ const cotaDeps = [];
95
+ for await (const cell of this.client.findCellsByLockAndType(lock, {
96
+ ...(await this.client.getKnownScript(ccc.KnownScript.COTA)),
97
+ args: "0x",
98
+ })) {
99
+ cotaDeps.push(ccc.CellDep.from({
100
+ depType: "code",
101
+ outPoint: cell.outPoint,
102
+ }));
103
+ }
104
+ if (cotaDeps.length === 0) {
105
+ throw new Error("No COTA cells for sub key wallet");
106
+ }
107
+ tx.cellDeps.unshift(...cotaDeps);
108
+ }
109
+ async signOnlyTransaction(txLike) {
110
+ const popup = openPopup("");
111
+ if (!popup) {
112
+ return createBlockDialog(async () => this.signOnlyTransaction(txLike));
113
+ }
114
+ const tx = ccc.Transaction.from(txLike);
115
+ const { script } = await this.getAddressObj();
116
+ popup.location.href = buildJoyIDURL({
117
+ joyidAppURL: await this.getUri(),
118
+ tx: JSON.parse(tx.stringify()),
119
+ signerAddress: (await this.assertConnection()).address,
120
+ redirectURL: location.href,
121
+ witnessIndex: await tx.findInputIndexByLock(script, this.client),
122
+ }, "popup", "/sign-ckb-raw-tx");
123
+ const res = await runPopup({
124
+ timeoutInSeconds: 3600,
125
+ popup,
126
+ type: DappRequestType.SignCkbRawTx,
127
+ });
128
+ return ccc.Transaction.from(res.tx);
129
+ }
130
+ async saveConnection() {
131
+ return this.connectionsRepo.set({
132
+ uri: await this.getUri(),
133
+ addressType: "ckb",
134
+ }, this.connection);
135
+ }
136
+ async restoreConnection() {
137
+ this.connection = await this.connectionsRepo.get({
138
+ uri: await this.getUri(),
139
+ addressType: "ckb",
140
+ });
141
+ }
142
+ }
@@ -0,0 +1,23 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ export type AccountSelector = {
3
+ uri: string;
4
+ addressType: string;
5
+ };
6
+ export declare function isSelectorEq(a: AccountSelector, b: AccountSelector): boolean;
7
+ export type Connection = {
8
+ readonly address: string;
9
+ readonly publicKey: ccc.Hex;
10
+ readonly keyType: string;
11
+ };
12
+ export interface ConnectionsRepo {
13
+ get(selector: AccountSelector): Promise<Connection | undefined>;
14
+ set(selector: AccountSelector, connection: Connection | undefined): Promise<void>;
15
+ }
16
+ export declare class ConnectionsRepoLocalStorage implements ConnectionsRepo {
17
+ private readonly storageKey;
18
+ constructor(storageKey?: string);
19
+ readConnections(): Promise<[AccountSelector, Connection][]>;
20
+ get(selector: AccountSelector): Promise<Connection | undefined>;
21
+ set(selector: AccountSelector, connection: Connection | undefined): Promise<void>;
22
+ }
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/connectionsStorage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,wBAAgB,YAAY,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,WAElE;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAChE,GAAG,CACD,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,UAAU,GAAG,SAAS,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,qBAAa,2BAA4B,YAAW,eAAe;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,SAAsB;IAEvD,eAAe,IAAI,OAAO,CAAC,CAAC,eAAe,EAAE,UAAU,CAAC,EAAE,CAAC;IAI3D,GAAG,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAM/D,GAAG,CAAC,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,GAAG,SAAS;CAkBxE"}
@@ -0,0 +1,30 @@
1
+ export function isSelectorEq(a, b) {
2
+ return a.uri === b.uri && a.addressType === b.addressType;
3
+ }
4
+ export class ConnectionsRepoLocalStorage {
5
+ constructor(storageKey = "ccc-joy-id-signer") {
6
+ this.storageKey = storageKey;
7
+ }
8
+ async readConnections() {
9
+ return JSON.parse(window.localStorage.getItem(this.storageKey) ?? "[]");
10
+ }
11
+ async get(selector) {
12
+ return (await this.readConnections()).find(([s]) => isSelectorEq(selector, s))?.[1];
13
+ }
14
+ async set(selector, connection) {
15
+ const connections = await this.readConnections();
16
+ if (connection) {
17
+ const existed = connections.find(([s]) => isSelectorEq(s, selector));
18
+ if (existed) {
19
+ existed[1] = connection;
20
+ }
21
+ else {
22
+ connections.push([selector, connection]);
23
+ }
24
+ window.localStorage.setItem(this.storageKey, JSON.stringify(connections));
25
+ }
26
+ else {
27
+ window.localStorage.setItem(this.storageKey, JSON.stringify(connections.filter(([s]) => !isSelectorEq(s, selector))));
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,2 @@
1
+ export * as JoyId from "./barrel";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * as JoyId from "./barrel";
@@ -0,0 +1,3 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ export declare function getJoyIdSigners(client: ccc.Client): ccc.SignerInfo[];
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/signerFactory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAIpC,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,UAAU,EAAE,CAuBpE"}
@@ -0,0 +1,27 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { BitcoinSigner } from "../btc";
3
+ import { CkbSigner } from "../ckb";
4
+ export function getJoyIdSigners(client) {
5
+ return [
6
+ {
7
+ type: ccc.SignerType.CKB,
8
+ name: "CKB",
9
+ signer: new CkbSigner(client),
10
+ },
11
+ {
12
+ type: ccc.SignerType.BTC,
13
+ name: "BTC",
14
+ signer: new BitcoinSigner(client),
15
+ },
16
+ {
17
+ type: ccc.SignerType.BTC,
18
+ name: "BTC (P2WPKH)",
19
+ signer: new BitcoinSigner(client, "p2wpkh"),
20
+ },
21
+ {
22
+ type: ccc.SignerType.BTC,
23
+ name: "BTC (P2TR)",
24
+ signer: new BitcoinSigner(client, "p2tr"),
25
+ },
26
+ ];
27
+ }
@@ -0,0 +1,2 @@
1
+ export * as JoyIdA from "./advancedBarrel";
2
+ //# sourceMappingURL=advanced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.JoyIdA = void 0;
27
+ exports.JoyIdA = __importStar(require("./advancedBarrel"));
@@ -0,0 +1,2 @@
1
+ export * from "./connectionsStorage";
2
+ //# sourceMappingURL=advancedBarrel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advancedBarrel.d.ts","sourceRoot":"","sources":["../src/advancedBarrel.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./connectionsStorage"), exports);
@@ -0,0 +1,4 @@
1
+ export * from "./btc";
2
+ export * from "./ckb";
3
+ export * from "./signerFactory";
4
+ //# sourceMappingURL=barrel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./btc"), exports);
18
+ __exportStar(require("./ckb"), exports);
19
+ __exportStar(require("./signerFactory"), exports);
@@ -0,0 +1,17 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { ConnectionsRepo } from "../connectionsStorage";
3
+ export declare class BitcoinSigner extends ccc.SignerBtc {
4
+ private readonly addressType;
5
+ private readonly uri;
6
+ private readonly connectionsRepo;
7
+ private connection?;
8
+ private assertConnection;
9
+ constructor(client: ccc.Client, addressType?: "auto" | "p2wpkh" | "p2tr", uri?: string, connectionsRepo?: ConnectionsRepo);
10
+ replaceClient(client: ccc.Client): Promise<BitcoinSigner>;
11
+ getBtcAccount(): Promise<string>;
12
+ getBtcPublicKey(): Promise<ccc.Hex>;
13
+ connect(): Promise<void>;
14
+ isConnected(): Promise<boolean>;
15
+ signMessage(message: string | ccc.BytesLike): Promise<string>;
16
+ }
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/btc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAE/B,qBAAa,aAAc,SAAQ,GAAG,CAAC,SAAS;IAa5C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAdlC,OAAO,CAAC,UAAU,CAAC,CAAa;IAEhC,OAAO,CAAC,gBAAgB;gBAStB,MAAM,EAAE,GAAG,CAAC,MAAM,EACD,WAAW,GAAE,MAAM,GAAG,QAAQ,GAAG,MAAe,EAChD,GAAG,SAAuB,EAC1B,eAAe,GAAE,eAAmD;IAKjF,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIzD,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAKhC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;IAKnC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BxB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAY/B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;CAgBpE"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BitcoinSigner = void 0;
4
+ const core_1 = require("@ckb-ccc/core");
5
+ const common_1 = require("@joyid/common");
6
+ const connectionsStorage_1 = require("../connectionsStorage");
7
+ class BitcoinSigner extends core_1.ccc.SignerBtc {
8
+ assertConnection() {
9
+ if (!this.isConnected() || !this.connection) {
10
+ throw new Error("Not connected");
11
+ }
12
+ return this.connection;
13
+ }
14
+ constructor(client, addressType = "auto", uri = "https://app.joy.id", connectionsRepo = new connectionsStorage_1.ConnectionsRepoLocalStorage()) {
15
+ super(client);
16
+ this.addressType = addressType;
17
+ this.uri = uri;
18
+ this.connectionsRepo = connectionsRepo;
19
+ }
20
+ async replaceClient(client) {
21
+ return new BitcoinSigner(client, this.addressType, this.uri);
22
+ }
23
+ async getBtcAccount() {
24
+ const { address } = this.assertConnection();
25
+ return address;
26
+ }
27
+ async getBtcPublicKey() {
28
+ const { publicKey } = this.assertConnection();
29
+ return publicKey;
30
+ }
31
+ async connect() {
32
+ const res = await (0, common_1.authWithPopup)({
33
+ joyidAppURL: this.uri,
34
+ redirectURL: location.href,
35
+ requestNetwork: `btc-${this.addressType}`,
36
+ });
37
+ const { address, pubkey } = (() => {
38
+ if (this.addressType === "auto") {
39
+ return res.btcAddressType === "p2wpkh" ? res.nativeSegwit : res.taproot;
40
+ }
41
+ return res.btcAddressType === "p2wpkh" ? res.nativeSegwit : res.taproot;
42
+ })();
43
+ this.connection = {
44
+ address,
45
+ publicKey: core_1.ccc.hexFrom(pubkey),
46
+ keyType: res.keyType,
47
+ };
48
+ await Promise.all([
49
+ this.connectionsRepo.set({ uri: this.uri, addressType: `btc-${res.btcAddressType}` }, this.connection),
50
+ this.connectionsRepo.set({ uri: this.uri, addressType: "btc-auto" }, this.connection),
51
+ ]);
52
+ }
53
+ async isConnected() {
54
+ if (this.connection) {
55
+ return true;
56
+ }
57
+ this.connection = await this.connectionsRepo.get({
58
+ uri: this.uri,
59
+ addressType: `btc-${this.addressType}`,
60
+ });
61
+ return this.connection !== undefined;
62
+ }
63
+ async signMessage(message) {
64
+ const { address } = this.assertConnection();
65
+ const challenge = typeof message === "string" ? message : core_1.ccc.hexFrom(message).slice(2);
66
+ const { signature } = await (0, common_1.signMessageWithPopup)({
67
+ joyidAppURL: this.uri,
68
+ requestNetwork: `btc-${this.addressType}`,
69
+ challenge,
70
+ address,
71
+ signMessageType: "ecdsa",
72
+ redirectURL: location.href,
73
+ });
74
+ return signature;
75
+ }
76
+ }
77
+ exports.BitcoinSigner = BitcoinSigner;