zksync-sso 0.0.0-beta.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 (300) hide show
  1. package/.gitignore +5 -0
  2. package/.lintstagedrc.js +5 -0
  3. package/.npmignore +10 -0
  4. package/README.md +3 -0
  5. package/dist/_cjs/abi/Factory.js +197 -0
  6. package/dist/_cjs/abi/Factory.js.map +1 -0
  7. package/dist/_cjs/abi/SessionKeyModule.js +1104 -0
  8. package/dist/_cjs/abi/SessionKeyModule.js.map +1 -0
  9. package/dist/_cjs/client/actions/account.js +140 -0
  10. package/dist/_cjs/client/actions/account.js.map +1 -0
  11. package/dist/_cjs/client/actions/index.js +19 -0
  12. package/dist/_cjs/client/actions/index.js.map +1 -0
  13. package/dist/_cjs/client/actions/passkey.js +122 -0
  14. package/dist/_cjs/client/actions/passkey.js.map +1 -0
  15. package/dist/_cjs/client/actions/session.js +40 -0
  16. package/dist/_cjs/client/actions/session.js.map +1 -0
  17. package/dist/_cjs/client/clients/passkey.js +46 -0
  18. package/dist/_cjs/client/clients/passkey.js.map +1 -0
  19. package/dist/_cjs/client/clients/session.js +48 -0
  20. package/dist/_cjs/client/clients/session.js.map +1 -0
  21. package/dist/_cjs/client/decorators/index.js +19 -0
  22. package/dist/_cjs/client/decorators/index.js.map +1 -0
  23. package/dist/_cjs/client/decorators/passkey.js +15 -0
  24. package/dist/_cjs/client/decorators/passkey.js.map +1 -0
  25. package/dist/_cjs/client/decorators/session.js +7 -0
  26. package/dist/_cjs/client/decorators/session.js.map +1 -0
  27. package/dist/_cjs/client/decorators/session_wallet.js +32 -0
  28. package/dist/_cjs/client/decorators/session_wallet.js.map +1 -0
  29. package/dist/_cjs/client/index.js +22 -0
  30. package/dist/_cjs/client/index.js.map +1 -0
  31. package/dist/_cjs/client/passkey.js +20 -0
  32. package/dist/_cjs/client/passkey.js.map +1 -0
  33. package/dist/_cjs/client/smart-account.js +45 -0
  34. package/dist/_cjs/client/smart-account.js.map +1 -0
  35. package/dist/_cjs/client/utils/assertEip712Transaction.js +44 -0
  36. package/dist/_cjs/client/utils/assertEip712Transaction.js.map +1 -0
  37. package/dist/_cjs/client/utils/getEip712Domain.js +57 -0
  38. package/dist/_cjs/client/utils/getEip712Domain.js.map +1 -0
  39. package/dist/_cjs/client/utils/isEip712Transaction.js +16 -0
  40. package/dist/_cjs/client/utils/isEip712Transaction.js.map +1 -0
  41. package/dist/_cjs/client-auth-server/Signer.js +264 -0
  42. package/dist/_cjs/client-auth-server/Signer.js.map +1 -0
  43. package/dist/_cjs/client-auth-server/WalletProvider.js +107 -0
  44. package/dist/_cjs/client-auth-server/WalletProvider.js.map +1 -0
  45. package/dist/_cjs/client-auth-server/index.js +20 -0
  46. package/dist/_cjs/client-auth-server/index.js.map +1 -0
  47. package/dist/_cjs/client-auth-server/interface.js +3 -0
  48. package/dist/_cjs/client-auth-server/interface.js.map +1 -0
  49. package/dist/_cjs/client-auth-server/rpc.js +3 -0
  50. package/dist/_cjs/client-auth-server/rpc.js.map +1 -0
  51. package/dist/_cjs/client-auth-server/session.js +90 -0
  52. package/dist/_cjs/client-auth-server/session.js.map +1 -0
  53. package/dist/_cjs/communicator/PopupCommunicator.js +138 -0
  54. package/dist/_cjs/communicator/PopupCommunicator.js.map +1 -0
  55. package/dist/_cjs/communicator/index.js +6 -0
  56. package/dist/_cjs/communicator/index.js.map +1 -0
  57. package/dist/_cjs/communicator/interface.js +3 -0
  58. package/dist/_cjs/communicator/interface.js.map +1 -0
  59. package/dist/_cjs/connector/index.js +148 -0
  60. package/dist/_cjs/connector/index.js.map +1 -0
  61. package/dist/_cjs/errors/constants.js +97 -0
  62. package/dist/_cjs/errors/constants.js.map +1 -0
  63. package/dist/_cjs/errors/errors.js +122 -0
  64. package/dist/_cjs/errors/errors.js.map +1 -0
  65. package/dist/_cjs/errors/index.js +10 -0
  66. package/dist/_cjs/errors/index.js.map +1 -0
  67. package/dist/_cjs/errors/serialize.js +63 -0
  68. package/dist/_cjs/errors/serialize.js.map +1 -0
  69. package/dist/_cjs/errors/utils.js +95 -0
  70. package/dist/_cjs/errors/utils.js.map +1 -0
  71. package/dist/_cjs/index.js +6 -0
  72. package/dist/_cjs/index.js.map +1 -0
  73. package/dist/_cjs/package.json +1 -0
  74. package/dist/_cjs/utils/encoding.js +32 -0
  75. package/dist/_cjs/utils/encoding.js.map +1 -0
  76. package/dist/_cjs/utils/helpers.js +43 -0
  77. package/dist/_cjs/utils/helpers.js.map +1 -0
  78. package/dist/_cjs/utils/index.js +20 -0
  79. package/dist/_cjs/utils/index.js.map +1 -0
  80. package/dist/_cjs/utils/passkey.js +243 -0
  81. package/dist/_cjs/utils/passkey.js.map +1 -0
  82. package/dist/_cjs/utils/session.js +30 -0
  83. package/dist/_cjs/utils/session.js.map +1 -0
  84. package/dist/_cjs/utils/storage.js +93 -0
  85. package/dist/_cjs/utils/storage.js.map +1 -0
  86. package/dist/_cjs/version.js +5 -0
  87. package/dist/_cjs/version.js.map +1 -0
  88. package/dist/_esm/abi/Factory.js +194 -0
  89. package/dist/_esm/abi/Factory.js.map +1 -0
  90. package/dist/_esm/abi/SessionKeyModule.js +1101 -0
  91. package/dist/_esm/abi/SessionKeyModule.js.map +1 -0
  92. package/dist/_esm/client/actions/account.js +137 -0
  93. package/dist/_esm/client/actions/account.js.map +1 -0
  94. package/dist/_esm/client/actions/index.js +3 -0
  95. package/dist/_esm/client/actions/index.js.map +1 -0
  96. package/dist/_esm/client/actions/passkey.js +121 -0
  97. package/dist/_esm/client/actions/passkey.js.map +1 -0
  98. package/dist/_esm/client/actions/session.js +36 -0
  99. package/dist/_esm/client/actions/session.js.map +1 -0
  100. package/dist/_esm/client/clients/passkey.js +43 -0
  101. package/dist/_esm/client/clients/passkey.js.map +1 -0
  102. package/dist/_esm/client/clients/session.js +45 -0
  103. package/dist/_esm/client/clients/session.js.map +1 -0
  104. package/dist/_esm/client/decorators/index.js +3 -0
  105. package/dist/_esm/client/decorators/index.js.map +1 -0
  106. package/dist/_esm/client/decorators/passkey.js +13 -0
  107. package/dist/_esm/client/decorators/passkey.js.map +1 -0
  108. package/dist/_esm/client/decorators/session.js +5 -0
  109. package/dist/_esm/client/decorators/session.js.map +1 -0
  110. package/dist/_esm/client/decorators/session_wallet.js +171 -0
  111. package/dist/_esm/client/decorators/session_wallet.js.map +1 -0
  112. package/dist/_esm/client/index.js +3 -0
  113. package/dist/_esm/client/index.js.map +1 -0
  114. package/dist/_esm/client/passkey.js +4 -0
  115. package/dist/_esm/client/passkey.js.map +1 -0
  116. package/dist/_esm/client/smart-account.js +46 -0
  117. package/dist/_esm/client/smart-account.js.map +1 -0
  118. package/dist/_esm/client/utils/assertEip712Transaction.js +39 -0
  119. package/dist/_esm/client/utils/assertEip712Transaction.js.map +1 -0
  120. package/dist/_esm/client/utils/getEip712Domain.js +57 -0
  121. package/dist/_esm/client/utils/getEip712Domain.js.map +1 -0
  122. package/dist/_esm/client/utils/isEip712Transaction.js +13 -0
  123. package/dist/_esm/client/utils/isEip712Transaction.js.map +1 -0
  124. package/dist/_esm/client-auth-server/Signer.js +262 -0
  125. package/dist/_esm/client-auth-server/Signer.js.map +1 -0
  126. package/dist/_esm/client-auth-server/WalletProvider.js +104 -0
  127. package/dist/_esm/client-auth-server/WalletProvider.js.map +1 -0
  128. package/dist/_esm/client-auth-server/index.js +4 -0
  129. package/dist/_esm/client-auth-server/index.js.map +1 -0
  130. package/dist/_esm/client-auth-server/interface.js +2 -0
  131. package/dist/_esm/client-auth-server/interface.js.map +1 -0
  132. package/dist/_esm/client-auth-server/rpc.js +2 -0
  133. package/dist/_esm/client-auth-server/rpc.js.map +1 -0
  134. package/dist/_esm/client-auth-server/session.js +91 -0
  135. package/dist/_esm/client-auth-server/session.js.map +1 -0
  136. package/dist/_esm/communicator/PopupCommunicator.js +136 -0
  137. package/dist/_esm/communicator/PopupCommunicator.js.map +1 -0
  138. package/dist/_esm/communicator/index.js +2 -0
  139. package/dist/_esm/communicator/index.js.map +1 -0
  140. package/dist/_esm/communicator/interface.js +2 -0
  141. package/dist/_esm/communicator/interface.js.map +1 -0
  142. package/dist/_esm/connector/index.js +146 -0
  143. package/dist/_esm/connector/index.js.map +1 -0
  144. package/dist/_esm/errors/constants.js +94 -0
  145. package/dist/_esm/errors/constants.js.map +1 -0
  146. package/dist/_esm/errors/errors.js +124 -0
  147. package/dist/_esm/errors/errors.js.map +1 -0
  148. package/dist/_esm/errors/index.js +4 -0
  149. package/dist/_esm/errors/index.js.map +1 -0
  150. package/dist/_esm/errors/serialize.js +69 -0
  151. package/dist/_esm/errors/serialize.js.map +1 -0
  152. package/dist/_esm/errors/utils.js +101 -0
  153. package/dist/_esm/errors/utils.js.map +1 -0
  154. package/dist/_esm/index.js +2 -0
  155. package/dist/_esm/index.js.map +1 -0
  156. package/dist/_esm/package.json +1 -0
  157. package/dist/_esm/utils/encoding.js +26 -0
  158. package/dist/_esm/utils/encoding.js.map +1 -0
  159. package/dist/_esm/utils/helpers.js +40 -0
  160. package/dist/_esm/utils/helpers.js.map +1 -0
  161. package/dist/_esm/utils/index.js +4 -0
  162. package/dist/_esm/utils/index.js.map +1 -0
  163. package/dist/_esm/utils/passkey.js +294 -0
  164. package/dist/_esm/utils/passkey.js.map +1 -0
  165. package/dist/_esm/utils/session.js +31 -0
  166. package/dist/_esm/utils/session.js.map +1 -0
  167. package/dist/_esm/utils/storage.js +89 -0
  168. package/dist/_esm/utils/storage.js.map +1 -0
  169. package/dist/_esm/version.js +2 -0
  170. package/dist/_esm/version.js.map +1 -0
  171. package/dist/_types/abi/Factory.d.ts +149 -0
  172. package/dist/_types/abi/Factory.d.ts.map +1 -0
  173. package/dist/_types/abi/SessionKeyModule.d.ts +846 -0
  174. package/dist/_types/abi/SessionKeyModule.d.ts.map +1 -0
  175. package/dist/_types/client/actions/account.d.ts +38 -0
  176. package/dist/_types/client/actions/account.d.ts.map +1 -0
  177. package/dist/_types/client/actions/index.d.ts +3 -0
  178. package/dist/_types/client/actions/index.d.ts.map +1 -0
  179. package/dist/_types/client/actions/passkey.d.ts +45 -0
  180. package/dist/_types/client/actions/passkey.d.ts.map +1 -0
  181. package/dist/_types/client/actions/session.d.ts +14 -0
  182. package/dist/_types/client/actions/session.d.ts.map +1 -0
  183. package/dist/_types/client/clients/passkey.d.ts +32 -0
  184. package/dist/_types/client/clients/passkey.d.ts.map +1 -0
  185. package/dist/_types/client/clients/session.d.ts +26 -0
  186. package/dist/_types/client/clients/session.d.ts.map +1 -0
  187. package/dist/_types/client/decorators/index.d.ts +3 -0
  188. package/dist/_types/client/decorators/index.d.ts.map +1 -0
  189. package/dist/_types/client/decorators/passkey.d.ts +8 -0
  190. package/dist/_types/client/decorators/passkey.d.ts.map +1 -0
  191. package/dist/_types/client/decorators/session.d.ts +5 -0
  192. package/dist/_types/client/decorators/session.d.ts.map +1 -0
  193. package/dist/_types/client/decorators/session_wallet.d.ts +5 -0
  194. package/dist/_types/client/decorators/session_wallet.d.ts.map +1 -0
  195. package/dist/_types/client/index.d.ts +3 -0
  196. package/dist/_types/client/index.d.ts.map +1 -0
  197. package/dist/_types/client/passkey.d.ts +4 -0
  198. package/dist/_types/client/passkey.d.ts.map +1 -0
  199. package/dist/_types/client/smart-account.d.ts +24 -0
  200. package/dist/_types/client/smart-account.d.ts.map +1 -0
  201. package/dist/_types/client/utils/assertEip712Transaction.d.ts +11 -0
  202. package/dist/_types/client/utils/assertEip712Transaction.d.ts.map +1 -0
  203. package/dist/_types/client/utils/getEip712Domain.d.ts +3 -0
  204. package/dist/_types/client/utils/getEip712Domain.d.ts.map +1 -0
  205. package/dist/_types/client/utils/isEip712Transaction.d.ts +4 -0
  206. package/dist/_types/client/utils/isEip712Transaction.d.ts.map +1 -0
  207. package/dist/_types/client-auth-server/Signer.d.ts +52 -0
  208. package/dist/_types/client-auth-server/Signer.d.ts.map +1 -0
  209. package/dist/_types/client-auth-server/WalletProvider.d.ts +27 -0
  210. package/dist/_types/client-auth-server/WalletProvider.d.ts.map +1 -0
  211. package/dist/_types/client-auth-server/index.d.ts +4 -0
  212. package/dist/_types/client-auth-server/index.d.ts.map +1 -0
  213. package/dist/_types/client-auth-server/interface.d.ts +34 -0
  214. package/dist/_types/client-auth-server/interface.d.ts.map +1 -0
  215. package/dist/_types/client-auth-server/rpc.d.ts +55 -0
  216. package/dist/_types/client-auth-server/rpc.d.ts.map +1 -0
  217. package/dist/_types/client-auth-server/session.d.ts +45 -0
  218. package/dist/_types/client-auth-server/session.d.ts.map +1 -0
  219. package/dist/_types/communicator/PopupCommunicator.d.ts +20 -0
  220. package/dist/_types/communicator/PopupCommunicator.d.ts.map +1 -0
  221. package/dist/_types/communicator/index.d.ts +3 -0
  222. package/dist/_types/communicator/index.d.ts.map +1 -0
  223. package/dist/_types/communicator/interface.d.ts +16 -0
  224. package/dist/_types/communicator/interface.d.ts.map +1 -0
  225. package/dist/_types/connector/index.d.ts +8 -0
  226. package/dist/_types/connector/index.d.ts.map +1 -0
  227. package/dist/_types/errors/constants.d.ts +96 -0
  228. package/dist/_types/errors/constants.d.ts.map +1 -0
  229. package/dist/_types/errors/errors.d.ts +48 -0
  230. package/dist/_types/errors/errors.d.ts.map +1 -0
  231. package/dist/_types/errors/index.d.ts +5 -0
  232. package/dist/_types/errors/index.d.ts.map +1 -0
  233. package/dist/_types/errors/serialize.d.ts +13 -0
  234. package/dist/_types/errors/serialize.d.ts.map +1 -0
  235. package/dist/_types/errors/utils.d.ts +30 -0
  236. package/dist/_types/errors/utils.d.ts.map +1 -0
  237. package/dist/_types/index.d.ts +4 -0
  238. package/dist/_types/index.d.ts.map +1 -0
  239. package/dist/_types/utils/encoding.d.ts +12 -0
  240. package/dist/_types/utils/encoding.d.ts.map +1 -0
  241. package/dist/_types/utils/helpers.d.ts +4 -0
  242. package/dist/_types/utils/helpers.d.ts.map +1 -0
  243. package/dist/_types/utils/index.d.ts +4 -0
  244. package/dist/_types/utils/index.d.ts.map +1 -0
  245. package/dist/_types/utils/passkey.d.ts +47 -0
  246. package/dist/_types/utils/passkey.d.ts.map +1 -0
  247. package/dist/_types/utils/session.d.ts +95 -0
  248. package/dist/_types/utils/session.d.ts.map +1 -0
  249. package/dist/_types/utils/storage.d.ts +30 -0
  250. package/dist/_types/utils/storage.d.ts.map +1 -0
  251. package/dist/_types/version.d.ts +2 -0
  252. package/dist/_types/version.d.ts.map +1 -0
  253. package/eslint.config.js +6 -0
  254. package/package.json +144 -0
  255. package/prepare-package.mjs +39 -0
  256. package/project.json +67 -0
  257. package/src/abi/Factory.ts +193 -0
  258. package/src/abi/SessionKeyModule.ts +1100 -0
  259. package/src/client/actions/account.ts +198 -0
  260. package/src/client/actions/index.ts +2 -0
  261. package/src/client/actions/passkey.ts +165 -0
  262. package/src/client/actions/session.ts +118 -0
  263. package/src/client/clients/passkey.ts +107 -0
  264. package/src/client/clients/session.ts +105 -0
  265. package/src/client/decorators/index.ts +2 -0
  266. package/src/client/decorators/passkey.ts +22 -0
  267. package/src/client/decorators/session.ts +17 -0
  268. package/src/client/decorators/session_wallet.ts +184 -0
  269. package/src/client/index.ts +2 -0
  270. package/src/client/passkey.ts +3 -0
  271. package/src/client/smart-account.ts +68 -0
  272. package/src/client/utils/assertEip712Transaction.ts +49 -0
  273. package/src/client/utils/getEip712Domain.ts +84 -0
  274. package/src/client/utils/isEip712Transaction.ts +18 -0
  275. package/src/client-auth-server/Signer.ts +260 -0
  276. package/src/client-auth-server/WalletProvider.ts +114 -0
  277. package/src/client-auth-server/index.ts +3 -0
  278. package/src/client-auth-server/interface.ts +39 -0
  279. package/src/client-auth-server/rpc.ts +69 -0
  280. package/src/client-auth-server/session.ts +139 -0
  281. package/src/communicator/PopupCommunicator.ts +111 -0
  282. package/src/communicator/index.ts +2 -0
  283. package/src/communicator/interface.ts +15 -0
  284. package/src/connector/index.ts +171 -0
  285. package/src/errors/constants.ts +119 -0
  286. package/src/errors/errors.ts +168 -0
  287. package/src/errors/index.ts +4 -0
  288. package/src/errors/serialize.ts +91 -0
  289. package/src/errors/utils.ts +152 -0
  290. package/src/index.ts +3 -0
  291. package/src/types/index.d.ts +9 -0
  292. package/src/utils/encoding.ts +36 -0
  293. package/src/utils/helpers.ts +43 -0
  294. package/src/utils/index.ts +3 -0
  295. package/src/utils/passkey.ts +344 -0
  296. package/src/utils/session.ts +103 -0
  297. package/src/utils/storage.ts +87 -0
  298. package/src/version.ts +1 -0
  299. package/tsconfig.base.json +44 -0
  300. package/tsconfig.json +11 -0
