@hfunlabs/hypurr-connect 0.1.13 → 0.1.15
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 +12 -0
- package/dist/index.d.ts +89 -4
- package/dist/index.js +1858 -348
- package/dist/index.js.map +1 -1
- package/package.json +17 -6
- package/src/AddWalletModal.tsx +744 -0
- package/src/AgentExpiryWarning.tsx +129 -0
- package/src/DeleteWalletModal.tsx +5 -1
- package/src/HypurrConnectProvider.tsx +193 -1
- package/src/LoginModal.tsx +30 -19
- package/src/RenameWalletModal.tsx +5 -1
- package/src/RenewAgentModal.tsx +380 -0
- package/src/UserProfileModal.tsx +157 -25
- package/src/WalletSelectorDropdown.tsx +146 -6
- package/src/agent.ts +38 -12
- package/src/agentWallet.ts +86 -0
- package/src/css.d.ts +1 -0
- package/src/icons/lucide.tsx +61 -0
- package/src/index.ts +17 -1
- package/src/profileStyles.ts +58 -0
- package/src/styles.css +1 -0
- package/src/tailwind.css +77 -0
- package/src/types.ts +13 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useRef,
|
|
4
|
+
useState,
|
|
5
|
+
type CSSProperties,
|
|
6
|
+
type RefCallback,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { AlertTriangle } from "./icons/lucide";
|
|
9
|
+
|
|
10
|
+
const EXPIRED_AGENT_COLOR = "#f59e0b";
|
|
11
|
+
|
|
12
|
+
interface TooltipPosition {
|
|
13
|
+
left: number;
|
|
14
|
+
top: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function AgentExpiryWarningIcon({
|
|
18
|
+
message,
|
|
19
|
+
onClick,
|
|
20
|
+
size = 13,
|
|
21
|
+
}: {
|
|
22
|
+
message: string;
|
|
23
|
+
onClick?: () => void;
|
|
24
|
+
size?: number;
|
|
25
|
+
}) {
|
|
26
|
+
const triggerRef = useRef<HTMLElement | null>(null);
|
|
27
|
+
const [tooltipPosition, setTooltipPosition] =
|
|
28
|
+
useState<TooltipPosition | null>(null);
|
|
29
|
+
|
|
30
|
+
const setTriggerRef: RefCallback<HTMLElement> = useCallback((node) => {
|
|
31
|
+
triggerRef.current = node;
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
const showTooltip = useCallback(() => {
|
|
35
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
36
|
+
if (!rect) return;
|
|
37
|
+
|
|
38
|
+
const tooltipWidth = 260;
|
|
39
|
+
const left = Math.min(
|
|
40
|
+
Math.max(rect.left + rect.width / 2, tooltipWidth / 2 + 8),
|
|
41
|
+
window.innerWidth - tooltipWidth / 2 - 8,
|
|
42
|
+
);
|
|
43
|
+
const top =
|
|
44
|
+
rect.bottom + 8 < window.innerHeight - 48
|
|
45
|
+
? rect.bottom + 8
|
|
46
|
+
: Math.max(8, rect.top - 44);
|
|
47
|
+
|
|
48
|
+
setTooltipPosition({ left, top });
|
|
49
|
+
}, []);
|
|
50
|
+
|
|
51
|
+
const hideTooltip = useCallback(() => {
|
|
52
|
+
setTooltipPosition(null);
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const triggerStyle: CSSProperties = {
|
|
56
|
+
width: size + 5,
|
|
57
|
+
height: size + 5,
|
|
58
|
+
padding: 0,
|
|
59
|
+
border: "none",
|
|
60
|
+
borderRadius: 4,
|
|
61
|
+
background: "transparent",
|
|
62
|
+
color: EXPIRED_AGENT_COLOR,
|
|
63
|
+
display: "inline-flex",
|
|
64
|
+
alignItems: "center",
|
|
65
|
+
justifyContent: "center",
|
|
66
|
+
flexShrink: 0,
|
|
67
|
+
cursor: onClick ? "pointer" : "help",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const sharedProps = {
|
|
71
|
+
ref: setTriggerRef,
|
|
72
|
+
"aria-label": "Agent approval expired",
|
|
73
|
+
onMouseEnter: showTooltip,
|
|
74
|
+
onMouseLeave: hideTooltip,
|
|
75
|
+
onFocus: showTooltip,
|
|
76
|
+
onBlur: hideTooltip,
|
|
77
|
+
style: triggerStyle,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<>
|
|
82
|
+
{onClick ? (
|
|
83
|
+
<button
|
|
84
|
+
type="button"
|
|
85
|
+
{...sharedProps}
|
|
86
|
+
onClick={(event) => {
|
|
87
|
+
event.stopPropagation();
|
|
88
|
+
onClick();
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
<AlertTriangle size={size} color={EXPIRED_AGENT_COLOR} />
|
|
92
|
+
</button>
|
|
93
|
+
) : (
|
|
94
|
+
<span {...sharedProps}>
|
|
95
|
+
<AlertTriangle size={size} color={EXPIRED_AGENT_COLOR} />
|
|
96
|
+
</span>
|
|
97
|
+
)}
|
|
98
|
+
{tooltipPosition && (
|
|
99
|
+
<div
|
|
100
|
+
role="tooltip"
|
|
101
|
+
style={{
|
|
102
|
+
position: "fixed",
|
|
103
|
+
left: tooltipPosition.left,
|
|
104
|
+
top: tooltipPosition.top,
|
|
105
|
+
transform: "translateX(-50%)",
|
|
106
|
+
zIndex: 10_000,
|
|
107
|
+
width: 260,
|
|
108
|
+
maxWidth: "calc(100vw - 16px)",
|
|
109
|
+
padding: "7px 9px",
|
|
110
|
+
borderRadius: 6,
|
|
111
|
+
border: "1px solid rgba(255,255,255,0.12)",
|
|
112
|
+
background: "#111827",
|
|
113
|
+
boxShadow: "0 10px 28px rgba(0,0,0,0.45)",
|
|
114
|
+
color: "#e5e7eb",
|
|
115
|
+
fontSize: 12,
|
|
116
|
+
lineHeight: "1rem",
|
|
117
|
+
fontWeight: 500,
|
|
118
|
+
pointerEvents: "none",
|
|
119
|
+
whiteSpace: "normal",
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
{message}
|
|
123
|
+
</div>
|
|
124
|
+
)}
|
|
125
|
+
</>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { EXPIRED_AGENT_COLOR };
|
|
@@ -132,6 +132,10 @@ export function DeleteWalletModal({
|
|
|
132
132
|
const [deleteHovered, setDeleteHovered] = useState(false);
|
|
133
133
|
|
|
134
134
|
const walletName = wallet?.name || "Unnamed Wallet";
|
|
135
|
+
const displayAddress =
|
|
136
|
+
wallet?.isAgent && wallet.agentEthereumAddress?.value
|
|
137
|
+
? wallet.agentEthereumAddress.value
|
|
138
|
+
: wallet?.ethereumAddress;
|
|
135
139
|
const isNameMatch = confirmName === walletName;
|
|
136
140
|
const canDelete = isNameMatch && !isDeleting;
|
|
137
141
|
|
|
@@ -258,7 +262,7 @@ export function DeleteWalletModal({
|
|
|
258
262
|
wordBreak: "break-all",
|
|
259
263
|
}}
|
|
260
264
|
>
|
|
261
|
-
{
|
|
265
|
+
{displayAddress}
|
|
262
266
|
</p>
|
|
263
267
|
</div>
|
|
264
268
|
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
import {
|
|
28
28
|
AGENT_NAME,
|
|
29
29
|
clearAgent as clearStoredAgent,
|
|
30
|
+
fetchAgentByAddress,
|
|
30
31
|
fetchActiveAgent,
|
|
31
32
|
generateAgentKey,
|
|
32
33
|
isAgentValid,
|
|
@@ -37,6 +38,7 @@ import {
|
|
|
37
38
|
import { createStaticClient, createTelegramClient } from "./grpc";
|
|
38
39
|
import { GrpcExchangeTransport } from "./GrpcExchangeTransport";
|
|
39
40
|
import { PrivateKeySigner } from "./privateKeySigner";
|
|
41
|
+
import { createTelegramAgentApprovalName } from "./agentWallet";
|
|
40
42
|
import type {
|
|
41
43
|
AuthMethod,
|
|
42
44
|
EoaSigner,
|
|
@@ -45,6 +47,7 @@ import type {
|
|
|
45
47
|
HypurrConnectConfig,
|
|
46
48
|
HypurrConnectState,
|
|
47
49
|
HypurrUser,
|
|
50
|
+
RenewAgentWalletParams,
|
|
48
51
|
SignTypedDataFn,
|
|
49
52
|
StoredAgent,
|
|
50
53
|
} from "./types";
|
|
@@ -60,6 +63,23 @@ const TELEGRAM_AUTH_STATE_KEY = "hypurr-connect-auth-state";
|
|
|
60
63
|
const TELEGRAM_AUTH_MESSAGE = "hypurr-connect:telegram-auth";
|
|
61
64
|
const DEFAULT_AUTH_HUB_URL = "https://auth.hypurr.fun/login";
|
|
62
65
|
const DEFAULT_MEDIA_URL = "https://media.hypurr.fun";
|
|
66
|
+
const USER_SIGNED_DOMAIN_NAME = "HyperliquidSignTransaction";
|
|
67
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" as const;
|
|
68
|
+
const APPROVE_AGENT_PRIMARY_TYPE = "HyperliquidTransaction:ApproveAgent";
|
|
69
|
+
const APPROVE_AGENT_TYPES = {
|
|
70
|
+
[APPROVE_AGENT_PRIMARY_TYPE]: [
|
|
71
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
72
|
+
{ name: "agentAddress", type: "address" },
|
|
73
|
+
{ name: "agentName", type: "string" },
|
|
74
|
+
{ name: "nonce", type: "uint64" },
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
const EIP712_DOMAIN_TYPES = [
|
|
78
|
+
{ name: "name", type: "string" },
|
|
79
|
+
{ name: "version", type: "string" },
|
|
80
|
+
{ name: "chainId", type: "uint256" },
|
|
81
|
+
{ name: "verifyingContract", type: "address" },
|
|
82
|
+
];
|
|
63
83
|
const IGNORED_EXTERNAL_SIGNATURE =
|
|
64
84
|
"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b" as const;
|
|
65
85
|
const DEFAULT_TELEGRAM_SCOPES = [
|
|
@@ -105,6 +125,67 @@ function isAddress(value?: string | null): value is Hex {
|
|
|
105
125
|
return !!value && /^0x[a-fA-F0-9]{40}$/.test(value);
|
|
106
126
|
}
|
|
107
127
|
|
|
128
|
+
function createApproveAgentAction(params: {
|
|
129
|
+
agentAddress: Hex;
|
|
130
|
+
agentName: string;
|
|
131
|
+
chainId: number;
|
|
132
|
+
isTestnet: boolean;
|
|
133
|
+
}) {
|
|
134
|
+
const nonce = Date.now();
|
|
135
|
+
return {
|
|
136
|
+
action: {
|
|
137
|
+
type: "approveAgent" as const,
|
|
138
|
+
signatureChainId: `0x${params.chainId.toString(16)}` as Hex,
|
|
139
|
+
hyperliquidChain: (params.isTestnet ? "Testnet" : "Mainnet") as
|
|
140
|
+
| "Testnet"
|
|
141
|
+
| "Mainnet",
|
|
142
|
+
agentAddress: params.agentAddress.toLowerCase() as Hex,
|
|
143
|
+
agentName: params.agentName,
|
|
144
|
+
nonce,
|
|
145
|
+
},
|
|
146
|
+
nonce,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
type ApproveAgentAction = ReturnType<typeof createApproveAgentAction>["action"];
|
|
151
|
+
|
|
152
|
+
async function signApproveAgentAction(params: {
|
|
153
|
+
signTypedDataAsync: SignTypedDataFn;
|
|
154
|
+
agentAddress: Hex;
|
|
155
|
+
agentName: string;
|
|
156
|
+
chainId: number;
|
|
157
|
+
isTestnet: boolean;
|
|
158
|
+
}): Promise<{
|
|
159
|
+
action: ApproveAgentAction;
|
|
160
|
+
signatureHex: Hex;
|
|
161
|
+
}> {
|
|
162
|
+
const { action } = createApproveAgentAction(params);
|
|
163
|
+
const signatureHex = await params.signTypedDataAsync({
|
|
164
|
+
domain: {
|
|
165
|
+
name: USER_SIGNED_DOMAIN_NAME,
|
|
166
|
+
version: "1",
|
|
167
|
+
chainId: params.chainId,
|
|
168
|
+
verifyingContract: ZERO_ADDRESS,
|
|
169
|
+
},
|
|
170
|
+
types: {
|
|
171
|
+
EIP712Domain: EIP712_DOMAIN_TYPES,
|
|
172
|
+
...APPROVE_AGENT_TYPES,
|
|
173
|
+
},
|
|
174
|
+
primaryType: APPROVE_AGENT_PRIMARY_TYPE,
|
|
175
|
+
message: {
|
|
176
|
+
hyperliquidChain: action.hyperliquidChain,
|
|
177
|
+
agentAddress: action.agentAddress,
|
|
178
|
+
agentName: action.agentName,
|
|
179
|
+
nonce: action.nonce,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
action,
|
|
185
|
+
signatureHex,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
108
189
|
function getRawSignedTransaction(result: unknown): Hex | null {
|
|
109
190
|
if (typeof result === "string" && result.startsWith("0x")) {
|
|
110
191
|
return result as Hex;
|
|
@@ -928,6 +1009,113 @@ export function HypurrConnectProvider({
|
|
|
928
1009
|
[tgClient, telegramRpcOptions, refreshWallets],
|
|
929
1010
|
);
|
|
930
1011
|
|
|
1012
|
+
const renewAgentWallet = useCallback(
|
|
1013
|
+
async ({
|
|
1014
|
+
walletId,
|
|
1015
|
+
ownerAddress,
|
|
1016
|
+
signTypedDataAsync,
|
|
1017
|
+
chainId,
|
|
1018
|
+
approvalDurationMs,
|
|
1019
|
+
agentName,
|
|
1020
|
+
}: RenewAgentWalletParams): Promise<void> => {
|
|
1021
|
+
if (authMethod !== "telegram") {
|
|
1022
|
+
throw new Error(
|
|
1023
|
+
"[HypurrConnect] Agent wallet renewal is only available for Telegram wallets.",
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
1026
|
+
if (!isAddress(ownerAddress)) {
|
|
1027
|
+
throw new Error(
|
|
1028
|
+
"[HypurrConnect] Connect the owner EOA wallet before renewing this agent.",
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
if (!telegramRpcOptions) {
|
|
1032
|
+
throw new Error("[HypurrConnect] No Telegram RPC session available.");
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
const wallet = wallets.find((w) => w.id === walletId);
|
|
1036
|
+
if (!wallet) {
|
|
1037
|
+
throw new Error("[HypurrConnect] Agent wallet not found.");
|
|
1038
|
+
}
|
|
1039
|
+
if (!wallet.isAgent) {
|
|
1040
|
+
throw new Error(
|
|
1041
|
+
"[HypurrConnect] Selected wallet is not an agent wallet.",
|
|
1042
|
+
);
|
|
1043
|
+
}
|
|
1044
|
+
if (!isAddress(wallet.ethereumAddress)) {
|
|
1045
|
+
throw new Error(
|
|
1046
|
+
"[HypurrConnect] Agent wallet does not have a valid owner EVM address.",
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
if (ownerAddress.toLowerCase() !== wallet.ethereumAddress.toLowerCase()) {
|
|
1050
|
+
throw new Error(
|
|
1051
|
+
"[HypurrConnect] Connect the owner EOA for this agent wallet before renewing.",
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
const agentAddress = wallet.agentEthereumAddress?.value;
|
|
1056
|
+
if (!isAddress(agentAddress)) {
|
|
1057
|
+
throw new Error(
|
|
1058
|
+
"[HypurrConnect] Agent wallet does not have a valid agent EVM address.",
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const isTestnet = config.isTestnet ?? false;
|
|
1063
|
+
const approvalAgentName =
|
|
1064
|
+
agentName ?? createTelegramAgentApprovalName(approvalDurationMs);
|
|
1065
|
+
setTgError(null);
|
|
1066
|
+
|
|
1067
|
+
try {
|
|
1068
|
+
const { action, signatureHex } = await signApproveAgentAction({
|
|
1069
|
+
signTypedDataAsync,
|
|
1070
|
+
agentAddress,
|
|
1071
|
+
agentName: approvalAgentName,
|
|
1072
|
+
chainId,
|
|
1073
|
+
isTestnet,
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
await tgClient.hyperliquidAgentWalletRenew(
|
|
1077
|
+
{
|
|
1078
|
+
authData: {},
|
|
1079
|
+
address: { value: wallet.ethereumAddress },
|
|
1080
|
+
signature: {
|
|
1081
|
+
agentAddress: action.agentAddress,
|
|
1082
|
+
agentName: action.agentName,
|
|
1083
|
+
nonce: action.nonce,
|
|
1084
|
+
chainId,
|
|
1085
|
+
signature: signatureHex,
|
|
1086
|
+
},
|
|
1087
|
+
},
|
|
1088
|
+
telegramRpcOptions,
|
|
1089
|
+
);
|
|
1090
|
+
|
|
1091
|
+
const remote = await fetchAgentByAddress(
|
|
1092
|
+
ownerAddress,
|
|
1093
|
+
agentAddress,
|
|
1094
|
+
isTestnet,
|
|
1095
|
+
);
|
|
1096
|
+
if (remote && remote.validUntil <= Date.now()) {
|
|
1097
|
+
throw new Error(
|
|
1098
|
+
"[HypurrConnect] Agent renewal was submitted, but the agent is still expired.",
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
refreshWallets();
|
|
1103
|
+
} catch (err) {
|
|
1104
|
+
console.error("[HypurrConnect] Agent wallet renewal failed:", err);
|
|
1105
|
+
setTgError(err instanceof Error ? err.message : String(err));
|
|
1106
|
+
throw err;
|
|
1107
|
+
}
|
|
1108
|
+
},
|
|
1109
|
+
[
|
|
1110
|
+
authMethod,
|
|
1111
|
+
config.isTestnet,
|
|
1112
|
+
refreshWallets,
|
|
1113
|
+
telegramRpcOptions,
|
|
1114
|
+
tgClient,
|
|
1115
|
+
wallets,
|
|
1116
|
+
],
|
|
1117
|
+
);
|
|
1118
|
+
|
|
931
1119
|
const createWalletPack = useCallback(
|
|
932
1120
|
async (name: string): Promise<number> => {
|
|
933
1121
|
const { response } = await tgClient.telegramChatWalletPackCreate(
|
|
@@ -1155,7 +1343,9 @@ export function HypurrConnectProvider({
|
|
|
1155
1343
|
? configuredReturnTo()
|
|
1156
1344
|
: configuredReturnTo || currentReturnTo();
|
|
1157
1345
|
|
|
1158
|
-
const authUrl = new URL(
|
|
1346
|
+
const authUrl = new URL(
|
|
1347
|
+
config.telegram?.authHubUrl || DEFAULT_AUTH_HUB_URL,
|
|
1348
|
+
);
|
|
1159
1349
|
authUrl.searchParams.set("return_to", returnTo);
|
|
1160
1350
|
authUrl.searchParams.set("state", state);
|
|
1161
1351
|
authUrl.searchParams.set("scope", normalizeScopes(config.telegram?.scope));
|
|
@@ -1350,6 +1540,7 @@ export function HypurrConnectProvider({
|
|
|
1350
1540
|
createWallet,
|
|
1351
1541
|
deleteWallet,
|
|
1352
1542
|
renameWallet,
|
|
1543
|
+
renewAgentWallet,
|
|
1353
1544
|
refreshWallets,
|
|
1354
1545
|
|
|
1355
1546
|
packs,
|
|
@@ -1399,6 +1590,7 @@ export function HypurrConnectProvider({
|
|
|
1399
1590
|
createWallet,
|
|
1400
1591
|
deleteWallet,
|
|
1401
1592
|
renameWallet,
|
|
1593
|
+
renewAgentWallet,
|
|
1402
1594
|
refreshWallets,
|
|
1403
1595
|
packs,
|
|
1404
1596
|
createWalletPack,
|
package/src/LoginModal.tsx
CHANGED
|
@@ -17,10 +17,14 @@ import { TelegramColorIcon } from "./icons/TelegramColorIcon";
|
|
|
17
17
|
export interface LoginModalProps {
|
|
18
18
|
onConnectWallet: () => void;
|
|
19
19
|
walletIcon?: ReactNode;
|
|
20
|
+
/** CSS color used as the modal/drawer background. Defaults to `rgba(20,20,20,0.95)`. */
|
|
21
|
+
backgroundColor?: string;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
const MOBILE_BREAKPOINT = 640;
|
|
23
25
|
|
|
26
|
+
const DEFAULT_BACKGROUND_COLOR = "rgba(20,20,20,0.95)";
|
|
27
|
+
|
|
24
28
|
const btnStyle: CSSProperties = {
|
|
25
29
|
display: "flex",
|
|
26
30
|
height: 53,
|
|
@@ -28,19 +32,19 @@ const btnStyle: CSSProperties = {
|
|
|
28
32
|
alignItems: "center",
|
|
29
33
|
gap: 12,
|
|
30
34
|
overflow: "hidden",
|
|
31
|
-
borderRadius:
|
|
32
|
-
background: "rgba(255,255,255,0.
|
|
33
|
-
padding: "
|
|
35
|
+
borderRadius: 4,
|
|
36
|
+
background: "rgba(255,255,255,0.1)",
|
|
37
|
+
padding: "4px 24px",
|
|
34
38
|
fontSize: 14,
|
|
35
|
-
fontWeight:
|
|
36
|
-
letterSpacing: "-0.
|
|
39
|
+
fontWeight: 500,
|
|
40
|
+
letterSpacing: "-0.03em",
|
|
37
41
|
color: "#fff",
|
|
38
42
|
cursor: "pointer",
|
|
39
43
|
border: "none",
|
|
40
44
|
transition: "background 150ms",
|
|
41
45
|
};
|
|
42
46
|
|
|
43
|
-
const btnHoverBg = { background: "rgba(255,255,255,0.
|
|
47
|
+
const btnHoverBg = { background: "rgba(255,255,255,0.15)" };
|
|
44
48
|
|
|
45
49
|
const backdropStyle: CSSProperties = {
|
|
46
50
|
position: "fixed",
|
|
@@ -70,14 +74,13 @@ const modalBoxStyle: CSSProperties = {
|
|
|
70
74
|
overflow: "hidden",
|
|
71
75
|
borderRadius: 12,
|
|
72
76
|
border: "1px solid rgba(255,255,255,0.1)",
|
|
73
|
-
background: "#282828",
|
|
74
77
|
padding: 24,
|
|
75
78
|
};
|
|
76
79
|
|
|
77
80
|
const headingStyle: CSSProperties = {
|
|
78
|
-
fontSize:
|
|
79
|
-
fontWeight:
|
|
80
|
-
letterSpacing: "-0.
|
|
81
|
+
fontSize: 20,
|
|
82
|
+
fontWeight: 500,
|
|
83
|
+
letterSpacing: "-0.03em",
|
|
81
84
|
color: "#fff",
|
|
82
85
|
margin: 0,
|
|
83
86
|
};
|
|
@@ -88,7 +91,7 @@ const dividerStyle: CSSProperties = {
|
|
|
88
91
|
background: "rgba(255,255,255,0.05)",
|
|
89
92
|
};
|
|
90
93
|
|
|
91
|
-
const iconSize: CSSProperties = { width:
|
|
94
|
+
const iconSize: CSSProperties = { width: 26, height: 26 };
|
|
92
95
|
|
|
93
96
|
const mobileQuery =
|
|
94
97
|
typeof window !== "undefined"
|
|
@@ -127,7 +130,11 @@ function HoverButton({
|
|
|
127
130
|
);
|
|
128
131
|
}
|
|
129
132
|
|
|
130
|
-
export function LoginModal({
|
|
133
|
+
export function LoginModal({
|
|
134
|
+
onConnectWallet,
|
|
135
|
+
walletIcon,
|
|
136
|
+
backgroundColor = DEFAULT_BACKGROUND_COLOR,
|
|
137
|
+
}: LoginModalProps) {
|
|
131
138
|
const { loginTelegram, loginModalOpen, closeLoginModal } =
|
|
132
139
|
useHypurrConnectInternal();
|
|
133
140
|
|
|
@@ -174,7 +181,11 @@ export function LoginModal({ onConnectWallet, walletIcon }: LoginModalProps) {
|
|
|
174
181
|
<AnimatePresence>
|
|
175
182
|
{loginModalOpen &&
|
|
176
183
|
(isMobile ? (
|
|
177
|
-
<MobileDrawer
|
|
184
|
+
<MobileDrawer
|
|
185
|
+
key="drawer"
|
|
186
|
+
onClose={closeLoginModal}
|
|
187
|
+
backgroundColor={backgroundColor}
|
|
188
|
+
>
|
|
178
189
|
{modalContent}
|
|
179
190
|
</MobileDrawer>
|
|
180
191
|
) : (
|
|
@@ -198,7 +209,7 @@ export function LoginModal({ onConnectWallet, walletIcon }: LoginModalProps) {
|
|
|
198
209
|
onClick={closeLoginModal}
|
|
199
210
|
>
|
|
200
211
|
<motion.div
|
|
201
|
-
style={modalBoxStyle}
|
|
212
|
+
style={{ ...modalBoxStyle, background: backgroundColor }}
|
|
202
213
|
initial={{ scale: 0.96, opacity: 0, y: 8 }}
|
|
203
214
|
animate={{ scale: 1, opacity: 1, y: 0 }}
|
|
204
215
|
exit={{ scale: 0.96, opacity: 0, y: 8 }}
|
|
@@ -230,7 +241,6 @@ const drawerSheetStyle: CSSProperties = {
|
|
|
230
241
|
borderLeft: "1px solid rgba(255,255,255,0.1)",
|
|
231
242
|
borderRight: "1px solid rgba(255,255,255,0.1)",
|
|
232
243
|
borderTop: "1px solid rgba(255,255,255,0.1)",
|
|
233
|
-
background: "#282828",
|
|
234
244
|
padding: "12px 24px max(24px, env(safe-area-inset-bottom))",
|
|
235
245
|
};
|
|
236
246
|
|
|
@@ -241,7 +251,6 @@ const drawerBgStyle: CSSProperties = {
|
|
|
241
251
|
top: 0,
|
|
242
252
|
bottom: "-100vh",
|
|
243
253
|
zIndex: -1,
|
|
244
|
-
background: "#282828",
|
|
245
254
|
borderTopLeftRadius: 12,
|
|
246
255
|
borderTopRightRadius: 12,
|
|
247
256
|
};
|
|
@@ -256,16 +265,18 @@ const grabHandleStyle: CSSProperties = {
|
|
|
256
265
|
margin: "0 auto",
|
|
257
266
|
height: 4,
|
|
258
267
|
width: 100,
|
|
259
|
-
borderRadius:
|
|
268
|
+
borderRadius: 4,
|
|
260
269
|
background: "rgba(255,255,255,0.05)",
|
|
261
270
|
};
|
|
262
271
|
|
|
263
272
|
function MobileDrawer({
|
|
264
273
|
children,
|
|
265
274
|
onClose,
|
|
275
|
+
backgroundColor,
|
|
266
276
|
}: {
|
|
267
277
|
children: ReactNode;
|
|
268
278
|
onClose: () => void;
|
|
279
|
+
backgroundColor: string;
|
|
269
280
|
}) {
|
|
270
281
|
const controls = useAnimationControls();
|
|
271
282
|
|
|
@@ -294,7 +305,7 @@ function MobileDrawer({
|
|
|
294
305
|
|
|
295
306
|
<motion.div
|
|
296
307
|
key="drawer-sheet"
|
|
297
|
-
style={drawerSheetStyle}
|
|
308
|
+
style={{ ...drawerSheetStyle, background: backgroundColor }}
|
|
298
309
|
initial={{ y: "100%" }}
|
|
299
310
|
animate={{ y: 0 }}
|
|
300
311
|
exit={{ y: "100%" }}
|
|
@@ -304,7 +315,7 @@ function MobileDrawer({
|
|
|
304
315
|
dragElastic={{ top: 0, bottom: 0.4 }}
|
|
305
316
|
onDragEnd={handleDragEnd}
|
|
306
317
|
>
|
|
307
|
-
<div style={drawerBgStyle} />
|
|
318
|
+
<div style={{ ...drawerBgStyle, background: backgroundColor }} />
|
|
308
319
|
|
|
309
320
|
<div style={grabHandleAreaStyle}>
|
|
310
321
|
<div style={grabHandleStyle} />
|
|
@@ -125,6 +125,10 @@ export function RenameWalletModal({
|
|
|
125
125
|
const [saveHovered, setSaveHovered] = useState(false);
|
|
126
126
|
|
|
127
127
|
const currentName = wallet?.name || "Unnamed";
|
|
128
|
+
const displayAddress =
|
|
129
|
+
wallet?.isAgent && wallet.agentEthereumAddress?.value
|
|
130
|
+
? wallet.agentEthereumAddress.value
|
|
131
|
+
: wallet?.ethereumAddress;
|
|
128
132
|
const trimmedName = name.trim();
|
|
129
133
|
const isNameChanged = trimmedName !== currentName;
|
|
130
134
|
const isNameValid = WALLET_NAME_REGEX.test(trimmedName);
|
|
@@ -233,7 +237,7 @@ export function RenameWalletModal({
|
|
|
233
237
|
wordBreak: "break-all",
|
|
234
238
|
}}
|
|
235
239
|
>
|
|
236
|
-
{
|
|
240
|
+
{displayAddress}
|
|
237
241
|
</p>
|
|
238
242
|
</div>
|
|
239
243
|
|