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,260 @@
1
+ import { type Address, type Chain, type Hash, hexToNumber, http, type RpcSchema as RpcSchemaGeneric, type SendTransactionParameters, type Transport } from "viem";
2
+
3
+ import { createZksyncSessionClient, type ZksyncSsoSessionClient } from "../client/index.js";
4
+ import type { Communicator } from "../communicator/index.js";
5
+ import { type SessionConfig } from "../utils/session.js";
6
+ import { StorageItem } from "../utils/storage.js";
7
+ import type { AppMetadata, RequestArguments } from "./interface.js";
8
+ import type { AuthServerRpcSchema, ExtractParams, ExtractReturnType, Method, RPCRequestMessage, RPCResponseMessage, RpcSchema } from "./rpc.js";
9
+ import type { SessionPreferences } from "./session.js";
10
+
11
+ type Account = {
12
+ address: Address;
13
+ activeChainId: Chain["id"];
14
+ session?: {
15
+ sessionKey: Hash;
16
+ sessionConfig: SessionConfig;
17
+ };
18
+ };
19
+
20
+ interface SignerInterface {
21
+ accounts: Address[];
22
+ chain: Chain;
23
+ handshake(): Promise<Address[]>;
24
+ request<TMethod extends Method>(request: RequestArguments<TMethod>): Promise<ExtractReturnType<TMethod>>;
25
+ disconnect: () => Promise<void>;
26
+ }
27
+
28
+ type UpdateListener = {
29
+ onAccountsUpdate: (_: Address[]) => void;
30
+ onChainUpdate: (_: number) => void;
31
+ };
32
+
33
+ type SignerConstructorParams = {
34
+ metadata: () => AppMetadata;
35
+ communicator: Communicator;
36
+ updateListener: UpdateListener;
37
+ chains: readonly Chain[];
38
+ transports?: Record<number, Transport>;
39
+ session?: () => SessionPreferences | Promise<SessionPreferences>;
40
+ };
41
+
42
+ type ChainsInfo = ExtractReturnType<"eth_requestAccounts", AuthServerRpcSchema>["chainsInfo"];
43
+
44
+ export class Signer implements SignerInterface {
45
+ private readonly getMetadata: () => AppMetadata;
46
+ private readonly communicator: Communicator;
47
+ private readonly updateListener: UpdateListener;
48
+ private readonly chains: readonly Chain[];
49
+ private readonly transports: Record<number, Transport> = {};
50
+ private readonly sessionParameters?: () => (SessionPreferences | Promise<SessionPreferences>);
51
+
52
+ private _account: StorageItem<Account | null>;
53
+ private _chainsInfo = new StorageItem<ChainsInfo>(StorageItem.scopedStorageKey("chainsInfo"), []);
54
+ private walletClient: ZksyncSsoSessionClient | undefined;
55
+
56
+ constructor({ metadata, communicator, updateListener, session, chains, transports }: SignerConstructorParams) {
57
+ if (!chains.length) throw new Error("At least one chain must be included in the config");
58
+
59
+ this.getMetadata = metadata;
60
+ this.communicator = communicator;
61
+ this.updateListener = updateListener;
62
+ this.sessionParameters = session;
63
+ this.chains = chains;
64
+ this.transports = transports || {};
65
+
66
+ this._account = new StorageItem<Account | null>(StorageItem.scopedStorageKey("account"), null, {
67
+ onChange: (newValue) => {
68
+ if (newValue) {
69
+ this.updateListener.onAccountsUpdate([newValue.address]);
70
+ this.updateListener.onChainUpdate(newValue.activeChainId);
71
+ this.createWalletClient();
72
+ } else {
73
+ this.updateListener.onAccountsUpdate([]);
74
+ }
75
+ },
76
+ });
77
+ try {
78
+ if (this.account) this.createWalletClient();
79
+ } catch (error) {
80
+ console.error("Failed to create wallet client", error);
81
+ console.error("Logging out to prevent crash loop");
82
+ this.clearState();
83
+ }
84
+ }
85
+
86
+ private get account(): Account | null {
87
+ const account = this._account.get();
88
+ if (!account) return null;
89
+ const chain = this.chains.find((e) => e.id === account.activeChainId);
90
+ return {
91
+ ...account,
92
+ activeChainId: chain?.id || this.chains[0]!.id,
93
+ };
94
+ }
95
+
96
+ private get session() { return this.account?.session; }
97
+ private get chainsInfo() { return this._chainsInfo.get(); }
98
+ private readonly clearState = () => {
99
+ this._account.remove();
100
+ this._chainsInfo.remove();
101
+ };
102
+
103
+ public get accounts() { return this.account ? [this.account.address] : []; }
104
+ public get chain() {
105
+ const chainId = this.account?.activeChainId || this.chains[0]!.id;
106
+ return this.chains.find((e) => e.id === chainId)!;
107
+ }
108
+
109
+ createWalletClient() {
110
+ const session = this.session;
111
+ const chain = this.chain;
112
+ const chainInfo = this.chainsInfo.find((e) => e.id === chain.id);
113
+ if (!this.account) throw new Error("Account is not set");
114
+ if (!chainInfo) throw new Error(`Chain info for ${chain} wasn't set during handshake`);
115
+ if (session) {
116
+ this.walletClient = createZksyncSessionClient({
117
+ address: this.account.address,
118
+ sessionKey: session.sessionKey,
119
+ sessionConfig: session.sessionConfig,
120
+ contracts: chainInfo.contracts,
121
+ chain,
122
+ transport: this.transports[chain.id] || http(),
123
+ });
124
+ } else {
125
+ this.walletClient = undefined;
126
+ }
127
+ }
128
+
129
+ async handshake(): Promise<Address[]> {
130
+ let sessionPreferences: SessionPreferences | undefined;
131
+ let metadata: AppMetadata = {
132
+ name: "Unknown DApp",
133
+ icon: null,
134
+ };
135
+ try {
136
+ metadata = this.getMetadata();
137
+ } catch (error) {
138
+ console.error("Failed to get website metadata. Proceeding with default one.", error);
139
+ }
140
+ if (this.sessionParameters) {
141
+ try {
142
+ sessionPreferences = await this.sessionParameters();
143
+ } catch (error) {
144
+ console.error("Failed to get session data. Proceeding connection with no session.", error);
145
+ }
146
+ }
147
+ const responseMessage = await this.sendRpcRequest<"eth_requestAccounts", AuthServerRpcSchema>({
148
+ method: "eth_requestAccounts",
149
+ params: {
150
+ metadata,
151
+ sessionPreferences,
152
+ },
153
+ });
154
+ const handshakeData = responseMessage.content.result!;
155
+
156
+ this._chainsInfo.set(handshakeData.chainsInfo);
157
+ this._account.set({
158
+ address: handshakeData.account.address,
159
+ activeChainId: handshakeData.account.activeChainId || this.chain.id,
160
+ session: handshakeData.account.session,
161
+ });
162
+ return this.accounts;
163
+ }
164
+
165
+ switchChain(chainId: number): boolean {
166
+ const chain = this.chains.find((chain) => chain.id === chainId);
167
+ const chainInfo = this.chainsInfo.find((e) => e.id === chainId);
168
+ if (!chainInfo) {
169
+ console.error(`Chain ${chainId} is not supported or chain info was not set during handshake`);
170
+ return false;
171
+ };
172
+ if (!chain) {
173
+ console.error(`Chain ${chainId} is missing in the configuration`);
174
+ return false;
175
+ };
176
+ if (chain.id === this.chain.id) return true;
177
+
178
+ this._account.set({
179
+ ...this.account!,
180
+ activeChainId: chain.id,
181
+ });
182
+ return true;
183
+ }
184
+
185
+ async request<TMethod extends Method>(request: RequestArguments<TMethod>): Promise<ExtractReturnType<TMethod>> {
186
+ const localResult = await this.tryLocalHandling(request);
187
+ if (localResult !== undefined) return localResult;
188
+
189
+ const response = await this.sendRpcRequest(request);
190
+ return response.content.result as ExtractReturnType<TMethod>;
191
+ }
192
+
193
+ async disconnect() {
194
+ this.clearState();
195
+ }
196
+
197
+ private async tryLocalHandling<TMethod extends Method>(request: RequestArguments<TMethod>): Promise<ExtractReturnType<TMethod> | undefined> {
198
+ switch (request.method) {
199
+ case "eth_estimateGas": {
200
+ if (!this.walletClient || !this.session) return undefined;
201
+ const params = request.params as ExtractParams<"eth_estimateGas">;
202
+ const res = await this.walletClient.request({ method: request.method, params: params });
203
+ return res as ExtractReturnType<TMethod>;
204
+ }
205
+ case "eth_sendTransaction": {
206
+ if (!this.walletClient || !this.session) return undefined;
207
+ const params = request.params as ExtractParams<"eth_sendTransaction">;
208
+ const transactionRequest = params[0];
209
+ const res = await this.walletClient.sendTransaction(transactionRequest as unknown as SendTransactionParameters);
210
+ return res as ExtractReturnType<TMethod>;
211
+ }
212
+ case "wallet_switchEthereumChain": {
213
+ const params = request.params as ExtractParams<"wallet_switchEthereumChain">;
214
+ const chainId = params[0].chainId;
215
+ const switched = this.switchChain(typeof chainId === "string" ? hexToNumber(chainId as Hash) : chainId);
216
+ return switched ? (null as ExtractReturnType<TMethod>) : undefined;
217
+ }
218
+ case "wallet_getCapabilities": {
219
+ const chainInfo = this.chainsInfo.find((e) => e.id === this.chain.id);
220
+ if (!chainInfo) throw new Error("Chain info is not set");
221
+ return { [this.chain.id]: chainInfo.capabilities } as ExtractReturnType<TMethod>;
222
+ }
223
+ case "eth_accounts": {
224
+ return this.accounts as ExtractReturnType<TMethod>;
225
+ }
226
+ default:
227
+ return undefined;
228
+ }
229
+ }
230
+
231
+ private async sendRpcRequest<
232
+ TMethod extends Method<TSchema>,
233
+ TSchema extends RpcSchemaGeneric = RpcSchema,
234
+ >(request: RequestArguments<TMethod, TSchema>): Promise<RPCResponseMessage<ExtractReturnType<TMethod, TSchema>>> {
235
+ // Open popup immediately to make sure popup won't be blocked by Safari
236
+ await this.communicator.ready();
237
+
238
+ const message = this.createRequestMessage<TMethod, TSchema>({
239
+ action: request,
240
+ chainId: this.chain.id,
241
+ });
242
+ const response: RPCResponseMessage<ExtractReturnType<TMethod, TSchema>>
243
+ = await this.communicator.postRequestAndWaitForResponse(message);
244
+
245
+ const content = response.content;
246
+ if ("error" in content) throw content.error;
247
+
248
+ return response;
249
+ }
250
+
251
+ private createRequestMessage<
252
+ TMethod extends Method<TSchema>,
253
+ TSchema extends RpcSchemaGeneric = RpcSchema,
254
+ >(content: RPCRequestMessage<TMethod, TSchema>["content"]): RPCRequestMessage<TMethod, TSchema> {
255
+ return {
256
+ id: crypto.randomUUID(),
257
+ content,
258
+ };
259
+ }
260
+ }
@@ -0,0 +1,114 @@
1
+ import { EventEmitter } from "eventemitter3";
2
+ import type { Address, Chain, Transport } from "viem";
3
+ import { toHex } from "viem";
4
+
5
+ import { PopupCommunicator } from "../communicator/PopupCommunicator.js";
6
+ import { serializeError, standardErrors } from "../errors/index.js";
7
+ import { getFavicon, getWebsiteName } from "../utils/helpers.js";
8
+ import type {
9
+ AppMetadata,
10
+ ProviderInterface,
11
+ RequestArguments,
12
+ } from "./interface.js";
13
+ import { type ExtractReturnType, type Method } from "./rpc.js";
14
+ import type { SessionPreferences } from "./session.js";
15
+ import { Signer } from "./Signer.js";
16
+
17
+ const DEFAULT_AUTH_SERVER_URL = "https://auth-test.zksync.dev/confirm";
18
+
19
+ export type WalletProviderConstructorOptions = {
20
+ metadata: Partial<AppMetadata> | undefined;
21
+ chains: readonly Chain[];
22
+ transports?: Record<number, Transport>;
23
+ session?: SessionPreferences | (() => SessionPreferences | Promise<SessionPreferences>);
24
+ authServerUrl?: string;
25
+ };
26
+
27
+ export class WalletProvider extends EventEmitter implements ProviderInterface {
28
+ readonly isZksyncSso = true;
29
+ private signer: Signer;
30
+
31
+ constructor({ metadata, chains, transports, session, authServerUrl }: WalletProviderConstructorOptions) {
32
+ super();
33
+ const communicator = new PopupCommunicator(authServerUrl || DEFAULT_AUTH_SERVER_URL);
34
+ this.signer = new Signer({
35
+ metadata: () => ({
36
+ name: metadata?.name || getWebsiteName() || "Unknown DApp",
37
+ icon: metadata?.icon || getFavicon(),
38
+ }),
39
+ updateListener: this.updateListener,
40
+ communicator: communicator,
41
+ chains,
42
+ transports,
43
+ session: typeof session === "object" ? () => session : session,
44
+ });
45
+ }
46
+
47
+ protected get chain() {
48
+ return this.signer.chain;
49
+ }
50
+
51
+ public get connected() {
52
+ return this.signer.accounts.length > 0;
53
+ }
54
+
55
+ public async request<M extends Method>(request: RequestArguments<M>): Promise<ExtractReturnType<M>> {
56
+ try {
57
+ switch (request.method) {
58
+ case "eth_requestAccounts": {
59
+ return await this.handshake() as ExtractReturnType<M>;
60
+ }
61
+ case "personal_sign":
62
+ case "eth_accounts":
63
+ case "eth_estimateGas":
64
+ case "eth_signTransaction":
65
+ case "eth_sendTransaction":
66
+ case "eth_signTypedData_v4":
67
+ case "wallet_addEthereumChain":
68
+ case "wallet_switchEthereumChain":
69
+ case "wallet_watchAsset":
70
+ case "wallet_getCapabilities":
71
+ case "wallet_sendCalls":
72
+ case "wallet_showCallsStatus": {
73
+ if (!this.connected) {
74
+ throw standardErrors.provider.unauthorized(
75
+ "Must call 'eth_requestAccounts' before other methods",
76
+ );
77
+ }
78
+ return await this.signer.request(request) as ExtractReturnType<M>;
79
+ }
80
+ case "eth_chainId":
81
+ case "net_version": {
82
+ return toHex(this.chain.id) as ExtractReturnType<M>;
83
+ }
84
+ }
85
+ throw standardErrors.rpc.methodNotSupported(`Method ${request.method} is not supported.`);
86
+ } catch (error) {
87
+ return Promise.reject(serializeError(error, request.method));
88
+ }
89
+ }
90
+
91
+ public async handshake(): Promise<Address[]> {
92
+ if (this.connected) {
93
+ this.emit("connect", { chainId: this.chain.id });
94
+ return this.signer.accounts;
95
+ }
96
+ const accounts = await this.signer.handshake();
97
+ this.emit("connect", { chainId: this.chain.id });
98
+ return accounts;
99
+ }
100
+
101
+ async disconnect(): Promise<void> {
102
+ this.signer.disconnect();
103
+ this.emit("disconnect", standardErrors.provider.disconnected("User initiated disconnection"));
104
+ }
105
+
106
+ protected readonly updateListener = {
107
+ onAccountsUpdate: (accounts: Address[]) => {
108
+ this.emit("accountsChanged", accounts);
109
+ },
110
+ onChainUpdate: (chainId: number) => {
111
+ this.emit("chainChanged", chainId);
112
+ },
113
+ };
114
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./interface.js";
2
+ export * from "./rpc.js";
3
+ export * from "./session.js";
@@ -0,0 +1,39 @@
1
+ import { EventEmitter } from "eventemitter3";
2
+ import type { RpcSchema as RpcSchemaGeneric } from "viem";
3
+
4
+ import type { ExtractParams, ExtractReturnType, Method, RpcSchema } from "./rpc.js";
5
+
6
+ export interface RequestArguments<M extends Method<TSchema>, TSchema extends RpcSchemaGeneric = RpcSchema> {
7
+ readonly method: M;
8
+ readonly params?: ExtractParams<M, TSchema>;
9
+ }
10
+
11
+ export interface ProviderRpcError extends Error {
12
+ message: string;
13
+ code: number;
14
+ data?: unknown;
15
+ }
16
+
17
+ interface ProviderMessage {
18
+ type: string;
19
+ data: unknown;
20
+ }
21
+
22
+ interface ProviderConnectInfo {
23
+ readonly chainId: string;
24
+ }
25
+
26
+ export interface ProviderInterface extends EventEmitter {
27
+ request<M extends Method>(args: RequestArguments<M>): Promise<ExtractReturnType<M>>;
28
+ disconnect(): Promise<void>;
29
+ on(event: "connect", listener: (info: ProviderConnectInfo) => void): this;
30
+ on(event: "disconnect", listener: (error: ProviderRpcError) => void): this;
31
+ on(event: "chainChanged", listener: (chainId: string) => void): this;
32
+ on(event: "accountsChanged", listener: (accounts: string[]) => void): this;
33
+ on(event: "message", listener: (message: ProviderMessage) => void): this;
34
+ }
35
+
36
+ export interface AppMetadata {
37
+ name: string;
38
+ icon: string | null;
39
+ }
@@ -0,0 +1,69 @@
1
+ import type { Address, Chain, Hash, PublicRpcSchema, RpcSchema as RpcSchemaGeneric, WalletRpcSchema } from "viem";
2
+
3
+ import type { SessionRequiredContracts } from "../client/index.js";
4
+ import type { Message } from "../communicator/index.js";
5
+ import type { SerializedEthereumRpcError } from "../errors/index.js";
6
+ import type { SessionConfig } from "../utils/session.js";
7
+ import type { AppMetadata, RequestArguments } from "./interface.js";
8
+ import type { SessionPreferences } from "./session.js";
9
+
10
+ export type AuthServerRpcSchema = [
11
+ {
12
+ Method: "eth_requestAccounts";
13
+ Parameters: {
14
+ metadata: AppMetadata;
15
+ sessionPreferences?: SessionPreferences;
16
+ };
17
+ ReturnType: {
18
+ account: {
19
+ address: Address;
20
+ activeChainId: Chain["id"];
21
+ session?: {
22
+ sessionKey: Hash;
23
+ sessionConfig: SessionConfig;
24
+ };
25
+ };
26
+ chainsInfo: {
27
+ id: Chain["id"];
28
+ capabilities: Record<string, unknown>;
29
+ contracts: SessionRequiredContracts;
30
+ }[];
31
+ };
32
+ },
33
+ ];
34
+ export type RpcSchema = WalletRpcSchema | PublicRpcSchema | AuthServerRpcSchema;
35
+ export type Method<TSchema extends RpcSchemaGeneric = RpcSchema> = TSchema[number]["Method"];
36
+ export type ExtractParams<
37
+ TMethod extends Method<TSchema>,
38
+ TSchema extends RpcSchemaGeneric = RpcSchema,
39
+ > = TSchema extends Array<infer T>
40
+ ? T extends { Method: TMethod; Parameters: infer R }
41
+ ? R
42
+ : never
43
+ : never;
44
+ export type ExtractReturnType<
45
+ TMethod extends Method<TSchema>,
46
+ TSchema extends RpcSchemaGeneric = RpcSchema,
47
+ > = TSchema extends Array<infer T>
48
+ ? T extends { Method: TMethod; ReturnType: infer R }
49
+ ? R
50
+ : never
51
+ : never;
52
+
53
+ export interface RPCRequestMessage<
54
+ TMethod extends Method<TSchema>,
55
+ TSchema extends RpcSchemaGeneric = RpcSchema,
56
+ > extends Message {
57
+ content: {
58
+ action: RequestArguments<TMethod, TSchema>;
59
+ chainId: number;
60
+ };
61
+ }
62
+
63
+ export interface RPCResponseMessage<T = unknown> extends Message {
64
+ requestId: NonNullable<Message["requestId"]>;
65
+ content: {
66
+ result?: T; // For successful responses
67
+ error?: SerializedEthereumRpcError; // For error responses
68
+ };
69
+ }
@@ -0,0 +1,139 @@
1
+ import { type AbiFunction, type Address, type Hash, toFunctionSelector, toHex } from "viem";
2
+
3
+ import { ConstraintCondition, type Limit, LimitType, LimitUnlimited, LimitZero, type SessionConfig } from "../utils/session.js";
4
+
5
+ type PartialLimit = bigint | {
6
+ limit: bigint;
7
+ period?: bigint;
8
+ } | {
9
+ limitType: "lifetime" | LimitType.Lifetime;
10
+ limit: bigint;
11
+ } | {
12
+ limitType: "unlimited" | LimitType.Unlimited;
13
+ } | {
14
+ limitType: "allowance" | LimitType.Allowance;
15
+ limit: bigint;
16
+ period: bigint;
17
+ };
18
+
19
+ type PartialCallPolicy = {
20
+ address: Address;
21
+ function?: string | AbiFunction;
22
+ selector?: Hash; // if function is not provided
23
+ maxValuePerUse?: bigint;
24
+ valueLimit?: PartialLimit;
25
+ constraints?: {
26
+ index: number;
27
+ condition?: ConstraintCondition | keyof typeof ConstraintCondition;
28
+ refValue?: Hash;
29
+ limit?: PartialLimit;
30
+ }[];
31
+ };
32
+
33
+ type PartialTransferPolicy = {
34
+ to: Address;
35
+ maxValuePerUse?: bigint;
36
+ valueLimit?: PartialLimit;
37
+ };
38
+
39
+ export interface SessionPreferences {
40
+ expiresAt?: bigint | Date;
41
+ feeLimit?: PartialLimit;
42
+ contractCalls?: PartialCallPolicy[];
43
+ transfers?: PartialTransferPolicy[];
44
+ };
45
+
46
+ const formatLimitPreferences = (limit: PartialLimit): Limit => {
47
+ /* Just bigint was passed */
48
+ if (typeof limit === "bigint") {
49
+ return {
50
+ limitType: LimitType.Lifetime,
51
+ limit,
52
+ period: 0n,
53
+ };
54
+ }
55
+
56
+ /* LimitType was specified */
57
+ if ("limitType" in limit) {
58
+ if (limit.limitType === "lifetime" || limit.limitType === LimitType.Lifetime) {
59
+ return {
60
+ limitType: LimitType.Lifetime,
61
+ limit: limit.limit,
62
+ period: 0n,
63
+ };
64
+ } else if (limit.limitType === "unlimited" || limit.limitType === LimitType.Unlimited) {
65
+ return {
66
+ limitType: LimitType.Unlimited,
67
+ limit: 0n,
68
+ period: 0n,
69
+ };
70
+ } else if (limit.limitType === "allowance" || limit.limitType === LimitType.Allowance) {
71
+ return {
72
+ limitType: LimitType.Allowance,
73
+ limit: limit.limit,
74
+ period: limit.period,
75
+ };
76
+ }
77
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+ throw new Error(`Invalid limit type: ${(limit as any).limitType}`);
79
+ }
80
+
81
+ /* LimitType not selected */
82
+ if (!limit.period) {
83
+ return {
84
+ limitType: LimitType.Lifetime,
85
+ limit: limit.limit,
86
+ period: 0n,
87
+ };
88
+ }
89
+ return {
90
+ limitType: LimitType.Allowance,
91
+ limit: limit.limit,
92
+ period: limit.period,
93
+ };
94
+ };
95
+
96
+ const formatDatePreferences = (date: bigint | Date): bigint => {
97
+ if (date instanceof Date) {
98
+ return BigInt(Math.floor(date.getTime() / 1000));
99
+ }
100
+ return date;
101
+ };
102
+
103
+ export function formatSessionPreferences(
104
+ preferences: SessionPreferences,
105
+ defaults: {
106
+ expiresAt: bigint;
107
+ feeLimit: Limit;
108
+ },
109
+ ): Omit<SessionConfig, "signer"> {
110
+ return {
111
+ expiresAt: preferences.expiresAt ? formatDatePreferences(preferences.expiresAt) : defaults.expiresAt,
112
+ feeLimit: preferences.feeLimit ? formatLimitPreferences(preferences.feeLimit) : defaults.feeLimit,
113
+ callPolicies: preferences.contractCalls?.map((policy) => {
114
+ const valueLimit = policy.valueLimit ? formatLimitPreferences(policy.valueLimit) : LimitZero;
115
+ const selector = policy.function ? toFunctionSelector(policy.function) : policy.selector;
116
+ if (!selector) throw new Error("Missing function or selector in contract call policy");
117
+ return {
118
+ target: policy.address,
119
+ maxValuePerUse: policy.maxValuePerUse ?? valueLimit.limit,
120
+ valueLimit,
121
+ selector: selector,
122
+ constraints: policy.constraints?.map((constraint) => ({
123
+ index: BigInt(constraint.index),
124
+ condition: typeof constraint.condition == "string" ? ConstraintCondition[constraint.condition] : (constraint.condition ?? 0),
125
+ refValue: constraint.refValue ?? toHex("", { size: 32 }),
126
+ limit: constraint.limit ? formatLimitPreferences(constraint.limit) : LimitUnlimited,
127
+ })) ?? [],
128
+ };
129
+ }) ?? [],
130
+ transferPolicies: preferences.transfers?.map((policy) => {
131
+ const valueLimit = policy.valueLimit ? formatLimitPreferences(policy.valueLimit) : LimitZero;
132
+ return {
133
+ target: policy.to,
134
+ maxValuePerUse: policy.maxValuePerUse ?? valueLimit.limit,
135
+ valueLimit,
136
+ };
137
+ }) ?? [],
138
+ };
139
+ }