@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/README.md +80 -64
- package/dist/index.d.ts +21 -15
- package/dist/index.js +333 -257
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/GrpcExchangeTransport.ts +16 -10
- package/src/HypurrConnectProvider.tsx +341 -129
- package/src/LoginModal.tsx +15 -74
- package/src/grpc.ts +2 -2
- package/src/index.ts +0 -2
- package/src/types.ts +27 -5
|
@@ -3,7 +3,11 @@ import {
|
|
|
3
3
|
HttpTransport,
|
|
4
4
|
type IRequestTransport,
|
|
5
5
|
} from "@hfunlabs/hyperliquid";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
PrivateKeySigner,
|
|
8
|
+
signUserSignedAction,
|
|
9
|
+
} from "@hfunlabs/hyperliquid/signing";
|
|
10
|
+
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
|
7
11
|
import type { TelegramUserResponse } from "hypurr-grpc/ts/hypurr/telegram/telegram_service";
|
|
8
12
|
import type {
|
|
9
13
|
TelegramUser as HypurrTelegramUser,
|
|
@@ -40,30 +44,30 @@ import type {
|
|
|
40
44
|
HypurrUser,
|
|
41
45
|
SignTypedDataFn,
|
|
42
46
|
StoredAgent,
|
|
43
|
-
TelegramLoginData,
|
|
44
47
|
} from "./types";
|
|
45
48
|
|
|
46
49
|
/** @internal context value — extends the public type with fields used only by library internals */
|
|
47
50
|
interface InternalConnectState extends HypurrConnectState {
|
|
48
|
-
loginTelegram: (
|
|
51
|
+
loginTelegram: () => void;
|
|
49
52
|
botUsername: string;
|
|
50
53
|
useWidget: boolean;
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
const TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
const TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-jwt";
|
|
57
|
+
const LEGACY_TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-user";
|
|
58
|
+
const TELEGRAM_AUTH_STATE_KEY = "hypurr-connect-auth-state";
|
|
59
|
+
const TELEGRAM_AUTH_MESSAGE = "hypurr-connect:telegram-auth";
|
|
60
|
+
const DEFAULT_AUTH_HUB_URL = "https://127.0.0.1:443/login";
|
|
61
|
+
const DEFAULT_TELEGRAM_SCOPES = [
|
|
62
|
+
"telegram:user:read",
|
|
63
|
+
"telegram:wallet:read",
|
|
64
|
+
"telegram:wallet:write",
|
|
65
|
+
"telegram:trade:read",
|
|
66
|
+
"telegram:trade:write",
|
|
67
|
+
"telegram:cabal:read",
|
|
68
|
+
"telegram:cabal:write",
|
|
69
|
+
"telegram:agent:write",
|
|
70
|
+
];
|
|
67
71
|
|
|
68
72
|
function isInvalidTelegramAuthError(err: unknown): boolean {
|
|
69
73
|
const msg =
|
|
@@ -72,7 +76,55 @@ function isInvalidTelegramAuthError(err: unknown): boolean {
|
|
|
72
76
|
: typeof err === "object" && err !== null && "message" in err
|
|
73
77
|
? String((err as { message: unknown }).message)
|
|
74
78
|
: String(err);
|
|
75
|
-
return /invalid telegram auth data/i.test(
|
|
79
|
+
return /invalid telegram auth data|invalid auth token|missing authorization token/i.test(
|
|
80
|
+
msg,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function currentReturnTo(): string {
|
|
85
|
+
const url = new URL(window.location.href);
|
|
86
|
+
for (const param of [
|
|
87
|
+
"token",
|
|
88
|
+
"token_type",
|
|
89
|
+
"token_source",
|
|
90
|
+
"state",
|
|
91
|
+
"scope",
|
|
92
|
+
]) {
|
|
93
|
+
url.searchParams.delete(param);
|
|
94
|
+
}
|
|
95
|
+
return url.toString();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function randomState(): string {
|
|
99
|
+
const bytes = new Uint8Array(16);
|
|
100
|
+
crypto.getRandomValues(bytes);
|
|
101
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
102
|
+
"",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function normalizeScopes(scope?: string | string[]): string {
|
|
107
|
+
if (Array.isArray(scope)) return scope.join(" ");
|
|
108
|
+
return scope?.trim() || DEFAULT_TELEGRAM_SCOPES.join(" ");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function isTelegramAuthMessage(
|
|
112
|
+
data: unknown,
|
|
113
|
+
): data is {
|
|
114
|
+
type: typeof TELEGRAM_AUTH_MESSAGE;
|
|
115
|
+
token: string;
|
|
116
|
+
state: string;
|
|
117
|
+
} {
|
|
118
|
+
return (
|
|
119
|
+
typeof data === "object" &&
|
|
120
|
+
data !== null &&
|
|
121
|
+
"type" in data &&
|
|
122
|
+
"token" in data &&
|
|
123
|
+
"state" in data &&
|
|
124
|
+
(data as { type: unknown }).type === TELEGRAM_AUTH_MESSAGE &&
|
|
125
|
+
typeof (data as { token: unknown }).token === "string" &&
|
|
126
|
+
typeof (data as { state: unknown }).state === "string"
|
|
127
|
+
);
|
|
76
128
|
}
|
|
77
129
|
|
|
78
130
|
const HypurrConnectContext = createContext<InternalConnectState | null>(null);
|
|
@@ -107,23 +159,24 @@ export function HypurrConnectProvider({
|
|
|
107
159
|
const staticClient = useMemo(() => createStaticClient(config), [config]);
|
|
108
160
|
|
|
109
161
|
// ── Telegram auth state ──────────────────────────────────────
|
|
110
|
-
const [
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
);
|
|
162
|
+
const [tgAuthToken, setTgAuthToken] = useState<string | null>(() => {
|
|
163
|
+
try {
|
|
164
|
+
return localStorage.getItem(TELEGRAM_STORAGE_KEY);
|
|
165
|
+
} catch {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
120
169
|
const [tgUser, setTgUser] = useState<HypurrTelegramUser | null>(null);
|
|
121
170
|
const [tgLoading, setTgLoading] = useState(false);
|
|
122
171
|
const [tgError, setTgError] = useState<string | null>(null);
|
|
123
172
|
|
|
124
|
-
const authDataMap = useMemo(
|
|
125
|
-
|
|
126
|
-
|
|
173
|
+
const authDataMap = useMemo(() => ({}), []);
|
|
174
|
+
const telegramRpcOptions = useMemo<RpcOptions | undefined>(
|
|
175
|
+
() =>
|
|
176
|
+
tgAuthToken
|
|
177
|
+
? { meta: { authorization: `Bearer ${tgAuthToken}` } }
|
|
178
|
+
: undefined,
|
|
179
|
+
[tgAuthToken],
|
|
127
180
|
);
|
|
128
181
|
|
|
129
182
|
const [tgUserTick, setTgUserTick] = useState(0);
|
|
@@ -131,26 +184,99 @@ export function HypurrConnectProvider({
|
|
|
131
184
|
// Auto-disconnect when the server rejects telegram auth data.
|
|
132
185
|
const onInvalidAuthRef = useRef<(() => void) | null>(null);
|
|
133
186
|
onInvalidAuthRef.current = () => {
|
|
134
|
-
console.warn(
|
|
135
|
-
|
|
187
|
+
console.warn(
|
|
188
|
+
"[HypurrConnect] Invalid Telegram auth token — disconnecting.",
|
|
189
|
+
);
|
|
190
|
+
setTgAuthToken(null);
|
|
136
191
|
setTgUser(null);
|
|
137
192
|
setTgError(null);
|
|
138
193
|
localStorage.removeItem(TELEGRAM_STORAGE_KEY);
|
|
194
|
+
localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
|
|
139
195
|
};
|
|
140
196
|
|
|
197
|
+
const acceptTelegramToken = useCallback((token: string) => {
|
|
198
|
+
setTgAuthToken(token);
|
|
199
|
+
setTgError(null);
|
|
200
|
+
localStorage.setItem(TELEGRAM_STORAGE_KEY, token);
|
|
201
|
+
localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
|
|
202
|
+
}, []);
|
|
203
|
+
|
|
141
204
|
useEffect(() => {
|
|
142
|
-
|
|
205
|
+
const params = new URLSearchParams(window.location.search);
|
|
206
|
+
const token = params.get("token");
|
|
207
|
+
if (!token) {
|
|
208
|
+
localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const callbackState = params.get("state") ?? "";
|
|
213
|
+
|
|
214
|
+
if (window.opener && window.opener !== window) {
|
|
215
|
+
window.opener.postMessage(
|
|
216
|
+
{
|
|
217
|
+
type: TELEGRAM_AUTH_MESSAGE,
|
|
218
|
+
token,
|
|
219
|
+
state: callbackState,
|
|
220
|
+
},
|
|
221
|
+
window.location.origin,
|
|
222
|
+
);
|
|
223
|
+
window.close();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const expectedState = sessionStorage.getItem(TELEGRAM_AUTH_STATE_KEY);
|
|
228
|
+
sessionStorage.removeItem(TELEGRAM_AUTH_STATE_KEY);
|
|
229
|
+
if (!expectedState || callbackState !== expectedState) {
|
|
230
|
+
setTgError("Invalid auth callback state.");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
acceptTelegramToken(token);
|
|
235
|
+
|
|
236
|
+
const cleanUrl = new URL(window.location.href);
|
|
237
|
+
for (const param of [
|
|
238
|
+
"token",
|
|
239
|
+
"token_type",
|
|
240
|
+
"token_source",
|
|
241
|
+
"state",
|
|
242
|
+
"scope",
|
|
243
|
+
]) {
|
|
244
|
+
cleanUrl.searchParams.delete(param);
|
|
245
|
+
}
|
|
246
|
+
window.history.replaceState({}, document.title, cleanUrl.toString());
|
|
247
|
+
}, [acceptTelegramToken]);
|
|
248
|
+
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
function onMessage(event: MessageEvent) {
|
|
251
|
+
if (event.origin !== window.location.origin) return;
|
|
252
|
+
if (!isTelegramAuthMessage(event.data)) return;
|
|
253
|
+
|
|
254
|
+
const expectedState = sessionStorage.getItem(TELEGRAM_AUTH_STATE_KEY);
|
|
255
|
+
sessionStorage.removeItem(TELEGRAM_AUTH_STATE_KEY);
|
|
256
|
+
if (!expectedState || event.data.state !== expectedState) {
|
|
257
|
+
setTgError("Invalid auth callback state.");
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
acceptTelegramToken(event.data.token);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
window.addEventListener("message", onMessage);
|
|
265
|
+
return () => window.removeEventListener("message", onMessage);
|
|
266
|
+
}, [acceptTelegramToken]);
|
|
267
|
+
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
if (!tgAuthToken || !telegramRpcOptions) return;
|
|
143
270
|
let cancelled = false;
|
|
144
271
|
setTgLoading(true);
|
|
145
272
|
setTgError(null);
|
|
146
273
|
|
|
147
274
|
(async () => {
|
|
148
275
|
try {
|
|
149
|
-
const authData = toAuthDataMap(tgLoginData);
|
|
150
276
|
const [{ response: userResp }, { response: walletsResp }] =
|
|
151
277
|
await Promise.all([
|
|
152
|
-
tgClient.telegramUser({ authData }),
|
|
153
|
-
tgClient.telegramUserWallets({ authData }),
|
|
278
|
+
tgClient.telegramUser({ authData: {} }, telegramRpcOptions),
|
|
279
|
+
tgClient.telegramUserWallets({ authData: {} }, telegramRpcOptions),
|
|
154
280
|
]);
|
|
155
281
|
if (cancelled) return;
|
|
156
282
|
const user = (userResp as TelegramUserResponse).user ?? null;
|
|
@@ -176,7 +302,7 @@ export function HypurrConnectProvider({
|
|
|
176
302
|
return () => {
|
|
177
303
|
cancelled = true;
|
|
178
304
|
};
|
|
179
|
-
}, [
|
|
305
|
+
}, [tgAuthToken, telegramRpcOptions, tgClient, tgUserTick]);
|
|
180
306
|
|
|
181
307
|
// ── EOA auth state ───────────────────────────────────────────
|
|
182
308
|
const [eoaAddress, setEoaAddress] = useState<`0x${string}` | null>(null);
|
|
@@ -186,7 +312,7 @@ export function HypurrConnectProvider({
|
|
|
186
312
|
const eoaSignerRef = useRef<EoaSigner | null>(null);
|
|
187
313
|
|
|
188
314
|
// ── Derived auth ─────────────────────────────────────────────
|
|
189
|
-
const authMethod: AuthMethod =
|
|
315
|
+
const authMethod: AuthMethod = tgAuthToken
|
|
190
316
|
? "telegram"
|
|
191
317
|
: eoaAddress
|
|
192
318
|
? "eoa"
|
|
@@ -244,14 +370,20 @@ export function HypurrConnectProvider({
|
|
|
244
370
|
try {
|
|
245
371
|
const [{ response: twapResp }, { response: scaleResp }] =
|
|
246
372
|
await Promise.all([
|
|
247
|
-
tgClient.hyperliquidWalletTwapSessions(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
373
|
+
tgClient.hyperliquidWalletTwapSessions(
|
|
374
|
+
{
|
|
375
|
+
authData: {},
|
|
376
|
+
walletId: selectedWalletId,
|
|
377
|
+
},
|
|
378
|
+
telegramRpcOptions,
|
|
379
|
+
),
|
|
380
|
+
tgClient.hyperliquidWalletScaleSessions(
|
|
381
|
+
{
|
|
382
|
+
authData: {},
|
|
383
|
+
walletId: selectedWalletId,
|
|
384
|
+
},
|
|
385
|
+
telegramRpcOptions,
|
|
386
|
+
),
|
|
255
387
|
]);
|
|
256
388
|
if (cancelled) return;
|
|
257
389
|
setWallets((prev) =>
|
|
@@ -281,19 +413,24 @@ export function HypurrConnectProvider({
|
|
|
281
413
|
cancelled = true;
|
|
282
414
|
clearInterval(id);
|
|
283
415
|
};
|
|
284
|
-
}, [
|
|
416
|
+
}, [
|
|
417
|
+
authMethod,
|
|
418
|
+
selectedWalletId,
|
|
419
|
+
pollInterval,
|
|
420
|
+
tgClient,
|
|
421
|
+
telegramRpcOptions,
|
|
422
|
+
]);
|
|
285
423
|
|
|
286
424
|
const user = useMemo<HypurrUser | null>(() => {
|
|
287
|
-
if (
|
|
425
|
+
if (tgAuthToken && authMethod === "telegram" && selectedWallet && tgUser) {
|
|
288
426
|
return {
|
|
289
427
|
address: selectedWallet.ethereumAddress,
|
|
290
428
|
walletId: selectedWallet.id,
|
|
291
|
-
displayName:
|
|
292
|
-
? `@${
|
|
293
|
-
:
|
|
294
|
-
photoUrl: tgLoginData.photo_url,
|
|
429
|
+
displayName: tgUser.telegramUsername
|
|
430
|
+
? `@${tgUser.telegramUsername}`
|
|
431
|
+
: `Telegram ${tgUser.telegramId}`,
|
|
295
432
|
authMethod: "telegram",
|
|
296
|
-
telegramId: String(
|
|
433
|
+
telegramId: String(tgUser.telegramId),
|
|
297
434
|
hfunScore: tgUser?.reputation?.hfunScore,
|
|
298
435
|
reputationScore: tgUser?.reputation?.reputationScore,
|
|
299
436
|
};
|
|
@@ -307,7 +444,7 @@ export function HypurrConnectProvider({
|
|
|
307
444
|
};
|
|
308
445
|
}
|
|
309
446
|
return null;
|
|
310
|
-
}, [
|
|
447
|
+
}, [tgAuthToken, selectedWallet, eoaAddress, authMethod, tgUser]);
|
|
311
448
|
|
|
312
449
|
// ── Exchange client ──────────────────────────────────────────
|
|
313
450
|
// Telegram: GrpcExchangeTransport → HyperliquidCoreAction (server signs)
|
|
@@ -350,7 +487,7 @@ export function HypurrConnectProvider({
|
|
|
350
487
|
const transport = new GrpcExchangeTransport({
|
|
351
488
|
isTestnet: config.isTestnet ?? false,
|
|
352
489
|
telegramClient: tgClient,
|
|
353
|
-
|
|
490
|
+
rpcOptions: telegramRpcOptions,
|
|
354
491
|
walletId: user.walletId,
|
|
355
492
|
onAuthError: () => onInvalidAuthRef.current?.(),
|
|
356
493
|
});
|
|
@@ -435,7 +572,8 @@ export function HypurrConnectProvider({
|
|
|
435
572
|
const { privateKey, address: agentAddress } =
|
|
436
573
|
await generateAgentKey();
|
|
437
574
|
|
|
438
|
-
const chainIdHex =
|
|
575
|
+
const chainIdHex =
|
|
576
|
+
`0x${signer.chainId.toString(16)}` as `0x${string}`;
|
|
439
577
|
const nonce = Date.now();
|
|
440
578
|
const action = {
|
|
441
579
|
type: "approveAgent" as const,
|
|
@@ -567,7 +705,7 @@ export function HypurrConnectProvider({
|
|
|
567
705
|
eoaAddress,
|
|
568
706
|
config.isTestnet,
|
|
569
707
|
tgClient,
|
|
570
|
-
|
|
708
|
+
telegramRpcOptions,
|
|
571
709
|
]);
|
|
572
710
|
|
|
573
711
|
const handleClearAgent = useCallback(() => {
|
|
@@ -580,43 +718,52 @@ export function HypurrConnectProvider({
|
|
|
580
718
|
// ── Wallet management (Telegram only) ───────────────────────
|
|
581
719
|
const createWallet = useCallback(
|
|
582
720
|
async (name: string): Promise<HyperliquidWallet> => {
|
|
583
|
-
const { response } = await tgClient.hyperliquidWalletCreate(
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
721
|
+
const { response } = await tgClient.hyperliquidWalletCreate(
|
|
722
|
+
{
|
|
723
|
+
authData: {},
|
|
724
|
+
name,
|
|
725
|
+
},
|
|
726
|
+
telegramRpcOptions,
|
|
727
|
+
);
|
|
587
728
|
refreshWallets();
|
|
588
729
|
if (!response.wallet)
|
|
589
730
|
throw new Error("Wallet creation returned no wallet");
|
|
590
731
|
return response.wallet;
|
|
591
732
|
},
|
|
592
|
-
[tgClient,
|
|
733
|
+
[tgClient, telegramRpcOptions, refreshWallets],
|
|
593
734
|
);
|
|
594
735
|
|
|
595
736
|
const deleteWallet = useCallback(
|
|
596
737
|
async (walletId: number): Promise<void> => {
|
|
597
|
-
await tgClient.hyperliquidWalletDelete(
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
738
|
+
await tgClient.hyperliquidWalletDelete(
|
|
739
|
+
{
|
|
740
|
+
authData: {},
|
|
741
|
+
walletId,
|
|
742
|
+
},
|
|
743
|
+
telegramRpcOptions,
|
|
744
|
+
);
|
|
601
745
|
if (walletId === selectedWalletId) {
|
|
602
746
|
const remaining = wallets.filter((w) => w.id !== walletId);
|
|
603
747
|
setSelectedWalletId(remaining[0]?.id ?? 0);
|
|
604
748
|
}
|
|
605
749
|
refreshWallets();
|
|
606
750
|
},
|
|
607
|
-
[tgClient,
|
|
751
|
+
[tgClient, telegramRpcOptions, selectedWalletId, wallets, refreshWallets],
|
|
608
752
|
);
|
|
609
753
|
|
|
610
754
|
const createWalletPack = useCallback(
|
|
611
755
|
async (name: string): Promise<number> => {
|
|
612
|
-
const { response } = await tgClient.telegramChatWalletPackCreate(
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
756
|
+
const { response } = await tgClient.telegramChatWalletPackCreate(
|
|
757
|
+
{
|
|
758
|
+
authData: {},
|
|
759
|
+
name,
|
|
760
|
+
},
|
|
761
|
+
telegramRpcOptions,
|
|
762
|
+
);
|
|
616
763
|
refreshWallets();
|
|
617
764
|
return response.packId;
|
|
618
765
|
},
|
|
619
|
-
[tgClient,
|
|
766
|
+
[tgClient, telegramRpcOptions, refreshWallets],
|
|
620
767
|
);
|
|
621
768
|
|
|
622
769
|
const addPackLabel = useCallback(
|
|
@@ -625,13 +772,16 @@ export function HypurrConnectProvider({
|
|
|
625
772
|
walletLabel: string;
|
|
626
773
|
packId: number;
|
|
627
774
|
}): Promise<void> => {
|
|
628
|
-
await tgClient.telegramChatWalletPackLabelAdd(
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
775
|
+
await tgClient.telegramChatWalletPackLabelAdd(
|
|
776
|
+
{
|
|
777
|
+
authData: {},
|
|
778
|
+
...params,
|
|
779
|
+
},
|
|
780
|
+
telegramRpcOptions,
|
|
781
|
+
);
|
|
632
782
|
refreshWallets();
|
|
633
783
|
},
|
|
634
|
-
[tgClient,
|
|
784
|
+
[tgClient, telegramRpcOptions, refreshWallets],
|
|
635
785
|
);
|
|
636
786
|
|
|
637
787
|
const modifyPackLabel = useCallback(
|
|
@@ -640,24 +790,30 @@ export function HypurrConnectProvider({
|
|
|
640
790
|
walletLabelNew: string;
|
|
641
791
|
packId: number;
|
|
642
792
|
}): Promise<void> => {
|
|
643
|
-
await tgClient.telegramChatWalletPackLabelModify(
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
793
|
+
await tgClient.telegramChatWalletPackLabelModify(
|
|
794
|
+
{
|
|
795
|
+
authData: {},
|
|
796
|
+
...params,
|
|
797
|
+
},
|
|
798
|
+
telegramRpcOptions,
|
|
799
|
+
);
|
|
647
800
|
refreshWallets();
|
|
648
801
|
},
|
|
649
|
-
[tgClient,
|
|
802
|
+
[tgClient, telegramRpcOptions, refreshWallets],
|
|
650
803
|
);
|
|
651
804
|
|
|
652
805
|
const removePackLabel = useCallback(
|
|
653
806
|
async (params: { walletLabel: string; packId: number }): Promise<void> => {
|
|
654
|
-
await tgClient.telegramChatWalletPackLabelRemove(
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
807
|
+
await tgClient.telegramChatWalletPackLabelRemove(
|
|
808
|
+
{
|
|
809
|
+
authData: {},
|
|
810
|
+
...params,
|
|
811
|
+
},
|
|
812
|
+
telegramRpcOptions,
|
|
813
|
+
);
|
|
658
814
|
refreshWallets();
|
|
659
815
|
},
|
|
660
|
-
[tgClient,
|
|
816
|
+
[tgClient, telegramRpcOptions, refreshWallets],
|
|
661
817
|
);
|
|
662
818
|
|
|
663
819
|
// ── TWAP session management (Telegram only) ─────────────────
|
|
@@ -668,11 +824,14 @@ export function HypurrConnectProvider({
|
|
|
668
824
|
"authData" | "walletId"
|
|
669
825
|
>,
|
|
670
826
|
) => {
|
|
671
|
-
const { response } = await tgClient.hyperliquidTwapCreate(
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
827
|
+
const { response } = await tgClient.hyperliquidTwapCreate(
|
|
828
|
+
{
|
|
829
|
+
authData: {},
|
|
830
|
+
walletId: selectedWalletId,
|
|
831
|
+
...params,
|
|
832
|
+
},
|
|
833
|
+
telegramRpcOptions,
|
|
834
|
+
);
|
|
676
835
|
if (!response.session)
|
|
677
836
|
throw new Error("TWAP creation returned no session");
|
|
678
837
|
const session = response.session;
|
|
@@ -685,7 +844,7 @@ export function HypurrConnectProvider({
|
|
|
685
844
|
);
|
|
686
845
|
return session;
|
|
687
846
|
},
|
|
688
|
-
[tgClient,
|
|
847
|
+
[tgClient, telegramRpcOptions, selectedWalletId],
|
|
689
848
|
);
|
|
690
849
|
|
|
691
850
|
const modifyTwap = useCallback(
|
|
@@ -695,13 +854,15 @@ export function HypurrConnectProvider({
|
|
|
695
854
|
"authData" | "walletId"
|
|
696
855
|
>,
|
|
697
856
|
) => {
|
|
698
|
-
const { response } = await tgClient.hyperliquidTwapModify(
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
857
|
+
const { response } = await tgClient.hyperliquidTwapModify(
|
|
858
|
+
{
|
|
859
|
+
authData: {},
|
|
860
|
+
walletId: selectedWalletId,
|
|
861
|
+
...params,
|
|
862
|
+
},
|
|
863
|
+
telegramRpcOptions,
|
|
864
|
+
);
|
|
865
|
+
if (!response.session) throw new Error("TWAP modify returned no session");
|
|
705
866
|
const session = response.session;
|
|
706
867
|
setWallets((prev) =>
|
|
707
868
|
prev.map((w) =>
|
|
@@ -717,16 +878,19 @@ export function HypurrConnectProvider({
|
|
|
717
878
|
);
|
|
718
879
|
return session;
|
|
719
880
|
},
|
|
720
|
-
[tgClient,
|
|
881
|
+
[tgClient, telegramRpcOptions, selectedWalletId],
|
|
721
882
|
);
|
|
722
883
|
|
|
723
884
|
const cancelTwap = useCallback(
|
|
724
885
|
async (sessionId: number) => {
|
|
725
|
-
await tgClient.hyperliquidTwapCancel(
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
886
|
+
await tgClient.hyperliquidTwapCancel(
|
|
887
|
+
{
|
|
888
|
+
authData: {},
|
|
889
|
+
walletId: selectedWalletId,
|
|
890
|
+
twapSessionId: sessionId,
|
|
891
|
+
},
|
|
892
|
+
telegramRpcOptions,
|
|
893
|
+
);
|
|
730
894
|
setWallets((prev) =>
|
|
731
895
|
prev.map((w) =>
|
|
732
896
|
w.id === selectedWalletId
|
|
@@ -738,7 +902,7 @@ export function HypurrConnectProvider({
|
|
|
738
902
|
),
|
|
739
903
|
);
|
|
740
904
|
},
|
|
741
|
-
[tgClient,
|
|
905
|
+
[tgClient, telegramRpcOptions, selectedWalletId],
|
|
742
906
|
);
|
|
743
907
|
|
|
744
908
|
// ── Scale session management (Telegram only) ───────────────
|
|
@@ -749,11 +913,14 @@ export function HypurrConnectProvider({
|
|
|
749
913
|
"authData" | "walletId"
|
|
750
914
|
>,
|
|
751
915
|
) => {
|
|
752
|
-
const { response } = await tgClient.hyperliquidScaleCreate(
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
916
|
+
const { response } = await tgClient.hyperliquidScaleCreate(
|
|
917
|
+
{
|
|
918
|
+
authData: {},
|
|
919
|
+
walletId: selectedWalletId,
|
|
920
|
+
...params,
|
|
921
|
+
},
|
|
922
|
+
telegramRpcOptions,
|
|
923
|
+
);
|
|
757
924
|
if (!response.session)
|
|
758
925
|
throw new Error("Scale creation returned no session");
|
|
759
926
|
const session = response.session;
|
|
@@ -766,16 +933,19 @@ export function HypurrConnectProvider({
|
|
|
766
933
|
);
|
|
767
934
|
return session;
|
|
768
935
|
},
|
|
769
|
-
[tgClient,
|
|
936
|
+
[tgClient, telegramRpcOptions, selectedWalletId],
|
|
770
937
|
);
|
|
771
938
|
|
|
772
939
|
const cancelScale = useCallback(
|
|
773
940
|
async (sessionId: number) => {
|
|
774
|
-
await tgClient.hyperliquidScaleCancel(
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
941
|
+
await tgClient.hyperliquidScaleCancel(
|
|
942
|
+
{
|
|
943
|
+
authData: {},
|
|
944
|
+
walletId: selectedWalletId,
|
|
945
|
+
scaleSessionId: sessionId,
|
|
946
|
+
},
|
|
947
|
+
telegramRpcOptions,
|
|
948
|
+
);
|
|
779
949
|
setWallets((prev) =>
|
|
780
950
|
prev.map((w) =>
|
|
781
951
|
w.id === selectedWalletId
|
|
@@ -789,7 +959,7 @@ export function HypurrConnectProvider({
|
|
|
789
959
|
),
|
|
790
960
|
);
|
|
791
961
|
},
|
|
792
|
-
[tgClient,
|
|
962
|
+
[tgClient, telegramRpcOptions, selectedWalletId],
|
|
793
963
|
);
|
|
794
964
|
|
|
795
965
|
// ── Login modal state ────────────────────────────────────────
|
|
@@ -798,23 +968,60 @@ export function HypurrConnectProvider({
|
|
|
798
968
|
const closeLoginModal = useCallback(() => setLoginModalOpen(false), []);
|
|
799
969
|
|
|
800
970
|
// ── Auth actions ─────────────────────────────────────────────
|
|
801
|
-
const loginTelegram = useCallback((
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
971
|
+
const loginTelegram = useCallback(() => {
|
|
972
|
+
const state = randomState();
|
|
973
|
+
sessionStorage.setItem(TELEGRAM_AUTH_STATE_KEY, state);
|
|
974
|
+
|
|
975
|
+
const configuredReturnTo = config.telegram.returnTo;
|
|
976
|
+
const returnTo =
|
|
977
|
+
typeof configuredReturnTo === "function"
|
|
978
|
+
? configuredReturnTo()
|
|
979
|
+
: configuredReturnTo || currentReturnTo();
|
|
980
|
+
|
|
981
|
+
const authUrl = new URL(config.telegram.authHubUrl || DEFAULT_AUTH_HUB_URL);
|
|
982
|
+
authUrl.searchParams.set("return_to", returnTo);
|
|
983
|
+
authUrl.searchParams.set("state", state);
|
|
984
|
+
authUrl.searchParams.set("scope", normalizeScopes(config.telegram.scope));
|
|
985
|
+
|
|
986
|
+
const width = 520;
|
|
987
|
+
const height = 720;
|
|
988
|
+
const left = window.screenX + Math.max(0, (window.outerWidth - width) / 2);
|
|
989
|
+
const top = window.screenY + Math.max(0, (window.outerHeight - height) / 2);
|
|
990
|
+
const popup = window.open(
|
|
991
|
+
authUrl.toString(),
|
|
992
|
+
"hypurr_telegram_auth",
|
|
993
|
+
[
|
|
994
|
+
`width=${width}`,
|
|
995
|
+
`height=${height}`,
|
|
996
|
+
`left=${Math.round(left)}`,
|
|
997
|
+
`top=${Math.round(top)}`,
|
|
998
|
+
"resizable=yes",
|
|
999
|
+
"scrollbars=yes",
|
|
1000
|
+
].join(","),
|
|
1001
|
+
);
|
|
1002
|
+
|
|
1003
|
+
if (popup) {
|
|
1004
|
+
popup.focus();
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
window.location.assign(authUrl.toString());
|
|
1009
|
+
}, [
|
|
1010
|
+
config.telegram.authHubUrl,
|
|
1011
|
+
config.telegram.returnTo,
|
|
1012
|
+
config.telegram.scope,
|
|
1013
|
+
]);
|
|
808
1014
|
|
|
809
1015
|
const connectEoa = useCallback(
|
|
810
1016
|
(address: `0x${string}`, signer?: EoaSigner) => {
|
|
811
1017
|
eoaSignerRef.current = signer ?? null;
|
|
812
1018
|
setEoaAddress(address);
|
|
813
|
-
|
|
1019
|
+
setTgAuthToken(null);
|
|
814
1020
|
setTgUser(null);
|
|
815
1021
|
setTgError(null);
|
|
816
1022
|
setEoaError(null);
|
|
817
1023
|
localStorage.removeItem(TELEGRAM_STORAGE_KEY);
|
|
1024
|
+
localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
|
|
818
1025
|
|
|
819
1026
|
const existing = loadAgent(address);
|
|
820
1027
|
if (existing && existing.validUntil > Date.now()) {
|
|
@@ -932,14 +1139,15 @@ export function HypurrConnectProvider({
|
|
|
932
1139
|
);
|
|
933
1140
|
|
|
934
1141
|
const logout = useCallback(() => {
|
|
935
|
-
setTgLoginData(null);
|
|
936
1142
|
setTgUser(null);
|
|
937
1143
|
setTgError(null);
|
|
1144
|
+
setTgAuthToken(null);
|
|
938
1145
|
setEoaAddress(null);
|
|
939
1146
|
setAgent(null);
|
|
940
1147
|
setEoaError(null);
|
|
941
1148
|
eoaSignerRef.current = null;
|
|
942
1149
|
localStorage.removeItem(TELEGRAM_STORAGE_KEY);
|
|
1150
|
+
localStorage.removeItem(LEGACY_TELEGRAM_STORAGE_KEY);
|
|
943
1151
|
}, []);
|
|
944
1152
|
|
|
945
1153
|
// ── Context value ────────────────────────────────────────────
|
|
@@ -991,6 +1199,8 @@ export function HypurrConnectProvider({
|
|
|
991
1199
|
useWidget: config.telegram?.useWidget ?? false,
|
|
992
1200
|
|
|
993
1201
|
authDataMap,
|
|
1202
|
+
authToken: tgAuthToken,
|
|
1203
|
+
telegramRpcOptions,
|
|
994
1204
|
telegramClient: tgClient,
|
|
995
1205
|
staticClient,
|
|
996
1206
|
}),
|
|
@@ -1032,6 +1242,8 @@ export function HypurrConnectProvider({
|
|
|
1032
1242
|
config.telegram?.botUsername,
|
|
1033
1243
|
config.telegram?.useWidget,
|
|
1034
1244
|
authDataMap,
|
|
1245
|
+
tgAuthToken,
|
|
1246
|
+
telegramRpcOptions,
|
|
1035
1247
|
tgClient,
|
|
1036
1248
|
staticClient,
|
|
1037
1249
|
],
|