@talken/talkenkit 2.3.15 → 2.4.4

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 (170) hide show
  1. package/dist/{chunk-UWHLB4MJ.js → chunk-RQ637EP3.js} +0 -2
  2. package/dist/components/ConnectOptions/ExternalWallets/EthereumWallet/EthereumWalletList.d.ts +4 -4
  3. package/dist/index.d.ts +6 -5
  4. package/dist/index.js +6783 -6571
  5. package/dist/{secure-SSSSQ4NA.js → secure-X6ZSGFOB.js} +1 -1
  6. package/dist/services/AbcAuthService.d.ts +1 -1
  7. package/dist/solana/AbcSolanaAutoConnector.d.ts +7 -0
  8. package/dist/solana/SolanaWalletProvider.d.ts +18 -2
  9. package/dist/solana/config.d.ts +26 -0
  10. package/dist/wallets/walletConnectors/abcWallet/AbcEvmAutoConnector.d.ts +7 -0
  11. package/dist/wallets/walletConnectors/abcWallet/AbcEvmAutoConnector.js +37 -0
  12. package/dist/wallets/walletConnectors/abcWallet/abcApi.js +4 -4
  13. package/dist/wallets/walletConnectors/abcWallet/abcBitcoinConnector.js +3 -3
  14. package/dist/wallets/walletConnectors/abcWallet/abcBitcoinProvider.js +1 -1
  15. package/dist/wallets/walletConnectors/abcWallet/abcConnector.js +6 -6
  16. package/dist/wallets/walletConnectors/abcWallet/abcProvider.js +3 -3
  17. package/dist/wallets/walletConnectors/abcWallet/abcSolanaWalletAdapter.d.ts +166 -0
  18. package/dist/wallets/walletConnectors/abcWallet/abcSolanaWalletAdapter.js +725 -0
  19. package/dist/wallets/walletConnectors/abcWallet/abcWallet.js +7 -7
  20. package/dist/wallets/walletConnectors/abcWallet/api/AuthApi.js +5 -5
  21. package/dist/wallets/walletConnectors/abcWallet/api/BaseApiClient.d.ts +5 -0
  22. package/dist/wallets/walletConnectors/abcWallet/api/BaseApiClient.js +4 -4
  23. package/dist/wallets/walletConnectors/abcWallet/api/BitcoinApi.js +5 -5
  24. package/dist/wallets/walletConnectors/abcWallet/api/SigningApi.js +5 -5
  25. package/dist/wallets/walletConnectors/abcWallet/api/SolanaApi.d.ts +16 -5
  26. package/dist/wallets/walletConnectors/abcWallet/api/SolanaApi.js +5 -5
  27. package/dist/wallets/walletConnectors/abcWallet/api/TransactionApi.js +5 -5
  28. package/dist/wallets/walletConnectors/abcWallet/api/WalletApi.js +5 -5
  29. package/dist/wallets/walletConnectors/abcWallet/api/index.js +13 -13
  30. package/dist/wallets/walletConnectors/abcWallet/googleAuth.d.ts +1 -1
  31. package/dist/wallets/walletConnectors/abcWallet/googleAuth.js +5 -7
  32. package/dist/wallets/walletConnectors/abcWallet/index.d.ts +3 -7
  33. package/dist/wallets/walletConnectors/abcWallet/index.js +36 -46
  34. package/dist/wallets/walletConnectors/abcWallet/secure.js +1 -1
  35. package/dist/wallets/walletConnectors/abcWallet/sessionUtils.d.ts +38 -0
  36. package/dist/wallets/walletConnectors/abcWallet/sessionUtils.js +15 -0
  37. package/dist/wallets/walletConnectors/abcWallet/types.d.ts +34 -1
  38. package/dist/wallets/walletConnectors/abcWallet/types.js +1 -1
  39. package/dist/wallets/walletConnectors/abcWallet/utils.d.ts +1 -1
  40. package/dist/wallets/walletConnectors/abcWallet/utils.js +2 -2
  41. package/dist/wallets/walletConnectors/abcWallet/walletGeneration.js +2 -2
  42. package/dist/wallets/walletConnectors/chunk-2GNL2GNB.js +154 -0
  43. package/dist/wallets/walletConnectors/{chunk-5DDAV4BZ.js → chunk-2NAY6X3G.js} +1 -1
  44. package/dist/wallets/walletConnectors/{chunk-ZIYAL44B.js → chunk-2NVHWZUE.js} +1 -1
  45. package/dist/wallets/walletConnectors/{chunk-LENPUTNQ.js → chunk-36J4NGMW.js} +12 -20
  46. package/dist/wallets/walletConnectors/{chunk-4MF5RSML.js → chunk-3CTIR723.js} +1 -1
  47. package/dist/wallets/walletConnectors/{chunk-AVPBPELO.js → chunk-3WLUH24A.js} +10 -10
  48. package/dist/wallets/walletConnectors/{chunk-YEHCPL4R.js → chunk-53LPTQ6J.js} +2 -2
  49. package/dist/wallets/walletConnectors/{chunk-GXGRTWJM.js → chunk-5CZGFT24.js} +10 -10
  50. package/dist/wallets/walletConnectors/{chunk-BJHGC546.js → chunk-5JIPWC5W.js} +12 -24
  51. package/dist/wallets/walletConnectors/{chunk-4N6JD6LY.js → chunk-5LPD35BU.js} +9 -9
  52. package/dist/wallets/walletConnectors/{chunk-UV5HHESJ.js → chunk-5RSS3SRV.js} +29 -12
  53. package/dist/wallets/walletConnectors/{chunk-3ZE57J3R.js → chunk-64TRAZ6V.js} +1 -1
  54. package/dist/wallets/walletConnectors/{chunk-KKPINUPY.js → chunk-6BAXMYSN.js} +2 -2
  55. package/dist/wallets/walletConnectors/{chunk-PPIFAF7N.js → chunk-7MOCKWA7.js} +65 -19
  56. package/dist/wallets/walletConnectors/{chunk-75RN2RLT.js → chunk-7TYZCXIR.js} +12 -12
  57. package/dist/wallets/walletConnectors/{chunk-HVPQO6ZG.js → chunk-7UIXGYOT.js} +5 -20
  58. package/dist/wallets/walletConnectors/{chunk-BL57XWJY.js → chunk-7UQQKSV7.js} +1 -1
  59. package/dist/wallets/walletConnectors/{chunk-FGBDWBWQ.js → chunk-AIKTQX6B.js} +2 -2
  60. package/dist/wallets/walletConnectors/chunk-AO24PU7X.js +104 -0
  61. package/dist/wallets/walletConnectors/{chunk-4YJWX7I3.js → chunk-APLOMU6R.js} +1 -1
  62. package/dist/wallets/walletConnectors/chunk-AZAV5URB.js +267 -0
  63. package/dist/wallets/walletConnectors/chunk-BO6OI7XU.js +63 -0
  64. package/dist/wallets/walletConnectors/{chunk-P2GV6NQG.js → chunk-BV3DCJXA.js} +12 -20
  65. package/dist/wallets/walletConnectors/{chunk-KJHOGJ3A.js → chunk-CNRPEVLV.js} +16 -4
  66. package/dist/wallets/walletConnectors/{chunk-OC2O4BHA.js → chunk-COPAK5YT.js} +2 -2
  67. package/dist/wallets/walletConnectors/chunk-CZVBS7QE.js +436 -0
  68. package/dist/wallets/walletConnectors/{chunk-QKUFFUM5.js → chunk-DA5J6GHZ.js} +14 -4
  69. package/dist/wallets/walletConnectors/chunk-FMDSZ2CE.js +63 -0
  70. package/dist/wallets/walletConnectors/{chunk-5CCU7PNU.js → chunk-FQTLYAWT.js} +2 -2
  71. package/dist/wallets/walletConnectors/chunk-FUOQBONI.js +47 -0
  72. package/dist/wallets/walletConnectors/chunk-FWCS4HBL.js +1695 -0
  73. package/dist/wallets/walletConnectors/chunk-FY7UDC3W.js +63 -0
  74. package/dist/wallets/walletConnectors/chunk-GZUP3M2X.js +63 -0
  75. package/dist/wallets/walletConnectors/chunk-H52W4ZFE.js +272 -0
  76. package/dist/wallets/walletConnectors/chunk-HEQZLRTH.js +309 -0
  77. package/dist/wallets/walletConnectors/{chunk-ISAMATTH.js → chunk-HFC4AK72.js} +2 -2
  78. package/dist/wallets/walletConnectors/chunk-HKIV22NT.js +63 -0
  79. package/dist/wallets/walletConnectors/chunk-HLC24OGS.js +63 -0
  80. package/dist/wallets/walletConnectors/{chunk-5TDZSXJ4.js → chunk-HTD7IRKM.js} +2 -2
  81. package/dist/wallets/walletConnectors/chunk-IQJWD4IN.js +269 -0
  82. package/dist/wallets/walletConnectors/chunk-IZUAJRJ4.js +311 -0
  83. package/dist/wallets/walletConnectors/{chunk-NX5MQHSQ.js → chunk-J6VUIOSE.js} +23 -2
  84. package/dist/wallets/walletConnectors/chunk-JQ57SCY6.js +313 -0
  85. package/dist/wallets/walletConnectors/{chunk-F5P2INHS.js → chunk-KB7OGAUC.js} +14 -4
  86. package/dist/wallets/walletConnectors/chunk-KXEAFXAA.js +226 -0
  87. package/dist/wallets/walletConnectors/{chunk-JR2C4XXX.js → chunk-LLWI2QWC.js} +74 -18
  88. package/dist/wallets/walletConnectors/{chunk-H2MX4NAL.js → chunk-LQ2U33WM.js} +29 -16
  89. package/dist/wallets/walletConnectors/{chunk-BNSBK5PQ.js → chunk-M7KXDTM6.js} +14 -4
  90. package/dist/wallets/walletConnectors/{chunk-CYYBGUSO.js → chunk-MKAXMNZM.js} +4 -4
  91. package/dist/wallets/walletConnectors/chunk-MNRRJSFM.js +272 -0
  92. package/dist/wallets/walletConnectors/chunk-MPFE6GP2.js +306 -0
  93. package/dist/wallets/walletConnectors/{chunk-EEY5CXKO.js → chunk-MPNSYA4E.js} +2 -2
  94. package/dist/wallets/walletConnectors/chunk-NDLQSZ2F.js +63 -0
  95. package/dist/wallets/walletConnectors/{chunk-G2LI5MVX.js → chunk-NDYGTKP5.js} +0 -2
  96. package/dist/wallets/walletConnectors/chunk-NLBRSN6Q.js +63 -0
  97. package/dist/wallets/walletConnectors/{chunk-BSBRWKNG.js → chunk-NPF7NOA7.js} +69 -23
  98. package/dist/wallets/walletConnectors/{chunk-7DEZCGNV.js → chunk-NUJ6VD2U.js} +82 -16
  99. package/dist/wallets/walletConnectors/chunk-PSRATZTN.js +47 -0
  100. package/dist/wallets/walletConnectors/{chunk-MZOFZ2NQ.js → chunk-QCIIXMAZ.js} +2 -2
  101. package/dist/wallets/walletConnectors/{chunk-GHLLVM7O.js → chunk-RCI7QYCZ.js} +82 -18
  102. package/dist/wallets/walletConnectors/{chunk-QI2VB7LL.js → chunk-RHQXGWIW.js} +82 -16
  103. package/dist/wallets/walletConnectors/chunk-RPOLRZ4N.js +276 -0
  104. package/dist/wallets/walletConnectors/{chunk-5UEBEMEE.js → chunk-RQIUWXDF.js} +2 -1
  105. package/dist/wallets/walletConnectors/{chunk-RLR4Y5WO.js → chunk-SCD35IRD.js} +4 -0
  106. package/dist/wallets/walletConnectors/{chunk-EGOIRXTV.js → chunk-SOCVQ5N3.js} +2 -2
  107. package/dist/wallets/walletConnectors/chunk-TTRSCIGA.js +194 -0
  108. package/dist/wallets/walletConnectors/chunk-TYUEB4VT.js +477 -0
  109. package/dist/wallets/walletConnectors/{chunk-WTYSUOKN.js → chunk-UZXTNCDO.js} +17 -5
  110. package/dist/wallets/walletConnectors/chunk-V33I7JGZ.js +156 -0
  111. package/dist/wallets/walletConnectors/chunk-V4Q3GNBX.js +484 -0
  112. package/dist/wallets/walletConnectors/chunk-VCCTIYUJ.js +63 -0
  113. package/dist/wallets/walletConnectors/chunk-VGOISIH3.js +223 -0
  114. package/dist/wallets/walletConnectors/chunk-XFGVJOQL.js +223 -0
  115. package/dist/wallets/walletConnectors/chunk-XIOPKI2F.js +47 -0
  116. package/dist/wallets/walletConnectors/{chunk-O6EAIC4G.js → chunk-XJ4SP35I.js} +4 -1
  117. package/dist/wallets/walletConnectors/chunk-XKGUE56S.js +226 -0
  118. package/dist/wallets/walletConnectors/chunk-XQEAXENJ.js +63 -0
  119. package/dist/wallets/walletConnectors/{chunk-RY4RAB3D.js → chunk-YCZ4CZQ6.js} +106 -66
  120. package/dist/wallets/walletConnectors/chunk-Z2DC2J7S.js +345 -0
  121. package/dist/wallets/walletConnectors/chunk-Z2K3RHWK.js +47 -0
  122. package/dist/wallets/walletConnectors/chunk-ZASMSEC3.js +63 -0
  123. package/dist/wallets/walletConnectors/{chunk-G7PEFBL6.js → chunk-ZNBWRE3K.js} +2 -2
  124. package/dist/wallets/walletConnectors/chunk-ZNVFM2J2.js +156 -0
  125. package/dist/wallets/walletConnectors/chunk-ZQLQELFC.js +309 -0
  126. package/dist/wallets/walletConnectors/chunk-ZR7CEF64.js +63 -0
  127. package/dist/wallets/walletConnectors/chunk-ZSGFDK77.js +63 -0
  128. package/dist/wallets/walletConnectors/chunk-ZUIY2TRJ.js +1695 -0
  129. package/dist/wallets/walletConnectors/index.js +22 -22
  130. package/package.json +12 -11
  131. package/LICENSE +0 -9
  132. package/dist/solana/hooks/index.d.ts +0 -12
  133. package/dist/solana/hooks/useSolanaAccount.d.ts +0 -98
  134. package/dist/solana/hooks/useSolanaConnection.d.ts +0 -72
  135. package/dist/solana/hooks/useSolanaSendTransaction.d.ts +0 -98
  136. package/dist/solana/hooks/useSolanaSignMessage.d.ts +0 -82
  137. package/dist/wallets/walletConnectors/abcWallet/abcSolProvider.d.ts +0 -45
  138. package/dist/wallets/walletConnectors/abcWallet/abcSolProvider.js +0 -10
  139. package/dist/wallets/walletConnectors/abcWallet/abcSolanaConnector.d.ts +0 -115
  140. package/dist/wallets/walletConnectors/abcWallet/abcSolanaConnector.js +0 -12
  141. package/dist/wallets/walletConnectors/abcWallet/abcSolanaProvider.d.ts +0 -143
  142. package/dist/wallets/walletConnectors/abcWallet/abcSolanaProvider.js +0 -13
  143. package/dist/wallets/walletConnectors/abcWallet/abcSolanaWallet.d.ts +0 -18
  144. package/dist/wallets/walletConnectors/abcWallet/abcSolanaWallet.js +0 -15
  145. package/dist/wallets/walletConnectors/chunk-2XZBPMQJ.js +0 -39
  146. package/dist/wallets/walletConnectors/chunk-3SVPZCA6.js +0 -71
  147. package/dist/wallets/walletConnectors/chunk-3ZZXE7EL.js +0 -39
  148. package/dist/wallets/walletConnectors/chunk-5QEUEPNY.js +0 -94
  149. package/dist/wallets/walletConnectors/chunk-75W4VLFA.js +0 -482
  150. package/dist/wallets/walletConnectors/chunk-B6JLYR3I.js +0 -66
  151. package/dist/wallets/walletConnectors/chunk-FROV5VDF.js +0 -346
  152. package/dist/wallets/walletConnectors/chunk-HKWBR5B7.js +0 -102
  153. package/dist/wallets/walletConnectors/chunk-K4APJ4PE.js +0 -96
  154. package/dist/wallets/walletConnectors/chunk-LJ2B47VF.js +0 -108
  155. package/dist/wallets/walletConnectors/chunk-LXINMUQC.js +0 -186
  156. package/dist/wallets/walletConnectors/chunk-MORUEOYX.js +0 -76
  157. package/dist/wallets/walletConnectors/chunk-MQTXA63X.js +0 -27
  158. package/dist/wallets/walletConnectors/chunk-N4FOYXQD.js +0 -63
  159. package/dist/wallets/walletConnectors/chunk-NEXFU6BZ.js +0 -39
  160. package/dist/wallets/walletConnectors/chunk-PMZJGS7X.js +0 -73
  161. package/dist/wallets/walletConnectors/chunk-QEHZXKRF.js +0 -39
  162. package/dist/wallets/walletConnectors/chunk-T6KJZAPR.js +0 -47
  163. package/dist/wallets/walletConnectors/chunk-UBCMBPX3.js +0 -58
  164. package/dist/wallets/walletConnectors/chunk-UGQXI3RN.js +0 -284
  165. package/dist/wallets/walletConnectors/chunk-WZZVA3LW.js +0 -101
  166. package/dist/wallets/walletConnectors/chunk-X4WUD7PF.js +0 -63
  167. package/dist/wallets/walletConnectors/chunk-XOQNQKZE.js +0 -98
  168. package/dist/wallets/walletConnectors/chunk-XPSCFUX6.js +0 -372
  169. package/dist/wallets/walletConnectors/chunk-Y3LWEDF6.js +0 -63
  170. package/dist/wallets/walletConnectors/chunk-ZJ6OFFD5.js +0 -95
