@hfunlabs/hypurr-connect 0.1.9 → 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,14 @@ function createStaticClient(config) {
98
101
  var GrpcExchangeTransport = class {
99
102
  isTestnet;
100
103
  telegramClient;
101
- authDataMap;
104
+ rpcOptions;
102
105
  walletId;
103
106
  infoUrl;
104
107
  onAuthError;
105
108
  constructor(config) {
106
109
  this.isTestnet = config.isTestnet ?? false;
107
110
  this.telegramClient = config.telegramClient;
108
- this.authDataMap = config.authDataMap;
111
+ this.rpcOptions = config.rpcOptions;
109
112
  this.walletId = config.walletId;
110
113
  this.onAuthError = config.onAuthError;
111
114
  this.infoUrl = this.isTestnet ? "https://api.hyperliquid-testnet.xyz" : "https://api.hyperliquid.xyz";
@@ -126,14 +129,19 @@ var GrpcExchangeTransport = class {
126
129
  console.debug("[GrpcExchangeTransport] sending action:", payload.action);
127
130
  let response;
128
131
  try {
129
- ({ response } = await this.telegramClient.hyperliquidCoreAction({
130
- authData: this.authDataMap,
131
- walletId: this.walletId,
132
- action: actionBytes,
133
- nonce: payload.nonce || Date.now()
134
- }));
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
+ ));
135
141
  } catch (err) {
136
- if (this.onAuthError && err instanceof Error && /invalid telegram auth data/i.test(err.message)) {
142
+ if (this.onAuthError && err instanceof Error && /invalid telegram auth data|invalid auth token|missing authorization token/i.test(
143
+ err.message
144
+ )) {
137
145
  this.onAuthError();
138
146
  }
139
147
  throw err;
@@ -174,22 +182,53 @@ var GrpcExchangeTransport = class {
174
182
 
175
183
  // src/HypurrConnectProvider.tsx
176
184
  import { jsx } from "react/jsx-runtime";
177
- var TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-user";
178
- function toAuthDataMap(data) {
179
- const map = {
180
- id: String(data.id),
181
- first_name: data.first_name,
182
- auth_date: String(data.auth_date),
183
- hash: data.hash
184
- };
185
- if (data.last_name) map.last_name = data.last_name;
186
- if (data.username) map.username = data.username;
187
- if (data.photo_url) map.photo_url = data.photo_url;
188
- return map;
189
- }
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
+ ];
190
200
  function isInvalidTelegramAuthError(err) {
191
201
  const msg = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : String(err);
192
- return /invalid telegram auth data/i.test(msg);
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";
193
232
  }
194
233
  var HypurrConnectContext = createContext(null);
195
234
  function useHypurrConnect() {
@@ -214,43 +253,103 @@ function HypurrConnectProvider({
214
253
  }) {
215
254
  const tgClient = useMemo(() => createTelegramClient(config), [config]);
216
255
  const staticClient = useMemo(() => createStaticClient(config), [config]);
217
- const [tgLoginData, setTgLoginData] = useState(
218
- () => {
219
- try {
220
- const stored = localStorage.getItem(TELEGRAM_STORAGE_KEY);
221
- return stored ? JSON.parse(stored) : null;
222
- } catch {
223
- return null;
224
- }
256
+ const [tgAuthToken, setTgAuthToken] = useState(() => {
257
+ try {
258
+ return localStorage.getItem(TELEGRAM_STORAGE_KEY);
259
+ } catch {
260
+ return null;
225
261
  }
226
- );
262
+ });
227
263
  const [tgUser, setTgUser] = useState(null);
228
264
  const [tgLoading, setTgLoading] = useState(false);
229
265
  const [tgError, setTgError] = useState(null);
230
- const authDataMap = useMemo(
231
- () => tgLoginData ? toAuthDataMap(tgLoginData) : {},
232
- [tgLoginData]
266
+ const authDataMap = useMemo(() => ({}), []);
267
+ const telegramRpcOptions = useMemo(
268
+ () => tgAuthToken ? { meta: { authorization: `Bearer ${tgAuthToken}` } } : void 0,
269
+ [tgAuthToken]
233
270
  );
234
271
  const [tgUserTick, setTgUserTick] = useState(0);
235
272
  const onInvalidAuthRef = useRef(null);
236
273
  onInvalidAuthRef.current = () => {
237
- console.warn("[HypurrConnect] Invalid telegram auth data \u2014 disconnecting.");
238
- setTgLoginData(null);
274
+ console.warn(
275
+ "[HypurrConnect] Invalid Telegram auth token \u2014 disconnecting."
276
+ );
277
+ setTgAuthToken(null);
239
278
  setTgUser(null);
240
279
  setTgError(null);
241
280
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
281
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
242
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
+ }, []);
243
289
  useEffect(() => {
244
- 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;
245
345
  let cancelled = false;
246
346
  setTgLoading(true);
247
347
  setTgError(null);
248
348
  (async () => {
249
349
  try {
250
- const authData = toAuthDataMap(tgLoginData);
251
350
  const [{ response: userResp }, { response: walletsResp }] = await Promise.all([
252
- tgClient.telegramUser({ authData }),
253
- tgClient.telegramUserWallets({ authData })
351
+ tgClient.telegramUser({ authData: {} }, telegramRpcOptions),
352
+ tgClient.telegramUserWallets({ authData: {} }, telegramRpcOptions)
254
353
  ]);
255
354
  if (cancelled) return;
256
355
  const user2 = userResp.user ?? null;
@@ -273,13 +372,13 @@ function HypurrConnectProvider({
273
372
  return () => {
274
373
  cancelled = true;
275
374
  };
276
- }, [tgLoginData, tgClient, tgUserTick]);
375
+ }, [tgAuthToken, telegramRpcOptions, tgClient, tgUserTick]);
277
376
  const [eoaAddress, setEoaAddress] = useState(null);
278
377
  const [agent, setAgent] = useState(null);
279
378
  const [eoaLoading, setEoaLoading] = useState(false);
280
379
  const [eoaError, setEoaError] = useState(null);
281
380
  const eoaSignerRef = useRef(null);
282
- const authMethod = tgLoginData ? "telegram" : eoaAddress ? "eoa" : null;
381
+ const authMethod = tgAuthToken ? "telegram" : eoaAddress ? "eoa" : null;
283
382
  const [wallets, setWallets] = useState([]);
284
383
  const [selectedWalletId, setSelectedWalletId] = useState(0);
285
384
  const [packs, setPacks] = useState([]);
@@ -319,14 +418,20 @@ function HypurrConnectProvider({
319
418
  const poll = async () => {
320
419
  try {
321
420
  const [{ response: twapResp }, { response: scaleResp }] = await Promise.all([
322
- tgClient.hyperliquidWalletTwapSessions({
323
- authData: authDataMap,
324
- walletId: selectedWalletId
325
- }),
326
- tgClient.hyperliquidWalletScaleSessions({
327
- authData: authDataMap,
328
- walletId: selectedWalletId
329
- })
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
+ )
330
435
  ]);
331
436
  if (cancelled) return;
332
437
  setWallets(
@@ -351,16 +456,21 @@ function HypurrConnectProvider({
351
456
  cancelled = true;
352
457
  clearInterval(id);
353
458
  };
354
- }, [authMethod, selectedWalletId, pollInterval, tgClient, authDataMap]);
459
+ }, [
460
+ authMethod,
461
+ selectedWalletId,
462
+ pollInterval,
463
+ tgClient,
464
+ telegramRpcOptions
465
+ ]);
355
466
  const user = useMemo(() => {
356
- if (tgLoginData && authMethod === "telegram" && selectedWallet) {
467
+ if (tgAuthToken && authMethod === "telegram" && selectedWallet && tgUser) {
357
468
  return {
358
469
  address: selectedWallet.ethereumAddress,
359
470
  walletId: selectedWallet.id,
360
- displayName: tgLoginData.username ? `@${tgLoginData.username}` : tgLoginData.first_name,
361
- photoUrl: tgLoginData.photo_url,
471
+ displayName: tgUser.telegramUsername ? `@${tgUser.telegramUsername}` : `Telegram ${tgUser.telegramId}`,
362
472
  authMethod: "telegram",
363
- telegramId: String(tgLoginData.id),
473
+ telegramId: String(tgUser.telegramId),
364
474
  hfunScore: tgUser?.reputation?.hfunScore,
365
475
  reputationScore: tgUser?.reputation?.reputationScore
366
476
  };
@@ -374,7 +484,7 @@ function HypurrConnectProvider({
374
484
  };
375
485
  }
376
486
  return null;
377
- }, [tgLoginData, selectedWallet, eoaAddress, authMethod, tgUser]);
487
+ }, [tgAuthToken, selectedWallet, eoaAddress, authMethod, tgUser]);
378
488
  const onDeadAgentRef = useRef(
379
489
  null
380
490
  );
@@ -396,7 +506,7 @@ function HypurrConnectProvider({
396
506
  const transport = new GrpcExchangeTransport({
397
507
  isTestnet: config.isTestnet ?? false,
398
508
  telegramClient: tgClient,
399
- authDataMap,
509
+ rpcOptions: telegramRpcOptions,
400
510
  walletId: user.walletId,
401
511
  onAuthError: () => onInvalidAuthRef.current?.()
402
512
  });
@@ -553,7 +663,7 @@ function HypurrConnectProvider({
553
663
  eoaAddress,
554
664
  config.isTestnet,
555
665
  tgClient,
556
- authDataMap
666
+ telegramRpcOptions
557
667
  ]);
558
668
  const handleClearAgent = useCallback(() => {
559
669
  if (eoaAddress) {
@@ -563,79 +673,100 @@ function HypurrConnectProvider({
563
673
  }, [eoaAddress]);
564
674
  const createWallet = useCallback(
565
675
  async (name) => {
566
- const { response } = await tgClient.hyperliquidWalletCreate({
567
- authData: authDataMap,
568
- name
569
- });
676
+ const { response } = await tgClient.hyperliquidWalletCreate(
677
+ {
678
+ authData: {},
679
+ name
680
+ },
681
+ telegramRpcOptions
682
+ );
570
683
  refreshWallets();
571
684
  if (!response.wallet)
572
685
  throw new Error("Wallet creation returned no wallet");
573
686
  return response.wallet;
574
687
  },
575
- [tgClient, authDataMap, refreshWallets]
688
+ [tgClient, telegramRpcOptions, refreshWallets]
576
689
  );
577
690
  const deleteWallet = useCallback(
578
691
  async (walletId) => {
579
- await tgClient.hyperliquidWalletDelete({
580
- authData: authDataMap,
581
- walletId
582
- });
692
+ await tgClient.hyperliquidWalletDelete(
693
+ {
694
+ authData: {},
695
+ walletId
696
+ },
697
+ telegramRpcOptions
698
+ );
583
699
  if (walletId === selectedWalletId) {
584
700
  const remaining = wallets.filter((w) => w.id !== walletId);
585
701
  setSelectedWalletId(remaining[0]?.id ?? 0);
586
702
  }
587
703
  refreshWallets();
588
704
  },
589
- [tgClient, authDataMap, selectedWalletId, wallets, refreshWallets]
705
+ [tgClient, telegramRpcOptions, selectedWalletId, wallets, refreshWallets]
590
706
  );
591
707
  const createWalletPack = useCallback(
592
708
  async (name) => {
593
- const { response } = await tgClient.telegramChatWalletPackCreate({
594
- authData: authDataMap,
595
- name
596
- });
709
+ const { response } = await tgClient.telegramChatWalletPackCreate(
710
+ {
711
+ authData: {},
712
+ name
713
+ },
714
+ telegramRpcOptions
715
+ );
597
716
  refreshWallets();
598
717
  return response.packId;
599
718
  },
600
- [tgClient, authDataMap, refreshWallets]
719
+ [tgClient, telegramRpcOptions, refreshWallets]
601
720
  );
602
721
  const addPackLabel = useCallback(
603
722
  async (params) => {
604
- await tgClient.telegramChatWalletPackLabelAdd({
605
- authData: authDataMap,
606
- ...params
607
- });
723
+ await tgClient.telegramChatWalletPackLabelAdd(
724
+ {
725
+ authData: {},
726
+ ...params
727
+ },
728
+ telegramRpcOptions
729
+ );
608
730
  refreshWallets();
609
731
  },
610
- [tgClient, authDataMap, refreshWallets]
732
+ [tgClient, telegramRpcOptions, refreshWallets]
611
733
  );
612
734
  const modifyPackLabel = useCallback(
613
735
  async (params) => {
614
- await tgClient.telegramChatWalletPackLabelModify({
615
- authData: authDataMap,
616
- ...params
617
- });
736
+ await tgClient.telegramChatWalletPackLabelModify(
737
+ {
738
+ authData: {},
739
+ ...params
740
+ },
741
+ telegramRpcOptions
742
+ );
618
743
  refreshWallets();
619
744
  },
620
- [tgClient, authDataMap, refreshWallets]
745
+ [tgClient, telegramRpcOptions, refreshWallets]
621
746
  );
622
747
  const removePackLabel = useCallback(
623
748
  async (params) => {
624
- await tgClient.telegramChatWalletPackLabelRemove({
625
- authData: authDataMap,
626
- ...params
627
- });
749
+ await tgClient.telegramChatWalletPackLabelRemove(
750
+ {
751
+ authData: {},
752
+ ...params
753
+ },
754
+ telegramRpcOptions
755
+ );
628
756
  refreshWallets();
629
757
  },
630
- [tgClient, authDataMap, refreshWallets]
758
+ [tgClient, telegramRpcOptions, refreshWallets]
631
759
  );
632
760
  const createTwap = useCallback(
633
761
  async (params) => {
634
- const { response } = await tgClient.hyperliquidTwapCreate({
635
- authData: authDataMap,
636
- walletId: selectedWalletId,
637
- ...params
638
- });
762
+ const { response } = await tgClient.hyperliquidTwapCreate(
763
+ {
764
+ authData: {},
765
+ walletId: selectedWalletId,
766
+ ...params
767
+ },
768
+ telegramRpcOptions
769
+ );
639
770
  if (!response.session)
640
771
  throw new Error("TWAP creation returned no session");
641
772
  const session = response.session;
@@ -646,17 +777,19 @@ function HypurrConnectProvider({
646
777
  );
647
778
  return session;
648
779
  },
649
- [tgClient, authDataMap, selectedWalletId]
780
+ [tgClient, telegramRpcOptions, selectedWalletId]
650
781
  );
651
782
  const modifyTwap = useCallback(
652
783
  async (params) => {
653
- const { response } = await tgClient.hyperliquidTwapModify({
654
- authData: authDataMap,
655
- walletId: selectedWalletId,
656
- ...params
657
- });
658
- if (!response.session)
659
- 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");
660
793
  const session = response.session;
661
794
  setWallets(
662
795
  (prev) => prev.map(
@@ -670,15 +803,18 @@ function HypurrConnectProvider({
670
803
  );
671
804
  return session;
672
805
  },
673
- [tgClient, authDataMap, selectedWalletId]
806
+ [tgClient, telegramRpcOptions, selectedWalletId]
674
807
  );
675
808
  const cancelTwap = useCallback(
676
809
  async (sessionId) => {
677
- await tgClient.hyperliquidTwapCancel({
678
- authData: authDataMap,
679
- walletId: selectedWalletId,
680
- twapSessionId: sessionId
681
- });
810
+ await tgClient.hyperliquidTwapCancel(
811
+ {
812
+ authData: {},
813
+ walletId: selectedWalletId,
814
+ twapSessionId: sessionId
815
+ },
816
+ telegramRpcOptions
817
+ );
682
818
  setWallets(
683
819
  (prev) => prev.map(
684
820
  (w) => w.id === selectedWalletId ? {
@@ -688,15 +824,18 @@ function HypurrConnectProvider({
688
824
  )
689
825
  );
690
826
  },
691
- [tgClient, authDataMap, selectedWalletId]
827
+ [tgClient, telegramRpcOptions, selectedWalletId]
692
828
  );
693
829
  const createScale = useCallback(
694
830
  async (params) => {
695
- const { response } = await tgClient.hyperliquidScaleCreate({
696
- authData: authDataMap,
697
- walletId: selectedWalletId,
698
- ...params
699
- });
831
+ const { response } = await tgClient.hyperliquidScaleCreate(
832
+ {
833
+ authData: {},
834
+ walletId: selectedWalletId,
835
+ ...params
836
+ },
837
+ telegramRpcOptions
838
+ );
700
839
  if (!response.session)
701
840
  throw new Error("Scale creation returned no session");
702
841
  const session = response.session;
@@ -707,15 +846,18 @@ function HypurrConnectProvider({
707
846
  );
708
847
  return session;
709
848
  },
710
- [tgClient, authDataMap, selectedWalletId]
849
+ [tgClient, telegramRpcOptions, selectedWalletId]
711
850
  );
712
851
  const cancelScale = useCallback(
713
852
  async (sessionId) => {
714
- await tgClient.hyperliquidScaleCancel({
715
- authData: authDataMap,
716
- walletId: selectedWalletId,
717
- scaleSessionId: sessionId
718
- });
853
+ await tgClient.hyperliquidScaleCancel(
854
+ {
855
+ authData: {},
856
+ walletId: selectedWalletId,
857
+ scaleSessionId: sessionId
858
+ },
859
+ telegramRpcOptions
860
+ );
719
861
  setWallets(
720
862
  (prev) => prev.map(
721
863
  (w) => w.id === selectedWalletId ? {
@@ -727,27 +869,56 @@ function HypurrConnectProvider({
727
869
  )
728
870
  );
729
871
  },
730
- [tgClient, authDataMap, selectedWalletId]
872
+ [tgClient, telegramRpcOptions, selectedWalletId]
731
873
  );
732
874
  const [loginModalOpen, setLoginModalOpen] = useState(false);
733
875
  const openLoginModal = useCallback(() => setLoginModalOpen(true), []);
734
876
  const closeLoginModal = useCallback(() => setLoginModalOpen(false), []);
735
- const loginTelegram = useCallback((data) => {
736
- setTgLoginData(data);
737
- localStorage.setItem(TELEGRAM_STORAGE_KEY, JSON.stringify(data));
738
- setEoaAddress(null);
739
- setAgent(null);
740
- setEoaError(null);
741
- }, []);
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
+ ]);
742
912
  const connectEoa = useCallback(
743
913
  (address, signer) => {
744
914
  eoaSignerRef.current = signer ?? null;
745
915
  setEoaAddress(address);
746
- setTgLoginData(null);
916
+ setTgAuthToken(null);
747
917
  setTgUser(null);
748
918
  setTgError(null);
749
919
  setEoaError(null);
750
920
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
921
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
751
922
  const existing = loadAgent(address);
752
923
  if (existing && existing.validUntil > Date.now()) {
753
924
  setAgent(existing);
@@ -845,14 +1016,15 @@ function HypurrConnectProvider({
845
1016
  [eoaAddress, config.isTestnet]
846
1017
  );
847
1018
  const logout = useCallback(() => {
848
- setTgLoginData(null);
849
1019
  setTgUser(null);
850
1020
  setTgError(null);
1021
+ setTgAuthToken(null);
851
1022
  setEoaAddress(null);
852
1023
  setAgent(null);
853
1024
  setEoaError(null);
854
1025
  eoaSignerRef.current = null;
855
1026
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
1027
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
856
1028
  }, []);
857
1029
  const value = useMemo(
858
1030
  () => ({
@@ -892,6 +1064,8 @@ function HypurrConnectProvider({
892
1064
  botUsername: config.telegram?.botUsername ?? "",
893
1065
  useWidget: config.telegram?.useWidget ?? false,
894
1066
  authDataMap,
1067
+ authToken: tgAuthToken,
1068
+ telegramRpcOptions,
895
1069
  telegramClient: tgClient,
896
1070
  staticClient
897
1071
  }),
@@ -933,6 +1107,8 @@ function HypurrConnectProvider({
933
1107
  config.telegram?.botUsername,
934
1108
  config.telegram?.useWidget,
935
1109
  authDataMap,
1110
+ tgAuthToken,
1111
+ telegramRpcOptions,
936
1112
  tgClient,
937
1113
  staticClient
938
1114
  ]
@@ -948,7 +1124,6 @@ import {
948
1124
  } from "framer-motion";
949
1125
  import {
950
1126
  useCallback as useCallback2,
951
- useEffect as useEffect3,
952
1127
  useSyncExternalStore
953
1128
  } from "react";
954
1129
 
@@ -1079,53 +1254,8 @@ function TelegramColorIcon({ style }) {
1079
1254
  );
1080
1255
  }
1081
1256
 
1082
- // src/TelegramLoginWidget.tsx
1083
- import { useEffect as useEffect2, useRef as useRef2 } from "react";
1084
- import { jsx as jsx4 } from "react/jsx-runtime";
1085
- var WIDGET_SCRIPT_URL = "https://telegram.org/js/telegram-widget.js?22";
1086
- var CALLBACK_NAME = "__hypurrConnectTelegramAuth";
1087
- function TelegramLoginWidget({
1088
- botUsername,
1089
- onAuth,
1090
- buttonSize = "large",
1091
- cornerRadius,
1092
- showUserPhoto = true,
1093
- requestAccess = true
1094
- }) {
1095
- const containerRef = useRef2(null);
1096
- const onAuthRef = useRef2(onAuth);
1097
- onAuthRef.current = onAuth;
1098
- useEffect2(() => {
1099
- const container = containerRef.current;
1100
- if (!container) return;
1101
- window[CALLBACK_NAME] = (user) => {
1102
- onAuthRef.current(user);
1103
- };
1104
- const script = document.createElement("script");
1105
- script.src = WIDGET_SCRIPT_URL;
1106
- script.async = true;
1107
- script.setAttribute("data-telegram-login", botUsername);
1108
- script.setAttribute("data-size", buttonSize);
1109
- script.setAttribute("data-onauth", `${CALLBACK_NAME}(user)`);
1110
- script.setAttribute("data-userpic", String(showUserPhoto));
1111
- if (requestAccess) {
1112
- script.setAttribute("data-request-access", "write");
1113
- }
1114
- if (cornerRadius !== void 0) {
1115
- script.setAttribute("data-radius", String(cornerRadius));
1116
- }
1117
- container.innerHTML = "";
1118
- container.appendChild(script);
1119
- return () => {
1120
- container.innerHTML = "";
1121
- delete window[CALLBACK_NAME];
1122
- };
1123
- }, [botUsername, buttonSize, cornerRadius, showUserPhoto, requestAccess]);
1124
- return /* @__PURE__ */ jsx4("div", { ref: containerRef });
1125
- }
1126
-
1127
1257
  // src/LoginModal.tsx
1128
- 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";
1129
1259
  var MOBILE_BREAKPOINT = 640;
1130
1260
  var btnStyle = {
1131
1261
  display: "flex",
@@ -1203,7 +1333,7 @@ function HoverButton({
1203
1333
  onClick,
1204
1334
  children
1205
1335
  }) {
1206
- return /* @__PURE__ */ jsx5(
1336
+ return /* @__PURE__ */ jsx4(
1207
1337
  motion.button,
1208
1338
  {
1209
1339
  type: "button",
@@ -1215,61 +1345,14 @@ function HoverButton({
1215
1345
  );
1216
1346
  }
1217
1347
  function LoginModal({ onConnectWallet, walletIcon }) {
1218
- const {
1219
- loginTelegram,
1220
- loginModalOpen,
1221
- closeLoginModal,
1222
- botId,
1223
- botUsername,
1224
- useWidget
1225
- } = useHypurrConnectInternal();
1226
- const handleTelegramAuth = useCallback2(
1227
- (user) => {
1228
- loginTelegram(user);
1229
- closeLoginModal();
1230
- },
1231
- [loginTelegram, closeLoginModal]
1232
- );
1233
- useEffect3(() => {
1234
- if (!loginModalOpen) return;
1235
- function onMessage(e) {
1236
- if (e.origin !== "https://oauth.telegram.org") return;
1237
- try {
1238
- const data = typeof e.data === "string" ? JSON.parse(e.data) : e.data;
1239
- if (data?.event === "auth_result" && data.result) {
1240
- const r = data.result;
1241
- handleTelegramAuth({
1242
- id: r.id,
1243
- first_name: r.first_name ?? "",
1244
- last_name: r.last_name ?? void 0,
1245
- username: r.username ?? void 0,
1246
- photo_url: r.photo_url ?? void 0,
1247
- auth_date: r.auth_date,
1248
- hash: r.hash
1249
- });
1250
- }
1251
- } catch {
1252
- }
1253
- }
1254
- window.addEventListener("message", onMessage);
1255
- return () => window.removeEventListener("message", onMessage);
1256
- }, [loginModalOpen, handleTelegramAuth]);
1257
- const openTelegramOAuth = useCallback2(() => {
1258
- const origin = encodeURIComponent(window.location.origin);
1259
- const url = `https://oauth.telegram.org/auth?bot_id=${botId}&origin=${origin}&request_access=write`;
1260
- const w = 550;
1261
- const h = 470;
1262
- const left = window.screenX + (window.outerWidth - w) / 2;
1263
- const top = window.screenY + (window.outerHeight - h) / 2;
1264
- window.open(
1265
- url,
1266
- "telegram_auth",
1267
- `width=${w},height=${h},left=${left},top=${top}`
1268
- );
1269
- }, [botId]);
1348
+ const { loginTelegram, loginModalOpen, closeLoginModal } = useHypurrConnectInternal();
1349
+ const handleTelegramAuth = useCallback2(() => {
1350
+ closeLoginModal();
1351
+ loginTelegram();
1352
+ }, [loginTelegram, closeLoginModal]);
1270
1353
  const isMobile = useIsMobile();
1271
1354
  const modalContent = /* @__PURE__ */ jsxs3(Fragment, { children: [
1272
- /* @__PURE__ */ jsx5(
1355
+ /* @__PURE__ */ jsx4(
1273
1356
  "div",
1274
1357
  {
1275
1358
  style: {
@@ -1280,19 +1363,13 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1280
1363
  gap: 8,
1281
1364
  overflow: "hidden"
1282
1365
  },
1283
- children: useWidget && botUsername ? /* @__PURE__ */ jsx5(
1284
- TelegramLoginWidget,
1285
- {
1286
- botUsername,
1287
- onAuth: handleTelegramAuth
1288
- }
1289
- ) : /* @__PURE__ */ jsxs3(HoverButton, { onClick: openTelegramOAuth, children: [
1290
- /* @__PURE__ */ jsx5(TelegramColorIcon, { style: iconSize }),
1366
+ children: /* @__PURE__ */ jsxs3(HoverButton, { onClick: handleTelegramAuth, children: [
1367
+ /* @__PURE__ */ jsx4(TelegramColorIcon, { style: iconSize }),
1291
1368
  "Telegram"
1292
1369
  ] })
1293
1370
  }
1294
1371
  ),
1295
- /* @__PURE__ */ jsx5("div", { style: dividerStyle }),
1372
+ /* @__PURE__ */ jsx4("div", { style: dividerStyle }),
1296
1373
  /* @__PURE__ */ jsxs3(
1297
1374
  HoverButton,
1298
1375
  {
@@ -1301,14 +1378,14 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1301
1378
  onConnectWallet();
1302
1379
  },
1303
1380
  children: [
1304
- walletIcon ?? /* @__PURE__ */ jsx5(MetaMaskColorIcon, { style: iconSize }),
1381
+ walletIcon ?? /* @__PURE__ */ jsx4(MetaMaskColorIcon, { style: iconSize }),
1305
1382
  "Wallet"
1306
1383
  ]
1307
1384
  }
1308
1385
  )
1309
1386
  ] });
1310
- return /* @__PURE__ */ jsx5(AnimatePresence, { children: loginModalOpen && (isMobile ? /* @__PURE__ */ jsx5(MobileDrawer, { onClose: closeLoginModal, children: modalContent }, "drawer") : /* @__PURE__ */ jsxs3(Fragment, { children: [
1311
- /* @__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(
1312
1389
  motion.div,
1313
1390
  {
1314
1391
  style: backdropStyle,
@@ -1320,7 +1397,7 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1320
1397
  },
1321
1398
  "backdrop"
1322
1399
  ),
1323
- /* @__PURE__ */ jsx5(
1400
+ /* @__PURE__ */ jsx4(
1324
1401
  motion.div,
1325
1402
  {
1326
1403
  style: modalWrapperStyle,
@@ -1333,13 +1410,13 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1333
1410
  motion.div,
1334
1411
  {
1335
1412
  style: modalBoxStyle,
1336
- initial: { opacity: 0, scale: 0.95, y: 10 },
1337
- animate: { opacity: 1, scale: 1, y: 0 },
1338
- exit: { opacity: 0, scale: 0.95, y: 10 },
1339
- 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 },
1340
1417
  onClick: (e) => e.stopPropagation(),
1341
1418
  children: [
1342
- /* @__PURE__ */ jsx5("p", { style: headingStyle, children: "Connect" }),
1419
+ /* @__PURE__ */ jsx4("h2", { style: headingStyle, children: "Connect" }),
1343
1420
  modalContent
1344
1421
  ]
1345
1422
  }
@@ -1406,7 +1483,7 @@ function MobileDrawer({
1406
1483
  [onClose, controls]
1407
1484
  );
1408
1485
  return /* @__PURE__ */ jsxs3(Fragment, { children: [
1409
- /* @__PURE__ */ jsx5(
1486
+ /* @__PURE__ */ jsx4(
1410
1487
  motion.div,
1411
1488
  {
1412
1489
  style: backdropStyle,
@@ -1431,9 +1508,9 @@ function MobileDrawer({
1431
1508
  dragElastic: { top: 0, bottom: 0.4 },
1432
1509
  onDragEnd: handleDragEnd,
1433
1510
  children: [
1434
- /* @__PURE__ */ jsx5("div", { style: drawerBgStyle }),
1435
- /* @__PURE__ */ jsx5("div", { style: grabHandleAreaStyle, children: /* @__PURE__ */ jsx5("div", { style: grabHandleStyle }) }),
1436
- /* @__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" }),
1437
1514
  children
1438
1515
  ]
1439
1516
  },
@@ -1454,7 +1531,6 @@ export {
1454
1531
  GrpcExchangeTransport,
1455
1532
  HypurrConnectProvider,
1456
1533
  LoginModal,
1457
- TelegramLoginWidget,
1458
1534
  createEoaSigner,
1459
1535
  createStaticClient,
1460
1536
  createTelegramClient,