@@ -0,0 +1,111 @@
1
+ import { standardErrors } from "../errors/index.js";
2
+ import type { Communicator, Message } from "./index.js";
3
+
4
+ export interface PopupConfigMessage extends Message {
5
+ event: "PopupLoaded" | "PopupUnload";
6
+ }
7
+
8
+ export class PopupCommunicator implements Communicator {
9
+ private readonly url: URL;
10
+ private popup: Window | null = null;
11
+ private listeners = new Map<(_: MessageEvent) => void, { reject: (_: Error) => void }>();
12
+
13
+ constructor(url: string) {
14
+ this.url = new URL(url);
15
+ }
16
+
17
+ postMessage = async (message: Message) => {
18
+ const popup = await this.waitForPopupLoaded();
19
+ popup.postMessage(message, this.url.origin);
20
+ };
21
+
22
+ postRequestAndWaitForResponse = async <M extends Message>(
23
+ request: Message & { id: NonNullable<Message["id"]> },
24
+ ): Promise<M> => {
25
+ const responsePromise = this.onMessage<M>(({ requestId }) => requestId === request.id);
26
+ this.postMessage(request);
27
+ return await responsePromise;
28
+ };
29
+
30
+ onMessage = async <M extends Message>(predicate: (_: Partial<M>) => boolean): Promise<M> => {
31
+ return new Promise((resolve, reject) => {
32
+ const listener = (event: MessageEvent<M>) => {
33
+ if (event.origin !== this.url.origin) return; // origin validation
34
+
35
+ const message = event.data;
36
+ if (predicate(message)) {
37
+ resolve(message);
38
+ window.removeEventListener("message", listener);
39
+ this.listeners.delete(listener);
40
+ }
41
+ };
42
+
43
+ window.addEventListener("message", listener);
44
+ this.listeners.set(listener, { reject });
45
+ });
46
+ };
47
+
48
+ private disconnect = () => {
49
+ // Note: Auth Server popup handles closing itself. this is a fallback.
50
+ try {
51
+ if (this.popup && !this.popup.closed) {
52
+ this.popup.close();
53
+ }
54
+ } catch (error) {
55
+ console.warn("Failed to close popup", error);
56
+ }
57
+ this.popup = null;
58
+
59
+ this.listeners.forEach(({ reject }, listener) => {
60
+ reject(standardErrors.provider.userRejectedRequest("Request rejected"));
61
+ window.removeEventListener("message", listener);
62
+ });
63
+ this.listeners.clear();
64
+ };
65
+
66
+ openPopup = () => {
67
+ const width = 420;
68
+ const height = 600;
69
+
70
+ const url = new URL(this.url.toString());
71
+ url.searchParams.set("origin", window.location.origin);
72
+
73
+ const left = (window.innerWidth - width) / 2 + window.screenX;
74
+ const top = (window.innerHeight - height) / 2 + window.screenY;
75
+
76
+ const popup = window.open(
77
+ url,
78
+ "ZKsync SSO",
79
+ `width=${width}, height=${height}, left=${left}, top=${top}`,
80
+ );
81
+ if (!popup) {
82
+ throw standardErrors.rpc.internal("Pop up window failed to open");
83
+ }
84
+ popup.focus();
85
+ return popup;
86
+ };
87
+
88
+ waitForPopupLoaded = async (): Promise<Window> => {
89
+ if (this.popup && !this.popup.closed) {
90
+ // Focus the popup if it's already open
91
+ this.popup.focus();
92
+ return this.popup;
93
+ }
94
+
95
+ this.popup = this.openPopup();
96
+
97
+ this.onMessage<PopupConfigMessage>(({ event }) => event === "PopupUnload")
98
+ .then(this.disconnect)
99
+ .catch(() => {});
100
+
101
+ return this.onMessage<PopupConfigMessage>(({ event }) => event === "PopupLoaded")
102
+ .then(() => {
103
+ if (!this.popup) throw standardErrors.rpc.internal();
104
+ return this.popup;
105
+ });
106
+ };
107
+
108
+ ready = async () => {
109
+ await this.waitForPopupLoaded();
110
+ };
111
+ }
@@ -0,0 +1,2 @@
1
+ export type { Communicator, Message } from "./interface.js";
2
+ export { PopupCommunicator, type PopupConfigMessage } from "./PopupCommunicator.js";
@@ -0,0 +1,15 @@
1
+ import type { UUID } from "crypto";
2
+
3
+ type MessageID = UUID;
4
+
5
+ export interface Message {
6
+ id: MessageID;
7
+ requestId?: MessageID; // For responses
8
+ }
9
+
10
+ export interface Communicator {
11
+ postMessage: (_: Message) => void;
12
+ postRequestAndWaitForResponse: <M extends Message>(_: Message & { id: string }) => Promise<M>;
13
+ onMessage: <M extends Message>(_: (_: Partial<M>) => boolean) => Promise<M>;
14
+ ready: () => Promise<void>;
15
+ }
@@ -0,0 +1,171 @@
1
+ import {
2
+ ChainNotConfiguredError,
3
+ type Connector,
4
+ createConnector,
5
+ } from "@wagmi/core";
6
+ import {
7
+ getAddress,
8
+ SwitchChainError,
9
+ toHex,
10
+ UserRejectedRequestError,
11
+ } from "viem";
12
+
13
+ import { type AppMetadata, type ProviderInterface, type SessionPreferences, WalletProvider } from "../index.js";
14
+
15
+ export type ZksyncSsoConnectorOptions = {
16
+ metadata?: Partial<AppMetadata>;
17
+ session?: SessionPreferences | (() => SessionPreferences | Promise<SessionPreferences>);
18
+ authServerUrl?: string;
19
+ };
20
+
21
+ export const zksyncSsoConnector = (parameters: ZksyncSsoConnectorOptions) => {
22
+ type Provider = ProviderInterface;
23
+
24
+ let walletProvider: WalletProvider | undefined;
25
+
26
+ let accountsChanged: Connector["onAccountsChanged"] | undefined;
27
+ let chainChanged: Connector["onChainChanged"] | undefined;
28
+ let disconnect: Connector["onDisconnect"] | undefined;
29
+
30
+ const destroyWallet = () => {
31
+ if (walletProvider) {
32
+ if (accountsChanged) {
33
+ walletProvider.removeListener("accountsChanged", accountsChanged);
34
+ accountsChanged = undefined;
35
+ }
36
+ if (chainChanged) {
37
+ walletProvider.removeListener("chainChanged", chainChanged);
38
+ chainChanged = undefined;
39
+ }
40
+ if (disconnect) {
41
+ walletProvider.removeListener("disconnect", disconnect);
42
+ disconnect = undefined;
43
+ }
44
+ }
45
+ walletProvider = undefined;
46
+ };
47
+
48
+ return createConnector<Provider>((config) => ({
49
+ icon: "https://zksync.io/favicon.ico",
50
+ id: "zksync-sso",
51
+ name: "ZKsync",
52
+ // supportsSimulation: true,
53
+ type: "zksync-sso",
54
+ async connect({ chainId } = {}) {
55
+ try {
56
+ const provider = await this.getProvider();
57
+ const accounts = (
58
+ (await provider.request({
59
+ method: "eth_requestAccounts",
60
+ })) as string[]
61
+ ).map((x) => getAddress(x));
62
+
63
+ if (!accountsChanged) {
64
+ accountsChanged = this.onAccountsChanged.bind(this);
65
+ provider.on("accountsChanged", accountsChanged);
66
+ }
67
+ if (!chainChanged) {
68
+ chainChanged = this.onChainChanged.bind(this);
69
+ provider.on("chainChanged", chainChanged);
70
+ }
71
+ if (!disconnect) {
72
+ disconnect = this.onDisconnect.bind(this);
73
+ provider.on("disconnect", disconnect);
74
+ }
75
+
76
+ // Switch to chain if provided
77
+ let walletChainId = await this.getChainId();
78
+ if (chainId && walletChainId !== chainId) {
79
+ const chain = await this.switchChain!({ chainId }).catch((error) => {
80
+ if (error.code === UserRejectedRequestError.code) throw error;
81
+ return { id: walletChainId };
82
+ });
83
+ walletChainId = chain?.id ?? walletChainId;
84
+ }
85
+
86
+ return { accounts, chainId: walletChainId };
87
+ } catch (error) {
88
+ console.error(`Error connecting to ${this.name}`, error);
89
+ if (
90
+ /(user closed modal|accounts received is empty|user denied account|request rejected)/i.test(
91
+ (error as Error).message,
92
+ )
93
+ )
94
+ throw new UserRejectedRequestError(error as Error);
95
+ throw error;
96
+ }
97
+ },
98
+ async disconnect() {
99
+ const provider = await this.getProvider();
100
+ provider.disconnect();
101
+ destroyWallet();
102
+ },
103
+ async getAccounts() {
104
+ const provider = await this.getProvider();
105
+ return (
106
+ await provider.request({
107
+ method: "eth_accounts",
108
+ })
109
+ ).map((x) => getAddress(x));
110
+ },
111
+ async getChainId() {
112
+ const provider = await this.getProvider();
113
+ const chainId = await provider.request({
114
+ method: "eth_chainId",
115
+ });
116
+ if (!chainId) return config.chains[0].id;
117
+ return Number(chainId);
118
+ },
119
+ async getProvider() {
120
+ if (!walletProvider) {
121
+ walletProvider = new WalletProvider({
122
+ metadata: {
123
+ name: parameters.metadata?.name,
124
+ icon: parameters.metadata?.icon,
125
+ },
126
+ authServerUrl: parameters.authServerUrl,
127
+ session: parameters.session,
128
+ transports: config.transports,
129
+ chains: config.chains,
130
+ });
131
+ }
132
+ return walletProvider;
133
+ },
134
+ async isAuthorized() {
135
+ try {
136
+ const accounts = await this.getAccounts();
137
+ return !!accounts.length;
138
+ } catch {
139
+ return false;
140
+ }
141
+ },
142
+ async switchChain({ chainId }) {
143
+ const chain = config.chains.find((chain) => chain.id === chainId);
144
+ if (!chain) throw new SwitchChainError(new ChainNotConfiguredError());
145
+
146
+ try {
147
+ const provider = await this.getProvider();
148
+ await provider.request({
149
+ method: "wallet_switchEthereumChain",
150
+ params: [{ chainId: toHex(chainId) }],
151
+ });
152
+ return chain;
153
+ } catch (error) {
154
+ throw new SwitchChainError(error as Error);
155
+ }
156
+ },
157
+ onAccountsChanged(accounts) {
158
+ if (accounts.length === 0) this.onDisconnect();
159
+ else config.emitter.emit("change", {
160
+ accounts: accounts.map((x) => getAddress(x)),
161
+ });
162
+ },
163
+ onChainChanged(chain) {
164
+ config.emitter.emit("change", { chainId: Number(chain) });
165
+ },
166
+ async onDisconnect(_error) {
167
+ console.error("onDisconnect", _error);
168
+ config.emitter.emit("disconnect");
169
+ },
170
+ }));
171
+ };
@@ -0,0 +1,119 @@
1
+ interface ErrorCodes {
2
+ readonly rpc: {
3
+ readonly invalidInput: -32000;
4
+ readonly resourceNotFound: -32001;
5
+ readonly resourceUnavailable: -32002;
6
+ readonly transactionRejected: -32003;
7
+ readonly methodNotSupported: -32004;
8
+ readonly limitExceeded: -32005;
9
+ readonly parse: -32700;
10
+ readonly invalidRequest: -32600;
11
+ readonly methodNotFound: -32601;
12
+ readonly invalidParams: -32602;
13
+ readonly internal: -32603;
14
+ };
15
+ readonly provider: {
16
+ readonly userRejectedRequest: 4001;
17
+ readonly unauthorized: 4100;
18
+ readonly unsupportedMethod: 4200;
19
+ readonly disconnected: 4900;
20
+ readonly chainDisconnected: 4901;
21
+ readonly unsupportedChain: 4902;
22
+ };
23
+ }
24
+
25
+ export const standardErrorCodes: ErrorCodes = {
26
+ rpc: {
27
+ invalidInput: -32000,
28
+ resourceNotFound: -32001,
29
+ resourceUnavailable: -32002,
30
+ transactionRejected: -32003,
31
+ methodNotSupported: -32004,
32
+ limitExceeded: -32005,
33
+ parse: -32700,
34
+ invalidRequest: -32600,
35
+ methodNotFound: -32601,
36
+ invalidParams: -32602,
37
+ internal: -32603,
38
+ },
39
+ provider: {
40
+ userRejectedRequest: 4001,
41
+ unauthorized: 4100,
42
+ unsupportedMethod: 4200,
43
+ disconnected: 4900,
44
+ chainDisconnected: 4901,
45
+ unsupportedChain: 4902,
46
+ },
47
+ };
48
+
49
+ export const errorValues = {
50
+ "-32700": {
51
+ standard: "JSON RPC 2.0",
52
+ message:
53
+ "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.",
54
+ },
55
+ "-32600": {
56
+ standard: "JSON RPC 2.0",
57
+ message: "The JSON sent is not a valid Request object.",
58
+ },
59
+ "-32601": {
60
+ standard: "JSON RPC 2.0",
61
+ message: "The method does not exist / is not available.",
62
+ },
63
+ "-32602": {
64
+ standard: "JSON RPC 2.0",
65
+ message: "Invalid method parameter(s).",
66
+ },
67
+ "-32603": {
68
+ standard: "JSON RPC 2.0",
69
+ message: "Internal JSON-RPC error.",
70
+ },
71
+ "-32000": {
72
+ standard: "EIP-1474",
73
+ message: "Invalid input.",
74
+ },
75
+ "-32001": {
76
+ standard: "EIP-1474",
77
+ message: "Resource not found.",
78
+ },
79
+ "-32002": {
80
+ standard: "EIP-1474",
81
+ message: "Resource unavailable.",
82
+ },
83
+ "-32003": {
84
+ standard: "EIP-1474",
85
+ message: "Transaction rejected.",
86
+ },
87
+ "-32004": {
88
+ standard: "EIP-1474",
89
+ message: "Method not supported.",
90
+ },
91
+ "-32005": {
92
+ standard: "EIP-1474",
93
+ message: "Request limit exceeded.",
94
+ },
95
+ 4001: {
96
+ standard: "EIP-1193",
97
+ message: "User rejected the request.",
98
+ },
99
+ 4100: {
100
+ standard: "EIP-1193",
101
+ message: "The requested account and/or method has not been authorized by the user.",
102
+ },
103
+ 4200: {
104
+ standard: "EIP-1193",
105
+ message: "The requested method is not supported by this Ethereum provider.",
106
+ },
107
+ 4900: {
108
+ standard: "EIP-1193",
109
+ message: "The provider is disconnected from all chains.",
110
+ },
111
+ 4901: {
112
+ standard: "EIP-1193",
113
+ message: "The provider is disconnected from the specified chain.",
114
+ },
115
+ 4902: {
116
+ standard: "EIP-3085",
117
+ message: "Unrecognized chain ID.",
118
+ },
119
+ };
@@ -0,0 +1,168 @@
1
+ import { standardErrorCodes } from "./constants.js";
2
+ import { getMessageFromCode } from "./utils.js";
3
+
4
+ export const standardErrors = {
5
+ rpc: {
6
+ parse: <T>(arg?: EthErrorsArg<T>) => getEthJsonRpcError(standardErrorCodes.rpc.parse, arg),
7
+
8
+ invalidRequest: <T>(arg?: EthErrorsArg<T>) =>
9
+ getEthJsonRpcError(standardErrorCodes.rpc.invalidRequest, arg),
10
+
11
+ invalidParams: <T>(arg?: EthErrorsArg<T>) =>
12
+ getEthJsonRpcError(standardErrorCodes.rpc.invalidParams, arg),
13
+
14
+ methodNotFound: <T>(arg?: EthErrorsArg<T>) =>
15
+ getEthJsonRpcError(standardErrorCodes.rpc.methodNotFound, arg),
16
+
17
+ internal: <T>(arg?: EthErrorsArg<T>) =>
18
+ getEthJsonRpcError(standardErrorCodes.rpc.internal, arg),
19
+
20
+ server: <T>(opts: ServerErrorOptions<T>) => {
21
+ if (!opts || typeof opts !== "object" || Array.isArray(opts)) {
22
+ throw new Error("Ethereum RPC Server errors must provide single object argument.");
23
+ }
24
+ const { code } = opts;
25
+ if (!Number.isInteger(code) || code > -32005 || code < -32099) {
26
+ throw new Error("\"code\" must be an integer such that: -32099 <= code <= -32005");
27
+ }
28
+ return getEthJsonRpcError(code, opts);
29
+ },
30
+
31
+ invalidInput: <T>(arg?: EthErrorsArg<T>) =>
32
+ getEthJsonRpcError(standardErrorCodes.rpc.invalidInput, arg),
33
+
34
+ resourceNotFound: <T>(arg?: EthErrorsArg<T>) =>
35
+ getEthJsonRpcError(standardErrorCodes.rpc.resourceNotFound, arg),
36
+
37
+ resourceUnavailable: <T>(arg?: EthErrorsArg<T>) =>
38
+ getEthJsonRpcError(standardErrorCodes.rpc.resourceUnavailable, arg),
39
+
40
+ transactionRejected: <T>(arg?: EthErrorsArg<T>) =>
41
+ getEthJsonRpcError(standardErrorCodes.rpc.transactionRejected, arg),
42
+
43
+ methodNotSupported: <T>(arg?: EthErrorsArg<T>) =>
44
+ getEthJsonRpcError(standardErrorCodes.rpc.methodNotSupported, arg),
45
+
46
+ limitExceeded: <T>(arg?: EthErrorsArg<T>) =>
47
+ getEthJsonRpcError(standardErrorCodes.rpc.limitExceeded, arg),
48
+ },
49
+
50
+ provider: {
51
+ userRejectedRequest: <T>(arg?: EthErrorsArg<T>) => {
52
+ return getEthProviderError(standardErrorCodes.provider.userRejectedRequest, arg);
53
+ },
54
+
55
+ unauthorized: <T>(arg?: EthErrorsArg<T>) => {
56
+ return getEthProviderError(standardErrorCodes.provider.unauthorized, arg);
57
+ },
58
+
59
+ unsupportedMethod: <T>(arg?: EthErrorsArg<T>) => {
60
+ return getEthProviderError(standardErrorCodes.provider.unsupportedMethod, arg);
61
+ },
62
+
63
+ disconnected: <T>(arg?: EthErrorsArg<T>) => {
64
+ return getEthProviderError(standardErrorCodes.provider.disconnected, arg);
65
+ },
66
+
67
+ chainDisconnected: <T>(arg?: EthErrorsArg<T>) => {
68
+ return getEthProviderError(standardErrorCodes.provider.chainDisconnected, arg);
69
+ },
70
+
71
+ unsupportedChain: <T>(arg?: EthErrorsArg<T>) => {
72
+ return getEthProviderError(standardErrorCodes.provider.unsupportedChain, arg);
73
+ },
74
+
75
+ custom: <T>(opts: CustomErrorArg<T>) => {
76
+ if (!opts || typeof opts !== "object" || Array.isArray(opts)) {
77
+ throw new Error("Ethereum Provider custom errors must provide single object argument.");
78
+ }
79
+
80
+ const { code, message, data } = opts;
81
+
82
+ if (!message || typeof message !== "string") {
83
+ throw new Error("\"message\" must be a nonempty string");
84
+ }
85
+ return new EthereumProviderError(code, message, data);
86
+ },
87
+ },
88
+ };
89
+
90
+ // Internal
91
+
92
+ function getEthJsonRpcError<T>(code: number, arg?: EthErrorsArg<T>): EthereumRpcError<T> {
93
+ const [message, data] = parseOpts(arg);
94
+ return new EthereumRpcError(code, message || getMessageFromCode(code), data);
95
+ }
96
+
97
+ function getEthProviderError<T>(code: number, arg?: EthErrorsArg<T>): EthereumProviderError<T> {
98
+ const [message, data] = parseOpts(arg);
99
+ return new EthereumProviderError(code, message || getMessageFromCode(code), data);
100
+ }
101
+
102
+ function parseOpts<T>(arg?: EthErrorsArg<T>): [string?, T?] {
103
+ if (arg) {
104
+ if (typeof arg === "string") {
105
+ return [arg];
106
+ } else if (typeof arg === "object" && !Array.isArray(arg)) {
107
+ const { message, data } = arg;
108
+
109
+ if (message && typeof message !== "string") {
110
+ throw new Error("Must specify string message.");
111
+ }
112
+ return [message || undefined, data];
113
+ }
114
+ }
115
+ return [];
116
+ }
117
+
118
+ interface EthereumErrorOptions<T> {
119
+ message?: string;
120
+ data?: T;
121
+ }
122
+
123
+ interface ServerErrorOptions<T> extends EthereumErrorOptions<T> {
124
+ code: number;
125
+ }
126
+
127
+ type CustomErrorArg<T> = ServerErrorOptions<T>;
128
+
129
+ type EthErrorsArg<T> = EthereumErrorOptions<T> | string;
130
+
131
+ class EthereumRpcError<T> extends Error {
132
+ code: number;
133
+
134
+ data?: T;
135
+
136
+ constructor(code: number, message: string, data?: T) {
137
+ if (!Number.isInteger(code)) {
138
+ throw new Error("\"code\" must be an integer.");
139
+ }
140
+ if (!message || typeof message !== "string") {
141
+ throw new Error("\"message\" must be a nonempty string.");
142
+ }
143
+
144
+ super(message);
145
+ this.code = code;
146
+ if (data !== undefined) {
147
+ this.data = data;
148
+ }
149
+ }
150
+ }
151
+
152
+ class EthereumProviderError<T> extends EthereumRpcError<T> {
153
+ /**
154
+ * Create an Ethereum Provider JSON-RPC error.
155
+ * `code` must be an integer in the 1000 <= 4999 range.
156
+ */
157
+ constructor(code: number, message: string, data?: T) {
158
+ if (!isValidEthProviderCode(code)) {
159
+ throw new Error("\"code\" must be an integer such that: 1000 <= code <= 4999");
160
+ }
161
+
162
+ super(code, message, data);
163
+ }
164
+ }
165
+
166
+ function isValidEthProviderCode(code: number): boolean {
167
+ return Number.isInteger(code) && code >= 1000 && code <= 4999;
168
+ }
@@ -0,0 +1,4 @@
1
+ export { standardErrorCodes } from "./constants.js";
2
+ export { standardErrors } from "./errors.js";
3
+ export { serializeError } from "./serialize.js";
4
+ export type { SerializedEthereumRpcError } from "./utils.js";
@@ -0,0 +1,91 @@
1
+ import { LIB_VERSION } from "../version.js";
2
+ import { standardErrorCodes } from "./constants.js";
3
+ import { serialize, type SerializedEthereumRpcError } from "./utils.js";
4
+
5
+ type ErrorResponse = {
6
+ method: unknown;
7
+ errorCode?: number;
8
+ errorMessage: string;
9
+ };
10
+
11
+ /**
12
+ * Serializes an error to a format that is compatible with the Ethereum JSON RPC error format.
13
+ */
14
+ export function serializeError(
15
+ error: unknown,
16
+ requestOrMethod?: JSONRPCRequest | JSONRPCRequest[] | string,
17
+ ): SerializedError {
18
+ const serialized = serialize(getErrorObject(error), {
19
+ shouldIncludeStack: true,
20
+ });
21
+
22
+ const docUrl = new URL("https://docs.zksync.io/zksync-account-sdk/docs/errors");
23
+ docUrl.searchParams.set("version", LIB_VERSION);
24
+ docUrl.searchParams.set("code", serialized.code.toString());
25
+ const method = getMethod(serialized.data, requestOrMethod);
26
+ if (method) {
27
+ docUrl.searchParams.set("method", method);
28
+ }
29
+ docUrl.searchParams.set("message", serialized.message);
30
+
31
+ return {
32
+ ...serialized,
33
+ docUrl: docUrl.href,
34
+ };
35
+ }
36
+
37
+ function isErrorResponse(response: unknown): response is ErrorResponse {
38
+ return (response as ErrorResponse).errorMessage !== undefined;
39
+ }
40
+
41
+ /**
42
+ * Converts an error to a serializable object.
43
+ */
44
+ function getErrorObject(error: unknown) {
45
+ if (typeof error === "string") {
46
+ return {
47
+ message: error,
48
+ code: standardErrorCodes.rpc.internal,
49
+ };
50
+ } else if (isErrorResponse(error)) {
51
+ return {
52
+ ...error,
53
+ message: error.errorMessage,
54
+ code: error.errorCode,
55
+ data: { method: error.method },
56
+ };
57
+ }
58
+ return error;
59
+ }
60
+
61
+ /**
62
+ * Gets the method name from the serialized data or the request.
63
+ */
64
+ function getMethod(
65
+ serializedData: unknown,
66
+ request?: JSONRPCRequest | JSONRPCRequest[] | string,
67
+ ): string | undefined {
68
+ const methodInData = (serializedData as { method: string })?.method;
69
+ if (methodInData) {
70
+ return methodInData;
71
+ }
72
+
73
+ if (request === undefined) {
74
+ return undefined;
75
+ } else if (typeof request === "string") {
76
+ return request;
77
+ } else if (!Array.isArray(request)) {
78
+ return request.method;
79
+ } else if (request.length > 0) {
80
+ return request[0]!.method;
81
+ }
82
+ return undefined;
83
+ }
84
+
85
+ interface SerializedError extends SerializedEthereumRpcError {
86
+ docUrl: string;
87
+ }
88
+
89
+ interface JSONRPCRequest {
90
+ method: string;
91
+ }