@hfunlabs/hypurr-connect 0.1.11 → 0.1.13

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/src/agent.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { StoredAgent } from "./types";
2
+ import { PrivateKeySigner } from "./privateKeySigner";
2
3
 
3
4
  export const AGENT_NAME = "hypurr-connect";
4
5
 
@@ -27,7 +28,7 @@ export function clearAgent(masterAddress: string): void {
27
28
 
28
29
  /**
29
30
  * Generate a random 32-byte private key and derive its address using the
30
- * SDK's PrivateKeySigner (no viem dependency needed).
31
+ * local PrivateKeySigner compatibility wrapper.
31
32
  */
32
33
  export async function generateAgentKey(): Promise<{
33
34
  privateKey: `0x${string}`;
@@ -39,7 +40,6 @@ export async function generateAgentKey(): Promise<{
39
40
  .join("");
40
41
  const privateKey = `0x${hex}` as `0x${string}`;
41
42
 
42
- const { PrivateKeySigner } = await import("@hfunlabs/hyperliquid/signing");
43
43
  const signer = new PrivateKeySigner(privateKey);
44
44
  return { privateKey, address: signer.address };
45
45
  }
@@ -0,0 +1,197 @@
1
+ import type { CSSProperties, SVGProps } from "react";
2
+
3
+ interface IconProps extends Omit<SVGProps<SVGSVGElement>, "fill"> {
4
+ size?: number;
5
+ color?: string;
6
+ fill?: string;
7
+ style?: CSSProperties;
8
+ }
9
+
10
+ function svgBase({
11
+ size = 16,
12
+ color = "currentColor",
13
+ fill = "none",
14
+ ...rest
15
+ }: IconProps) {
16
+ return {
17
+ width: size,
18
+ height: size,
19
+ viewBox: "0 0 24 24",
20
+ fill,
21
+ stroke: color,
22
+ strokeWidth: 2,
23
+ strokeLinecap: "round" as const,
24
+ strokeLinejoin: "round" as const,
25
+ ...rest,
26
+ };
27
+ }
28
+
29
+ export function Copy(props: IconProps) {
30
+ return (
31
+ <svg {...svgBase(props)}>
32
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
33
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
34
+ </svg>
35
+ );
36
+ }
37
+
38
+ export function Star(props: IconProps) {
39
+ return (
40
+ <svg {...svgBase(props)}>
41
+ <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
42
+ </svg>
43
+ );
44
+ }
45
+
46
+ export function User(props: IconProps) {
47
+ return (
48
+ <svg {...svgBase(props)}>
49
+ <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
50
+ <circle cx="12" cy="7" r="4" />
51
+ </svg>
52
+ );
53
+ }
54
+
55
+ export function Zap(props: IconProps) {
56
+ return (
57
+ <svg {...svgBase(props)}>
58
+ <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
59
+ </svg>
60
+ );
61
+ }
62
+
63
+ export function Wallet(props: IconProps) {
64
+ return (
65
+ <svg {...svgBase(props)}>
66
+ <path d="M20 12V8H6a2 2 0 0 1-2-2c0-1.1.9-2 2-2h12v4" />
67
+ <path d="M4 6v12c0 1.1.9 2 2 2h14v-4" />
68
+ <path d="M18 12a2 2 0 0 0-2 2c0 1.1.9 2 2 2h4v-4z" />
69
+ </svg>
70
+ );
71
+ }
72
+
73
+ export function TrendingUp(props: IconProps) {
74
+ return (
75
+ <svg {...svgBase(props)}>
76
+ <polyline points="22 7 13.5 15.5 8.5 10.5 2 17" />
77
+ <polyline points="16 7 22 7 22 13" />
78
+ </svg>
79
+ );
80
+ }
81
+
82
+ export function Trash2(props: IconProps) {
83
+ return (
84
+ <svg {...svgBase(props)}>
85
+ <path d="M3 6h18" />
86
+ <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" />
87
+ <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
88
+ <line x1="10" x2="10" y1="11" y2="17" />
89
+ <line x1="14" x2="14" y1="11" y2="17" />
90
+ </svg>
91
+ );
92
+ }
93
+
94
+ export function Pencil(props: IconProps) {
95
+ return (
96
+ <svg {...svgBase(props)}>
97
+ <path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" />
98
+ <path d="m15 5 4 4" />
99
+ </svg>
100
+ );
101
+ }
102
+
103
+ export function LayoutDashboard(props: IconProps) {
104
+ return (
105
+ <svg {...svgBase(props)}>
106
+ <rect width="7" height="9" x="3" y="3" rx="1" />
107
+ <rect width="7" height="5" x="14" y="3" rx="1" />
108
+ <rect width="7" height="9" x="14" y="12" rx="1" />
109
+ <rect width="7" height="5" x="3" y="16" rx="1" />
110
+ </svg>
111
+ );
112
+ }
113
+
114
+ export function AlertTriangle(props: IconProps) {
115
+ return (
116
+ <svg {...svgBase(props)}>
117
+ <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" />
118
+ <line x1="12" x2="12" y1="9" y2="13" />
119
+ <line x1="12" x2="12.01" y1="17" y2="17" />
120
+ </svg>
121
+ );
122
+ }
123
+
124
+ export function Loader2(props: IconProps) {
125
+ const { size = 16, color = "currentColor", style, ...rest } = props;
126
+ return (
127
+ <svg
128
+ width={size}
129
+ height={size}
130
+ viewBox="0 0 24 24"
131
+ fill="none"
132
+ stroke={color}
133
+ strokeWidth={2}
134
+ strokeLinecap="round"
135
+ strokeLinejoin="round"
136
+ style={{
137
+ animation: "hypurr-spin 1s linear infinite",
138
+ ...style,
139
+ }}
140
+ {...rest}
141
+ >
142
+ <path d="M21 12a9 9 0 1 1-6.219-8.56" />
143
+ </svg>
144
+ );
145
+ }
146
+
147
+ export function Crown(props: IconProps) {
148
+ return (
149
+ <svg {...svgBase(props)}>
150
+ <path d="M11.562 3.266a.5.5 0 0 1 .876 0L15.39 8.87a1 1 0 0 0 1.516.294L21.183 5.5a.5.5 0 0 1 .798.519l-2.834 10.246a1 1 0 0 1-.956.734H5.81a1 1 0 0 1-.957-.734L2.02 6.02a.5.5 0 0 1 .798-.519l4.276 3.664a1 1 0 0 0 1.516-.294z" />
151
+ <path d="M5 21h14" />
152
+ </svg>
153
+ );
154
+ }
155
+
156
+ export function Folder(props: IconProps) {
157
+ return (
158
+ <svg {...svgBase(props)}>
159
+ <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />
160
+ </svg>
161
+ );
162
+ }
163
+
164
+ export function LogOut(props: IconProps) {
165
+ return (
166
+ <svg {...svgBase(props)}>
167
+ <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
168
+ <polyline points="16 17 21 12 16 7" />
169
+ <line x1="21" x2="9" y1="12" y2="12" />
170
+ </svg>
171
+ );
172
+ }
173
+
174
+ export function Plus(props: IconProps) {
175
+ return (
176
+ <svg {...svgBase(props)}>
177
+ <path d="M5 12h14" />
178
+ <path d="M12 5v14" />
179
+ </svg>
180
+ );
181
+ }
182
+
183
+ export function X(props: IconProps) {
184
+ return (
185
+ <svg {...svgBase(props)}>
186
+ <path d="M18 6 6 18" />
187
+ <path d="m6 6 12 12" />
188
+ </svg>
189
+ );
190
+ }
191
+
192
+ /** Inject the keyframes used by {@link Loader2}. Mount once at the top of any modal that spins. */
193
+ export function SpinKeyframes() {
194
+ return (
195
+ <style>{`@keyframes hypurr-spin { to { transform: rotate(360deg); } }`}</style>
196
+ );
197
+ }
package/src/index.ts CHANGED
@@ -4,17 +4,33 @@ export {
4
4
  } from "./HypurrConnectProvider";
5
5
  export { LoginModal } from "./LoginModal";
6
6
  export type { LoginModalProps } from "./LoginModal";
7
+ export { WalletSelectorDropdown } from "./WalletSelectorDropdown";
8
+ export type { WalletSelectorDropdownProps } from "./WalletSelectorDropdown";
9
+ export { UserProfileModal } from "./UserProfileModal";
10
+ export type { UserProfileModalProps, SlippageOption } from "./UserProfileModal";
11
+ export { DeleteWalletModal } from "./DeleteWalletModal";
12
+ export type { DeleteWalletModalProps } from "./DeleteWalletModal";
13
+ export { RenameWalletModal } from "./RenameWalletModal";
14
+ export type { RenameWalletModalProps } from "./RenameWalletModal";
15
+ export type { PrincipalColors, PrincipalColorOverrides } from "./profileStyles";
7
16
  export { GrpcExchangeTransport } from "./GrpcExchangeTransport";
8
17
  export type { GrpcExchangeTransportConfig } from "./GrpcExchangeTransport";
9
18
  export { createTelegramClient, createStaticClient } from "./grpc";
19
+ export { PrivateKeySigner } from "./privateKeySigner";
10
20
  export { createEoaSigner } from "./types";
11
21
  export type {
12
22
  AuthMethod,
23
+ EoaSignerOptions,
24
+ EoaSignTransactionFn,
13
25
  EoaSigner,
26
+ EvmRequestFn,
27
+ EvmTransactionRequest,
28
+ Hex,
14
29
  HypurrConnectConfig,
15
30
  HypurrConnectState,
16
31
  HypurrUser,
17
32
  ScaleCreateParams,
33
+ SignEvmTransactionFn,
18
34
  SignTypedDataFn,
19
35
  StoredAgent,
20
36
  TelegramLoginData,
@@ -0,0 +1,32 @@
1
+ import type { AbstractViemLocalAccount } from "@hfunlabs/hyperliquid/signing";
2
+ import { privateKeyToAccount, type PrivateKeyAccount } from "viem/accounts";
3
+ import type { Hex } from "./types";
4
+
5
+ type SignTypedDataParams = Parameters<
6
+ AbstractViemLocalAccount["signTypedData"]
7
+ >[0];
8
+
9
+ /**
10
+ * Compatibility wrapper for SDK versions that removed PrivateKeySigner.
11
+ *
12
+ * It exposes the viem local-account shape accepted by the Hyperliquid SDK.
13
+ */
14
+ export class PrivateKeySigner implements AbstractViemLocalAccount {
15
+ #account: PrivateKeyAccount;
16
+ readonly address: Hex;
17
+
18
+ constructor(privateKey: string) {
19
+ this.#account = privateKeyToAccount(normalizePrivateKey(privateKey));
20
+ this.address = this.#account.address;
21
+ }
22
+
23
+ signTypedData(params: SignTypedDataParams): Promise<Hex> {
24
+ return this.#account.signTypedData(
25
+ params as Parameters<PrivateKeyAccount["signTypedData"]>[0],
26
+ );
27
+ }
28
+ }
29
+
30
+ function normalizePrivateKey(privateKey: string): Hex {
31
+ return (privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`) as Hex;
32
+ }
@@ -0,0 +1,213 @@
1
+ import type { CSSProperties } from "react";
2
+
3
+ export const profileColors = {
4
+ accent: "#a855f7",
5
+ panel: "rgba(14,18,24,0.8)",
6
+ panelSolid: "#0e1218",
7
+ backdrop: "rgba(0,0,0,0.7)",
8
+ border: "#1f2937",
9
+ surfaceBtn: "#0D1219",
10
+ surfaceBtnHover: "#15171A",
11
+ surfaceBtnActive: "#1E2124",
12
+ surfaceBd: "#262A30",
13
+ surfaceBdHover: "#444548",
14
+ surfaceBdActive: "#4B4D50",
15
+ text: "#ffffff",
16
+ muted: "#aab1c1",
17
+ subdued: "#7d8597",
18
+ disabled: "#4b5563",
19
+ danger: "#f87171",
20
+ dangerStrong: "#ef4444",
21
+ purple: "#d8b4fe",
22
+ yellow: "#eab308",
23
+ };
24
+
25
+ export const fontFamily = {
26
+ sans: "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif",
27
+ mono: "Google Sans Code, Roboto Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
28
+ };
29
+
30
+ export interface PrincipalColors {
31
+ accent: string;
32
+ accentText: string;
33
+ accentBackground: string;
34
+ accentBorder: string;
35
+ accentHoverBackground: string;
36
+ }
37
+
38
+ export type PrincipalColorOverrides = Partial<PrincipalColors>;
39
+
40
+ const colorWithAlpha = (color: string, alpha: number): string => {
41
+ const hex = color.trim();
42
+ const shortHex = /^#([0-9a-f]{3})$/i.exec(hex);
43
+ const longHex = /^#([0-9a-f]{6})$/i.exec(hex);
44
+
45
+ if (shortHex) {
46
+ const [r, g, b] = shortHex[1].split("").map((value) => value + value);
47
+ return `rgba(${parseInt(r, 16)},${parseInt(g, 16)},${parseInt(b, 16)},${alpha})`;
48
+ }
49
+
50
+ if (longHex) {
51
+ const value = longHex[1];
52
+ return `rgba(${parseInt(value.slice(0, 2), 16)},${parseInt(
53
+ value.slice(2, 4),
54
+ 16,
55
+ )},${parseInt(value.slice(4, 6), 16)},${alpha})`;
56
+ }
57
+
58
+ return `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent)`;
59
+ };
60
+
61
+ export const resolvePrincipalColors = (
62
+ accentColor?: string,
63
+ overrides: PrincipalColorOverrides = {},
64
+ ): PrincipalColors => {
65
+ const hasCustomAccent = !!accentColor || !!overrides.accent;
66
+ const accent = overrides.accent ?? accentColor ?? profileColors.accent;
67
+ const accentText =
68
+ overrides.accentText ?? (hasCustomAccent ? accent : profileColors.purple);
69
+
70
+ return {
71
+ accent,
72
+ accentText,
73
+ accentBackground: overrides.accentBackground ?? colorWithAlpha(accent, 0.1),
74
+ accentBorder: overrides.accentBorder ?? colorWithAlpha(accent, 0.25),
75
+ accentHoverBackground:
76
+ overrides.accentHoverBackground ?? colorWithAlpha(accent, 0.1),
77
+ };
78
+ };
79
+
80
+ export const modalBackdropStyle = (zIndex: number): CSSProperties => ({
81
+ position: "fixed",
82
+ inset: 0,
83
+ zIndex,
84
+ background: profileColors.backdrop,
85
+ backdropFilter: "blur(4px)",
86
+ WebkitBackdropFilter: "blur(4px)",
87
+ });
88
+
89
+ export const modalWrapperStyle = (
90
+ zIndex: number,
91
+ padding = 0,
92
+ ): CSSProperties => ({
93
+ position: "fixed",
94
+ inset: 0,
95
+ zIndex,
96
+ display: "flex",
97
+ alignItems: "center",
98
+ justifyContent: "center",
99
+ padding,
100
+ });
101
+
102
+ export const modalPanelStyle = (solid = false): CSSProperties => ({
103
+ position: "relative",
104
+ width: "100%",
105
+ maxWidth: 448,
106
+ background: solid ? profileColors.panelSolid : profileColors.panel,
107
+ backdropFilter: solid ? undefined : "blur(10px)",
108
+ WebkitBackdropFilter: solid ? undefined : "blur(10px)",
109
+ border: `1px solid ${profileColors.border}`,
110
+ borderRadius: 8,
111
+ boxShadow: "0 25px 50px -12px rgba(0,0,0,0.6)",
112
+ overflow: "hidden",
113
+ fontFamily: fontFamily.sans,
114
+ });
115
+
116
+ export const modalHeaderStyle: CSSProperties = {
117
+ position: "relative",
118
+ display: "flex",
119
+ alignItems: "center",
120
+ justifyContent: "center",
121
+ padding: "24px 24px 20px",
122
+ borderBottom: `1px solid ${profileColors.border}`,
123
+ };
124
+
125
+ export const titleStyle: CSSProperties = {
126
+ margin: 0,
127
+ fontSize: 14,
128
+ lineHeight: "1.25rem",
129
+ fontWeight: 600,
130
+ color: profileColors.text,
131
+ };
132
+
133
+ export const closeBtnStyle = (disabled = false): CSSProperties => ({
134
+ position: "absolute",
135
+ right: 24,
136
+ background: "transparent",
137
+ border: "none",
138
+ color: profileColors.muted,
139
+ cursor: disabled ? "not-allowed" : "pointer",
140
+ padding: 0,
141
+ display: "flex",
142
+ opacity: disabled ? 0.4 : 1,
143
+ transition: "color 150ms",
144
+ });
145
+
146
+ export const upperLabelStyle: CSSProperties = {
147
+ fontSize: 11,
148
+ lineHeight: "1rem",
149
+ fontWeight: 500,
150
+ textTransform: "uppercase",
151
+ letterSpacing: "0.1em",
152
+ };
153
+
154
+ export const raisedButtonStyle = (
155
+ state: "default" | "hover" | "active" | "disabled" = "default",
156
+ ): CSSProperties => {
157
+ if (state === "active") {
158
+ return {
159
+ backgroundColor: profileColors.surfaceBtnActive,
160
+ backgroundImage:
161
+ "linear-gradient(to bottom, rgba(255,255,255,0.05), transparent)",
162
+ boxShadow:
163
+ "inset 0 1px 0 rgba(255,255,255,0.18), inset 0 -1px 0 rgba(0,0,0,0.45), inset 0 0 0 1px #4B4D50, 0 1px 2px rgba(0,0,0,0.5)",
164
+ color: profileColors.text,
165
+ border: "none",
166
+ };
167
+ }
168
+
169
+ if (state === "disabled") {
170
+ return {
171
+ backgroundColor: profileColors.surfaceBtn,
172
+ backgroundImage:
173
+ "linear-gradient(to bottom, rgba(255,255,255,0.02), transparent)",
174
+ boxShadow:
175
+ "inset 0 1px 0 rgba(255,255,255,0.05), inset 0 -1px 0 rgba(0,0,0,0.25), inset 0 0 0 1px #1c2026",
176
+ color: profileColors.subdued,
177
+ border: "none",
178
+ cursor: "not-allowed",
179
+ };
180
+ }
181
+
182
+ if (state === "hover") {
183
+ return {
184
+ backgroundColor: profileColors.surfaceBtnHover,
185
+ backgroundImage:
186
+ "linear-gradient(to bottom, rgba(255,255,255,0.04), transparent)",
187
+ boxShadow:
188
+ "inset 0 1px 0 rgba(255,255,255,0.14), inset 0 -1px 0 rgba(0,0,0,0.40), inset 0 0 0 1px #444548",
189
+ color: "#d1d5db",
190
+ border: "none",
191
+ };
192
+ }
193
+
194
+ return {
195
+ backgroundColor: profileColors.surfaceBtn,
196
+ backgroundImage:
197
+ "linear-gradient(to bottom, rgba(255,255,255,0.03), transparent)",
198
+ boxShadow:
199
+ "inset 0 1px 0 rgba(255,255,255,0.10), inset 0 -1px 0 rgba(0,0,0,0.35), inset 0 0 0 1px #262A30",
200
+ color: profileColors.muted,
201
+ border: "none",
202
+ };
203
+ };
204
+
205
+ export const dangerOutlineButtonStyle = (
206
+ enabled: boolean,
207
+ hovered = false,
208
+ ): CSSProperties => ({
209
+ background: enabled && hovered ? "rgba(248,113,113,0.1)" : "transparent",
210
+ border: `1px solid ${enabled ? profileColors.danger : "#374151"}`,
211
+ color: enabled ? profileColors.danger : profileColors.disabled,
212
+ cursor: enabled ? "pointer" : "not-allowed",
213
+ });
package/src/types.ts CHANGED
@@ -25,19 +25,15 @@ export interface HypurrConnectConfig {
25
25
  isTestnet?: boolean;
26
26
  /** Polling interval in ms for TWAP/Scale session updates. Default 5000. Set 0 to disable. */
27
27
  sessionPollInterval?: number;
28
- telegram: {
29
- /** Deprecated for the hub flow; retained for older consumers. */
30
- botUsername?: string;
31
- /** Deprecated for the hub flow; retained for older consumers. */
32
- botId?: string;
33
- /** Deprecated: Telegram login is now handled by the auth hub. */
34
- useWidget?: boolean;
28
+ telegram?: {
35
29
  /** Auth hub login URL. Defaults to https://auth.hypurr.fun/login. */
36
30
  authHubUrl?: string;
37
31
  /** Optional callback URL. Defaults to the current page without auth query params. */
38
32
  returnTo?: string | (() => string);
39
33
  /** Requested hub scopes. Defaults to the scopes required by this SDK. */
40
34
  scope?: string | string[];
35
+ /** @deprecated Telegram login is handled by the auth hub; this option is ignored. */
36
+ useWidget?: boolean;
41
37
  };
42
38
  }
43
39
 
@@ -86,12 +82,52 @@ export type SignTypedDataFn = (params: {
86
82
  message: Record<string, unknown>;
87
83
  }) => Promise<`0x${string}`>;
88
84
 
85
+ export type Hex = `0x${string}`;
86
+
87
+ export interface EvmTransactionRequest {
88
+ from?: Hex;
89
+ to?: Hex;
90
+ gas?: Hex;
91
+ gasPrice?: Hex;
92
+ value?: Hex;
93
+ data?: Hex;
94
+ nonce?: Hex;
95
+ chainId?: Hex;
96
+ maxFeePerGas?: Hex;
97
+ maxPriorityFeePerGas?: Hex;
98
+ type?: Hex;
99
+ accessList?: unknown;
100
+ [key: string]: unknown;
101
+ }
102
+
103
+ export type EvmRequestFn = (args: {
104
+ method: string;
105
+ params?: unknown[];
106
+ }) => Promise<unknown>;
107
+
108
+ export type SignEvmTransactionFn = (
109
+ transaction: EvmTransactionRequest,
110
+ ) => Promise<Hex>;
111
+
112
+ export type EoaSignTransactionFn = (
113
+ transaction: EvmTransactionRequest,
114
+ ) => Promise<unknown>;
115
+
89
116
  /** Wallet signer provided at EOA connect time for user-signed actions. */
90
117
  export interface EoaSigner {
91
118
  signTypedData: SignTypedDataFn;
119
+ /** Optional raw EVM transaction signer. Used by `signEvmTransaction()` in EOA mode. */
120
+ signTransaction?: EoaSignTransactionFn;
121
+ /** Optional EIP-1193 provider request function. Used as a fallback for `eth_signTransaction`. */
122
+ request?: EvmRequestFn;
92
123
  chainId: number;
93
124
  }
94
125
 
126
+ export interface EoaSignerOptions {
127
+ signTransaction?: EoaSignTransactionFn;
128
+ request?: EvmRequestFn;
129
+ }
130
+
95
131
  /**
96
132
  * Create an {@link EoaSigner} from any EIP-712 signing function.
97
133
  *
@@ -120,6 +156,7 @@ export function createEoaSigner(
120
156
  | ((args: Record<string, unknown>) => Promise<`0x${string}`>)
121
157
  | { current: (args: Record<string, unknown>) => Promise<`0x${string}`> },
122
158
  chainId: number,
159
+ options: EoaSignerOptions = {},
123
160
  ): EoaSigner {
124
161
  const resolve =
125
162
  typeof signTypedDataAsync === "function"
@@ -127,6 +164,8 @@ export function createEoaSigner(
127
164
  : (args: Record<string, unknown>) => signTypedDataAsync.current(args);
128
165
  return {
129
166
  signTypedData: (params) => resolve(params),
167
+ signTransaction: options.signTransaction,
168
+ request: options.request,
130
169
  chainId,
131
170
  };
132
171
  }
@@ -174,6 +213,7 @@ export interface HypurrConnectState {
174
213
  // Wallet management (Telegram only)
175
214
  createWallet: (name: string) => Promise<HyperliquidWallet>;
176
215
  deleteWallet: (walletId: number) => Promise<void>;
216
+ renameWallet: (walletId: number, name: string) => Promise<void>;
177
217
  refreshWallets: () => void;
178
218
 
179
219
  // Wallet packs & labels (Telegram only)
@@ -216,6 +256,7 @@ export interface HypurrConnectState {
216
256
 
217
257
  // Auth actions
218
258
  connectEoa: (address: `0x${string}`, signer?: EoaSigner) => void;
259
+ signEvmTransaction: SignEvmTransactionFn;
219
260
  approveAgent: (
220
261
  signTypedDataAsync: SignTypedDataFn,
221
262
  chainId: number,
@@ -227,9 +268,6 @@ export interface HypurrConnectState {
227
268
  agentReady: boolean;
228
269
  clearAgent: () => void;
229
270
 
230
- // Telegram config
231
- botId: string;
232
-
233
271
  // Low-level access
234
272
  /** Deprecated: JWT auth leaves authData empty; use `telegramRpcOptions` for low-level calls. */
235
273
  authDataMap: Record<string, string>;
@@ -1,62 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- import type { TelegramLoginData } from "./types";
3
-
4
- const WIDGET_SCRIPT_URL = "https://telegram.org/js/telegram-widget.js?22";
5
- const CALLBACK_NAME = "__hypurrConnectTelegramAuth";
6
-
7
- export interface TelegramLoginWidgetProps {
8
- botUsername: string;
9
- onAuth: (data: TelegramLoginData) => void;
10
- buttonSize?: "large" | "medium" | "small";
11
- cornerRadius?: number;
12
- showUserPhoto?: boolean;
13
- requestAccess?: boolean;
14
- }
15
-
16
- export function TelegramLoginWidget({
17
- botUsername,
18
- onAuth,
19
- buttonSize = "large",
20
- cornerRadius,
21
- showUserPhoto = true,
22
- requestAccess = true,
23
- }: TelegramLoginWidgetProps) {
24
- const containerRef = useRef<HTMLDivElement>(null);
25
- const onAuthRef = useRef(onAuth);
26
- onAuthRef.current = onAuth;
27
-
28
- useEffect(() => {
29
- const container = containerRef.current;
30
- if (!container) return;
31
-
32
- (window as unknown as Record<string, unknown>)[CALLBACK_NAME] = (
33
- user: TelegramLoginData,
34
- ) => {
35
- onAuthRef.current(user);
36
- };
37
-
38
- const script = document.createElement("script");
39
- script.src = WIDGET_SCRIPT_URL;
40
- script.async = true;
41
- script.setAttribute("data-telegram-login", botUsername);
42
- script.setAttribute("data-size", buttonSize);
43
- script.setAttribute("data-onauth", `${CALLBACK_NAME}(user)`);
44
- script.setAttribute("data-userpic", String(showUserPhoto));
45
- if (requestAccess) {
46
- script.setAttribute("data-request-access", "write");
47
- }
48
- if (cornerRadius !== undefined) {
49
- script.setAttribute("data-radius", String(cornerRadius));
50
- }
51
-
52
- container.innerHTML = "";
53
- container.appendChild(script);
54
-
55
- return () => {
56
- container.innerHTML = "";
57
- delete (window as unknown as Record<string, unknown>)[CALLBACK_NAME];
58
- };
59
- }, [botUsername, buttonSize, cornerRadius, showUserPhoto, requestAccess]);
60
-
61
- return <div ref={containerRef} />;
62
- }