@hfunlabs/hypurr-connect 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,7 +3,10 @@ import {
3
3
  ExchangeClient,
4
4
  HttpTransport
5
5
  } from "@hfunlabs/hyperliquid";
6
- import { PrivateKeySigner, signUserSignedAction } from "@hfunlabs/hyperliquid/signing";
6
+ import {
7
+ PrivateKeySigner,
8
+ signUserSignedAction
9
+ } from "@hfunlabs/hyperliquid/signing";
7
10
  import {
8
11
  createContext,
9
12
  useCallback,
@@ -80,10 +83,10 @@ function isDeadAgentError(err) {
80
83
  import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
81
84
  import { StaticClient } from "hypurr-grpc/ts/hypurr/static/static_service.client";
82
85
  import { TelegramClient } from "hypurr-grpc/ts/hypurr/telegram/telegram_service.client";
83
- var GRPC_URL = "https://grpc.hypurr.fun";
86
+ var DEFAULT_GRPC_URL = "https://grpc.hypurr.fun";
84
87
  function createTransport(config) {
85
88
  return new GrpcWebFetchTransport({
86
- baseUrl: GRPC_URL,
89
+ baseUrl: config.grpcUrl ?? DEFAULT_GRPC_URL,
87
90
  timeout: config.grpcTimeout ?? 15e3
88
91
  });
89
92
  }
@@ -98,14 +101,16 @@ function createStaticClient(config) {
98
101
  var GrpcExchangeTransport = class {
99
102
  isTestnet;
100
103
  telegramClient;
101
- authDataMap;
104
+ rpcOptions;
102
105
  walletId;
103
106
  infoUrl;
107
+ onAuthError;
104
108
  constructor(config) {
105
109
  this.isTestnet = config.isTestnet ?? false;
106
110
  this.telegramClient = config.telegramClient;
107
- this.authDataMap = config.authDataMap;
111
+ this.rpcOptions = config.rpcOptions;
108
112
  this.walletId = config.walletId;
113
+ this.onAuthError = config.onAuthError;
109
114
  this.infoUrl = this.isTestnet ? "https://api.hyperliquid-testnet.xyz" : "https://api.hyperliquid.xyz";
110
115
  }
111
116
  async request(endpoint, payload, signal) {
@@ -122,12 +127,25 @@ var GrpcExchangeTransport = class {
122
127
  JSON.stringify(payload.action)
123
128
  );
124
129
  console.debug("[GrpcExchangeTransport] sending action:", payload.action);
125
- const { response } = await this.telegramClient.hyperliquidCoreAction({
126
- authData: this.authDataMap,
127
- walletId: this.walletId,
128
- action: actionBytes,
129
- nonce: payload.nonce || Date.now()
130
- });
130
+ let response;
131
+ try {
132
+ ({ response } = await this.telegramClient.hyperliquidCoreAction(
133
+ {
134
+ authData: {},
135
+ walletId: this.walletId,
136
+ action: actionBytes,
137
+ nonce: payload.nonce || Date.now()
138
+ },
139
+ this.rpcOptions
140
+ ));
141
+ } catch (err) {
142
+ if (this.onAuthError && err instanceof Error && /invalid telegram auth data|invalid auth token|missing authorization token/i.test(
143
+ err.message
144
+ )) {
145
+ this.onAuthError();
146
+ }
147
+ throw err;
148
+ }
131
149
  if (signal?.aborted) {
132
150
  throw new DOMException("Request aborted", "AbortError");
133
151
  }
@@ -164,18 +182,53 @@ var GrpcExchangeTransport = class {
164
182
 
165
183
  // src/HypurrConnectProvider.tsx
166
184
  import { jsx } from "react/jsx-runtime";
167
- var TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-user";
168
- function toAuthDataMap(data) {
169
- const map = {
170
- id: String(data.id),
171
- first_name: data.first_name,
172
- auth_date: String(data.auth_date),
173
- hash: data.hash
174
- };
175
- if (data.last_name) map.last_name = data.last_name;
176
- if (data.username) map.username = data.username;
177
- if (data.photo_url) map.photo_url = data.photo_url;
178
- return map;
185
+ var TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-jwt";
186
+ var LEGACY_TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-user";
187
+ var TELEGRAM_AUTH_STATE_KEY = "hypurr-connect-auth-state";
188
+ var TELEGRAM_AUTH_MESSAGE = "hypurr-connect:telegram-auth";
189
+ var DEFAULT_AUTH_HUB_URL = "https://127.0.0.1:443/login";
190
+ var DEFAULT_TELEGRAM_SCOPES = [
191
+ "telegram:user:read",
192
+ "telegram:wallet:read",
193
+ "telegram:wallet:write",
194
+ "telegram:trade:read",
195
+ "telegram:trade:write",
196
+ "telegram:cabal:read",
197
+ "telegram:cabal:write",
198
+ "telegram:agent:write"
199
+ ];
200
+ function isInvalidTelegramAuthError(err) {
201
+ const msg = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : String(err);
202
+ return /invalid telegram auth data|invalid auth token|missing authorization token/i.test(
203
+ msg
204
+ );
205
+ }
206
+ function currentReturnTo() {
207
+ const url = new URL(window.location.href);
208
+ for (const param of [
209
+ "token",
210
+ "token_type",
211
+ "token_source",
212
+ "state",
213
+ "scope"
214
+ ]) {
215
+ url.searchParams.delete(param);
216
+ }
217
+ return url.toString();
218
+ }
219
+ function randomState() {
220
+ const bytes = new Uint8Array(16);
221
+ crypto.getRandomValues(bytes);
222
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(
223
+ ""
224
+ );
225
+ }
226
+ function normalizeScopes(scope) {
227
+ if (Array.isArray(scope)) return scope.join(" ");
228
+ return scope?.trim() || DEFAULT_TELEGRAM_SCOPES.join(" ");
229
+ }
230
+ function isTelegramAuthMessage(data) {
231
+ return typeof data === "object" && data !== null && "type" in data && "token" in data && "state" in data && data.type === TELEGRAM_AUTH_MESSAGE && typeof data.token === "string" && typeof data.state === "string";
179
232
  }
180
233
  var HypurrConnectContext = createContext(null);
181
234
  function useHypurrConnect() {
@@ -200,35 +253,103 @@ function HypurrConnectProvider({
200
253
  }) {
201
254
  const tgClient = useMemo(() => createTelegramClient(config), [config]);
202
255
  const staticClient = useMemo(() => createStaticClient(config), [config]);
203
- const [tgLoginData, setTgLoginData] = useState(
204
- () => {
205
- try {
206
- const stored = localStorage.getItem(TELEGRAM_STORAGE_KEY);
207
- return stored ? JSON.parse(stored) : null;
208
- } catch {
209
- return null;
210
- }
256
+ const [tgAuthToken, setTgAuthToken] = useState(() => {
257
+ try {
258
+ return localStorage.getItem(TELEGRAM_STORAGE_KEY);
259
+ } catch {
260
+ return null;
211
261
  }
212
- );
262
+ });
213
263
  const [tgUser, setTgUser] = useState(null);
214
264
  const [tgLoading, setTgLoading] = useState(false);
215
265
  const [tgError, setTgError] = useState(null);
216
- const authDataMap = useMemo(
217
- () => tgLoginData ? toAuthDataMap(tgLoginData) : {},
218
- [tgLoginData]
266
+ const authDataMap = useMemo(() => ({}), []);
267
+ const telegramRpcOptions = useMemo(
268
+ () => tgAuthToken ? { meta: { authorization: `Bearer ${tgAuthToken}` } } : void 0,
269
+ [tgAuthToken]
219
270
  );
220
271
  const [tgUserTick, setTgUserTick] = useState(0);
272
+ const onInvalidAuthRef = useRef(null);
273
+ onInvalidAuthRef.current = () => {
274
+ console.warn(
275
+ "[HypurrConnect] Invalid Telegram auth token \u2014 disconnecting."
276
+ );
277
+ setTgAuthToken(null);
278
+ setTgUser(null);
279
+ setTgError(null);
280
+ localStorage.removeItem(TELEGRAM_STORAGE_KEY);
281
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
282
+ };
283
+ const acceptTelegramToken = useCallback((token) => {
284
+ setTgAuthToken(token);
285
+ setTgError(null);
286
+ localStorage.setItem(TELEGRAM_STORAGE_KEY, token);
287
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
288
+ }, []);
221
289
  useEffect(() => {
222
- if (!tgLoginData) return;
290
+ const params = new URLSearchParams(window.location.search);
291
+ const token = params.get("token");
292
+ if (!token) {
293
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
294
+ return;
295
+ }
296
+ const callbackState = params.get("state") ?? "";
297
+ if (window.opener && window.opener !== window) {
298
+ window.opener.postMessage(
299
+ {
300
+ type: TELEGRAM_AUTH_MESSAGE,
301
+ token,
302
+ state: callbackState
303
+ },
304
+ window.location.origin
305
+ );
306
+ window.close();
307
+ return;
308
+ }
309
+ const expectedState = sessionStorage.getItem(TELEGRAM_AUTH_STATE_KEY);
310
+ sessionStorage.removeItem(TELEGRAM_AUTH_STATE_KEY);
311
+ if (!expectedState || callbackState !== expectedState) {
312
+ setTgError("Invalid auth callback state.");
313
+ return;
314
+ }
315
+ acceptTelegramToken(token);
316
+ const cleanUrl = new URL(window.location.href);
317
+ for (const param of [
318
+ "token",
319
+ "token_type",
320
+ "token_source",
321
+ "state",
322
+ "scope"
323
+ ]) {
324
+ cleanUrl.searchParams.delete(param);
325
+ }
326
+ window.history.replaceState({}, document.title, cleanUrl.toString());
327
+ }, [acceptTelegramToken]);
328
+ useEffect(() => {
329
+ function onMessage(event) {
330
+ if (event.origin !== window.location.origin) return;
331
+ if (!isTelegramAuthMessage(event.data)) return;
332
+ const expectedState = sessionStorage.getItem(TELEGRAM_AUTH_STATE_KEY);
333
+ sessionStorage.removeItem(TELEGRAM_AUTH_STATE_KEY);
334
+ if (!expectedState || event.data.state !== expectedState) {
335
+ setTgError("Invalid auth callback state.");
336
+ return;
337
+ }
338
+ acceptTelegramToken(event.data.token);
339
+ }
340
+ window.addEventListener("message", onMessage);
341
+ return () => window.removeEventListener("message", onMessage);
342
+ }, [acceptTelegramToken]);
343
+ useEffect(() => {
344
+ if (!tgAuthToken || !telegramRpcOptions) return;
223
345
  let cancelled = false;
224
346
  setTgLoading(true);
225
347
  setTgError(null);
226
348
  (async () => {
227
349
  try {
228
- const authData = toAuthDataMap(tgLoginData);
229
350
  const [{ response: userResp }, { response: walletsResp }] = await Promise.all([
230
- tgClient.telegramUser({ authData }),
231
- tgClient.telegramUserWallets({ authData })
351
+ tgClient.telegramUser({ authData: {} }, telegramRpcOptions),
352
+ tgClient.telegramUserWallets({ authData: {} }, telegramRpcOptions)
232
353
  ]);
233
354
  if (cancelled) return;
234
355
  const user2 = userResp.user ?? null;
@@ -238,6 +359,10 @@ function HypurrConnectProvider({
238
359
  setTgUser(user2);
239
360
  } catch (err) {
240
361
  if (cancelled) return;
362
+ if (isInvalidTelegramAuthError(err)) {
363
+ onInvalidAuthRef.current?.();
364
+ return;
365
+ }
241
366
  console.error("[HypurrConnect] gRPC TelegramUser failed:", err);
242
367
  setTgError(err instanceof Error ? err.message : String(err));
243
368
  } finally {
@@ -247,13 +372,13 @@ function HypurrConnectProvider({
247
372
  return () => {
248
373
  cancelled = true;
249
374
  };
250
- }, [tgLoginData, tgClient, tgUserTick]);
375
+ }, [tgAuthToken, telegramRpcOptions, tgClient, tgUserTick]);
251
376
  const [eoaAddress, setEoaAddress] = useState(null);
252
377
  const [agent, setAgent] = useState(null);
253
378
  const [eoaLoading, setEoaLoading] = useState(false);
254
379
  const [eoaError, setEoaError] = useState(null);
255
380
  const eoaSignerRef = useRef(null);
256
- const authMethod = tgLoginData ? "telegram" : eoaAddress ? "eoa" : null;
381
+ const authMethod = tgAuthToken ? "telegram" : eoaAddress ? "eoa" : null;
257
382
  const [wallets, setWallets] = useState([]);
258
383
  const [selectedWalletId, setSelectedWalletId] = useState(0);
259
384
  const [packs, setPacks] = useState([]);
@@ -293,14 +418,20 @@ function HypurrConnectProvider({
293
418
  const poll = async () => {
294
419
  try {
295
420
  const [{ response: twapResp }, { response: scaleResp }] = await Promise.all([
296
- tgClient.hyperliquidWalletTwapSessions({
297
- authData: authDataMap,
298
- walletId: selectedWalletId
299
- }),
300
- tgClient.hyperliquidWalletScaleSessions({
301
- authData: authDataMap,
302
- walletId: selectedWalletId
303
- })
421
+ tgClient.hyperliquidWalletTwapSessions(
422
+ {
423
+ authData: {},
424
+ walletId: selectedWalletId
425
+ },
426
+ telegramRpcOptions
427
+ ),
428
+ tgClient.hyperliquidWalletScaleSessions(
429
+ {
430
+ authData: {},
431
+ walletId: selectedWalletId
432
+ },
433
+ telegramRpcOptions
434
+ )
304
435
  ]);
305
436
  if (cancelled) return;
306
437
  setWallets(
@@ -312,7 +443,11 @@ function HypurrConnectProvider({
312
443
  } : w
313
444
  )
314
445
  );
315
- } catch {
446
+ } catch (err) {
447
+ if (isInvalidTelegramAuthError(err)) {
448
+ onInvalidAuthRef.current?.();
449
+ return;
450
+ }
316
451
  }
317
452
  };
318
453
  poll();
@@ -321,16 +456,21 @@ function HypurrConnectProvider({
321
456
  cancelled = true;
322
457
  clearInterval(id);
323
458
  };
324
- }, [authMethod, selectedWalletId, pollInterval, tgClient, authDataMap]);
459
+ }, [
460
+ authMethod,
461
+ selectedWalletId,
462
+ pollInterval,
463
+ tgClient,
464
+ telegramRpcOptions
465
+ ]);
325
466
  const user = useMemo(() => {
326
- if (tgLoginData && authMethod === "telegram" && selectedWallet) {
467
+ if (tgAuthToken && authMethod === "telegram" && selectedWallet && tgUser) {
327
468
  return {
328
469
  address: selectedWallet.ethereumAddress,
329
470
  walletId: selectedWallet.id,
330
- displayName: tgLoginData.username ? `@${tgLoginData.username}` : tgLoginData.first_name,
331
- photoUrl: tgLoginData.photo_url,
471
+ displayName: tgUser.telegramUsername ? `@${tgUser.telegramUsername}` : `Telegram ${tgUser.telegramId}`,
332
472
  authMethod: "telegram",
333
- telegramId: String(tgLoginData.id),
473
+ telegramId: String(tgUser.telegramId),
334
474
  hfunScore: tgUser?.reputation?.hfunScore,
335
475
  reputationScore: tgUser?.reputation?.reputationScore
336
476
  };
@@ -344,7 +484,7 @@ function HypurrConnectProvider({
344
484
  };
345
485
  }
346
486
  return null;
347
- }, [tgLoginData, selectedWallet, eoaAddress, authMethod, tgUser]);
487
+ }, [tgAuthToken, selectedWallet, eoaAddress, authMethod, tgUser]);
348
488
  const onDeadAgentRef = useRef(
349
489
  null
350
490
  );
@@ -366,8 +506,9 @@ function HypurrConnectProvider({
366
506
  const transport = new GrpcExchangeTransport({
367
507
  isTestnet: config.isTestnet ?? false,
368
508
  telegramClient: tgClient,
369
- authDataMap,
370
- walletId: user.walletId
509
+ rpcOptions: telegramRpcOptions,
510
+ walletId: user.walletId,
511
+ onAuthError: () => onInvalidAuthRef.current?.()
371
512
  });
372
513
  return new ExchangeClient({
373
514
  transport,
@@ -522,7 +663,7 @@ function HypurrConnectProvider({
522
663
  eoaAddress,
523
664
  config.isTestnet,
524
665
  tgClient,
525
- authDataMap
666
+ telegramRpcOptions
526
667
  ]);
527
668
  const handleClearAgent = useCallback(() => {
528
669
  if (eoaAddress) {
@@ -532,79 +673,100 @@ function HypurrConnectProvider({
532
673
  }, [eoaAddress]);
533
674
  const createWallet = useCallback(
534
675
  async (name) => {
535
- const { response } = await tgClient.hyperliquidWalletCreate({
536
- authData: authDataMap,
537
- name
538
- });
676
+ const { response } = await tgClient.hyperliquidWalletCreate(
677
+ {
678
+ authData: {},
679
+ name
680
+ },
681
+ telegramRpcOptions
682
+ );
539
683
  refreshWallets();
540
684
  if (!response.wallet)
541
685
  throw new Error("Wallet creation returned no wallet");
542
686
  return response.wallet;
543
687
  },
544
- [tgClient, authDataMap, refreshWallets]
688
+ [tgClient, telegramRpcOptions, refreshWallets]
545
689
  );
546
690
  const deleteWallet = useCallback(
547
691
  async (walletId) => {
548
- await tgClient.hyperliquidWalletDelete({
549
- authData: authDataMap,
550
- walletId
551
- });
692
+ await tgClient.hyperliquidWalletDelete(
693
+ {
694
+ authData: {},
695
+ walletId
696
+ },
697
+ telegramRpcOptions
698
+ );
552
699
  if (walletId === selectedWalletId) {
553
700
  const remaining = wallets.filter((w) => w.id !== walletId);
554
701
  setSelectedWalletId(remaining[0]?.id ?? 0);
555
702
  }
556
703
  refreshWallets();
557
704
  },
558
- [tgClient, authDataMap, selectedWalletId, wallets, refreshWallets]
705
+ [tgClient, telegramRpcOptions, selectedWalletId, wallets, refreshWallets]
559
706
  );
560
707
  const createWalletPack = useCallback(
561
708
  async (name) => {
562
- const { response } = await tgClient.telegramChatWalletPackCreate({
563
- authData: authDataMap,
564
- name
565
- });
709
+ const { response } = await tgClient.telegramChatWalletPackCreate(
710
+ {
711
+ authData: {},
712
+ name
713
+ },
714
+ telegramRpcOptions
715
+ );
566
716
  refreshWallets();
567
717
  return response.packId;
568
718
  },
569
- [tgClient, authDataMap, refreshWallets]
719
+ [tgClient, telegramRpcOptions, refreshWallets]
570
720
  );
571
721
  const addPackLabel = useCallback(
572
722
  async (params) => {
573
- await tgClient.telegramChatWalletPackLabelAdd({
574
- authData: authDataMap,
575
- ...params
576
- });
723
+ await tgClient.telegramChatWalletPackLabelAdd(
724
+ {
725
+ authData: {},
726
+ ...params
727
+ },
728
+ telegramRpcOptions
729
+ );
577
730
  refreshWallets();
578
731
  },
579
- [tgClient, authDataMap, refreshWallets]
732
+ [tgClient, telegramRpcOptions, refreshWallets]
580
733
  );
581
734
  const modifyPackLabel = useCallback(
582
735
  async (params) => {
583
- await tgClient.telegramChatWalletPackLabelModify({
584
- authData: authDataMap,
585
- ...params
586
- });
736
+ await tgClient.telegramChatWalletPackLabelModify(
737
+ {
738
+ authData: {},
739
+ ...params
740
+ },
741
+ telegramRpcOptions
742
+ );
587
743
  refreshWallets();
588
744
  },
589
- [tgClient, authDataMap, refreshWallets]
745
+ [tgClient, telegramRpcOptions, refreshWallets]
590
746
  );
591
747
  const removePackLabel = useCallback(
592
748
  async (params) => {
593
- await tgClient.telegramChatWalletPackLabelRemove({
594
- authData: authDataMap,
595
- ...params
596
- });
749
+ await tgClient.telegramChatWalletPackLabelRemove(
750
+ {
751
+ authData: {},
752
+ ...params
753
+ },
754
+ telegramRpcOptions
755
+ );
597
756
  refreshWallets();
598
757
  },
599
- [tgClient, authDataMap, refreshWallets]
758
+ [tgClient, telegramRpcOptions, refreshWallets]
600
759
  );
601
760
  const createTwap = useCallback(
602
761
  async (params) => {
603
- const { response } = await tgClient.hyperliquidTwapCreate({
604
- authData: authDataMap,
605
- walletId: selectedWalletId,
606
- ...params
607
- });
762
+ const { response } = await tgClient.hyperliquidTwapCreate(
763
+ {
764
+ authData: {},
765
+ walletId: selectedWalletId,
766
+ ...params
767
+ },
768
+ telegramRpcOptions
769
+ );
608
770
  if (!response.session)
609
771
  throw new Error("TWAP creation returned no session");
610
772
  const session = response.session;
@@ -615,17 +777,19 @@ function HypurrConnectProvider({
615
777
  );
616
778
  return session;
617
779
  },
618
- [tgClient, authDataMap, selectedWalletId]
780
+ [tgClient, telegramRpcOptions, selectedWalletId]
619
781
  );
620
782
  const modifyTwap = useCallback(
621
783
  async (params) => {
622
- const { response } = await tgClient.hyperliquidTwapModify({
623
- authData: authDataMap,
624
- walletId: selectedWalletId,
625
- ...params
626
- });
627
- if (!response.session)
628
- throw new Error("TWAP modify returned no session");
784
+ const { response } = await tgClient.hyperliquidTwapModify(
785
+ {
786
+ authData: {},
787
+ walletId: selectedWalletId,
788
+ ...params
789
+ },
790
+ telegramRpcOptions
791
+ );
792
+ if (!response.session) throw new Error("TWAP modify returned no session");
629
793
  const session = response.session;
630
794
  setWallets(
631
795
  (prev) => prev.map(
@@ -639,15 +803,18 @@ function HypurrConnectProvider({
639
803
  );
640
804
  return session;
641
805
  },
642
- [tgClient, authDataMap, selectedWalletId]
806
+ [tgClient, telegramRpcOptions, selectedWalletId]
643
807
  );
644
808
  const cancelTwap = useCallback(
645
809
  async (sessionId) => {
646
- await tgClient.hyperliquidTwapCancel({
647
- authData: authDataMap,
648
- walletId: selectedWalletId,
649
- twapSessionId: sessionId
650
- });
810
+ await tgClient.hyperliquidTwapCancel(
811
+ {
812
+ authData: {},
813
+ walletId: selectedWalletId,
814
+ twapSessionId: sessionId
815
+ },
816
+ telegramRpcOptions
817
+ );
651
818
  setWallets(
652
819
  (prev) => prev.map(
653
820
  (w) => w.id === selectedWalletId ? {
@@ -657,15 +824,18 @@ function HypurrConnectProvider({
657
824
  )
658
825
  );
659
826
  },
660
- [tgClient, authDataMap, selectedWalletId]
827
+ [tgClient, telegramRpcOptions, selectedWalletId]
661
828
  );
662
829
  const createScale = useCallback(
663
830
  async (params) => {
664
- const { response } = await tgClient.hyperliquidScaleCreate({
665
- authData: authDataMap,
666
- walletId: selectedWalletId,
667
- ...params
668
- });
831
+ const { response } = await tgClient.hyperliquidScaleCreate(
832
+ {
833
+ authData: {},
834
+ walletId: selectedWalletId,
835
+ ...params
836
+ },
837
+ telegramRpcOptions
838
+ );
669
839
  if (!response.session)
670
840
  throw new Error("Scale creation returned no session");
671
841
  const session = response.session;
@@ -676,15 +846,18 @@ function HypurrConnectProvider({
676
846
  );
677
847
  return session;
678
848
  },
679
- [tgClient, authDataMap, selectedWalletId]
849
+ [tgClient, telegramRpcOptions, selectedWalletId]
680
850
  );
681
851
  const cancelScale = useCallback(
682
852
  async (sessionId) => {
683
- await tgClient.hyperliquidScaleCancel({
684
- authData: authDataMap,
685
- walletId: selectedWalletId,
686
- scaleSessionId: sessionId
687
- });
853
+ await tgClient.hyperliquidScaleCancel(
854
+ {
855
+ authData: {},
856
+ walletId: selectedWalletId,
857
+ scaleSessionId: sessionId
858
+ },
859
+ telegramRpcOptions
860
+ );
688
861
  setWallets(
689
862
  (prev) => prev.map(
690
863
  (w) => w.id === selectedWalletId ? {
@@ -696,27 +869,56 @@ function HypurrConnectProvider({
696
869
  )
697
870
  );
698
871
  },
699
- [tgClient, authDataMap, selectedWalletId]
872
+ [tgClient, telegramRpcOptions, selectedWalletId]
700
873
  );
701
874
  const [loginModalOpen, setLoginModalOpen] = useState(false);
702
875
  const openLoginModal = useCallback(() => setLoginModalOpen(true), []);
703
876
  const closeLoginModal = useCallback(() => setLoginModalOpen(false), []);
704
- const loginTelegram = useCallback((data) => {
705
- setTgLoginData(data);
706
- localStorage.setItem(TELEGRAM_STORAGE_KEY, JSON.stringify(data));
707
- setEoaAddress(null);
708
- setAgent(null);
709
- setEoaError(null);
710
- }, []);
877
+ const loginTelegram = useCallback(() => {
878
+ const state = randomState();
879
+ sessionStorage.setItem(TELEGRAM_AUTH_STATE_KEY, state);
880
+ const configuredReturnTo = config.telegram.returnTo;
881
+ const returnTo = typeof configuredReturnTo === "function" ? configuredReturnTo() : configuredReturnTo || currentReturnTo();
882
+ const authUrl = new URL(config.telegram.authHubUrl || DEFAULT_AUTH_HUB_URL);
883
+ authUrl.searchParams.set("return_to", returnTo);
884
+ authUrl.searchParams.set("state", state);
885
+ authUrl.searchParams.set("scope", normalizeScopes(config.telegram.scope));
886
+ const width = 520;
887
+ const height = 720;
888
+ const left = window.screenX + Math.max(0, (window.outerWidth - width) / 2);
889
+ const top = window.screenY + Math.max(0, (window.outerHeight - height) / 2);
890
+ const popup = window.open(
891
+ authUrl.toString(),
892
+ "hypurr_telegram_auth",
893
+ [
894
+ `width=${width}`,
895
+ `height=${height}`,
896
+ `left=${Math.round(left)}`,
897
+ `top=${Math.round(top)}`,
898
+ "resizable=yes",
899
+ "scrollbars=yes"
900
+ ].join(",")
901
+ );
902
+ if (popup) {
903
+ popup.focus();
904
+ return;
905
+ }
906
+ window.location.assign(authUrl.toString());
907
+ }, [
908
+ config.telegram.authHubUrl,
909
+ config.telegram.returnTo,
910
+ config.telegram.scope
911
+ ]);
711
912
  const connectEoa = useCallback(
712
913
  (address, signer) => {
713
914
  eoaSignerRef.current = signer ?? null;
714
915
  setEoaAddress(address);
715
- setTgLoginData(null);
916
+ setTgAuthToken(null);
716
917
  setTgUser(null);
717
918
  setTgError(null);
718
919
  setEoaError(null);
719
920
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
921
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
720
922
  const existing = loadAgent(address);
721
923
  if (existing && existing.validUntil > Date.now()) {
722
924
  setAgent(existing);
@@ -814,14 +1016,15 @@ function HypurrConnectProvider({
814
1016
  [eoaAddress, config.isTestnet]
815
1017
  );
816
1018
  const logout = useCallback(() => {
817
- setTgLoginData(null);
818
1019
  setTgUser(null);
819
1020
  setTgError(null);
1021
+ setTgAuthToken(null);
820
1022
  setEoaAddress(null);
821
1023
  setAgent(null);
822
1024
  setEoaError(null);
823
1025
  eoaSignerRef.current = null;
824
1026
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
1027
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
825
1028
  }, []);
826
1029
  const value = useMemo(
827
1030
  () => ({
@@ -861,6 +1064,8 @@ function HypurrConnectProvider({
861
1064
  botUsername: config.telegram?.botUsername ?? "",
862
1065
  useWidget: config.telegram?.useWidget ?? false,
863
1066
  authDataMap,
1067
+ authToken: tgAuthToken,
1068
+ telegramRpcOptions,
864
1069
  telegramClient: tgClient,
865
1070
  staticClient
866
1071
  }),
@@ -902,6 +1107,8 @@ function HypurrConnectProvider({
902
1107
  config.telegram?.botUsername,
903
1108
  config.telegram?.useWidget,
904
1109
  authDataMap,
1110
+ tgAuthToken,
1111
+ telegramRpcOptions,
905
1112
  tgClient,
906
1113
  staticClient
907
1114
  ]
@@ -917,7 +1124,6 @@ import {
917
1124
  } from "framer-motion";
918
1125
  import {
919
1126
  useCallback as useCallback2,
920
- useEffect as useEffect3,
921
1127
  useSyncExternalStore
922
1128
  } from "react";
923
1129
 
@@ -1048,53 +1254,8 @@ function TelegramColorIcon({ style }) {
1048
1254
  );
1049
1255
  }
1050
1256
 
1051
- // src/TelegramLoginWidget.tsx
1052
- import { useEffect as useEffect2, useRef as useRef2 } from "react";
1053
- import { jsx as jsx4 } from "react/jsx-runtime";
1054
- var WIDGET_SCRIPT_URL = "https://telegram.org/js/telegram-widget.js?22";
1055
- var CALLBACK_NAME = "__hypurrConnectTelegramAuth";
1056
- function TelegramLoginWidget({
1057
- botUsername,
1058
- onAuth,
1059
- buttonSize = "large",
1060
- cornerRadius,
1061
- showUserPhoto = true,
1062
- requestAccess = true
1063
- }) {
1064
- const containerRef = useRef2(null);
1065
- const onAuthRef = useRef2(onAuth);
1066
- onAuthRef.current = onAuth;
1067
- useEffect2(() => {
1068
- const container = containerRef.current;
1069
- if (!container) return;
1070
- window[CALLBACK_NAME] = (user) => {
1071
- onAuthRef.current(user);
1072
- };
1073
- const script = document.createElement("script");
1074
- script.src = WIDGET_SCRIPT_URL;
1075
- script.async = true;
1076
- script.setAttribute("data-telegram-login", botUsername);
1077
- script.setAttribute("data-size", buttonSize);
1078
- script.setAttribute("data-onauth", `${CALLBACK_NAME}(user)`);
1079
- script.setAttribute("data-userpic", String(showUserPhoto));
1080
- if (requestAccess) {
1081
- script.setAttribute("data-request-access", "write");
1082
- }
1083
- if (cornerRadius !== void 0) {
1084
- script.setAttribute("data-radius", String(cornerRadius));
1085
- }
1086
- container.innerHTML = "";
1087
- container.appendChild(script);
1088
- return () => {
1089
- container.innerHTML = "";
1090
- delete window[CALLBACK_NAME];
1091
- };
1092
- }, [botUsername, buttonSize, cornerRadius, showUserPhoto, requestAccess]);
1093
- return /* @__PURE__ */ jsx4("div", { ref: containerRef });
1094
- }
1095
-
1096
1257
  // src/LoginModal.tsx
1097
- import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1258
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1098
1259
  var MOBILE_BREAKPOINT = 640;
1099
1260
  var btnStyle = {
1100
1261
  display: "flex",
@@ -1172,7 +1333,7 @@ function HoverButton({
1172
1333
  onClick,
1173
1334
  children
1174
1335
  }) {
1175
- return /* @__PURE__ */ jsx5(
1336
+ return /* @__PURE__ */ jsx4(
1176
1337
  motion.button,
1177
1338
  {
1178
1339
  type: "button",
@@ -1184,61 +1345,14 @@ function HoverButton({
1184
1345
  );
1185
1346
  }
1186
1347
  function LoginModal({ onConnectWallet, walletIcon }) {
1187
- const {
1188
- loginTelegram,
1189
- loginModalOpen,
1190
- closeLoginModal,
1191
- botId,
1192
- botUsername,
1193
- useWidget
1194
- } = useHypurrConnectInternal();
1195
- const handleTelegramAuth = useCallback2(
1196
- (user) => {
1197
- loginTelegram(user);
1198
- closeLoginModal();
1199
- },
1200
- [loginTelegram, closeLoginModal]
1201
- );
1202
- useEffect3(() => {
1203
- if (!loginModalOpen) return;
1204
- function onMessage(e) {
1205
- if (e.origin !== "https://oauth.telegram.org") return;
1206
- try {
1207
- const data = typeof e.data === "string" ? JSON.parse(e.data) : e.data;
1208
- if (data?.event === "auth_result" && data.result) {
1209
- const r = data.result;
1210
- handleTelegramAuth({
1211
- id: r.id,
1212
- first_name: r.first_name ?? "",
1213
- last_name: r.last_name ?? void 0,
1214
- username: r.username ?? void 0,
1215
- photo_url: r.photo_url ?? void 0,
1216
- auth_date: r.auth_date,
1217
- hash: r.hash
1218
- });
1219
- }
1220
- } catch {
1221
- }
1222
- }
1223
- window.addEventListener("message", onMessage);
1224
- return () => window.removeEventListener("message", onMessage);
1225
- }, [loginModalOpen, handleTelegramAuth]);
1226
- const openTelegramOAuth = useCallback2(() => {
1227
- const origin = encodeURIComponent(window.location.origin);
1228
- const url = `https://oauth.telegram.org/auth?bot_id=${botId}&origin=${origin}&request_access=write`;
1229
- const w = 550;
1230
- const h = 470;
1231
- const left = window.screenX + (window.outerWidth - w) / 2;
1232
- const top = window.screenY + (window.outerHeight - h) / 2;
1233
- window.open(
1234
- url,
1235
- "telegram_auth",
1236
- `width=${w},height=${h},left=${left},top=${top}`
1237
- );
1238
- }, [botId]);
1348
+ const { loginTelegram, loginModalOpen, closeLoginModal } = useHypurrConnectInternal();
1349
+ const handleTelegramAuth = useCallback2(() => {
1350
+ closeLoginModal();
1351
+ loginTelegram();
1352
+ }, [loginTelegram, closeLoginModal]);
1239
1353
  const isMobile = useIsMobile();
1240
1354
  const modalContent = /* @__PURE__ */ jsxs3(Fragment, { children: [
1241
- /* @__PURE__ */ jsx5(
1355
+ /* @__PURE__ */ jsx4(
1242
1356
  "div",
1243
1357
  {
1244
1358
  style: {
@@ -1249,19 +1363,13 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1249
1363
  gap: 8,
1250
1364
  overflow: "hidden"
1251
1365
  },
1252
- children: useWidget && botUsername ? /* @__PURE__ */ jsx5(
1253
- TelegramLoginWidget,
1254
- {
1255
- botUsername,
1256
- onAuth: handleTelegramAuth
1257
- }
1258
- ) : /* @__PURE__ */ jsxs3(HoverButton, { onClick: openTelegramOAuth, children: [
1259
- /* @__PURE__ */ jsx5(TelegramColorIcon, { style: iconSize }),
1366
+ children: /* @__PURE__ */ jsxs3(HoverButton, { onClick: handleTelegramAuth, children: [
1367
+ /* @__PURE__ */ jsx4(TelegramColorIcon, { style: iconSize }),
1260
1368
  "Telegram"
1261
1369
  ] })
1262
1370
  }
1263
1371
  ),
1264
- /* @__PURE__ */ jsx5("div", { style: dividerStyle }),
1372
+ /* @__PURE__ */ jsx4("div", { style: dividerStyle }),
1265
1373
  /* @__PURE__ */ jsxs3(
1266
1374
  HoverButton,
1267
1375
  {
@@ -1270,14 +1378,14 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1270
1378
  onConnectWallet();
1271
1379
  },
1272
1380
  children: [
1273
- walletIcon ?? /* @__PURE__ */ jsx5(MetaMaskColorIcon, { style: iconSize }),
1381
+ walletIcon ?? /* @__PURE__ */ jsx4(MetaMaskColorIcon, { style: iconSize }),
1274
1382
  "Wallet"
1275
1383
  ]
1276
1384
  }
1277
1385
  )
1278
1386
  ] });
1279
- return /* @__PURE__ */ jsx5(AnimatePresence, { children: loginModalOpen && (isMobile ? /* @__PURE__ */ jsx5(MobileDrawer, { onClose: closeLoginModal, children: modalContent }, "drawer") : /* @__PURE__ */ jsxs3(Fragment, { children: [
1280
- /* @__PURE__ */ jsx5(
1387
+ return /* @__PURE__ */ jsx4(AnimatePresence, { children: loginModalOpen && (isMobile ? /* @__PURE__ */ jsx4(MobileDrawer, { onClose: closeLoginModal, children: modalContent }, "drawer") : /* @__PURE__ */ jsxs3(Fragment, { children: [
1388
+ /* @__PURE__ */ jsx4(
1281
1389
  motion.div,
1282
1390
  {
1283
1391
  style: backdropStyle,
@@ -1289,7 +1397,7 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1289
1397
  },
1290
1398
  "backdrop"
1291
1399
  ),
1292
- /* @__PURE__ */ jsx5(
1400
+ /* @__PURE__ */ jsx4(
1293
1401
  motion.div,
1294
1402
  {
1295
1403
  style: modalWrapperStyle,
@@ -1302,13 +1410,13 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1302
1410
  motion.div,
1303
1411
  {
1304
1412
  style: modalBoxStyle,
1305
- initial: { opacity: 0, scale: 0.95, y: 10 },
1306
- animate: { opacity: 1, scale: 1, y: 0 },
1307
- exit: { opacity: 0, scale: 0.95, y: 10 },
1308
- transition: { duration: 0.2, ease: "easeOut" },
1413
+ initial: { scale: 0.96, opacity: 0, y: 8 },
1414
+ animate: { scale: 1, opacity: 1, y: 0 },
1415
+ exit: { scale: 0.96, opacity: 0, y: 8 },
1416
+ transition: { duration: 0.12 },
1309
1417
  onClick: (e) => e.stopPropagation(),
1310
1418
  children: [
1311
- /* @__PURE__ */ jsx5("p", { style: headingStyle, children: "Connect" }),
1419
+ /* @__PURE__ */ jsx4("h2", { style: headingStyle, children: "Connect" }),
1312
1420
  modalContent
1313
1421
  ]
1314
1422
  }
@@ -1375,7 +1483,7 @@ function MobileDrawer({
1375
1483
  [onClose, controls]
1376
1484
  );
1377
1485
  return /* @__PURE__ */ jsxs3(Fragment, { children: [
1378
- /* @__PURE__ */ jsx5(
1486
+ /* @__PURE__ */ jsx4(
1379
1487
  motion.div,
1380
1488
  {
1381
1489
  style: backdropStyle,
@@ -1400,9 +1508,9 @@ function MobileDrawer({
1400
1508
  dragElastic: { top: 0, bottom: 0.4 },
1401
1509
  onDragEnd: handleDragEnd,
1402
1510
  children: [
1403
- /* @__PURE__ */ jsx5("div", { style: drawerBgStyle }),
1404
- /* @__PURE__ */ jsx5("div", { style: grabHandleAreaStyle, children: /* @__PURE__ */ jsx5("div", { style: grabHandleStyle }) }),
1405
- /* @__PURE__ */ jsx5("p", { style: headingStyle, children: "Connect" }),
1511
+ /* @__PURE__ */ jsx4("div", { style: drawerBgStyle }),
1512
+ /* @__PURE__ */ jsx4("div", { style: grabHandleAreaStyle, children: /* @__PURE__ */ jsx4("div", { style: grabHandleStyle }) }),
1513
+ /* @__PURE__ */ jsx4("p", { style: headingStyle, children: "Connect" }),
1406
1514
  children
1407
1515
  ]
1408
1516
  },
@@ -1423,7 +1531,6 @@ export {
1423
1531
  GrpcExchangeTransport,
1424
1532
  HypurrConnectProvider,
1425
1533
  LoginModal,
1426
- TelegramLoginWidget,
1427
1534
  createEoaSigner,
1428
1535
  createStaticClient,
1429
1536
  createTelegramClient,