@hfunlabs/hypurr-connect 0.1.9 → 0.1.11

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,57 @@ 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://auth.hypurr.fun/login";
190
+ var DEFAULT_MEDIA_URL = "https://media.hypurr.fun";
191
+ var DEFAULT_TELEGRAM_SCOPES = [
192
+ "telegram:user:read",
193
+ "telegram:wallet:read",
194
+ "telegram:wallet:write",
195
+ "telegram:trade:read",
196
+ "telegram:trade:write",
197
+ "telegram:cabal:read",
198
+ "telegram:cabal:write",
199
+ "telegram:agent:write"
200
+ ];
190
201
  function isInvalidTelegramAuthError(err) {
191
202
  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);
203
+ return /invalid telegram auth data|invalid auth token|missing authorization token/i.test(
204
+ msg
205
+ );
206
+ }
207
+ function normalizeMediaUrl(mediaUrl) {
208
+ return (mediaUrl?.trim() || DEFAULT_MEDIA_URL).replace(/\/+$/, "");
209
+ }
210
+ function currentReturnTo() {
211
+ const url = new URL(window.location.href);
212
+ for (const param of [
213
+ "token",
214
+ "token_type",
215
+ "token_source",
216
+ "state",
217
+ "scope"
218
+ ]) {
219
+ url.searchParams.delete(param);
220
+ }
221
+ return url.toString();
222
+ }
223
+ function randomState() {
224
+ const bytes = new Uint8Array(16);
225
+ crypto.getRandomValues(bytes);
226
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(
227
+ ""
228
+ );
229
+ }
230
+ function normalizeScopes(scope) {
231
+ if (Array.isArray(scope)) return scope.join(" ");
232
+ return scope?.trim() || DEFAULT_TELEGRAM_SCOPES.join(" ");
233
+ }
234
+ function isTelegramAuthMessage(data) {
235
+ 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
236
  }
194
237
  var HypurrConnectContext = createContext(null);
195
238
  function useHypurrConnect() {
@@ -214,43 +257,103 @@ function HypurrConnectProvider({
214
257
  }) {
215
258
  const tgClient = useMemo(() => createTelegramClient(config), [config]);
216
259
  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
- }
260
+ const [tgAuthToken, setTgAuthToken] = useState(() => {
261
+ try {
262
+ return localStorage.getItem(TELEGRAM_STORAGE_KEY);
263
+ } catch {
264
+ return null;
225
265
  }
226
- );
266
+ });
227
267
  const [tgUser, setTgUser] = useState(null);
228
268
  const [tgLoading, setTgLoading] = useState(false);
229
269
  const [tgError, setTgError] = useState(null);
