@hfunlabs/hypurr-connect 0.1.10 → 0.1.12
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 +28 -1
- package/dist/index.d.ts +49 -2
- package/dist/index.js +179 -12
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/HypurrConnectProvider.tsx +194 -25
- package/src/agent.ts +2 -2
- package/src/index.ts +7 -0
- package/src/privateKeySigner.ts +32 -0
- package/src/types.ts +46 -0
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
type IRequestTransport,
|
|
5
5
|
} from "@hfunlabs/hyperliquid";
|
|
6
6
|
import {
|
|
7
|
-
PrivateKeySigner,
|
|
8
7
|
signUserSignedAction,
|
|
8
|
+
type AbstractViemLocalAccount,
|
|
9
9
|
} from "@hfunlabs/hyperliquid/signing";
|
|
10
10
|
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
|
11
11
|
import type { TelegramUserResponse } from "hypurr-grpc/ts/hypurr/telegram/telegram_service";
|
|
@@ -36,9 +36,12 @@ import {
|
|
|
36
36
|
} from "./agent";
|
|
37
37
|
import { createStaticClient, createTelegramClient } from "./grpc";
|
|
38
38
|
import { GrpcExchangeTransport } from "./GrpcExchangeTransport";
|
|
39
|
+
import { PrivateKeySigner } from "./privateKeySigner";
|
|
39
40
|
import type {
|
|
40
41
|
AuthMethod,
|
|
41
42
|
EoaSigner,
|
|
43
|
+
EvmTransactionRequest,
|
|
44
|
+
Hex,
|
|
42
45
|
HypurrConnectConfig,
|
|
43
46
|
HypurrConnectState,
|
|
44
47
|
HypurrUser,
|
|
@@ -57,7 +60,10 @@ const TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-jwt";
|
|
|
57
60
|
const LEGACY_TELEGRAM_STORAGE_KEY = "hypurr-connect-tg-user";
|
|
58
61
|
const TELEGRAM_AUTH_STATE_KEY = "hypurr-connect-auth-state";
|
|
59
62
|
const TELEGRAM_AUTH_MESSAGE = "hypurr-connect:telegram-auth";
|
|
60
|
-
const DEFAULT_AUTH_HUB_URL = "https://
|
|
63
|
+
const DEFAULT_AUTH_HUB_URL = "https://auth.hypurr.fun/login";
|
|
64
|
+
const DEFAULT_MEDIA_URL = "https://media.hypurr.fun";
|
|
65
|
+
const IGNORED_EXTERNAL_SIGNATURE =
|
|
66
|
+
"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b" as const;
|
|
61
67
|
const DEFAULT_TELEGRAM_SCOPES = [
|
|
62
68
|
"telegram:user:read",
|
|
63
69
|
"telegram:wallet:read",
|
|
@@ -67,8 +73,20 @@ const DEFAULT_TELEGRAM_SCOPES = [
|
|
|
67
73
|
"telegram:cabal:read",
|
|
68
74
|
"telegram:cabal:write",
|
|
69
75
|
"telegram:agent:write",
|
|
76
|
+
"telegram:support:read",
|
|
77
|
+
"telegram:support:write",
|
|
70
78
|
];
|
|
71
79
|
|
|
80
|
+
function createExternalSigningWallet(address: Hex): AbstractViemLocalAccount {
|
|
81
|
+
return {
|
|
82
|
+
address,
|
|
83
|
+
signTypedData(params) {
|
|
84
|
+
void params;
|
|
85
|
+
return Promise.resolve(IGNORED_EXTERNAL_SIGNATURE);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
72
90
|
function isInvalidTelegramAuthError(err: unknown): boolean {
|
|
73
91
|
const msg =
|
|
74
92
|
err instanceof Error
|
|
@@ -81,6 +99,64 @@ function isInvalidTelegramAuthError(err: unknown): boolean {
|
|
|
81
99
|
);
|
|
82
100
|
}
|
|
83
101
|
|
|
102
|
+
function normalizeMediaUrl(mediaUrl?: string): string {
|
|
103
|
+
return (mediaUrl?.trim() || DEFAULT_MEDIA_URL).replace(/\/+$/, "");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isAddress(value?: string | null): value is Hex {
|
|
107
|
+
return !!value && /^0x[a-fA-F0-9]{40}$/.test(value);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getRawSignedTransaction(result: unknown): Hex | null {
|
|
111
|
+
if (typeof result === "string" && result.startsWith("0x")) {
|
|
112
|
+
return result as Hex;
|
|
113
|
+
}
|
|
114
|
+
if (!result || typeof result !== "object") return null;
|
|
115
|
+
|
|
116
|
+
const record = result as Record<string, unknown>;
|
|
117
|
+
const candidates = [
|
|
118
|
+
record.raw,
|
|
119
|
+
record.rawTransaction,
|
|
120
|
+
record.signedTransaction,
|
|
121
|
+
record.serializedTransaction,
|
|
122
|
+
record.result,
|
|
123
|
+
];
|
|
124
|
+
const raw = candidates.find(
|
|
125
|
+
(value): value is string =>
|
|
126
|
+
typeof value === "string" && value.startsWith("0x"),
|
|
127
|
+
);
|
|
128
|
+
return raw ? (raw as Hex) : null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function decodeJsonBytes(bytes: Uint8Array): unknown {
|
|
132
|
+
const text = new TextDecoder().decode(bytes);
|
|
133
|
+
if (!text) return null;
|
|
134
|
+
try {
|
|
135
|
+
return JSON.parse(text);
|
|
136
|
+
} catch {
|
|
137
|
+
return text;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function encodeJsonBytes(value: unknown): Uint8Array {
|
|
142
|
+
return new TextEncoder().encode(JSON.stringify(value));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function withExpectedFrom(
|
|
146
|
+
transaction: EvmTransactionRequest,
|
|
147
|
+
address: Hex,
|
|
148
|
+
): EvmTransactionRequest {
|
|
149
|
+
if (
|
|
150
|
+
transaction.from &&
|
|
151
|
+
transaction.from.toLowerCase() !== address.toLowerCase()
|
|
152
|
+
) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"[HypurrConnect] EVM transaction `from` does not match the connected wallet.",
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return transaction.from ? transaction : { ...transaction, from: address };
|
|
158
|
+
}
|
|
159
|
+
|
|
84
160
|
function currentReturnTo(): string {
|
|
85
161
|
const url = new URL(window.location.href);
|
|
86
162
|
for (const param of [
|
|
@@ -108,9 +184,7 @@ function normalizeScopes(scope?: string | string[]): string {
|
|
|
108
184
|
return scope?.trim() || DEFAULT_TELEGRAM_SCOPES.join(" ");
|
|
109
185
|
}
|
|
110
186
|
|
|
111
|
-
function isTelegramAuthMessage(
|
|
112
|
-
data: unknown,
|
|
113
|
-
): data is {
|
|
187
|
+
function isTelegramAuthMessage(data: unknown): data is {
|
|
114
188
|
type: typeof TELEGRAM_AUTH_MESSAGE;
|
|
115
189
|
token: string;
|
|
116
190
|
state: string;
|
|
@@ -423,12 +497,16 @@ export function HypurrConnectProvider({
|
|
|
423
497
|
|
|
424
498
|
const user = useMemo<HypurrUser | null>(() => {
|
|
425
499
|
if (tgAuthToken && authMethod === "telegram" && selectedWallet && tgUser) {
|
|
500
|
+
const mediaUrl = normalizeMediaUrl(config.mediaUrl);
|
|
426
501
|
return {
|
|
427
502
|
address: selectedWallet.ethereumAddress,
|
|
428
503
|
walletId: selectedWallet.id,
|
|
429
504
|
displayName: tgUser.telegramUsername
|
|
430
505
|
? `@${tgUser.telegramUsername}`
|
|
431
506
|
: `Telegram ${tgUser.telegramId}`,
|
|
507
|
+
photoUrl: tgUser.pictureFileId
|
|
508
|
+
? `${mediaUrl}/${tgUser.pictureFileId}`
|
|
509
|
+
: undefined,
|
|
432
510
|
authMethod: "telegram",
|
|
433
511
|
telegramId: String(tgUser.telegramId),
|
|
434
512
|
hfunScore: tgUser?.reputation?.hfunScore,
|
|
@@ -444,10 +522,17 @@ export function HypurrConnectProvider({
|
|
|
444
522
|
};
|
|
445
523
|
}
|
|
446
524
|
return null;
|
|
447
|
-
}, [
|
|
525
|
+
}, [
|
|
526
|
+
tgAuthToken,
|
|
527
|
+
selectedWallet,
|
|
528
|
+
eoaAddress,
|
|
529
|
+
authMethod,
|
|
530
|
+
tgUser,
|
|
531
|
+
config.mediaUrl,
|
|
532
|
+
]);
|
|
448
533
|
|
|
449
534
|
// ── Exchange client ──────────────────────────────────────────
|
|
450
|
-
// Telegram: GrpcExchangeTransport → HyperliquidCoreAction (server signs)
|
|
535
|
+
// Telegram: dummy local wallet → GrpcExchangeTransport → HyperliquidCoreAction (server signs)
|
|
451
536
|
// EOA: dual wallet — agent key for L1 actions, master signer for user-signed
|
|
452
537
|
// actions (transfers, withdrawals, etc.). The dual wallet inspects the
|
|
453
538
|
// EIP-712 domain name to decide which key signs each request.
|
|
@@ -493,8 +578,7 @@ export function HypurrConnectProvider({
|
|
|
493
578
|
});
|
|
494
579
|
return new ExchangeClient({
|
|
495
580
|
transport,
|
|
496
|
-
|
|
497
|
-
userAddress: user.address as `0x${string}`,
|
|
581
|
+
wallet: createExternalSigningWallet(user.address as Hex),
|
|
498
582
|
});
|
|
499
583
|
}
|
|
500
584
|
|
|
@@ -514,8 +598,7 @@ export function HypurrConnectProvider({
|
|
|
514
598
|
};
|
|
515
599
|
return new ExchangeClient({
|
|
516
600
|
transport: noAgentTransport,
|
|
517
|
-
|
|
518
|
-
userAddress: eoaAddress,
|
|
601
|
+
wallet: createExternalSigningWallet(eoaAddress),
|
|
519
602
|
});
|
|
520
603
|
}
|
|
521
604
|
|
|
@@ -655,20 +738,9 @@ export function HypurrConnectProvider({
|
|
|
655
738
|
// Dual wallet: routes signing based on the EIP-712 domain.
|
|
656
739
|
// "Exchange" domain → L1 action → agent key signs (auto-provisions if needed).
|
|
657
740
|
// "HyperliquidSignTransaction" domain → user-signed → master wallet (popup).
|
|
658
|
-
const dualWallet = {
|
|
741
|
+
const dualWallet: AbstractViemLocalAccount = {
|
|
659
742
|
address: ownerAddress,
|
|
660
|
-
async signTypedData(params: {
|
|
661
|
-
domain: {
|
|
662
|
-
name?: string;
|
|
663
|
-
version?: string;
|
|
664
|
-
chainId?: number;
|
|
665
|
-
verifyingContract?: `0x${string}`;
|
|
666
|
-
salt?: `0x${string}`;
|
|
667
|
-
};
|
|
668
|
-
types: Record<string, { name: string; type: string }[]>;
|
|
669
|
-
primaryType: string;
|
|
670
|
-
message: Record<string, unknown>;
|
|
671
|
-
}): Promise<`0x${string}`> {
|
|
743
|
+
async signTypedData(params): Promise<`0x${string}`> {
|
|
672
744
|
if (params.domain.name === "HyperliquidSignTransaction") {
|
|
673
745
|
const signer = signerRef.current;
|
|
674
746
|
if (!signer) {
|
|
@@ -715,6 +787,95 @@ export function HypurrConnectProvider({
|
|
|
715
787
|
}
|
|
716
788
|
}, [eoaAddress]);
|
|
717
789
|
|
|
790
|
+
const signEvmTransaction = useCallback(
|
|
791
|
+
async (transaction: EvmTransactionRequest): Promise<Hex> => {
|
|
792
|
+
if (authMethod === "eoa") {
|
|
793
|
+
if (!eoaAddress) {
|
|
794
|
+
throw new Error("[HypurrConnect] No EOA wallet connected.");
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const signer = eoaSignerRef.current;
|
|
798
|
+
if (!signer) {
|
|
799
|
+
throw new Error(
|
|
800
|
+
"[HypurrConnect] No EOA signer available. Pass a signer to connectEoa(address, signer).",
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const tx = withExpectedFrom(transaction, eoaAddress);
|
|
805
|
+
const result = signer.signTransaction
|
|
806
|
+
? await signer.signTransaction(tx)
|
|
807
|
+
: signer.request
|
|
808
|
+
? await signer.request({
|
|
809
|
+
method: "eth_signTransaction",
|
|
810
|
+
params: [tx],
|
|
811
|
+
})
|
|
812
|
+
: null;
|
|
813
|
+
const rawTransaction = getRawSignedTransaction(result);
|
|
814
|
+
if (!rawTransaction) {
|
|
815
|
+
throw new Error(
|
|
816
|
+
"[HypurrConnect] EOA signer did not return a raw transaction.",
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
return rawTransaction;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
if (authMethod === "telegram") {
|
|
823
|
+
if (!telegramRpcOptions) {
|
|
824
|
+
throw new Error("[HypurrConnect] No Telegram RPC session available.");
|
|
825
|
+
}
|
|
826
|
+
if (!selectedWallet) {
|
|
827
|
+
throw new Error("[HypurrConnect] No Telegram wallet selected.");
|
|
828
|
+
}
|
|
829
|
+
if (
|
|
830
|
+
selectedWallet.id <= 0 ||
|
|
831
|
+
selectedWallet.isReadOnly ||
|
|
832
|
+
selectedWallet.isAgent
|
|
833
|
+
) {
|
|
834
|
+
throw new Error(
|
|
835
|
+
"[HypurrConnect] Select a Telegram private-key wallet to sign EVM transactions.",
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
if (!isAddress(selectedWallet.ethereumAddress)) {
|
|
839
|
+
throw new Error(
|
|
840
|
+
"[HypurrConnect] Selected Telegram wallet does not have a valid EVM address.",
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const tx = withExpectedFrom(
|
|
845
|
+
transaction,
|
|
846
|
+
selectedWallet.ethereumAddress,
|
|
847
|
+
);
|
|
848
|
+
try {
|
|
849
|
+
const signResponse = await tgClient.eVMSignTransaction(
|
|
850
|
+
{
|
|
851
|
+
authData: {},
|
|
852
|
+
walletId: selectedWallet.id,
|
|
853
|
+
params: encodeJsonBytes(tx),
|
|
854
|
+
},
|
|
855
|
+
telegramRpcOptions,
|
|
856
|
+
);
|
|
857
|
+
const rawTransaction = getRawSignedTransaction(
|
|
858
|
+
decodeJsonBytes(signResponse.response.result),
|
|
859
|
+
);
|
|
860
|
+
if (!rawTransaction) {
|
|
861
|
+
throw new Error(
|
|
862
|
+
"[HypurrConnect] Telegram signer did not return a raw transaction.",
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
return rawTransaction;
|
|
866
|
+
} catch (err) {
|
|
867
|
+
if (isInvalidTelegramAuthError(err)) {
|
|
868
|
+
onInvalidAuthRef.current?.();
|
|
869
|
+
}
|
|
870
|
+
throw err;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
throw new Error("[HypurrConnect] No wallet connected.");
|
|
875
|
+
},
|
|
876
|
+
[authMethod, eoaAddress, selectedWallet, telegramRpcOptions, tgClient],
|
|
877
|
+
);
|
|
878
|
+
|
|
718
879
|
// ── Wallet management (Telegram only) ───────────────────────
|
|
719
880
|
const createWallet = useCallback(
|
|
720
881
|
async (name: string): Promise<HyperliquidWallet> => {
|
|
@@ -1042,7 +1203,13 @@ export function HypurrConnectProvider({
|
|
|
1042
1203
|
);
|
|
1043
1204
|
}
|
|
1044
1205
|
|
|
1045
|
-
eoaSignerRef.current
|
|
1206
|
+
const currentSigner = eoaSignerRef.current;
|
|
1207
|
+
eoaSignerRef.current = {
|
|
1208
|
+
signTypedData: signTypedDataAsync,
|
|
1209
|
+
signTransaction: currentSigner?.signTransaction,
|
|
1210
|
+
request: currentSigner?.request,
|
|
1211
|
+
chainId,
|
|
1212
|
+
};
|
|
1046
1213
|
|
|
1047
1214
|
setEoaLoading(true);
|
|
1048
1215
|
setEoaError(null);
|
|
@@ -1187,6 +1354,7 @@ export function HypurrConnectProvider({
|
|
|
1187
1354
|
|
|
1188
1355
|
loginTelegram,
|
|
1189
1356
|
connectEoa,
|
|
1357
|
+
signEvmTransaction,
|
|
1190
1358
|
approveAgent: approveAgentFn,
|
|
1191
1359
|
logout,
|
|
1192
1360
|
|
|
@@ -1233,6 +1401,7 @@ export function HypurrConnectProvider({
|
|
|
1233
1401
|
closeLoginModal,
|
|
1234
1402
|
loginTelegram,
|
|
1235
1403
|
connectEoa,
|
|
1404
|
+
signEvmTransaction,
|
|
1236
1405
|
approveAgentFn,
|
|
1237
1406
|
logout,
|
|
1238
1407
|
agent,
|
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
|
-
*
|
|
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
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,14 +7,21 @@ export type { LoginModalProps } from "./LoginModal";
|
|
|
7
7
|
export { GrpcExchangeTransport } from "./GrpcExchangeTransport";
|
|
8
8
|
export type { GrpcExchangeTransportConfig } from "./GrpcExchangeTransport";
|
|
9
9
|
export { createTelegramClient, createStaticClient } from "./grpc";
|
|
10
|
+
export { PrivateKeySigner } from "./privateKeySigner";
|
|
10
11
|
export { createEoaSigner } from "./types";
|
|
11
12
|
export type {
|
|
12
13
|
AuthMethod,
|
|
14
|
+
EoaSignerOptions,
|
|
15
|
+
EoaSignTransactionFn,
|
|
13
16
|
EoaSigner,
|
|
17
|
+
EvmRequestFn,
|
|
18
|
+
EvmTransactionRequest,
|
|
19
|
+
Hex,
|
|
14
20
|
HypurrConnectConfig,
|
|
15
21
|
HypurrConnectState,
|
|
16
22
|
HypurrUser,
|
|
17
23
|
ScaleCreateParams,
|
|
24
|
+
SignEvmTransactionFn,
|
|
18
25
|
SignTypedDataFn,
|
|
19
26
|
StoredAgent,
|
|
20
27
|
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
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -19,6 +19,8 @@ import type { HyperliquidWallet } from "hypurr-grpc/ts/hypurr/wallet";
|
|
|
19
19
|
export interface HypurrConnectConfig {
|
|
20
20
|
/** gRPC-web base URL. Defaults to https://grpc.hypurr.fun. */
|
|
21
21
|
grpcUrl?: string;
|
|
22
|
+
/** Media base URL for user-uploaded assets. Defaults to https://media.hypurr.fun. */
|
|
23
|
+
mediaUrl?: string;
|
|
22
24
|
grpcTimeout?: number;
|
|
23
25
|
isTestnet?: boolean;
|
|
24
26
|
/** Polling interval in ms for TWAP/Scale session updates. Default 5000. Set 0 to disable. */
|
|
@@ -84,12 +86,52 @@ export type SignTypedDataFn = (params: {
|
|
|
84
86
|
message: Record<string, unknown>;
|
|
85
87
|
}) => Promise<`0x${string}`>;
|
|
86
88
|
|
|
89
|
+
export type Hex = `0x${string}`;
|
|
90
|
+
|
|
91
|
+
export interface EvmTransactionRequest {
|
|
92
|
+
from?: Hex;
|
|
93
|
+
to?: Hex;
|
|
94
|
+
gas?: Hex;
|
|
95
|
+
gasPrice?: Hex;
|
|
96
|
+
value?: Hex;
|
|
97
|
+
data?: Hex;
|
|
98
|
+
nonce?: Hex;
|
|
99
|
+
chainId?: Hex;
|
|
100
|
+
maxFeePerGas?: Hex;
|
|
101
|
+
maxPriorityFeePerGas?: Hex;
|
|
102
|
+
type?: Hex;
|
|
103
|
+
accessList?: unknown;
|
|
104
|
+
[key: string]: unknown;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type EvmRequestFn = (args: {
|
|
108
|
+
method: string;
|
|
109
|
+
params?: unknown[];
|
|
110
|
+
}) => Promise<unknown>;
|
|
111
|
+
|
|
112
|
+
export type SignEvmTransactionFn = (
|
|
113
|
+
transaction: EvmTransactionRequest,
|
|
114
|
+
) => Promise<Hex>;
|
|
115
|
+
|
|
116
|
+
export type EoaSignTransactionFn = (
|
|
117
|
+
transaction: EvmTransactionRequest,
|
|
118
|
+
) => Promise<unknown>;
|
|
119
|
+
|
|
87
120
|
/** Wallet signer provided at EOA connect time for user-signed actions. */
|
|
88
121
|
export interface EoaSigner {
|
|
89
122
|
signTypedData: SignTypedDataFn;
|
|
123
|
+
/** Optional raw EVM transaction signer. Used by `signEvmTransaction()` in EOA mode. */
|
|
124
|
+
signTransaction?: EoaSignTransactionFn;
|
|
125
|
+
/** Optional EIP-1193 provider request function. Used as a fallback for `eth_signTransaction`. */
|
|
126
|
+
request?: EvmRequestFn;
|
|
90
127
|
chainId: number;
|
|
91
128
|
}
|
|
92
129
|
|
|
130
|
+
export interface EoaSignerOptions {
|
|
131
|
+
signTransaction?: EoaSignTransactionFn;
|
|
132
|
+
request?: EvmRequestFn;
|
|
133
|
+
}
|
|
134
|
+
|
|
93
135
|
/**
|
|
94
136
|
* Create an {@link EoaSigner} from any EIP-712 signing function.
|
|
95
137
|
*
|
|
@@ -118,6 +160,7 @@ export function createEoaSigner(
|
|
|
118
160
|
| ((args: Record<string, unknown>) => Promise<`0x${string}`>)
|
|
119
161
|
| { current: (args: Record<string, unknown>) => Promise<`0x${string}`> },
|
|
120
162
|
chainId: number,
|
|
163
|
+
options: EoaSignerOptions = {},
|
|
121
164
|
): EoaSigner {
|
|
122
165
|
const resolve =
|
|
123
166
|
typeof signTypedDataAsync === "function"
|
|
@@ -125,6 +168,8 @@ export function createEoaSigner(
|
|
|
125
168
|
: (args: Record<string, unknown>) => signTypedDataAsync.current(args);
|
|
126
169
|
return {
|
|
127
170
|
signTypedData: (params) => resolve(params),
|
|
171
|
+
signTransaction: options.signTransaction,
|
|
172
|
+
request: options.request,
|
|
128
173
|
chainId,
|
|
129
174
|
};
|
|
130
175
|
}
|
|
@@ -214,6 +259,7 @@ export interface HypurrConnectState {
|
|
|
214
259
|
|
|
215
260
|
// Auth actions
|
|
216
261
|
connectEoa: (address: `0x${string}`, signer?: EoaSigner) => void;
|
|
262
|
+
signEvmTransaction: SignEvmTransactionFn;
|
|
217
263
|
approveAgent: (
|
|
218
264
|
signTypedDataAsync: SignTypedDataFn,
|
|
219
265
|
chainId: number,
|