@@ -0,0 +1,1695 @@
1
+ "use client";
2
+ import {
3
+ secure_default
4
+ } from "./chunk-NDYGTKP5.js";
5
+ import {
6
+ getSolanaNetwork
7
+ } from "./chunk-A7FIBI6X.js";
8
+ import {
9
+ calculateExpiryTimestamp,
10
+ createAbcError,
11
+ isTokenExpired,
12
+ loadFromStorage,
13
+ parseApiError,
14
+ removeFromStorage,
15
+ saveToStorage
16
+ } from "./chunk-TYUEB4VT.js";
17
+ import {
18
+ ABC_AUDIENCE,
19
+ ABC_ENDPOINTS,
20
+ DEFAULT_HEADERS,
21
+ REQUEST_TIMEOUT
22
+ } from "./chunk-VETRBBA2.js";
23
+
24
+ // src/wallets/walletConnectors/abcWallet/abcApi.ts
25
+ import { getAddress } from "viem";
26
+ var AbcWaasClient = class {
27
+ constructor(config) {
28
+ this.accessToken = null;
29
+ this.refreshToken = null;
30
+ this.expiresAt = null;
31
+ this.isRefreshing = false;
32
+ this.refreshPromise = null;
33
+ this.config = config;
34
+ this.baseURL = config.waasUrl;
35
+ this.secure = new secure_default(this.baseURL);
36
+ this.loadTokens();
37
+ }
38
+ /**
39
+ * Load tokens from storage
40
+ */
41
+ loadTokens() {
42
+ this.accessToken = loadFromStorage("access_token" /* ACCESS_TOKEN */);
43
+ this.refreshToken = loadFromStorage("refresh_token" /* REFRESH_TOKEN */);
44
+ this.expiresAt = loadFromStorage("expires_at" /* EXPIRES_AT */);
45
+ }
46
+ /**
47
+ * Save tokens to storage
48
+ */
49
+ saveTokens(accessToken, refreshToken, expiresIn) {
50
+ this.accessToken = accessToken;
51
+ this.refreshToken = refreshToken;
52
+ this.expiresAt = calculateExpiryTimestamp(expiresIn);
53
+ saveToStorage("access_token" /* ACCESS_TOKEN */, accessToken);
54
+ saveToStorage("refresh_token" /* REFRESH_TOKEN */, refreshToken);
55
+ saveToStorage("expires_at" /* EXPIRES_AT */, this.expiresAt);
56
+ }
57
+ /**
58
+ * Clear tokens
59
+ */
60
+ clearTokens() {
61
+ this.accessToken = null;
62
+ this.refreshToken = null;
63
+ this.expiresAt = null;
64
+ removeFromStorage("access_token" /* ACCESS_TOKEN */);
65
+ removeFromStorage("refresh_token" /* REFRESH_TOKEN */);
66
+ removeFromStorage("expires_at" /* EXPIRES_AT */);
67
+ }
68
+ /**
69
+ * Check if access token is expired
70
+ */
71
+ isTokenExpired() {
72
+ return isTokenExpired(this.expiresAt);
73
+ }
74
+ /**
75
+ * Get current access token
76
+ */
77
+ getAccessToken() {
78
+ return this.accessToken;
79
+ }
80
+ /**
81
+ * Refresh access token
82
+ */
83
+ async refreshAccessToken() {
84
+ if (this.isRefreshing) {
85
+ if (this.refreshPromise) {
86
+ await this.refreshPromise;
87
+ }
88
+ return;
89
+ }
90
+ if (!this.refreshToken) {
91
+ throw createAbcError(
92
+ "TOKEN_EXPIRED" /* TOKEN_EXPIRED */,
93
+ "No refresh token available"
94
+ );
95
+ }
96
+ this.isRefreshing = true;
97
+ this.refreshPromise = (async () => {
98
+ try {
99
+ const isIframe = typeof window !== "undefined" && window.self !== window.top;
100
+ const talkenApiUrl = process.env.NEXT_PUBLIC_API_SERVER || "https://dev.walletapi.talken.io";
101
+ const response = await fetch(
102
+ `${talkenApiUrl}${ABC_ENDPOINTS.REFRESH_TOKEN}`,
103
+ {
104
+ method: "POST",
105
+ headers: DEFAULT_HEADERS,
106
+ credentials: "include",
107
+ // Important: withCredentials from reference
108
+ body: new URLSearchParams({
109
+ refresh_token: this.refreshToken || "",
110
+ // Use snake_case (reference pattern)
111
+ isIframe: String(isIframe)
112
+ }).toString()
113
+ }
114
+ );
115
+ const text = await response.text();
116
+ const data = text ? JSON.parse(text) : {};
117
+ if (response.ok && data.access_token) {
118
+ const expiresIn = data.expire_in || 3600;
119
+ this.saveTokens(
120
+ data.access_token,
121
+ data.refresh_token || this.refreshToken,
122
+ // Keep old if not provided
123
+ expiresIn
124
+ );
125
+ } else {
126
+ throw createAbcError(
127
+ "TOKEN_EXPIRED" /* TOKEN_EXPIRED */,
128
+ "Failed to refresh token"
129
+ );
130
+ }
131
+ } finally {
132
+ this.isRefreshing = false;
133
+ this.refreshPromise = null;
134
+ }
135
+ })();
136
+ await this.refreshPromise;
137
+ }
138
+ /**
139
+ * Make HTTP request
140
+ */
141
+ async request(endpoint, options = {}) {
142
+ const {
143
+ method = "GET",
144
+ body,
145
+ headers = {},
146
+ skipAuth = false,
147
+ isRetry = false
148
+ } = options;
149
+ if (!skipAuth && this.isTokenExpired() && this.refreshToken) {
150
+ await this.refreshAccessToken();
151
+ }
152
+ const url = `${this.baseURL}${endpoint}`;
153
+ const requestHeaders = {
154
+ ...DEFAULT_HEADERS,
155
+ ...headers
156
+ };
157
+ if (!skipAuth && this.accessToken) {
158
+ requestHeaders.Authorization = `Bearer ${this.accessToken}`;
159
+ }
160
+ if (this.config.apiKey) {
161
+ requestHeaders["X-API-Key"] = this.config.apiKey;
162
+ }
163
+ try {
164
+ const controller = new AbortController();
165
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
166
+ const requestBody = body ? new URLSearchParams(body).toString() : void 0;
167
+ const response = await fetch(url, {
168
+ method,
169
+ headers: requestHeaders,
170
+ body: requestBody,
171
+ signal: controller.signal
172
+ });
173
+ clearTimeout(timeoutId);
174
+ const text = await response.text();
175
+ let data;
176
+ if (text) {
177
+ try {
178
+ data = JSON.parse(text);
179
+ } catch (parseError) {
180
+ console.error("[AbcWaasClient] \u274C JSON parse error:", {
181
+ url,
182
+ method,
183
+ status: response.status,
184
+ responseText: text.substring(0, 200)
185
+ // Log first 200 chars
186
+ });
187
+ throw createAbcError(
188
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
189
+ "Invalid JSON response from server",
190
+ { text, parseError }
191
+ );
192
+ }
193
+ } else {
194
+ console.log("[AbcWaasClient] \u2139\uFE0F Empty response received:", {
195
+ url,
196
+ method,
197
+ status: response.status
198
+ });
199
+ data = { status: "success" };
200
+ }
201
+ if (response.status === 401 && !skipAuth && this.refreshToken && !isRetry) {
202
+ try {
203
+ await this.refreshAccessToken();
204
+ return await this.request(endpoint, {
205
+ ...options,
206
+ isRetry: true
207
+ // Prevent infinite retry loop
208
+ });
209
+ } catch (refreshError) {
210
+ console.error("Token refresh failed:", refreshError);
211
+ throw parseApiError({
212
+ response: {
213
+ status: response.status,
214
+ data
215
+ }
216
+ });
217
+ }
218
+ }
219
+ if (!response.ok) {
220
+ console.error("[AbcWaasClient] \u274C API Error:", {
221
+ url,
222
+ method,
223
+ status: response.status,
224
+ statusText: response.statusText,
225
+ data
226
+ });
227
+ throw parseApiError({
228
+ response: {
229
+ status: response.status,
230
+ data
231
+ }
232
+ });
233
+ }
234
+ return data;
235
+ } catch (error) {
236
+ console.error("[AbcWaasClient] \u274C Request failed:", {
237
+ url,
238
+ method,
239
+ error: error.message,
240
+ errorName: error.name,
241
+ errorType: error.constructor.name,
242
+ stack: error.stack
243
+ });
244
+ if (error.name === "AbortError") {
245
+ throw createAbcError(
246
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
247
+ "Request timeout",
248
+ error
249
+ );
250
+ }
251
+ if (error.code && error.message) {
252
+ throw error;
253
+ }
254
+ throw parseApiError(error);
255
+ }
256
+ }
257
+ /**
258
+ * Login with email and password
259
+ * NOTE: Tokens are stored in memory only. Call persistTokens() after PIN verification to save to localStorage.
260
+ */
261
+ async loginWithEmail(email, password) {
262
+ const response = await this.request(
263
+ ABC_ENDPOINTS.SNS_LOGIN,
264
+ {
265
+ method: "POST",
266
+ body: {
267
+ email,
268
+ token: password,
269
+ // Use password as token
270
+ service: "email",
271
+ audience: ABC_AUDIENCE
272
+ },
273
+ skipAuth: true
274
+ }
275
+ );
276
+ if (response.status === "success" && response.data) {
277
+ this.accessToken = response.data.accessToken;
278
+ this.refreshToken = response.data.refreshToken;
279
+ this.expiresAt = calculateExpiryTimestamp(response.data.expiresIn);
280
+ console.log(
281
+ "[AbcWaasClient] \u2705 Login successful, tokens stored in memory (not persisted yet)"
282
+ );
283
+ return response.data;
284
+ }
285
+ throw createAbcError(
286
+ "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */,
287
+ "Email login failed",
288
+ response
289
+ );
290
+ }
291
+ /**
292
+ * Login with email and OTP (for PIN recovery)
293
+ * NOTE: Tokens are stored in memory only. Call persistTokens() after PIN verification to save to localStorage.
294
+ */
295
+ async loginWithOtp(email, otpCode) {
296
+ const response = await this.request(
297
+ ABC_ENDPOINTS.SNS_LOGIN,
298
+ {
299
+ method: "POST",
300
+ body: {
301
+ email,
302
+ token: otpCode,
303
+ service: "email",
304
+ audience: ABC_AUDIENCE
305
+ },
306
+ skipAuth: true
307
+ }
308
+ );
309
+ if (response.status === "success" && response.data) {
310
+ this.accessToken = response.data.accessToken;
311
+ this.refreshToken = response.data.refreshToken;
312
+ this.expiresAt = calculateExpiryTimestamp(response.data.expiresIn);
313
+ console.log(
314
+ "[AbcWaasClient] \u2705 OTP login successful, tokens stored in memory (not persisted yet)"
315
+ );
316
+ return response.data;
317
+ }
318
+ throw createAbcError(
319
+ "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */,
320
+ "OTP login failed",
321
+ response
322
+ );
323
+ }
324
+ /**
325
+ * Login with social provider
326
+ * NOTE: Tokens are stored in memory only. Call persistTokens() after PIN verification to save to localStorage.
327
+ */
328
+ async loginWithSocial(provider, token, email) {
329
+ const response = await this.request(
330
+ ABC_ENDPOINTS.SNS_LOGIN,
331
+ {
332
+ method: "POST",
333
+ body: {
334
+ token,
335
+ service: provider,
336
+ audience: ABC_AUDIENCE,
337
+ email
338
+ },
339
+ skipAuth: true
340
+ }
341
+ );
342
+ if (response.status === "success" && response.data) {
343
+ this.accessToken = response.data.accessToken;
344
+ this.refreshToken = response.data.refreshToken;
345
+ this.expiresAt = calculateExpiryTimestamp(response.data.expiresIn);
346
+ console.log(
347
+ "[AbcWaasClient] \u2705 Social login successful, tokens stored in memory (not persisted yet)"
348
+ );
349
+ return response.data;
350
+ }
351
+ throw createAbcError(
352
+ "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */,
353
+ "Social login failed",
354
+ response
355
+ );
356
+ }
357
+ /**
358
+ * Refresh access token using refresh token (public wrapper)
359
+ */
360
+ async refreshTokens(refreshTokenValue) {
361
+ const oldRefreshToken = this.refreshToken;
362
+ this.refreshToken = refreshTokenValue;
363
+ try {
364
+ await this.refreshAccessToken();
365
+ return {
366
+ accessToken: this.accessToken,
367
+ refreshToken: this.refreshToken,
368
+ expiresIn: Math.floor((this.expiresAt - Date.now()) / 1e3)
369
+ };
370
+ } catch (error) {
371
+ this.refreshToken = oldRefreshToken;
372
+ throw error;
373
+ }
374
+ }
375
+ /**
376
+ * Request OTP code for email
377
+ */
378
+ async requestOtpCode(email) {
379
+ const response = await this.request(
380
+ ABC_ENDPOINTS.SEND_OTP,
381
+ {
382
+ method: "POST",
383
+ body: { email },
384
+ skipAuth: true
385
+ }
386
+ );
387
+ if (response.status === "success" && response.data) {
388
+ return response.data;
389
+ }
390
+ throw createAbcError(
391
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
392
+ "Failed to request OTP",
393
+ response
394
+ );
395
+ }
396
+ /**
397
+ * Verify OTP code
398
+ */
399
+ async verifyOtpCode(email, code) {
400
+ const response = await this.request(ABC_ENDPOINTS.VERIFY_OTP, {
401
+ method: "POST",
402
+ body: { email, code },
403
+ skipAuth: true
404
+ });
405
+ return response.status === "success";
406
+ }
407
+ /**
408
+ * Check if email already exists
409
+ * Reference: tg-wallet-frontend src/features/user/api/index.ts:63-69
410
+ */
411
+ async emailCheck(email) {
412
+ const talkenApiUrl = process.env.NEXT_PUBLIC_API_SERVER || "https://dev.walletapi.talken.io";
413
+ const url = `${talkenApiUrl}/abc/emailCheck?email=${encodeURIComponent(email)}`;
414
+ const method = "GET";
415
+ console.log("[AbcWaasClient] \u{1F4EC} Checking email");
416
+ try {
417
+ const response = await fetch(url, {
418
+ method,
419
+ headers: DEFAULT_HEADERS
420
+ });
421
+ const text = await response.text();
422
+ const data = text ? JSON.parse(text) : { status: "success" };
423
+ if (!response.ok) {
424
+ console.error("[AbcWaasClient] \u274C API Error:", {
425
+ url,
426
+ method,
427
+ status: response.status,
428
+ statusText: response.statusText,
429
+ data
430
+ });
431
+ throw parseApiError({
432
+ response: {
433
+ status: response.status,
434
+ data
435
+ }
436
+ });
437
+ }
438
+ return data;
439
+ } catch (error) {
440
+ if (error.name === "AbortError") {
441
+ throw createAbcError(
442
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
443
+ "Request timeout",
444
+ error
445
+ );
446
+ }
447
+ throw parseApiError(error);
448
+ }
449
+ }
450
+ /**
451
+ * Send OTP code to email for signup
452
+ * Reference: tg-wallet-frontend src/features/user/api/index.ts:105-110
453
+ * Note: Uses ABC WaaS endpoint, not Talken API
454
+ */
455
+ async sendOtpCode(email) {
456
+ const endpoint = `/member/mail-service/${encodeURIComponent(email)}/sendcode`;
457
+ console.log("[AbcWaasClient] \u{1F4E7} Sending OTP code");
458
+ const response = await this.request(endpoint, {
459
+ method: "GET",
460
+ skipAuth: true
461
+ });
462
+ if (response.status === "success") {
463
+ return response;
464
+ }
465
+ throw createAbcError(
466
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
467
+ "Failed to send OTP code",
468
+ response
469
+ );
470
+ }
471
+ /**
472
+ * Verify OTP code for signup
473
+ * Reference: tg-wallet-frontend src/features/user/api/index.ts:112-123
474
+ * Note: Uses ABC WaaS endpoint, not Talken API
475
+ */
476
+ async verifyOtpCodeSignup(email, code) {
477
+ const endpoint = `/member/mail-service/${encodeURIComponent(email)}/verifycode`;
478
+ const requestBody = {
479
+ email,
480
+ code,
481
+ serviceid: ABC_AUDIENCE
482
+ // 'https://mw.myabcwallet.com'
483
+ };
484
+ console.log("[AbcWaasClient] \u{1F510} Verifying OTP code");
485
+ const response = await this.request(endpoint, {
486
+ method: "POST",
487
+ body: requestBody,
488
+ skipAuth: true
489
+ });
490
+ console.log("[verifyOtpCodeSignup] Response:", response);
491
+ const isSuccess = response.status === "success" || response.status === 200 || response.message === "success";
492
+ if (isSuccess) {
493
+ return response;
494
+ }
495
+ console.error("[verifyOtpCodeSignup] Failed:", response);
496
+ throw createAbcError(
497
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
498
+ "Invalid or expired OTP code",
499
+ response
500
+ );
501
+ }
502
+ /**
503
+ * SNS (Social) Login via Google/Apple/Kakao
504
+ * Reference: tg-wallet-frontend src/features/user/api/index.ts:43-51
505
+ * Note: Uses Talken API server, not ABC WaaS
506
+ */
507
+ async snsLogin(params) {
508
+ const talkenApiUrl = process.env.NEXT_PUBLIC_API_SERVER || "https://dev.walletapi.talken.io";
509
+ const url = `${talkenApiUrl}/abc/snsLogin`;
510
+ console.log("[AbcWaasClient] \u{1F510} SNS Login");
511
+ try {
512
+ const response = await fetch(url, {
513
+ method: "POST",
514
+ headers: {
515
+ ...DEFAULT_HEADERS
516
+ },
517
+ credentials: "include",
518
+ // withCredentials from reference
519
+ body: new URLSearchParams(params).toString()
520
+ });
521
+ const data = await response.json();
522
+ if (!response.ok) {
523
+ console.error("[AbcWaasClient] \u274C SNS Login failed:", {
524
+ url,
525
+ status: response.status,
526
+ statusText: response.statusText,
527
+ data
528
+ });
529
+ throw parseApiError({
530
+ response: {
531
+ status: response.status,
532
+ data
533
+ }
534
+ });
535
+ }
536
+ if (!data.access_token) {
537
+ throw createAbcError(
538
+ "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */,
539
+ "SNS login failed: Invalid response from server",
540
+ { service: params.service, response: data }
541
+ );
542
+ }
543
+ console.log("[AbcWaasClient] \u2705 SNS login successful");
544
+ return {
545
+ uid: "",
546
+ // Will be fetched later via info() API
547
+ email: params.email,
548
+ access_token: data.access_token,
549
+ refresh_token: data.refresh_token,
550
+ user_type: "existing"
551
+ // Default to existing, will be determined later
552
+ };
553
+ } catch (error) {
554
+ if (error.name === "AbortError") {
555
+ throw createAbcError(
556
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
557
+ "SNS login request timeout",
558
+ error
559
+ );
560
+ }
561
+ throw error;
562
+ }
563
+ }
564
+ /**
565
+ * Register new user
566
+ * Reference: tg-wallet-frontend src/features/user/api/index.ts:71-78
567
+ * Note: Uses Talken API server, not ABC WaaS
568
+ */
569
+ async registerUser(params) {
570
+ const talkenApiUrl = process.env.NEXT_PUBLIC_API_SERVER || "https://dev.walletapi.talken.io";
571
+ const url = `${talkenApiUrl}/abc/adduser`;
572
+ const method = "POST";
573
+ console.log("[AbcWaasClient] \u{1F4DD} Registering user");
574
+ try {
575
+ const response = await fetch(url, {
576
+ method,
577
+ headers: {
578
+ ...DEFAULT_HEADERS
579
+ },
580
+ credentials: "include",
581
+ // withCredentials from reference
582
+ body: new URLSearchParams(params).toString()
583
+ });
584
+ const text = await response.text();
585
+ const data = text ? JSON.parse(text) : { status: "success" };
586
+ if (!response.ok) {
587
+ console.error("[AbcWaasClient] \u274C API Error:", {
588
+ url,
589
+ method,
590
+ status: response.status,
591
+ statusText: response.statusText,
592
+ data
593
+ });
594
+ throw parseApiError({
595
+ response: {
596
+ status: response.status,
597
+ data
598
+ }
599
+ });
600
+ }
601
+ return data;
602
+ } catch (error) {
603
+ if (error.name === "AbortError") {
604
+ throw createAbcError(
605
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
606
+ "Request timeout",
607
+ error
608
+ );
609
+ }
610
+ throw parseApiError(error);
611
+ }
612
+ }
613
+ /**
614
+ * Register new SNS user (email-based registration with OTP)
615
+ * Reference: tg-wallet-frontend src/features/user/api/index.ts:80-87
616
+ * Note: Uses Talken API server, not ABC WaaS
617
+ */
618
+ async registerSnsUser(params) {
619
+ const talkenApiUrl = process.env.NEXT_PUBLIC_API_SERVER || "https://dev.walletapi.talken.io";
620
+ const url = `${talkenApiUrl}/abc/snsAdduser`;
621
+ const method = "POST";
622
+ console.log("[AbcWaasClient] \u{1F4DD} Registering SNS user");
623
+ try {
624
+ const response = await fetch(url, {
625
+ method,
626
+ headers: {
627
+ ...DEFAULT_HEADERS
628
+ },
629
+ credentials: "include",
630
+ // withCredentials from reference
631
+ body: new URLSearchParams(params).toString()
632
+ });
633
+ const text = await response.text();
634
+ const data = text ? JSON.parse(text) : { status: "success" };
635
+ if (!response.ok) {
636
+ console.error("[AbcWaasClient] \u274C API Error:", {
637
+ url,
638
+ method,
639
+ status: response.status,
640
+ statusText: response.statusText,
641
+ data
642
+ });
643
+ throw parseApiError({
644
+ response: {
645
+ status: response.status,
646
+ data
647
+ }
648
+ });
649
+ }
650
+ console.log("[AbcWaasClient] \u2705 SNS user registered successfully");
651
+ return data;
652
+ } catch (error) {
653
+ if (error.name === "AbortError") {
654
+ throw createAbcError(
655
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
656
+ "Request timeout",
657
+ error
658
+ );
659
+ }
660
+ throw parseApiError(error);
661
+ }
662
+ }
663
+ /**
664
+ * Reset/Set password for existing user
665
+ * Reference: tg-wallet-frontend src/features/user/api/index.ts:89-95
666
+ * Note: Uses Talken API server, not ABC WaaS
667
+ */
668
+ async resetPassword(params) {
669
+ const talkenApiUrl = process.env.NEXT_PUBLIC_API_SERVER || "https://dev.walletapi.talken.io";
670
+ const url = `${talkenApiUrl}/abc/initpassword`;
671
+ const method = "POST";
672
+ console.log("[AbcWaasClient] \u{1F510} Setting password");
673
+ try {
674
+ const response = await fetch(url, {
675
+ method,
676
+ headers: {
677
+ ...DEFAULT_HEADERS
678
+ },
679
+ credentials: "include",
680
+ body: new URLSearchParams(params).toString()
681
+ });
682
+ const text = await response.text();
683
+ const data = text ? JSON.parse(text) : { status: "success" };
684
+ if (!response.ok) {
685
+ console.error("[AbcWaasClient] \u274C API Error:", {
686
+ url,
687
+ method,
688
+ status: response.status,
689
+ statusText: response.statusText,
690
+ data
691
+ });
692
+ throw parseApiError({
693
+ response: {
694
+ status: response.status,
695
+ data
696
+ }
697
+ });
698
+ }
699
+ console.log("[AbcWaasClient] \u2705 Password set successfully");
700
+ return data;
701
+ } catch (error) {
702
+ if (error.name === "AbortError") {
703
+ throw createAbcError(
704
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
705
+ "Request timeout",
706
+ error
707
+ );
708
+ }
709
+ throw parseApiError(error);
710
+ }
711
+ }
712
+ /**
713
+ * Generate or recover wallet
714
+ */
715
+ async generateOrRecoverWallet(params) {
716
+ const response = await this.request(
717
+ // Use 'any' to get raw API response
718
+ ABC_ENDPOINTS.MPC_WALLETS,
719
+ // Use correct EVM endpoint, not WALLETS_V3 (Solana only)
720
+ {
721
+ method: "POST",
722
+ body: {
723
+ uid: params.uid,
724
+ pin: params.pin,
725
+ chainId: params.chainId,
726
+ network: params.network || "mainnet"
727
+ }
728
+ }
729
+ );
730
+ if (response.status === "success" && response.data) {
731
+ const raw = response.data;
732
+ console.log("[AbcWaasClient] Raw wallet API response:", {
733
+ hasUid: !!raw.uid,
734
+ hasSid: !!raw.sid,
735
+ hasKeyId: !!raw.key_id,
736
+ hasWid: !!raw.wid,
737
+ hasPvencstr: !!raw.pvencstr,
738
+ hasEncryptDevicePassword: !!raw.encryptDevicePassword,
739
+ hasEncryptedShare: !!raw.encrypted_share,
740
+ hasPubkey: !!raw.pubkey,
741
+ allKeys: Object.keys(raw)
742
+ });
743
+ return {
744
+ address: raw.sid || "",
745
+ // FIX: sid is the EVM address
746
+ keyId: raw.key_id || raw.keyId || raw.sid,
747
+ encryptedShare: raw.encrypted_share || raw.key_id || "",
748
+ // Use key_id as fallback
749
+ uid: raw.uid,
750
+ sid: raw.sid,
751
+ wid: raw.wid,
752
+ // Preserve for Bitcoin signing
753
+ pvencstr: raw.pvencstr,
754
+ // Preserve for Bitcoin signing
755
+ encryptDevicePassword: raw.encryptDevicePassword,
756
+ // Preserve for Bitcoin signing
757
+ pubkey: raw.pubkey || null
758
+ };
759
+ }
760
+ throw createAbcError(
761
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
762
+ "Failed to generate wallet",
763
+ response
764
+ );
765
+ }
766
+ /**
767
+ * Sign EVM transaction (EIP-1559)
768
+ * Based on ABC WaaS official documentation
769
+ */
770
+ async signTransaction(params) {
771
+ this.loadTokens();
772
+ const wallet = loadFromStorage("wallet" /* WALLET */);
773
+ if (!wallet) {
774
+ throw createAbcError(
775
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
776
+ "Wallet information not found in storage"
777
+ );
778
+ }
779
+ const encryptedDevicePassword = await this.secure.getEncryptPlain(
780
+ wallet.encryptDevicePassword
781
+ );
782
+ const encryptedPvencstr = await this.secure.getEncryptPlain(
783
+ wallet.pvencstr
784
+ );
785
+ const encryptedWid = await this.secure.getEncryptPlain(wallet.wid);
786
+ const secureChannelId = await this.secure.getSecureChannelId();
787
+ const networkMap = {
788
+ // Ethereum Networks
789
+ 1: "ethereum",
790
+ // Ethereum Mainnet
791
+ 11155111: "ethereum_sepolia",
792
+ // Ethereum Sepolia Testnet
793
+ 17e3: "ethereum_holesky",
794
+ // Ethereum Holesky Testnet
795
+ // Polygon Networks
796
+ 137: "polygon",
797
+ // Polygon Mainnet
798
+ 80001: "polygon_amoy",
799
+ // Polygon Amoy Testnet
800
+ // Arbitrum Networks
801
+ 42161: "arbitrum",
802
+ // Arbitrum One
803
+ 421614: "arbitrum_sepolia",
804
+ // Arbitrum Sepolia
805
+ // Optimism Networks
806
+ 10: "optimism",
807
+ // Optimism Mainnet
808
+ 420: "optimism_sepolia",
809
+ // Optimism Sepolia
810
+ // Binance Smart Chain
811
+ 56: "binance",
812
+ // BSC Mainnet
813
+ 97: "binance_testnet",
814
+ // BSC Testnet
815
+ // Avalanche
816
+ 43114: "avalanche",
817
+ // Avalanche C-Chain
818
+ 43113: "avalanche_fuji",
819
+ // Avalanche Fuji Testnet
820
+ // Kaia (formerly Klaytn)
821
+ 8217: "kaia",
822
+ // Kaia Mainnet
823
+ 1001: "kaia_kairos",
824
+ // Kaia Kairos Testnet
825
+ // Other EVM Networks
826
+ 5e3: "mantle",
827
+ // Mantle Mainnet
828
+ 5001: "mantle_testnet",
829
+ // Mantle Testnet
830
+ 1284: "moonbeam",
831
+ // Moonbeam
832
+ 1285: "moonriver",
833
+ // Moonriver
834
+ 534352: "scroll",
835
+ // Scroll Mainnet
836
+ 534351: "scroll_testnet",
837
+ // Scroll Testnet
838
+ 2355: "silicon",
839
+ // Silicon
840
+ 1722641160: "silicon_sepolia",
841
+ // Silicon Sepolia
842
+ // Note: Taiko Mainnet has same Chain ID as Ethereum Holesky (17000)
843
+ // 17000: 'taiko', // Taiko Mainnet (conflicts with ethereum_holesky)
844
+ 167009: "taiko_hekla",
845
+ // Taiko Hekla Testnet
846
+ 1111: "wemix",
847
+ // Wemix Mainnet
848
+ 1112: "wemix_testnet",
849
+ // Wemix Testnet
850
+ 51828: "chainbounty",
851
+ // ChainBounty
852
+ 56580: "chainbounty_testnet"
853
+ // ChainBounty Testnet
854
+ };
855
+ const network = networkMap[params.chainId] || "ethereum";
856
+ const tx = params.transaction;
857
+ if (!tx.maxFeePerGas || !tx.maxPriorityFeePerGas || !tx.gasLimit || !tx.gas) {
858
+ try {
859
+ if (!tx.maxFeePerGas || !tx.maxPriorityFeePerGas) {
860
+ const gasFeeUrl = `${this.baseURL}${ABC_ENDPOINTS.GAS_SUGGESTED_FEES}?network=${network}`;
861
+ const gasFeeResponse = await fetch(gasFeeUrl, {
862
+ method: "GET",
863
+ headers: {
864
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
865
+ }
866
+ });
867
+ if (gasFeeResponse.ok) {
868
+ const gasData = await gasFeeResponse.json();
869
+ if (gasData.medium) {
870
+ if (!tx.maxFeePerGas) {
871
+ const maxFeeGwei = Number.parseFloat(
872
+ gasData.medium.suggestedMaxFeePerGas
873
+ );
874
+ tx.maxFeePerGas = Math.floor(maxFeeGwei * 1e9).toString();
875
+ }
876
+ if (!tx.maxPriorityFeePerGas) {
877
+ const priorityFeeGwei = Number.parseFloat(
878
+ gasData.medium.suggestedMaxPriorityFeePerGas
879
+ );
880
+ tx.maxPriorityFeePerGas = Math.floor(
881
+ priorityFeeGwei * 1e9
882
+ ).toString();
883
+ }
884
+ }
885
+ }
886
+ }
887
+ if (!tx.gasLimit && !tx.gas) {
888
+ const estimateBody = new URLSearchParams({
889
+ network,
890
+ to: tx.to || "0x",
891
+ // Use '0x' for contract deployment
892
+ ...tx.from ? { from: tx.from } : {},
893
+ ...tx.value ? { value: tx.value } : {},
894
+ ...tx.data && tx.data !== "0x" ? { data: tx.data } : {},
895
+ ...tx.maxFeePerGas ? { maxFeePerGas: tx.maxFeePerGas } : {},
896
+ ...tx.maxPriorityFeePerGas ? { maxPriorityFeePerGas: tx.maxPriorityFeePerGas } : {}
897
+ });
898
+ const estimateUrl = `${this.baseURL}${ABC_ENDPOINTS.GAS_ESTIMATE_EIP1559}`;
899
+ const estimateResponse = await fetch(estimateUrl, {
900
+ method: "POST",
901
+ headers: {
902
+ "Content-Type": "application/x-www-form-urlencoded",
903
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
904
+ },
905
+ body: estimateBody.toString()
906
+ });
907
+ const estimateData = await estimateResponse.json();
908
+ if (estimateResponse.ok && estimateData.result) {
909
+ tx.gasLimit = estimateData.result;
910
+ } else {
911
+ const fallbackGasLimit = "0x2dc6c0";
912
+ tx.gasLimit = fallbackGasLimit;
913
+ }
914
+ }
915
+ } catch (error) {
916
+ console.warn("Failed to fetch gas parameters from ABC WaaS:", error);
917
+ }
918
+ }
919
+ const bodyData = {
920
+ network,
921
+ encryptDevicePassword: encryptedDevicePassword,
922
+ pvencstr: encryptedPvencstr,
923
+ uid: wallet.uid,
924
+ wid: encryptedWid,
925
+ sid: getAddress(wallet.address),
926
+ // EIP-55 checksum format
927
+ // For contract deployment, 'to' is '0x' (ABC WaaS convention)
928
+ // Reference: talken-nft-drops/src/libs/abc-waas-provider/index.ts:800 - to: to ?? '0x'
929
+ to: tx.to === "0x" ? "0x" : getAddress(tx.to),
930
+ // Required by ABC WaaS API
931
+ // Always use EIP1559 type (ABC WaaS handles network-specific conversion)
932
+ type: "EIP1559",
933
+ // ourpubkey and ucpubkey are required by ABC WaaS (empty strings for now)
934
+ // Based on successful tg-wallet payload analysis
935
+ ourpubkey: "",
936
+ ucpubkey: ""
937
+ };
938
+ bodyData.from = getAddress(tx.from || wallet.address);
939
+ if (tx.value) {
940
+ let hexValue = tx.value.startsWith("0x") ? tx.value.slice(2) : tx.value;
941
+ if (hexValue.length % 2 !== 0) {
942
+ hexValue = `0${hexValue}`;
943
+ }
944
+ bodyData.value = `0x${hexValue}`;
945
+ } else {
946
+ bodyData.value = "0x0";
947
+ }
948
+ if (tx.gasLimit || tx.gas) {
949
+ const gasLimitValue = tx.gasLimit || tx.gas;
950
+ if (gasLimitValue.toString().startsWith("0x")) {
951
+ bodyData.gasLimit = gasLimitValue.toString();
952
+ } else {
953
+ bodyData.gasLimit = `0x${BigInt(gasLimitValue).toString(16)}`;
954
+ }
955
+ }
956
+ if (tx.maxFeePerGas) {
957
+ if (tx.maxFeePerGas.toString().startsWith("0x")) {
958
+ bodyData.maxFeePerGas = tx.maxFeePerGas.toString();
959
+ } else {
960
+ bodyData.maxFeePerGas = `0x${BigInt(tx.maxFeePerGas).toString(16)}`;
961
+ }
962
+ }
963
+ if (tx.maxPriorityFeePerGas) {
964
+ if (tx.maxPriorityFeePerGas.toString().startsWith("0x")) {
965
+ bodyData.maxPriorityFeePerGas = tx.maxPriorityFeePerGas.toString();
966
+ } else {
967
+ bodyData.maxPriorityFeePerGas = `0x${BigInt(tx.maxPriorityFeePerGas).toString(16)}`;
968
+ }
969
+ }
970
+ if (tx.gasPrice) {
971
+ if (tx.gasPrice.toString().startsWith("0x")) {
972
+ bodyData.gasPrice = tx.gasPrice.toString();
973
+ } else {
974
+ bodyData.gasPrice = `0x${BigInt(tx.gasPrice).toString(16)}`;
975
+ }
976
+ }
977
+ if (tx.data !== void 0 && tx.data !== null) {
978
+ bodyData.data = tx.data || "0x";
979
+ } else {
980
+ bodyData.data = "0x";
981
+ }
982
+ const bodyString = new URLSearchParams(bodyData).toString();
983
+ const url = `${this.baseURL}${ABC_ENDPOINTS.SIGN_TRANSACTION}`;
984
+ const response = await fetch(url, {
985
+ method: "POST",
986
+ headers: {
987
+ "Content-Type": "application/x-www-form-urlencoded",
988
+ "Secure-Channel": secureChannelId,
989
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
990
+ },
991
+ body: bodyString
992
+ });
993
+ const res = await response.json();
994
+ console.log("\u{1F4E1} ABC WaaS /sign response:", {
995
+ status: response.status,
996
+ ok: response.ok,
997
+ response: res
998
+ });
999
+ if (!response.ok) {
1000
+ console.error("\u274C ABC WaaS API error details:", {
1001
+ status: response.status,
1002
+ statusText: response.statusText,
1003
+ errorCode: res.code,
1004
+ errorMessage: res.msg || res.message || res.detail,
1005
+ fullResponse: res
1006
+ });
1007
+ }
1008
+ if (response.status === 401 && this.refreshToken) {
1009
+ try {
1010
+ await this.refreshAccessToken();
1011
+ const retryResponse = await fetch(url, {
1012
+ method: "POST",
1013
+ headers: {
1014
+ "Content-Type": "application/x-www-form-urlencoded",
1015
+ "Secure-Channel": secureChannelId,
1016
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1017
+ },
1018
+ body: bodyString
1019
+ });
1020
+ const retryRes = await retryResponse.json();
1021
+ if (retryRes.serializedTx && retryRes.rawTx) {
1022
+ return {
1023
+ signature: retryRes.serializedTx,
1024
+ txHash: retryRes.rawTx
1025
+ };
1026
+ }
1027
+ throw createAbcError(
1028
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1029
+ "Failed to sign transaction after token refresh",
1030
+ retryRes
1031
+ );
1032
+ } catch (refreshError) {
1033
+ console.error("Token refresh failed in signTransaction:", refreshError);
1034
+ throw refreshError;
1035
+ }
1036
+ }
1037
+ if (res.serializedTx && res.rawTx) {
1038
+ return {
1039
+ signature: res.serializedTx,
1040
+ txHash: res.rawTx
1041
+ };
1042
+ }
1043
+ throw createAbcError(
1044
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1045
+ "Failed to sign transaction",
1046
+ res
1047
+ );
1048
+ }
1049
+ /**
1050
+ * Sign message (Personal Sign - EIP-191)
1051
+ * Based on tg-wallet-frontend reference implementation
1052
+ */
1053
+ async signMessage(params) {
1054
+ this.loadTokens();
1055
+ const wallet = loadFromStorage("wallet" /* WALLET */);
1056
+ if (!wallet) {
1057
+ throw createAbcError(
1058
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1059
+ "Wallet information not found in storage"
1060
+ );
1061
+ }
1062
+ const ethers = await import("ethers");
1063
+ const messageHash = ethers.utils.hashMessage(params.message);
1064
+ const hash = messageHash.startsWith("0x") ? messageHash.slice(2) : messageHash;
1065
+ const encryptedDevicePassword = await this.secure.getEncryptPlain(
1066
+ wallet.encryptDevicePassword
1067
+ );
1068
+ const encryptedPvencstr = await this.secure.getEncryptPlain(
1069
+ wallet.pvencstr
1070
+ );
1071
+ const encryptedWid = await this.secure.getEncryptPlain(wallet.wid);
1072
+ const secureChannelId = await this.secure.getSecureChannelId();
1073
+ const bodyData = {
1074
+ hash,
1075
+ encryptDevicePassword: encryptedDevicePassword,
1076
+ pvencstr: encryptedPvencstr,
1077
+ wid: encryptedWid,
1078
+ uid: wallet.uid,
1079
+ sid: wallet.sid
1080
+ };
1081
+ const bodyString = new URLSearchParams(bodyData).toString();
1082
+ const url = `${this.baseURL}${ABC_ENDPOINTS.SIGN_HASH}`;
1083
+ const response = await fetch(url, {
1084
+ method: "POST",
1085
+ headers: {
1086
+ "Content-Type": "application/x-www-form-urlencoded",
1087
+ "Secure-Channel": secureChannelId,
1088
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1089
+ },
1090
+ body: bodyString
1091
+ });
1092
+ const text = await response.text();
1093
+ if (!text) {
1094
+ throw createAbcError(
1095
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1096
+ `Empty response from sign API (status: ${response.status})`,
1097
+ { status: response.status }
1098
+ );
1099
+ }
1100
+ const res = JSON.parse(text);
1101
+ if (response.status === 401) {
1102
+ if (!this.refreshToken) {
1103
+ this.loadTokens();
1104
+ }
1105
+ if (this.refreshToken) {
1106
+ try {
1107
+ await this.refreshAccessToken();
1108
+ const retryResponse = await fetch(url, {
1109
+ method: "POST",
1110
+ headers: {
1111
+ "Content-Type": "application/x-www-form-urlencoded",
1112
+ "Secure-Channel": secureChannelId,
1113
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1114
+ },
1115
+ body: bodyString
1116
+ });
1117
+ const retryText = await retryResponse.text();
1118
+ if (!retryText) {
1119
+ throw createAbcError(
1120
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1121
+ `Empty response from retry (status: ${retryResponse.status})`,
1122
+ { status: retryResponse.status }
1123
+ );
1124
+ }
1125
+ const retryRes = JSON.parse(retryText);
1126
+ if (retryRes.status === "success" && retryRes.result?.signstr) {
1127
+ return { signature: retryRes.result.signstr };
1128
+ }
1129
+ throw createAbcError(
1130
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1131
+ "Failed to sign message after token refresh",
1132
+ retryRes
1133
+ );
1134
+ } catch (refreshError) {
1135
+ console.error("Token refresh failed in signMessage:", refreshError);
1136
+ throw refreshError;
1137
+ }
1138
+ }
1139
+ }
1140
+ if (res.signstr) {
1141
+ const signData = JSON.parse(res.signstr);
1142
+ const sigList = signData.sig_list?.[0];
1143
+ if (!sigList || !sigList.r || !sigList.s) {
1144
+ throw createAbcError(
1145
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1146
+ "Invalid signature format",
1147
+ res
1148
+ );
1149
+ }
1150
+ const v = (sigList.vsource || 0) + 27;
1151
+ const signature = sigList.r + sigList.s.slice(2) + v.toString(16).padStart(2, "0");
1152
+ return { signature };
1153
+ }
1154
+ throw createAbcError(
1155
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1156
+ "Failed to sign message",
1157
+ res
1158
+ );
1159
+ }
1160
+ /**
1161
+ * Sign typed data (EIP-712)
1162
+ * Reference: tg-wallet-frontend src/features/wallet/api/index.ts sign_typed_data()
1163
+ */
1164
+ async signTypedData(params) {
1165
+ this.loadTokens();
1166
+ const wallet = loadFromStorage("wallet" /* WALLET */);
1167
+ if (!wallet) {
1168
+ throw createAbcError(
1169
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1170
+ "Wallet information not found in storage"
1171
+ );
1172
+ }
1173
+ const encryptedDevicePassword = await this.secure.getEncryptPlain(
1174
+ wallet.encryptDevicePassword
1175
+ );
1176
+ const encryptedPvencstr = await this.secure.getEncryptPlain(
1177
+ wallet.pvencstr
1178
+ );
1179
+ const encryptedWid = await this.secure.getEncryptPlain(wallet.wid);
1180
+ const secureChannelId = await this.secure.getSecureChannelId();
1181
+ const getNetworkName = (chainId) => {
1182
+ const networkMap = {
1183
+ 1: "ethereum",
1184
+ // Ethereum Mainnet
1185
+ 11155111: "ethereum_sepolia",
1186
+ // Sepolia Testnet
1187
+ 8217: "klaytn",
1188
+ // Klaytn Mainnet
1189
+ 1001: "klaytn_baobab",
1190
+ // Klaytn Baobab Testnet
1191
+ 137: "polygon",
1192
+ // Polygon Mainnet
1193
+ 80002: "polygon_amoy",
1194
+ // Polygon Amoy Testnet
1195
+ 42161: "arbitrum",
1196
+ // Arbitrum One
1197
+ 421614: "arbitrum_sepolia",
1198
+ // Arbitrum Sepolia
1199
+ 5e3: "mantle",
1200
+ // Mantle Mainnet
1201
+ 5003: "mantle_testnet"
1202
+ // Mantle Testnet
1203
+ };
1204
+ return networkMap[chainId] || "ethereum";
1205
+ };
1206
+ const network = getNetworkName(wallet.chainId);
1207
+ const bodyData = {
1208
+ messageJson: params.typedData,
1209
+ // Server expects "messageJson" field
1210
+ version: "v4",
1211
+ // EIP-712 version
1212
+ network,
1213
+ // Network name (required for JSON-RPC)
1214
+ encryptDevicePassword: encryptedDevicePassword,
1215
+ pvencstr: encryptedPvencstr,
1216
+ wid: encryptedWid,
1217
+ uid: wallet.uid,
1218
+ sid: wallet.sid
1219
+ };
1220
+ const bodyString = new URLSearchParams(bodyData).toString();
1221
+ const url = `${this.baseURL}${ABC_ENDPOINTS.SIGN_TYPED}`;
1222
+ const response = await fetch(url, {
1223
+ method: "POST",
1224
+ headers: {
1225
+ "Content-Type": "application/x-www-form-urlencoded",
1226
+ "Secure-Channel": secureChannelId,
1227
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1228
+ },
1229
+ body: bodyString
1230
+ });
1231
+ const text = await response.text();
1232
+ if (!text) {
1233
+ throw createAbcError(
1234
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1235
+ `Empty response from signTypedData API (status: ${response.status})`,
1236
+ { status: response.status }
1237
+ );
1238
+ }
1239
+ const res = JSON.parse(text);
1240
+ if (response.status === 401 && this.refreshToken) {
1241
+ try {
1242
+ await this.refreshAccessToken();
1243
+ const retryResponse = await fetch(url, {
1244
+ method: "POST",
1245
+ headers: {
1246
+ "Content-Type": "application/x-www-form-urlencoded",
1247
+ "Secure-Channel": secureChannelId,
1248
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1249
+ },
1250
+ body: bodyString
1251
+ });
1252
+ const retryText = await retryResponse.text();
1253
+ if (!retryText) {
1254
+ throw createAbcError(
1255
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1256
+ `Empty response after retry (status: ${retryResponse.status})`,
1257
+ { status: retryResponse.status }
1258
+ );
1259
+ }
1260
+ const retryRes = JSON.parse(retryText);
1261
+ if (retryRes.serializedTx) {
1262
+ return { signature: retryRes.serializedTx };
1263
+ }
1264
+ throw createAbcError(
1265
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1266
+ "Failed to sign typed data after token refresh",
1267
+ retryRes
1268
+ );
1269
+ } catch (refreshError) {
1270
+ console.error("Token refresh failed in signTypedData:", refreshError);
1271
+ throw refreshError;
1272
+ }
1273
+ }
1274
+ if (res.serializedTx) {
1275
+ return { signature: res.serializedTx };
1276
+ }
1277
+ throw createAbcError(
1278
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1279
+ "Failed to sign typed data",
1280
+ res
1281
+ );
1282
+ }
1283
+ /**
1284
+ * Send raw transaction
1285
+ * Reference: tg-wallet-frontend src/features/wallet/api/index.ts sendRawTx()
1286
+ */
1287
+ async sendRawTransaction(chainId, signedTransaction) {
1288
+ const wallet = loadFromStorage("wallet" /* WALLET */);
1289
+ if (!wallet) {
1290
+ throw createAbcError(
1291
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1292
+ "Wallet information not found in storage"
1293
+ );
1294
+ }
1295
+ const getNetworkName = (chainId2) => {
1296
+ const networkMap = {
1297
+ 1: "ethereum",
1298
+ 11155111: "ethereum_sepolia",
1299
+ 8217: "klaytn",
1300
+ 1001: "klaytn_baobab",
1301
+ 137: "polygon",
1302
+ 80002: "polygon_amoy",
1303
+ 42161: "arbitrum",
1304
+ 421614: "arbitrum_sepolia",
1305
+ 5e3: "mantle",
1306
+ 5003: "mantle_testnet"
1307
+ };
1308
+ return networkMap[chainId2] || "ethereum";
1309
+ };
1310
+ const network = getNetworkName(chainId);
1311
+ const secureChannelId = await this.secure.getSecureChannelId();
1312
+ const bodyData = {
1313
+ signedSerializeTx: signedTransaction,
1314
+ network
1315
+ // rpc parameter
1316
+ };
1317
+ const bodyString = new URLSearchParams(bodyData).toString();
1318
+ const url = `${this.baseURL}${ABC_ENDPOINTS.SEND_RAW_TX}`;
1319
+ const response = await fetch(url, {
1320
+ method: "POST",
1321
+ headers: {
1322
+ "Content-Type": "application/x-www-form-urlencoded",
1323
+ "Secure-Channel": secureChannelId,
1324
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1325
+ },
1326
+ body: bodyString
1327
+ });
1328
+ const text = await response.text();
1329
+ if (!text) {
1330
+ throw createAbcError(
1331
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
1332
+ `Empty response from sendRawTx API (status: ${response.status})`,
1333
+ { status: response.status }
1334
+ );
1335
+ }
1336
+ const res = JSON.parse(text);
1337
+ console.log("\u{1F4E1} sendRawTransaction response:", {
1338
+ status: response.status,
1339
+ ok: response.ok,
1340
+ response: res
1341
+ });
1342
+ if (!response.ok) {
1343
+ console.error("\u274C sendRawTransaction error:", {
1344
+ status: response.status,
1345
+ errorMessage: res.errorMessage || res.msg || res.message,
1346
+ fullResponse: res
1347
+ });
1348
+ }
1349
+ if (response.status === 401 && this.refreshToken) {
1350
+ try {
1351
+ await this.refreshAccessToken();
1352
+ const retryResponse = await fetch(url, {
1353
+ method: "POST",
1354
+ headers: {
1355
+ "Content-Type": "application/x-www-form-urlencoded",
1356
+ "Secure-Channel": secureChannelId,
1357
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1358
+ },
1359
+ body: bodyString
1360
+ });
1361
+ const retryText = await retryResponse.text();
1362
+ if (!retryText) {
1363
+ throw createAbcError(
1364
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
1365
+ `Empty response after retry (status: ${retryResponse.status})`,
1366
+ { status: retryResponse.status }
1367
+ );
1368
+ }
1369
+ const retryRes = JSON.parse(retryText);
1370
+ if (retryRes.item || retryRes.txHash || retryRes.result?.txHash) {
1371
+ const txHash = retryRes.item || retryRes.txHash || retryRes.result.txHash;
1372
+ return { txHash };
1373
+ }
1374
+ throw createAbcError(
1375
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
1376
+ "Failed to send transaction after token refresh",
1377
+ retryRes
1378
+ );
1379
+ } catch (refreshError) {
1380
+ console.error(
1381
+ "Token refresh failed in sendRawTransaction:",
1382
+ refreshError
1383
+ );
1384
+ throw refreshError;
1385
+ }
1386
+ }
1387
+ if (res.result) {
1388
+ if (typeof res.result === "string") {
1389
+ console.log("\u2705 Transaction hash from result:", res.result);
1390
+ return { txHash: res.result };
1391
+ }
1392
+ if (res.result.txHash) {
1393
+ return { txHash: res.result.txHash };
1394
+ }
1395
+ }
1396
+ if (res.item) {
1397
+ return { txHash: res.item };
1398
+ }
1399
+ if (res.txHash) {
1400
+ return { txHash: res.txHash };
1401
+ }
1402
+ throw createAbcError(
1403
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
1404
+ "Failed to send transaction",
1405
+ res
1406
+ );
1407
+ }
1408
+ /**
1409
+ * Get wallet info
1410
+ */
1411
+ async getWalletInfo(uid) {
1412
+ const response = await this.request(ABC_ENDPOINTS.INFO, {
1413
+ method: "POST",
1414
+ body: { uid }
1415
+ });
1416
+ if (response.status === "success") {
1417
+ return response.data;
1418
+ }
1419
+ throw createAbcError(
1420
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1421
+ "Failed to get wallet info",
1422
+ response
1423
+ );
1424
+ }
1425
+ /**
1426
+ * Logout (clear tokens)
1427
+ */
1428
+ async logout() {
1429
+ this.clearTokens();
1430
+ }
1431
+ /**
1432
+ * Check if user is authenticated
1433
+ */
1434
+ isAuthenticated() {
1435
+ return !!this.accessToken && !this.isTokenExpired();
1436
+ }
1437
+ /**
1438
+ * Set tokens in client instance (useful when restoring from storage or state)
1439
+ * Call this before persistTokens() if you need to set tokens from external source
1440
+ */
1441
+ setTokens(accessToken, refreshToken, expiresAt) {
1442
+ this.accessToken = accessToken;
1443
+ this.refreshToken = refreshToken;
1444
+ this.expiresAt = expiresAt;
1445
+ }
1446
+ /**
1447
+ * Persist tokens to localStorage
1448
+ * Call this after PIN verification is complete
1449
+ *
1450
+ * SECURITY NOTE: This should only be called after full authentication (password + PIN)
1451
+ * to ensure tokens are only persisted after the user has proven ownership of both credentials.
1452
+ */
1453
+ persistTokens() {
1454
+ if (!this.accessToken || !this.refreshToken || !this.expiresAt) {
1455
+ console.warn(
1456
+ "[AbcWaasClient] \u26A0\uFE0F No tokens to persist - ensure login was successful first"
1457
+ );
1458
+ return;
1459
+ }
1460
+ console.log(
1461
+ "[AbcWaasClient] \u{1F4BE} Persisting tokens to localStorage after PIN verification"
1462
+ );
1463
+ saveToStorage("access_token" /* ACCESS_TOKEN */, this.accessToken);
1464
+ saveToStorage("refresh_token" /* REFRESH_TOKEN */, this.refreshToken);
1465
+ saveToStorage("expires_at" /* EXPIRES_AT */, this.expiresAt);
1466
+ }
1467
+ // ==========================================================================
1468
+ // Solana Methods
1469
+ // ==========================================================================
1470
+ /**
1471
+ * Generate or recover Solana wallet (Ed25519)
1472
+ * Reference: SigningService.ts:56-72, wallet/api/index.ts:56-72
1473
+ */
1474
+ async generateSolanaWallet(pin, isRecover = false) {
1475
+ const url = `${this.baseURL}/v3/wallet/${isRecover ? "recover" : "generate"}`;
1476
+ const response = await fetch(url, {
1477
+ method: "POST",
1478
+ headers: {
1479
+ "Content-Type": "application/json",
1480
+ // V3 API requires JSON, not form-urlencoded
1481
+ Accept: "application/json",
1482
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1483
+ },
1484
+ body: JSON.stringify({
1485
+ curve: "ed25519",
1486
+ password: pin
1487
+ // PIN will be encrypted by Secure Channel
1488
+ // Note: network parameter not needed for v3 API
1489
+ })
1490
+ });
1491
+ let data;
1492
+ try {
1493
+ data = await response.json();
1494
+ } catch (e) {
1495
+ console.error(`[AbcWaasClient] Failed to parse response from ${url}:`, e);
1496
+ throw createAbcError(
1497
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1498
+ `Failed to ${isRecover ? "recover" : "generate"} Solana wallet - invalid response`,
1499
+ { status: response.status }
1500
+ );
1501
+ }
1502
+ if (!response.ok) {
1503
+ if (!isRecover && response.status === 409) {
1504
+ const error = createAbcError(
1505
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1506
+ "Wallet already exists",
1507
+ data
1508
+ );
1509
+ error.response = { status: 409 };
1510
+ throw error;
1511
+ }
1512
+ console.error(
1513
+ `[AbcWaasClient] ${isRecover ? "Recover" : "Generate"} failed:`,
1514
+ data
1515
+ );
1516
+ throw createAbcError(
1517
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1518
+ `Failed to ${isRecover ? "recover" : "generate"} Solana wallet`,
1519
+ data
1520
+ );
1521
+ }
1522
+ const result = data.result || data;
1523
+ if (!result.key_id || !result.public_key || !result.encrypted_share) {
1524
+ console.error(
1525
+ "[AbcWaasClient] Invalid wallet response, missing required fields:",
1526
+ result
1527
+ );
1528
+ throw createAbcError(
1529
+ "WALLET_NOT_FOUND" /* WALLET_NOT_FOUND */,
1530
+ `Invalid wallet response from ${isRecover ? "recover" : "generate"}`,
1531
+ data
1532
+ );
1533
+ }
1534
+ const solanaNetwork = getSolanaNetwork();
1535
+ const addressResult = await this.getSolanaAddress(
1536
+ result.public_key,
1537
+ solanaNetwork
1538
+ );
1539
+ return {
1540
+ uid: result.uid || "",
1541
+ sessionId: result.share_id || result.key_id,
1542
+ shareId: result.share_id || result.key_id,
1543
+ publicKey: result.public_key,
1544
+ address: addressResult,
1545
+ keyId: result.key_id,
1546
+ encryptedShare: result.encrypted_share || "",
1547
+ secretStore: result.secret_store || "",
1548
+ network: solanaNetwork
1549
+ };
1550
+ }
1551
+ /**
1552
+ * Get Solana address from Ed25519 public key
1553
+ * Reference: wallet/api/index.ts:74-82
1554
+ */
1555
+ async getSolanaAddress(publicKey, network) {
1556
+ const url = `${this.baseURL}/wapi/v2/solana/wallet/getAddress`;
1557
+ const body = new URLSearchParams({
1558
+ network,
1559
+ publicKey
1560
+ }).toString();
1561
+ const response = await fetch(url, {
1562
+ method: "POST",
1563
+ headers: {
1564
+ ...DEFAULT_HEADERS,
1565
+ // Contains 'Content-Type': 'application/x-www-form-urlencoded'
1566
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1567
+ },
1568
+ body
1569
+ });
1570
+ const data = await response.json();
1571
+ if (!response.ok || data.status !== "success") {
1572
+ throw createAbcError(
1573
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
1574
+ "Failed to get Solana address",
1575
+ data
1576
+ );
1577
+ }
1578
+ return data.result?.data?.address;
1579
+ }
1580
+ /**
1581
+ * Sign Solana transaction with Ed25519
1582
+ * Reference: SigningService.ts:587-626, wallet/api/index.ts:114-122
1583
+ */
1584
+ async signSolanaTransaction(params) {
1585
+ const url = `${this.baseURL}/v3/wallet/sign`;
1586
+ const response = await fetch(url, {
1587
+ method: "POST",
1588
+ headers: {
1589
+ "Content-Type": "application/json",
1590
+ Accept: "application/json",
1591
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1592
+ },
1593
+ body: JSON.stringify({
1594
+ uid: params.uid,
1595
+ share_id: params.shareId,
1596
+ key_id: params.keyId,
1597
+ encrypted_share: params.encryptedShare,
1598
+ public_key: params.publicKey,
1599
+ message: params.message,
1600
+ // Hex-encoded transaction
1601
+ password: params.pin,
1602
+ // PIN will be encrypted
1603
+ network: params.network
1604
+ // Required: 'solana' or 'solana_devnet'
1605
+ })
1606
+ });
1607
+ const data = await response.json();
1608
+ if (!response.ok || data.status !== "success") {
1609
+ throw createAbcError(
1610
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1611
+ "Failed to sign Solana transaction",
1612
+ data
1613
+ );
1614
+ }
1615
+ return {
1616
+ signature: data.result?.signature
1617
+ };
1618
+ }
1619
+ /**
1620
+ * Sign Solana message with Ed25519
1621
+ * Reference: SigningService.ts:546-579
1622
+ */
1623
+ async signSolanaMessage(params) {
1624
+ const url = `${this.baseURL}/v3/wallet/sign`;
1625
+ const response = await fetch(url, {
1626
+ method: "POST",
1627
+ headers: {
1628
+ "Content-Type": "application/json",
1629
+ Accept: "application/json",
1630
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1631
+ },
1632
+ body: JSON.stringify({
1633
+ uid: params.uid,
1634
+ share_id: params.shareId,
1635
+ key_id: params.keyId,
1636
+ encrypted_share: params.encryptedShare,
1637
+ public_key: params.publicKey,
1638
+ message: params.message,
1639
+ // Hex-encoded message
1640
+ password: params.pin,
1641
+ network: params.network
1642
+ // Required: 'solana' or 'solana_devnet'
1643
+ })
1644
+ });
1645
+ const data = await response.json();
1646
+ if (!response.ok || data.status !== "success") {
1647
+ throw createAbcError(
1648
+ "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1649
+ "Failed to sign Solana message",
1650
+ data
1651
+ );
1652
+ }
1653
+ return {
1654
+ signature: data.result?.signature
1655
+ };
1656
+ }
1657
+ /**
1658
+ * Send Solana transaction
1659
+ * Reference: SigningService.ts:418, wallet/api/index.ts:124-132
1660
+ */
1661
+ async sendSolanaTransaction(params) {
1662
+ const url = `${this.baseURL}/wapi/v2/solana/tx/sendTransaction`;
1663
+ const response = await fetch(url, {
1664
+ method: "POST",
1665
+ headers: {
1666
+ ...DEFAULT_HEADERS,
1667
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
1668
+ },
1669
+ body: JSON.stringify({
1670
+ network: params.network,
1671
+ serializedTX: params.serializedTX,
1672
+ signatures: params.signatures
1673
+ })
1674
+ });
1675
+ const data = await response.json();
1676
+ if (!response.ok || data.status !== "success") {
1677
+ throw createAbcError(
1678
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
1679
+ "Failed to send Solana transaction",
1680
+ data
1681
+ );
1682
+ }
1683
+ return {
1684
+ txHash: data.result?.data
1685
+ };
1686
+ }
1687
+ };
1688
+ function createAbcWaasClient(config) {
1689
+ return new AbcWaasClient(config);
1690
+ }
1691
+
1692
+ export {
1693
+ AbcWaasClient,
1694
+ createAbcWaasClient
1695
+ };