230
- const authDataMap = useMemo(
231
- () => tgLoginData ? toAuthDataMap(tgLoginData) : {},
232
- [tgLoginData]
270
+ const authDataMap = useMemo(() => ({}), []);
271
+ const telegramRpcOptions = useMemo(
272
+ () => tgAuthToken ? { meta: { authorization: `Bearer ${tgAuthToken}` } } : void 0,
273
+ [tgAuthToken]
233
274
  );
234
275
  const [tgUserTick, setTgUserTick] = useState(0);
235
276
  const onInvalidAuthRef = useRef(null);
236
277
  onInvalidAuthRef.current = () => {
237
- console.warn("[HypurrConnect] Invalid telegram auth data \u2014 disconnecting.");
238
- setTgLoginData(null);
278
+ console.warn(
279
+ "[HypurrConnect] Invalid Telegram auth token \u2014 disconnecting."
280
+ );
281
+ setTgAuthToken(null);
239
282
  setTgUser(null);
240
283
  setTgError(null);
241
284
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
285
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
242
286
  };
287
+ const acceptTelegramToken = useCallback((token) => {
288
+ setTgAuthToken(token);
289
+ setTgError(null);
290
+ localStorage.setItem(TELEGRAM_STORAGE_KEY, token);
291
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
292
+ }, []);
243
293
  useEffect(() => {
244
- if (!tgLoginData) return;
294
+ const params = new URLSearchParams(window.location.search);
295
+ const token = params.get("token");
296
+ if (!token) {
297
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
298
+ return;
299
+ }
300
+ const callbackState = params.get("state") ?? "";
301
+ if (window.opener && window.opener !== window) {
302
+ window.opener.postMessage(
303
+ {
304
+ type: TELEGRAM_AUTH_MESSAGE,
305
+ token,
306
+ state: callbackState
307
+ },
308
+ window.location.origin
309
+ );
310
+ window.close();
311
+ return;
312
+ }
313
+ const expectedState = sessionStorage.getItem(TELEGRAM_AUTH_STATE_KEY);
314
+ sessionStorage.removeItem(TELEGRAM_AUTH_STATE_KEY);
315
+ if (!expectedState || callbackState !== expectedState) {
316
+ setTgError("Invalid auth callback state.");
317
+ return;
318
+ }
319
+ acceptTelegramToken(token);
320
+ const cleanUrl = new URL(window.location.href);
321
+ for (const param of [
322
+ "token",
323
+ "token_type",
324
+ "token_source",
325
+ "state",
326
+ "scope"
327
+ ]) {
328
+ cleanUrl.searchParams.delete(param);
329
+ }
330
+ window.history.replaceState({}, document.title, cleanUrl.toString());
331
+ }, [acceptTelegramToken]);
332
+ useEffect(() => {
333
+ function onMessage(event) {
334
+ if (event.origin !== window.location.origin) return;
335
+ if (!isTelegramAuthMessage(event.data)) return;
336
+ const expectedState = sessionStorage.getItem(TELEGRAM_AUTH_STATE_KEY);
337
+ sessionStorage.removeItem(TELEGRAM_AUTH_STATE_KEY);
338
+ if (!expectedState || event.data.state !== expectedState) {
339
+ setTgError("Invalid auth callback state.");
340
+ return;
341
+ }
342
+ acceptTelegramToken(event.data.token);
343
+ }
344
+ window.addEventListener("message", onMessage);
345
+ return () => window.removeEventListener("message", onMessage);
346
+ }, [acceptTelegramToken]);
347
+ useEffect(() => {
348
+ if (!tgAuthToken || !telegramRpcOptions) return;
245
349
  let cancelled = false;
246
350
  setTgLoading(true);
247
351
  setTgError(null);
248
352
  (async () => {
249
353
  try {
250
- const authData = toAuthDataMap(tgLoginData);
251
354
  const [{ response: userResp }, { response: walletsResp }] = await Promise.all([
252
- tgClient.telegramUser({ authData }),
253
- tgClient.telegramUserWallets({ authData })
355
+ tgClient.telegramUser({ authData: {} }, telegramRpcOptions),
356
+ tgClient.telegramUserWallets({ authData: {} }, telegramRpcOptions)
254
357
  ]);
255
358
  if (cancelled) return;
256
359
  const user2 = userResp.user ?? null;
@@ -273,13 +376,13 @@ function HypurrConnectProvider({
273
376
  return () => {
274
377
  cancelled = true;
275
378
  };
276
- }, [tgLoginData, tgClient, tgUserTick]);
379
+ }, [tgAuthToken, telegramRpcOptions, tgClient, tgUserTick]);
277
380
  const [eoaAddress, setEoaAddress] = useState(null);
278
381
  const [agent, setAgent] = useState(null);
279
382
  const [eoaLoading, setEoaLoading] = useState(false);
280
383
  const [eoaError, setEoaError] = useState(null);
281
384
  const eoaSignerRef = useRef(null);
282
- const authMethod = tgLoginData ? "telegram" : eoaAddress ? "eoa" : null;
385
+ const authMethod = tgAuthToken ? "telegram" : eoaAddress ? "eoa" : null;
283
386
  const [wallets, setWallets] = useState([]);
284
387
  const [selectedWalletId, setSelectedWalletId] = useState(0);
285
388
  const [packs, setPacks] = useState([]);
@@ -319,14 +422,20 @@ function HypurrConnectProvider({
319
422
  const poll = async () => {
320
423
  try {
321
424
  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
- })
425
+ tgClient.hyperliquidWalletTwapSessions(
426
+ {
427
+ authData: {},
428
+ walletId: selectedWalletId
429
+ },
430
+ telegramRpcOptions
431
+ ),
432
+ tgClient.hyperliquidWalletScaleSessions(
433
+ {
434
+ authData: {},
435
+ walletId: selectedWalletId
436
+ },
437
+ telegramRpcOptions
438
+ )
330
439
  ]);
331
440
  if (cancelled) return;
332
441
  setWallets(
@@ -351,16 +460,23 @@ function HypurrConnectProvider({
351
460
  cancelled = true;
352
461
  clearInterval(id);
353
462
  };
354
- }, [authMethod, selectedWalletId, pollInterval, tgClient, authDataMap]);
463
+ }, [
464
+ authMethod,
465
+ selectedWalletId,
466
+ pollInterval,
467
+ tgClient,
468
+ telegramRpcOptions
469
+ ]);
355
470
  const user = useMemo(() => {
356
- if (tgLoginData && authMethod === "telegram" && selectedWallet) {
471
+ if (tgAuthToken && authMethod === "telegram" && selectedWallet && tgUser) {
472
+ const mediaUrl = normalizeMediaUrl(config.mediaUrl);
357
473
  return {
358
474
  address: selectedWallet.ethereumAddress,
359
475
  walletId: selectedWallet.id,
360
- displayName: tgLoginData.username ? `@${tgLoginData.username}` : tgLoginData.first_name,
361
- photoUrl: tgLoginData.photo_url,
476
+ displayName: tgUser.telegramUsername ? `@${tgUser.telegramUsername}` : `Telegram ${tgUser.telegramId}`,
477
+ photoUrl: tgUser.pictureFileId ? `${mediaUrl}/${tgUser.pictureFileId}` : void 0,
362
478
  authMethod: "telegram",
363
- telegramId: String(tgLoginData.id),
479
+ telegramId: String(tgUser.telegramId),
364
480
  hfunScore: tgUser?.reputation?.hfunScore,
365
481
  reputationScore: tgUser?.reputation?.reputationScore
366
482
  };
@@ -374,7 +490,14 @@ function HypurrConnectProvider({
374
490
  };
375
491
  }
376
492
  return null;
377
- }, [tgLoginData, selectedWallet, eoaAddress, authMethod, tgUser]);
493
+ }, [
494
+ tgAuthToken,
495
+ selectedWallet,
496
+ eoaAddress,
497
+ authMethod,
498
+ tgUser,
499
+ config.mediaUrl
500
+ ]);
378
501
  const onDeadAgentRef = useRef(
379
502
  null
380
503
  );
@@ -396,7 +519,7 @@ function HypurrConnectProvider({
396
519
  const transport = new GrpcExchangeTransport({
397
520
  isTestnet: config.isTestnet ?? false,
398
521
  telegramClient: tgClient,
399
- authDataMap,
522
+ rpcOptions: telegramRpcOptions,
400
523
  walletId: user.walletId,
401
524
  onAuthError: () => onInvalidAuthRef.current?.()
402
525
  });
@@ -553,7 +676,7 @@ function HypurrConnectProvider({
553
676
  eoaAddress,
554
677
  config.isTestnet,
555
678
  tgClient,
556
- authDataMap
679
+ telegramRpcOptions
557
680
  ]);
558
681
  const handleClearAgent = useCallback(() => {
559
682
  if (eoaAddress) {
@@ -563,79 +686,100 @@ function HypurrConnectProvider({
563
686
  }, [eoaAddress]);
564
687
  const createWallet = useCallback(
565
688
  async (name) => {
566
- const { response } = await tgClient.hyperliquidWalletCreate({
567
- authData: authDataMap,
568
- name
569
- });
689
+ const { response } = await tgClient.hyperliquidWalletCreate(
690
+ {
691
+ authData: {},
692
+ name
693
+ },
694
+ telegramRpcOptions
695
+ );
570
696
  refreshWallets();
571
697
  if (!response.wallet)
572
698
  throw new Error("Wallet creation returned no wallet");
573
699
  return response.wallet;
574
700
  },
575
- [tgClient, authDataMap, refreshWallets]
701
+ [tgClient, telegramRpcOptions, refreshWallets]
576
702
  );
577
703
  const deleteWallet = useCallback(
578
704
  async (walletId) => {
579
- await tgClient.hyperliquidWalletDelete({
580
- authData: authDataMap,
581
- walletId
582
- });
705
+ await tgClient.hyperliquidWalletDelete(
706
+ {
707
+ authData: {},
708
+ walletId
709
+ },
710
+ telegramRpcOptions
711
+ );
583
712
  if (walletId === selectedWalletId) {
584
713
  const remaining = wallets.filter((w) => w.id !== walletId);
585
714
  setSelectedWalletId(remaining[0]?.id ?? 0);
586
715
  }
587
716
  refreshWallets();
588
717
  },
589
- [tgClient, authDataMap, selectedWalletId, wallets, refreshWallets]
718
+ [tgClient, telegramRpcOptions, selectedWalletId, wallets, refreshWallets]
590
719
  );
591
720
  const createWalletPack = useCallback(
592
721
  async (name) => {
593
- const { response } = await tgClient.telegramChatWalletPackCreate({
594
- authData: authDataMap,
595
- name
596
- });
722
+ const { response } = await tgClient.telegramChatWalletPackCreate(
723
+ {
724
+ authData: {},
725
+ name
726
+ },
727
+ telegramRpcOptions
728
+ );
597
729
  refreshWallets();
598
730
  return response.packId;
599
731
  },
600
- [tgClient, authDataMap, refreshWallets]
732
+ [tgClient, telegramRpcOptions, refreshWallets]
601
733
  );
602
734
  const addPackLabel = useCallback(
603
735
  async (params) => {
604
- await tgClient.telegramChatWalletPackLabelAdd({
605
- authData: authDataMap,
606
- ...params
607
- });
736
+ await tgClient.telegramChatWalletPackLabelAdd(
737
+ {
738
+ authData: {},
739
+ ...params
740
+ },
741
+ telegramRpcOptions
742
+ );
608
743
  refreshWallets();
609
744
  },
610
- [tgClient, authDataMap, refreshWallets]
745
+ [tgClient, telegramRpcOptions, refreshWallets]
611
746
  );
612
747
  const modifyPackLabel = useCallback(
613
748
  async (params) => {
614
- await tgClient.telegramChatWalletPackLabelModify({
615
- authData: authDataMap,
616
- ...params
617
- });
749
+ await tgClient.telegramChatWalletPackLabelModify(
750
+ {
751
+ authData: {},
752
+ ...params
753
+ },
754
+ telegramRpcOptions
755
+ );
618
756
  refreshWallets();
619
757
  },
620
- [tgClient, authDataMap, refreshWallets]
758
+ [tgClient, telegramRpcOptions, refreshWallets]
621
759
  );
622
760
  const removePackLabel = useCallback(
623
761
  async (params) => {
624
- await tgClient.telegramChatWalletPackLabelRemove({
625
- authData: authDataMap,
626
- ...params
627
- });
762
+ await tgClient.telegramChatWalletPackLabelRemove(
763
+ {
764
+ authData: {},
765
+ ...params
766
+ },
767
+ telegramRpcOptions
768
+ );
628
769
  refreshWallets();
629
770
  },
630
- [tgClient, authDataMap, refreshWallets]
771
+ [tgClient, telegramRpcOptions, refreshWallets]
631
772
  );
632
773
  const createTwap = useCallback(
633
774
  async (params) => {
634
- const { response } = await tgClient.hyperliquidTwapCreate({
635
- authData: authDataMap,
636
- walletId: selectedWalletId,
637
- ...params
638
- });
775
+ const { response } = await tgClient.hyperliquidTwapCreate(
776
+ {
777
+ authData: {},
778
+ walletId: selectedWalletId,
779
+ ...params
780
+ },
781
+ telegramRpcOptions
782
+ );
639
783
  if (!response.session)
640
784
  throw new Error("TWAP creation returned no session");
641
785
  const session = response.session;
@@ -646,17 +790,19 @@ function HypurrConnectProvider({
646
790
  );
647
791
  return session;
648
792
  },
649
- [tgClient, authDataMap, selectedWalletId]
793
+ [tgClient, telegramRpcOptions, selectedWalletId]
650
794
  );
651
795
  const modifyTwap = useCallback(
652
796
  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");
797
+ const { response } = await tgClient.hyperliquidTwapModify(
798
+ {
799
+ authData: {},
800
+ walletId: selectedWalletId,
801
+ ...params
802
+ },
803
+ telegramRpcOptions
804
+ );
805
+ if (!response.session) throw new Error("TWAP modify returned no session");
660
806
  const session = response.session;
661
807
  setWallets(
662
808
  (prev) => prev.map(
@@ -670,15 +816,18 @@ function HypurrConnectProvider({
670
816
  );
671
817
  return session;
672
818
  },
673
- [tgClient, authDataMap, selectedWalletId]
819
+ [tgClient, telegramRpcOptions, selectedWalletId]
674
820
  );
675
821
  const cancelTwap = useCallback(
676
822
  async (sessionId) => {
677
- await tgClient.hyperliquidTwapCancel({
678
- authData: authDataMap,
679
- walletId: selectedWalletId,
680
- twapSessionId: sessionId
681
- });
823
+ await tgClient.hyperliquidTwapCancel(
824
+ {
825
+ authData: {},
826
+ walletId: selectedWalletId,
827
+ twapSessionId: sessionId
828
+ },
829
+ telegramRpcOptions
830
+ );
682
831
  setWallets(
683
832
  (prev) => prev.map(
684
833
  (w) => w.id === selectedWalletId ? {
@@ -688,15 +837,18 @@ function HypurrConnectProvider({
688
837
  )
689
838
  );
690
839
  },
691
- [tgClient, authDataMap, selectedWalletId]
840
+ [tgClient, telegramRpcOptions, selectedWalletId]
692
841
  );
693
842
  const createScale = useCallback(
694
843
  async (params) => {
695
- const { response } = await tgClient.hyperliquidScaleCreate({
696
- authData: authDataMap,
697
- walletId: selectedWalletId,
698
- ...params
699
- });
844
+ const { response } = await tgClient.hyperliquidScaleCreate(
845
+ {
846
+ authData: {},
847
+ walletId: selectedWalletId,
848
+ ...params
849
+ },
850
+ telegramRpcOptions
851
+ );
700
852
  if (!response.session)
701
853
  throw new Error("Scale creation returned no session");
702
854
  const session = response.session;
@@ -707,15 +859,18 @@ function HypurrConnectProvider({
707
859
  );
708
860
  return session;
709
861
  },
710
- [tgClient, authDataMap, selectedWalletId]
862
+ [tgClient, telegramRpcOptions, selectedWalletId]
711
863
  );
712
864
  const cancelScale = useCallback(
713
865
  async (sessionId) => {
714
- await tgClient.hyperliquidScaleCancel({
715
- authData: authDataMap,
716
- walletId: selectedWalletId,
717
- scaleSessionId: sessionId
718
- });
866
+ await tgClient.hyperliquidScaleCancel(
867
+ {
868
+ authData: {},
869
+ walletId: selectedWalletId,
870
+ scaleSessionId: sessionId
871
+ },
872
+ telegramRpcOptions
873
+ );
719
874
  setWallets(
720
875
  (prev) => prev.map(
721
876
  (w) => w.id === selectedWalletId ? {
@@ -727,27 +882,56 @@ function HypurrConnectProvider({
727
882
  )
728
883
  );
729
884
  },
730
- [tgClient, authDataMap, selectedWalletId]
885
+ [tgClient, telegramRpcOptions, selectedWalletId]
731
886
  );
732
887
  const [loginModalOpen, setLoginModalOpen] = useState(false);
733
888
  const openLoginModal = useCallback(() => setLoginModalOpen(true), []);
734
889
  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
- }, []);
890
+ const loginTelegram = useCallback(() => {
891
+ const state = randomState();
892
+ sessionStorage.setItem(TELEGRAM_AUTH_STATE_KEY, state);
893
+ const configuredReturnTo = config.telegram.returnTo;
894
+ const returnTo = typeof configuredReturnTo === "function" ? configuredReturnTo() : configuredReturnTo || currentReturnTo();
895
+ const authUrl = new URL(config.telegram.authHubUrl || DEFAULT_AUTH_HUB_URL);
896
+ authUrl.searchParams.set("return_to", returnTo);
897
+ authUrl.searchParams.set("state", state);
898
+ authUrl.searchParams.set("scope", normalizeScopes(config.telegram.scope));
899
+ const width = 520;
900
+ const height = 720;
901
+ const left = window.screenX + Math.max(0, (window.outerWidth - width) / 2);
902
+ const top = window.screenY + Math.max(0, (window.outerHeight - height) / 2);
903
+ const popup = window.open(
904
+ authUrl.toString(),
905
+ "hypurr_telegram_auth",
906
+ [
907
+ `width=${width}`,
908
+ `height=${height}`,
909
+ `left=${Math.round(left)}`,
910
+ `top=${Math.round(top)}`,
911
+ "resizable=yes",
912
+ "scrollbars=yes"
913
+ ].join(",")
914
+ );
915
+ if (popup) {
916
+ popup.focus();
917
+ return;
918
+ }
919
+ window.location.assign(authUrl.toString());
920
+ }, [
921
+ config.telegram.authHubUrl,
922
+ config.telegram.returnTo,
923
+ config.telegram.scope
924
+ ]);
742
925
  const connectEoa = useCallback(
743
926
  (address, signer) => {
744
927
  eoaSignerRef.current = signer ?? null;
745
928
  setEoaAddress(address);
746
- setTgLoginData(null);
929
+ setTgAuthToken(null);
747
930
  setTgUser(null);
748
931
  setTgError(null);
749
932
  setEoaError(null);
750
933
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
934
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
751
935
  const existing = loadAgent(address);
752
936
  if (existing && existing.validUntil > Date.now()) {
753
937
  setAgent(existing);
@@ -845,14 +1029,15 @@ function HypurrConnectProvider({
845
1029
  [eoaAddress, config.isTestnet]
846
1030
  );
847
1031
  const logout = useCallback(() => {
848
- setTgLoginData(null);
849
1032
  setTgUser(null);
850
1033
  setTgError(null);
1034
+ setTgAuthToken(null);
851
1035
  setEoaAddress(null);
852
1036
  setAgent(null);
853
1037
  setEoaError(null);
854
1038
  eoaSignerRef.current = null;
855
1039
  localStorage.removeItem(TELEGRAM_STORAGE_KEY);
1040
+ localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
856
1041
  }, []);
857
1042
  const value = useMemo(
858
1043
  () => ({
@@ -892,6 +1077,8 @@ function HypurrConnectProvider({
892
1077
  botUsername: config.telegram?.botUsername ?? "",
893
1078
  useWidget: config.telegram?.useWidget ?? false,
894
1079
  authDataMap,
1080
+ authToken: tgAuthToken,
1081
+ telegramRpcOptions,
895
1082
  telegramClient: tgClient,
896
1083
  staticClient
897
1084
  }),
@@ -933,6 +1120,8 @@ function HypurrConnectProvider({
933
1120
  config.telegram?.botUsername,
934
1121
  config.telegram?.useWidget,
935
1122
  authDataMap,
1123
+ tgAuthToken,
1124
+ telegramRpcOptions,
936
1125
  tgClient,
937
1126
  staticClient
938
1127
  ]
@@ -948,7 +1137,6 @@ import {
948
1137
  } from "framer-motion";
949
1138
  import {
950
1139
  useCallback as useCallback2,
951
- useEffect as useEffect3,
952
1140
  useSyncExternalStore
953
1141
  } from "react";
954
1142
 
@@ -1079,53 +1267,8 @@ function TelegramColorIcon({ style }) {
1079
1267
  );
1080
1268
  }
1081
1269
 
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
1270
  // src/LoginModal.tsx
1128
- import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1271
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1129
1272
  var MOBILE_BREAKPOINT = 640;
1130
1273
  var btnStyle = {
1131
1274
  display: "flex",
@@ -1203,7 +1346,7 @@ function HoverButton({
1203
1346
  onClick,
1204
1347
  children
1205
1348
  }) {
1206
- return /* @__PURE__ */ jsx5(
1349
+ return /* @__PURE__ */ jsx4(
1207
1350
  motion.button,
1208
1351
  {
1209
1352
  type: "button",
@@ -1215,61 +1358,14 @@ function HoverButton({
1215
1358
  );
1216
1359
  }
1217
1360
  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]);
1361
+ const { loginTelegram, loginModalOpen, closeLoginModal } = useHypurrConnectInternal();
1362
+ const handleTelegramAuth = useCallback2(() => {
1363
+ closeLoginModal();
1364
+ loginTelegram();
1365
+ }, [loginTelegram, closeLoginModal]);
1270
1366
  const isMobile = useIsMobile();
1271
1367
  const modalContent = /* @__PURE__ */ jsxs3(Fragment, { children: [
1272
- /* @__PURE__ */ jsx5(
1368
+ /* @__PURE__ */ jsx4(
1273
1369
  "div",
1274
1370
  {
1275
1371
  style: {
@@ -1280,19 +1376,13 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1280
1376
  gap: 8,
1281
1377
  overflow: "hidden"
1282
1378
  },
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 }),
1379
+ children: /* @__PURE__ */ jsxs3(HoverButton, { onClick: handleTelegramAuth, children: [
1380
+ /* @__PURE__ */ jsx4(TelegramColorIcon, { style: iconSize }),
1291
1381
  "Telegram"
1292
1382
  ] })
1293
1383
  }
1294
1384
  ),
1295
- /* @__PURE__ */ jsx5("div", { style: dividerStyle }),
1385
+ /* @__PURE__ */ jsx4("div", { style: dividerStyle }),
1296
1386
  /* @__PURE__ */ jsxs3(
1297
1387
  HoverButton,
1298
1388
  {
@@ -1301,14 +1391,14 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1301
1391
  onConnectWallet();
1302
1392
  },
1303
1393
  children: [
1304
- walletIcon ?? /* @__PURE__ */ jsx5(MetaMaskColorIcon, { style: iconSize }),
1394
+ walletIcon ?? /* @__PURE__ */ jsx4(MetaMaskColorIcon, { style: iconSize }),
1305
1395
  "Wallet"
1306
1396
  ]
1307
1397
  }
1308
1398
  )
1309
1399
  ] });
1310
- return /* @__PURE__ */ jsx5(AnimatePresence, { children: loginModalOpen && (isMobile ? /* @__PURE__ */ jsx5(MobileDrawer, { onClose: closeLoginModal, children: modalContent }, "drawer") : /* @__PURE__ */ jsxs3(Fragment, { children: [
1311
- /* @__PURE__ */ jsx5(
1400
+ return /* @__PURE__ */ jsx4(AnimatePresence, { children: loginModalOpen && (isMobile ? /* @__PURE__ */ jsx4(MobileDrawer, { onClose: closeLoginModal, children: modalContent }, "drawer") : /* @__PURE__ */ jsxs3(Fragment, { children: [
1401
+ /* @__PURE__ */ jsx4(
1312
1402
  motion.div,
1313
1403
  {
1314
1404
  style: backdropStyle,
@@ -1320,7 +1410,7 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1320
1410
  },
1321
1411
  "backdrop"
1322
1412
  ),
1323
- /* @__PURE__ */ jsx5(
1413
+ /* @__PURE__ */ jsx4(
1324
1414
  motion.div,
1325
1415
  {
1326
1416
  style: modalWrapperStyle,
@@ -1333,13 +1423,13 @@ function LoginModal({ onConnectWallet, walletIcon }) {
1333
1423
  motion.div,
1334
1424
  {
1335
1425
  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" },
1426
+ initial: { scale: 0.96, opacity: 0, y: 8 },
1427
+ animate: { scale: 1, opacity: 1, y: 0 },
1428
+ exit: { scale: 0.96, opacity: 0, y: 8 },
1429
+ transition: { duration: 0.12 },
1340
1430
  onClick: (e) => e.stopPropagation(),
1341
1431
  children: [
1342
- /* @__PURE__ */ jsx5("p", { style: headingStyle, children: "Connect" }),
1432
+ /* @__PURE__ */ jsx4("h2", { style: headingStyle, children: "Connect" }),
1343
1433
  modalContent
1344
1434
  ]
1345
1435
  }
@@ -1406,7 +1496,7 @@ function MobileDrawer({
1406
1496
  [onClose, controls]
1407
1497
  );
1408
1498
  return /* @__PURE__ */ jsxs3(Fragment, { children: [
1409
- /* @__PURE__ */ jsx5(
1499
+ /* @__PURE__ */ jsx4(
1410
1500
  motion.div,
1411
1501
  {
1412
1502
  style: backdropStyle,
@@ -1431,9 +1521,9 @@ function MobileDrawer({
1431
1521
  dragElastic: { top: 0, bottom: 0.4 },
1432
1522
  onDragEnd: handleDragEnd,
1433
1523
  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" }),
1524
+ /* @__PURE__ */ jsx4("div", { style: drawerBgStyle }),
1525
+ /* @__PURE__ */ jsx4("div", { style: grabHandleAreaStyle, children: /* @__PURE__ */ jsx4("div", { style: grabHandleStyle }) }),
1526
+ /* @__PURE__ */ jsx4("p", { style: headingStyle, children: "Connect" }),
1437
1527
  children
1438
1528
  ]
1439
1529
  },
@@ -1454,7 +1544,6 @@ export {
1454
1544
  GrpcExchangeTransport,
1455
1545
  HypurrConnectProvider,
1456
1546
  LoginModal,
1457
- TelegramLoginWidget,
1458
1547
  createEoaSigner,
1459
1548
  createStaticClient,
1460
1549
  createTelegramClient,