@ampvaleo/x402-hyperliquid-server 0.1.0
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/LICENSE +21 -0
- package/README.md +28 -0
- package/dist/index.cjs +461 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +143 -0
- package/dist/index.d.ts +143 -0
- package/dist/index.js +437 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as _ampvaleo_x402_hyperliquid_core from '@ampvaleo/x402-hyperliquid-core';
|
|
2
|
+
import { HyperliquidChainName, PaymentRequirements, PaymentPayload, HyperliquidChainConfig } from '@ampvaleo/x402-hyperliquid-core';
|
|
3
|
+
import { Hex, Address } from 'viem';
|
|
4
|
+
import * as express from 'express';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Tracks seen payment nonces to prevent replay. Keys are opaque (e.g. `signer:nonceMs`).
|
|
8
|
+
*/
|
|
9
|
+
interface NonceStore {
|
|
10
|
+
/** Returns true if the nonce was unused and is now recorded */
|
|
11
|
+
tryConsume(key: string): Promise<boolean>;
|
|
12
|
+
}
|
|
13
|
+
declare class InMemoryNonceStore implements NonceStore {
|
|
14
|
+
private readonly used;
|
|
15
|
+
tryConsume(key: string): Promise<boolean>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface BuildRequirementsInput {
|
|
19
|
+
price: string;
|
|
20
|
+
payTo: Hex;
|
|
21
|
+
chain: HyperliquidChainName;
|
|
22
|
+
/** Full HL token string; defaults to canonical USDC for the chain */
|
|
23
|
+
token?: string;
|
|
24
|
+
sourceDex: "spot" | "";
|
|
25
|
+
destinationDex: "spot" | "";
|
|
26
|
+
resource: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
maxTimeoutSeconds?: number;
|
|
29
|
+
}
|
|
30
|
+
declare function buildPaymentRequirements(input: BuildRequirementsInput): PaymentRequirements;
|
|
31
|
+
|
|
32
|
+
declare class HyperliquidExchangeError extends Error {
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly body: unknown;
|
|
35
|
+
constructor(message: string, status: number, body: unknown);
|
|
36
|
+
}
|
|
37
|
+
interface SubmitOptions {
|
|
38
|
+
fetch?: typeof fetch;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Submits a signed sendAsset payment to Hyperliquid's public exchange API.
|
|
42
|
+
*/
|
|
43
|
+
declare function submitToExchange(payload: PaymentPayload, chain: HyperliquidChainConfig, options?: SubmitOptions): Promise<unknown>;
|
|
44
|
+
|
|
45
|
+
interface SettlementMode {
|
|
46
|
+
settle: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* When true, log a loud warning on each successful verification when settlement is skipped
|
|
49
|
+
* because `X402_HL_DEV_VERIFY_ONLY=1` was used (not because `settle: false` was passed explicitly).
|
|
50
|
+
*/
|
|
51
|
+
warnDevVerifyOnlyEachPaidRequest: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Throws if `X402_HL_DEV_VERIFY_ONLY=1` is set in production without the explicit escape hatch.
|
|
55
|
+
* Call once at process startup (e.g. when creating middleware) or before handling traffic.
|
|
56
|
+
*/
|
|
57
|
+
declare function assertDevVerifyOnlyEnvAllowed(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Resolves whether to POST to Hyperliquid after verification.
|
|
60
|
+
*
|
|
61
|
+
* - If `explicitSettle` is set, it wins (no env). No dev-verify warning.
|
|
62
|
+
* - Otherwise, if `X402_HL_DEV_VERIFY_ONLY=1`, settlement is off and warnings apply (after assert).
|
|
63
|
+
* - Default: settle (direct mode).
|
|
64
|
+
*/
|
|
65
|
+
declare function resolveSettlementMode(explicitSettle?: boolean): SettlementMode;
|
|
66
|
+
declare const DEV_VERIFY_ONLY_ENV = "X402_HL_DEV_VERIFY_ONLY";
|
|
67
|
+
declare const ALLOW_VERIFY_ONLY_IN_PROD_ENV = "X402_HL_ALLOW_VERIFY_ONLY_IN_PROD";
|
|
68
|
+
|
|
69
|
+
interface VerifyContext {
|
|
70
|
+
chain: HyperliquidChainConfig;
|
|
71
|
+
nonceStore: NonceStore;
|
|
72
|
+
/** Max age of nonce timestamp in ms from now (default 60_000) */
|
|
73
|
+
nonceWindowMs?: number;
|
|
74
|
+
nowMs?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Verifies EIP-712 signature and that `payload.action` matches server `requirements`.
|
|
78
|
+
* Does **not** trust `payload.accepted` — compare only against `requirements`.
|
|
79
|
+
*/
|
|
80
|
+
declare function verifyPayment(payload: PaymentPayload, requirements: PaymentRequirements, ctx: VerifyContext): Promise<{
|
|
81
|
+
valid: true;
|
|
82
|
+
signer: Address;
|
|
83
|
+
} | {
|
|
84
|
+
valid: false;
|
|
85
|
+
error: string;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Detects the case where the client tampers with `accepted` so it no longer reflects
|
|
89
|
+
* the signed `action` (servers must never rely on `accepted` alone).
|
|
90
|
+
*/
|
|
91
|
+
declare function mismatchesAcceptedAttack(payload: PaymentPayload): boolean;
|
|
92
|
+
declare function assertValidPayment(result: {
|
|
93
|
+
valid: true;
|
|
94
|
+
signer: Address;
|
|
95
|
+
} | {
|
|
96
|
+
valid: false;
|
|
97
|
+
error: string;
|
|
98
|
+
}): asserts result is {
|
|
99
|
+
valid: true;
|
|
100
|
+
signer: Address;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
interface X402HyperliquidExpressOptions extends Omit<BuildRequirementsInput, "resource"> {
|
|
104
|
+
/** Defaults to request URL */
|
|
105
|
+
resource?: string;
|
|
106
|
+
nonceStore: NonceStore;
|
|
107
|
+
nonceWindowMs?: number;
|
|
108
|
+
/**
|
|
109
|
+
* When set, forces settlement on/off. When omitted, `X402_HL_DEV_VERIFY_ONLY=1` can disable
|
|
110
|
+
* settlement for local dev (see `settlementMode.ts`).
|
|
111
|
+
*/
|
|
112
|
+
settle?: boolean;
|
|
113
|
+
fetch?: SubmitOptions["fetch"];
|
|
114
|
+
}
|
|
115
|
+
type X402ExpressLocals = {
|
|
116
|
+
signer: Address;
|
|
117
|
+
payload: PaymentPayload;
|
|
118
|
+
};
|
|
119
|
+
/** Express middleware — returns 402 + `accepts` when unpaid; verifies + settles (default) when `X-PAYMENT` present */
|
|
120
|
+
declare function x402Hyperliquid(options: X402HyperliquidExpressOptions): (req: express.Request, res: express.Response, next: express.NextFunction) => Promise<void>;
|
|
121
|
+
|
|
122
|
+
interface X402HyperliquidNextOptions extends Omit<BuildRequirementsInput, "resource"> {
|
|
123
|
+
resource?: string;
|
|
124
|
+
nonceStore: NonceStore;
|
|
125
|
+
nonceWindowMs?: number;
|
|
126
|
+
settle?: boolean;
|
|
127
|
+
fetch?: SubmitOptions["fetch"];
|
|
128
|
+
}
|
|
129
|
+
type X402GateResult = {
|
|
130
|
+
ok: true;
|
|
131
|
+
signer: Address;
|
|
132
|
+
payload: _ampvaleo_x402_hyperliquid_core.PaymentPayload;
|
|
133
|
+
} | {
|
|
134
|
+
ok: false;
|
|
135
|
+
response: Response;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* App Router / edge-friendly gate: returns a `Response` to return early (402/400/502),
|
|
139
|
+
* or `{ ok: true, ... }` when the caller should continue the route.
|
|
140
|
+
*/
|
|
141
|
+
declare function runX402HyperliquidGate(request: Request, options: X402HyperliquidNextOptions): Promise<X402GateResult>;
|
|
142
|
+
|
|
143
|
+
export { ALLOW_VERIFY_ONLY_IN_PROD_ENV, type BuildRequirementsInput, DEV_VERIFY_ONLY_ENV, HyperliquidExchangeError, InMemoryNonceStore, type NonceStore, type SettlementMode, type SubmitOptions, type VerifyContext, type X402ExpressLocals, type X402GateResult, type X402HyperliquidExpressOptions, type X402HyperliquidNextOptions, assertDevVerifyOnlyEnvAllowed, assertValidPayment, buildPaymentRequirements, mismatchesAcceptedAttack, resolveSettlementMode, runX402HyperliquidGate, submitToExchange, verifyPayment, x402Hyperliquid };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as _ampvaleo_x402_hyperliquid_core from '@ampvaleo/x402-hyperliquid-core';
|
|
2
|
+
import { HyperliquidChainName, PaymentRequirements, PaymentPayload, HyperliquidChainConfig } from '@ampvaleo/x402-hyperliquid-core';
|
|
3
|
+
import { Hex, Address } from 'viem';
|
|
4
|
+
import * as express from 'express';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Tracks seen payment nonces to prevent replay. Keys are opaque (e.g. `signer:nonceMs`).
|
|
8
|
+
*/
|
|
9
|
+
interface NonceStore {
|
|
10
|
+
/** Returns true if the nonce was unused and is now recorded */
|
|
11
|
+
tryConsume(key: string): Promise<boolean>;
|
|
12
|
+
}
|
|
13
|
+
declare class InMemoryNonceStore implements NonceStore {
|
|
14
|
+
private readonly used;
|
|
15
|
+
tryConsume(key: string): Promise<boolean>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface BuildRequirementsInput {
|
|
19
|
+
price: string;
|
|
20
|
+
payTo: Hex;
|
|
21
|
+
chain: HyperliquidChainName;
|
|
22
|
+
/** Full HL token string; defaults to canonical USDC for the chain */
|
|
23
|
+
token?: string;
|
|
24
|
+
sourceDex: "spot" | "";
|
|
25
|
+
destinationDex: "spot" | "";
|
|
26
|
+
resource: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
maxTimeoutSeconds?: number;
|
|
29
|
+
}
|
|
30
|
+
declare function buildPaymentRequirements(input: BuildRequirementsInput): PaymentRequirements;
|
|
31
|
+
|
|
32
|
+
declare class HyperliquidExchangeError extends Error {
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly body: unknown;
|
|
35
|
+
constructor(message: string, status: number, body: unknown);
|
|
36
|
+
}
|
|
37
|
+
interface SubmitOptions {
|
|
38
|
+
fetch?: typeof fetch;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Submits a signed sendAsset payment to Hyperliquid's public exchange API.
|
|
42
|
+
*/
|
|
43
|
+
declare function submitToExchange(payload: PaymentPayload, chain: HyperliquidChainConfig, options?: SubmitOptions): Promise<unknown>;
|
|
44
|
+
|
|
45
|
+
interface SettlementMode {
|
|
46
|
+
settle: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* When true, log a loud warning on each successful verification when settlement is skipped
|
|
49
|
+
* because `X402_HL_DEV_VERIFY_ONLY=1` was used (not because `settle: false` was passed explicitly).
|
|
50
|
+
*/
|
|
51
|
+
warnDevVerifyOnlyEachPaidRequest: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Throws if `X402_HL_DEV_VERIFY_ONLY=1` is set in production without the explicit escape hatch.
|
|
55
|
+
* Call once at process startup (e.g. when creating middleware) or before handling traffic.
|
|
56
|
+
*/
|
|
57
|
+
declare function assertDevVerifyOnlyEnvAllowed(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Resolves whether to POST to Hyperliquid after verification.
|
|
60
|
+
*
|
|
61
|
+
* - If `explicitSettle` is set, it wins (no env). No dev-verify warning.
|
|
62
|
+
* - Otherwise, if `X402_HL_DEV_VERIFY_ONLY=1`, settlement is off and warnings apply (after assert).
|
|
63
|
+
* - Default: settle (direct mode).
|
|
64
|
+
*/
|
|
65
|
+
declare function resolveSettlementMode(explicitSettle?: boolean): SettlementMode;
|
|
66
|
+
declare const DEV_VERIFY_ONLY_ENV = "X402_HL_DEV_VERIFY_ONLY";
|
|
67
|
+
declare const ALLOW_VERIFY_ONLY_IN_PROD_ENV = "X402_HL_ALLOW_VERIFY_ONLY_IN_PROD";
|
|
68
|
+
|
|
69
|
+
interface VerifyContext {
|
|
70
|
+
chain: HyperliquidChainConfig;
|
|
71
|
+
nonceStore: NonceStore;
|
|
72
|
+
/** Max age of nonce timestamp in ms from now (default 60_000) */
|
|
73
|
+
nonceWindowMs?: number;
|
|
74
|
+
nowMs?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Verifies EIP-712 signature and that `payload.action` matches server `requirements`.
|
|
78
|
+
* Does **not** trust `payload.accepted` — compare only against `requirements`.
|
|
79
|
+
*/
|
|
80
|
+
declare function verifyPayment(payload: PaymentPayload, requirements: PaymentRequirements, ctx: VerifyContext): Promise<{
|
|
81
|
+
valid: true;
|
|
82
|
+
signer: Address;
|
|
83
|
+
} | {
|
|
84
|
+
valid: false;
|
|
85
|
+
error: string;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Detects the case where the client tampers with `accepted` so it no longer reflects
|
|
89
|
+
* the signed `action` (servers must never rely on `accepted` alone).
|
|
90
|
+
*/
|
|
91
|
+
declare function mismatchesAcceptedAttack(payload: PaymentPayload): boolean;
|
|
92
|
+
declare function assertValidPayment(result: {
|
|
93
|
+
valid: true;
|
|
94
|
+
signer: Address;
|
|
95
|
+
} | {
|
|
96
|
+
valid: false;
|
|
97
|
+
error: string;
|
|
98
|
+
}): asserts result is {
|
|
99
|
+
valid: true;
|
|
100
|
+
signer: Address;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
interface X402HyperliquidExpressOptions extends Omit<BuildRequirementsInput, "resource"> {
|
|
104
|
+
/** Defaults to request URL */
|
|
105
|
+
resource?: string;
|
|
106
|
+
nonceStore: NonceStore;
|
|
107
|
+
nonceWindowMs?: number;
|
|
108
|
+
/**
|
|
109
|
+
* When set, forces settlement on/off. When omitted, `X402_HL_DEV_VERIFY_ONLY=1` can disable
|
|
110
|
+
* settlement for local dev (see `settlementMode.ts`).
|
|
111
|
+
*/
|
|
112
|
+
settle?: boolean;
|
|
113
|
+
fetch?: SubmitOptions["fetch"];
|
|
114
|
+
}
|
|
115
|
+
type X402ExpressLocals = {
|
|
116
|
+
signer: Address;
|
|
117
|
+
payload: PaymentPayload;
|
|
118
|
+
};
|
|
119
|
+
/** Express middleware — returns 402 + `accepts` when unpaid; verifies + settles (default) when `X-PAYMENT` present */
|
|
120
|
+
declare function x402Hyperliquid(options: X402HyperliquidExpressOptions): (req: express.Request, res: express.Response, next: express.NextFunction) => Promise<void>;
|
|
121
|
+
|
|
122
|
+
interface X402HyperliquidNextOptions extends Omit<BuildRequirementsInput, "resource"> {
|
|
123
|
+
resource?: string;
|
|
124
|
+
nonceStore: NonceStore;
|
|
125
|
+
nonceWindowMs?: number;
|
|
126
|
+
settle?: boolean;
|
|
127
|
+
fetch?: SubmitOptions["fetch"];
|
|
128
|
+
}
|
|
129
|
+
type X402GateResult = {
|
|
130
|
+
ok: true;
|
|
131
|
+
signer: Address;
|
|
132
|
+
payload: _ampvaleo_x402_hyperliquid_core.PaymentPayload;
|
|
133
|
+
} | {
|
|
134
|
+
ok: false;
|
|
135
|
+
response: Response;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* App Router / edge-friendly gate: returns a `Response` to return early (402/400/502),
|
|
139
|
+
* or `{ ok: true, ... }` when the caller should continue the route.
|
|
140
|
+
*/
|
|
141
|
+
declare function runX402HyperliquidGate(request: Request, options: X402HyperliquidNextOptions): Promise<X402GateResult>;
|
|
142
|
+
|
|
143
|
+
export { ALLOW_VERIFY_ONLY_IN_PROD_ENV, type BuildRequirementsInput, DEV_VERIFY_ONLY_ENV, HyperliquidExchangeError, InMemoryNonceStore, type NonceStore, type SettlementMode, type SubmitOptions, type VerifyContext, type X402ExpressLocals, type X402GateResult, type X402HyperliquidExpressOptions, type X402HyperliquidNextOptions, assertDevVerifyOnlyEnvAllowed, assertValidPayment, buildPaymentRequirements, mismatchesAcceptedAttack, resolveSettlementMode, runX402HyperliquidGate, submitToExchange, verifyPayment, x402Hyperliquid };
|