@ampvaleo/x402-hyperliquid-core 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 +23 -0
- package/dist/index.cjs +198 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +169 -0
- package/dist/index.d.ts +169 -0
- package/dist/index.js +151 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Valeo Protocol
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @ampvaleo/x402-hyperliquid-core
|
|
2
|
+
|
|
3
|
+
Types, Hyperliquid chain constants, canonical EIP-712 `HyperliquidTransaction:SendAsset` helpers, and Base64 JSON helpers for the `X-PAYMENT` header.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { buildSendAssetTypedData, testnet } from "@ampvaleo/x402-hyperliquid-core";
|
|
7
|
+
|
|
8
|
+
const typed = buildSendAssetTypedData({
|
|
9
|
+
chainId: testnet.chainId,
|
|
10
|
+
message: {
|
|
11
|
+
hyperliquidChain: "Testnet",
|
|
12
|
+
destination: "0x…",
|
|
13
|
+
sourceDex: "spot",
|
|
14
|
+
destinationDex: "spot",
|
|
15
|
+
token: "USDC:0x…",
|
|
16
|
+
amount: "0.01",
|
|
17
|
+
fromSubAccount: "",
|
|
18
|
+
nonce: 1_700_000_000_000n,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
See the [root README](../../README.md) for context.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ALL_SEND_ASSET_EIP712_TYPES: () => ALL_SEND_ASSET_EIP712_TYPES,
|
|
24
|
+
DEFAULT_USDC_TOKEN: () => DEFAULT_USDC_TOKEN,
|
|
25
|
+
EIP712_DOMAIN_TYPES: () => EIP712_DOMAIN_TYPES,
|
|
26
|
+
EIP712_VERifyingContract: () => EIP712_VERifyingContract,
|
|
27
|
+
HYPERLIQUID_SENDASSET_SCHEME: () => HYPERLIQUID_SENDASSET_SCHEME,
|
|
28
|
+
SEND_ASSET_PRIMARY_TYPE: () => SEND_ASSET_PRIMARY_TYPE,
|
|
29
|
+
SEND_ASSET_TYPES: () => SEND_ASSET_TYPES,
|
|
30
|
+
SPOT_META_INFO_ENDPOINTS: () => SPOT_META_INFO_ENDPOINTS,
|
|
31
|
+
VIEM_SEND_ASSET_TYPES: () => VIEM_SEND_ASSET_TYPES,
|
|
32
|
+
buildDomain: () => buildDomain,
|
|
33
|
+
buildSendAssetTypedData: () => buildSendAssetTypedData,
|
|
34
|
+
decodePaymentHeader: () => decodePaymentHeader,
|
|
35
|
+
encodePaymentHeader: () => encodePaymentHeader,
|
|
36
|
+
getAmountDecimalsForToken: () => getAmountDecimalsForToken,
|
|
37
|
+
getChainConfig: () => getChainConfig,
|
|
38
|
+
getTokenString: () => getTokenString,
|
|
39
|
+
mainnet: () => mainnet,
|
|
40
|
+
registerToken: () => registerToken,
|
|
41
|
+
registerTokenAmountDecimals: () => registerTokenAmountDecimals,
|
|
42
|
+
resolveTokenString: () => resolveTokenString,
|
|
43
|
+
testnet: () => testnet
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(index_exports);
|
|
46
|
+
|
|
47
|
+
// src/chains.ts
|
|
48
|
+
var HYPERLIQUID_SENDASSET_SCHEME = "hyperliquid-sendasset-v1";
|
|
49
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
50
|
+
var EIP712_VERifyingContract = ZERO_ADDRESS;
|
|
51
|
+
var mainnet = {
|
|
52
|
+
key: "mainnet",
|
|
53
|
+
chainId: 999n,
|
|
54
|
+
signatureChainId: "0x3e7",
|
|
55
|
+
hyperliquidLabel: "Mainnet",
|
|
56
|
+
exchangeUrl: "https://api.hyperliquid.xyz/exchange",
|
|
57
|
+
network: "hyperliquid-mainnet"
|
|
58
|
+
};
|
|
59
|
+
var testnet = {
|
|
60
|
+
key: "testnet",
|
|
61
|
+
chainId: 998n,
|
|
62
|
+
signatureChainId: "0x3e6",
|
|
63
|
+
hyperliquidLabel: "Testnet",
|
|
64
|
+
exchangeUrl: "https://api.hyperliquid-testnet.xyz/exchange",
|
|
65
|
+
network: "hyperliquid-testnet"
|
|
66
|
+
};
|
|
67
|
+
function getChainConfig(chain) {
|
|
68
|
+
return chain === "mainnet" ? mainnet : testnet;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/tokens.ts
|
|
72
|
+
var SPOT_META_INFO_ENDPOINTS = {
|
|
73
|
+
mainnet: "https://api.hyperliquid.xyz/info",
|
|
74
|
+
testnet: "https://api.hyperliquid-testnet.xyz/info"
|
|
75
|
+
};
|
|
76
|
+
var DEFAULT_USDC_TOKEN = {
|
|
77
|
+
mainnet: "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
|
|
78
|
+
testnet: "USDC:0xeb62eee3685fc4c43992febcd9e75443"
|
|
79
|
+
};
|
|
80
|
+
var amountDecimalsByFullToken = /* @__PURE__ */ new Map([
|
|
81
|
+
[DEFAULT_USDC_TOKEN.mainnet, 8],
|
|
82
|
+
[DEFAULT_USDC_TOKEN.testnet, 8]
|
|
83
|
+
]);
|
|
84
|
+
var custom = /* @__PURE__ */ new Map();
|
|
85
|
+
function registryKey(chain, symbol) {
|
|
86
|
+
return `${chain}:${symbol.toUpperCase()}`;
|
|
87
|
+
}
|
|
88
|
+
function registerTokenAmountDecimals(fullTokenString, weiDecimals) {
|
|
89
|
+
amountDecimalsByFullToken.set(fullTokenString, weiDecimals);
|
|
90
|
+
}
|
|
91
|
+
function getAmountDecimalsForToken(fullTokenString) {
|
|
92
|
+
const d = amountDecimalsByFullToken.get(fullTokenString);
|
|
93
|
+
if (d === void 0) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`No amount decimals registered for token "${fullTokenString}". Call registerTokenAmountDecimals() (weiDecimals from spotMeta).`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return d;
|
|
99
|
+
}
|
|
100
|
+
function registerToken(chain, symbol, tokenString, amountDecimals) {
|
|
101
|
+
custom.set(registryKey(chain, symbol), tokenString);
|
|
102
|
+
if (amountDecimals !== void 0) {
|
|
103
|
+
registerTokenAmountDecimals(tokenString, amountDecimals);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function getTokenString(chain, symbol) {
|
|
107
|
+
return custom.get(registryKey(chain, symbol));
|
|
108
|
+
}
|
|
109
|
+
function resolveTokenString(chain, symbol) {
|
|
110
|
+
const upper = symbol.toUpperCase();
|
|
111
|
+
const customHit = getTokenString(chain, upper);
|
|
112
|
+
if (customHit) return customHit;
|
|
113
|
+
if (upper === "USDC") return DEFAULT_USDC_TOKEN[chain];
|
|
114
|
+
throw new Error(`Unknown token symbol "${symbol}" for ${chain}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/eip712.ts
|
|
118
|
+
var SEND_ASSET_PRIMARY_TYPE = "HyperliquidTransaction:SendAsset";
|
|
119
|
+
var EIP712_DOMAIN_TYPES = [
|
|
120
|
+
{ name: "name", type: "string" },
|
|
121
|
+
{ name: "version", type: "string" },
|
|
122
|
+
{ name: "chainId", type: "uint256" },
|
|
123
|
+
{ name: "verifyingContract", type: "address" }
|
|
124
|
+
];
|
|
125
|
+
var SEND_ASSET_TYPES = [
|
|
126
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
127
|
+
{ name: "destination", type: "string" },
|
|
128
|
+
{ name: "sourceDex", type: "string" },
|
|
129
|
+
{ name: "destinationDex", type: "string" },
|
|
130
|
+
{ name: "token", type: "string" },
|
|
131
|
+
{ name: "amount", type: "string" },
|
|
132
|
+
{ name: "fromSubAccount", type: "string" },
|
|
133
|
+
{ name: "nonce", type: "uint64" }
|
|
134
|
+
];
|
|
135
|
+
var ALL_SEND_ASSET_EIP712_TYPES = {
|
|
136
|
+
EIP712Domain: EIP712_DOMAIN_TYPES,
|
|
137
|
+
[SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES
|
|
138
|
+
};
|
|
139
|
+
var VIEM_SEND_ASSET_TYPES = {
|
|
140
|
+
[SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES
|
|
141
|
+
};
|
|
142
|
+
function buildDomain(chainId) {
|
|
143
|
+
return {
|
|
144
|
+
name: "HyperliquidSignTransaction",
|
|
145
|
+
version: "1",
|
|
146
|
+
chainId,
|
|
147
|
+
verifyingContract: EIP712_VERifyingContract
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function buildSendAssetTypedData(params) {
|
|
151
|
+
return {
|
|
152
|
+
domain: buildDomain(params.chainId),
|
|
153
|
+
types: ALL_SEND_ASSET_EIP712_TYPES,
|
|
154
|
+
primaryType: SEND_ASSET_PRIMARY_TYPE,
|
|
155
|
+
message: params.message
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/encode.ts
|
|
160
|
+
var import_node_buffer = require("buffer");
|
|
161
|
+
function encodePaymentHeader(payload) {
|
|
162
|
+
return import_node_buffer.Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
|
|
163
|
+
}
|
|
164
|
+
function normalizeBase64(b64) {
|
|
165
|
+
const normalized = b64.replace(/-/g, "+").replace(/_/g, "/");
|
|
166
|
+
const pad = (4 - normalized.length % 4) % 4;
|
|
167
|
+
return normalized + "=".repeat(pad);
|
|
168
|
+
}
|
|
169
|
+
function decodePaymentHeader(header) {
|
|
170
|
+
const trimmed = header.trim();
|
|
171
|
+
const json = import_node_buffer.Buffer.from(normalizeBase64(trimmed), "base64").toString("utf8");
|
|
172
|
+
return JSON.parse(json);
|
|
173
|
+
}
|
|
174
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
175
|
+
0 && (module.exports = {
|
|
176
|
+
ALL_SEND_ASSET_EIP712_TYPES,
|
|
177
|
+
DEFAULT_USDC_TOKEN,
|
|
178
|
+
EIP712_DOMAIN_TYPES,
|
|
179
|
+
EIP712_VERifyingContract,
|
|
180
|
+
HYPERLIQUID_SENDASSET_SCHEME,
|
|
181
|
+
SEND_ASSET_PRIMARY_TYPE,
|
|
182
|
+
SEND_ASSET_TYPES,
|
|
183
|
+
SPOT_META_INFO_ENDPOINTS,
|
|
184
|
+
VIEM_SEND_ASSET_TYPES,
|
|
185
|
+
buildDomain,
|
|
186
|
+
buildSendAssetTypedData,
|
|
187
|
+
decodePaymentHeader,
|
|
188
|
+
encodePaymentHeader,
|
|
189
|
+
getAmountDecimalsForToken,
|
|
190
|
+
getChainConfig,
|
|
191
|
+
getTokenString,
|
|
192
|
+
mainnet,
|
|
193
|
+
registerToken,
|
|
194
|
+
registerTokenAmountDecimals,
|
|
195
|
+
resolveTokenString,
|
|
196
|
+
testnet
|
|
197
|
+
});
|
|
198
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/chains.ts","../src/tokens.ts","../src/eip712.ts","../src/encode.ts"],"sourcesContent":["export {\n EIP712_VERifyingContract,\n HYPERLIQUID_SENDASSET_SCHEME,\n getChainConfig,\n mainnet,\n testnet,\n type HyperliquidChainConfig,\n type HyperliquidChainName,\n} from \"./chains.js\";\nexport {\n DEFAULT_USDC_TOKEN,\n SPOT_META_INFO_ENDPOINTS,\n getAmountDecimalsForToken,\n getTokenString,\n registerToken,\n registerTokenAmountDecimals,\n resolveTokenString,\n} from \"./tokens.js\";\nexport type {\n HyperliquidPaymentExtra,\n HyperliquidSignatureComponents,\n PaymentPayload,\n PaymentRequirements,\n SendAssetEip712Message,\n SendAssetExchangeAction,\n} from \"./types.js\";\nexport {\n ALL_SEND_ASSET_EIP712_TYPES,\n EIP712_DOMAIN_TYPES,\n SEND_ASSET_PRIMARY_TYPE,\n SEND_ASSET_TYPES,\n VIEM_SEND_ASSET_TYPES,\n buildDomain,\n buildSendAssetTypedData,\n type BuildSendAssetTypedDataParams,\n type SendAssetTypedData,\n} from \"./eip712.js\";\nexport { decodePaymentHeader, encodePaymentHeader } from \"./encode.js\";\n","import type { Address, Hex } from \"viem\";\n\n/** x402 scheme id for HyperCore sendAsset payments */\nexport const HYPERLIQUID_SENDASSET_SCHEME = \"hyperliquid-sendasset-v1\" as const;\n\nexport type HyperliquidChainName = \"mainnet\" | \"testnet\";\n\nexport interface HyperliquidChainConfig {\n /** HyperEVM chain id — must match wallet EIP-712 domain chainId */\n chainId: bigint;\n /** Hex chain id sent on the exchange action (e.g. 0x3e7) */\n signatureChainId: Hex;\n /** Mainnet / Testnet label used in EIP-712 message and API action */\n hyperliquidLabel: \"Mainnet\" | \"Testnet\";\n /** Public exchange HTTP API */\n exchangeUrl: string;\n /** Network string echoed in PaymentRequirements */\n network: string;\n key: HyperliquidChainName;\n}\n\nconst ZERO_ADDRESS =\n \"0x0000000000000000000000000000000000000000\" as const satisfies Address;\n\nexport const EIP712_VERifyingContract: Address = ZERO_ADDRESS;\n\nexport const mainnet: HyperliquidChainConfig = {\n key: \"mainnet\",\n chainId: 999n,\n signatureChainId: \"0x3e7\",\n hyperliquidLabel: \"Mainnet\",\n exchangeUrl: \"https://api.hyperliquid.xyz/exchange\",\n network: \"hyperliquid-mainnet\",\n};\n\nexport const testnet: HyperliquidChainConfig = {\n key: \"testnet\",\n chainId: 998n,\n signatureChainId: \"0x3e6\",\n hyperliquidLabel: \"Testnet\",\n exchangeUrl: \"https://api.hyperliquid-testnet.xyz/exchange\",\n network: \"hyperliquid-testnet\",\n};\n\nexport function getChainConfig(\n chain: HyperliquidChainName,\n): HyperliquidChainConfig {\n return chain === \"mainnet\" ? mainnet : testnet;\n}\n","import type { HyperliquidChainName } from \"./chains.js\";\n\n/**\n * Hyperliquid publishes spot token metadata via POST `{ \"type\": \"spotMeta\" }` to `/info`:\n * - Mainnet: https://api.hyperliquid.xyz/info\n * - Testnet: https://api.hyperliquid-testnet.xyz/info\n *\n * Each token entry includes `szDecimals` (display / size precision) and `weiDecimals` (unit for\n * balances and for `amount` in EIP-712 `HyperliquidTransaction:SendAsset`). **Verification must\n * parse decimal `amount` strings using `weiDecimals`**, not assumptions from EVM USDC (6) or from\n * `szDecimals` alone.\n *\n * Last cross-check (automated): USDC on mainnet + testnet both reported `weiDecimals: 8` and\n * `szDecimals: 8`. If `spotMeta` changes, update `DEFAULT_TOKEN_AMOUNT_DECIMALS` and/or run your\n * own `spotMeta` fetch before production deploys.\n */\nexport const SPOT_META_INFO_ENDPOINTS: Record<HyperliquidChainName, string> = {\n mainnet: \"https://api.hyperliquid.xyz/info\",\n testnet: \"https://api.hyperliquid-testnet.xyz/info\",\n};\n\n/** Default USDC spot token ids from Hyperliquid spotMeta (`tokenId` field). */\nexport const DEFAULT_USDC_TOKEN: Record<HyperliquidChainName, string> = {\n mainnet: \"USDC:0x6d1e7cde53ba9467b783cb7c530ce054\",\n testnet: \"USDC:0xeb62eee3685fc4c43992febcd9e75443\",\n};\n\n/**\n * `amount` string precision for `parseUnits` / server-side comparisons, keyed by full HL token\n * string (`SYMBOL:0x…`). Values must match **`weiDecimals`** from `spotMeta` for that token.\n */\nconst amountDecimalsByFullToken = new Map<string, number>([\n [DEFAULT_USDC_TOKEN.mainnet, 8],\n [DEFAULT_USDC_TOKEN.testnet, 8],\n]);\n\n/** Custom HIP-1 style token strings: SYMBOL:0x... */\nconst custom = new Map<string, string>();\n\nfunction registryKey(chain: HyperliquidChainName, symbol: string): string {\n return `${chain}:${symbol.toUpperCase()}`;\n}\n\n/**\n * Register how many fractional digits the `amount` field uses for this full token string\n * (must match `weiDecimals` from `spotMeta` for that token).\n */\nexport function registerTokenAmountDecimals(\n fullTokenString: string,\n weiDecimals: number,\n): void {\n amountDecimalsByFullToken.set(fullTokenString, weiDecimals);\n}\n\n/**\n * Decimals used when interpreting `action.amount` / `maxAmountRequired` decimal strings for this\n * token (Hyperliquid `weiDecimals`).\n */\nexport function getAmountDecimalsForToken(fullTokenString: string): number {\n const d = amountDecimalsByFullToken.get(fullTokenString);\n if (d === undefined) {\n throw new Error(\n `No amount decimals registered for token \"${fullTokenString}\". Call registerTokenAmountDecimals() (weiDecimals from spotMeta).`,\n );\n }\n return d;\n}\n\n/**\n * Register a custom token string for a chain (e.g. HIP-1 spot assets).\n * Symbol is matched case-insensitively.\n * Pass `amountDecimals` (weiDecimals from spotMeta) so verification can parse amounts.\n */\nexport function registerToken(\n chain: HyperliquidChainName,\n symbol: string,\n tokenString: string,\n amountDecimals?: number,\n): void {\n custom.set(registryKey(chain, symbol), tokenString);\n if (amountDecimals !== undefined) {\n registerTokenAmountDecimals(tokenString, amountDecimals);\n }\n}\n\nexport function getTokenString(\n chain: HyperliquidChainName,\n symbol: string,\n): string | undefined {\n return custom.get(registryKey(chain, symbol));\n}\n\n/** Resolve USDC or a previously registered custom symbol. */\nexport function resolveTokenString(\n chain: HyperliquidChainName,\n symbol: string,\n): string {\n const upper = symbol.toUpperCase();\n const customHit = getTokenString(chain, upper);\n if (customHit) return customHit;\n if (upper === \"USDC\") return DEFAULT_USDC_TOKEN[chain];\n throw new Error(`Unknown token symbol \"${symbol}\" for ${chain}`);\n}\n","import type { TypedDataDomain, TypedDataParameter } from \"viem\";\n\nimport { EIP712_VERifyingContract } from \"./chains.js\";\nimport type { SendAssetEip712Message } from \"./types.js\";\n\n/** Primary type — must match Hyperliquid's signer exactly */\nexport const SEND_ASSET_PRIMARY_TYPE = \"HyperliquidTransaction:SendAsset\" as const;\n\n/** Frozen EIP-712 types — do not modify field order or names */\nexport const EIP712_DOMAIN_TYPES: TypedDataParameter[] = [\n { name: \"name\", type: \"string\" },\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n];\n\nexport const SEND_ASSET_TYPES: TypedDataParameter[] = [\n { name: \"hyperliquidChain\", type: \"string\" },\n { name: \"destination\", type: \"string\" },\n { name: \"sourceDex\", type: \"string\" },\n { name: \"destinationDex\", type: \"string\" },\n { name: \"token\", type: \"string\" },\n { name: \"amount\", type: \"string\" },\n { name: \"fromSubAccount\", type: \"string\" },\n { name: \"nonce\", type: \"uint64\" },\n];\n\nexport const ALL_SEND_ASSET_EIP712_TYPES = {\n EIP712Domain: EIP712_DOMAIN_TYPES,\n [SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES,\n} as const;\n\n/** Use with viem/ethers signTypedData — omit EIP712Domain (domain is passed separately). */\nexport const VIEM_SEND_ASSET_TYPES = {\n [SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES,\n} as const;\n\nexport interface BuildSendAssetTypedDataParams {\n /** HyperEVM chain id (999 mainnet / 998 testnet) — wallet must be on this chain */\n chainId: bigint;\n message: SendAssetEip712Message;\n}\n\nexport interface SendAssetTypedData {\n domain: TypedDataDomain;\n types: typeof ALL_SEND_ASSET_EIP712_TYPES;\n primaryType: typeof SEND_ASSET_PRIMARY_TYPE;\n message: SendAssetEip712Message;\n}\n\nexport function buildDomain(chainId: bigint): TypedDataDomain {\n return {\n name: \"HyperliquidSignTransaction\",\n version: \"1\",\n chainId,\n verifyingContract: EIP712_VERifyingContract,\n };\n}\n\n/**\n * Builds EIP-712 typed data for HyperCore sendAsset — domain, types, and message\n * match Hyperliquid's signing spec exactly.\n */\nexport function buildSendAssetTypedData(\n params: BuildSendAssetTypedDataParams,\n): SendAssetTypedData {\n return {\n domain: buildDomain(params.chainId),\n types: ALL_SEND_ASSET_EIP712_TYPES,\n primaryType: SEND_ASSET_PRIMARY_TYPE,\n message: params.message,\n };\n}\n","import { Buffer } from \"node:buffer\";\n\nimport type { PaymentPayload } from \"./types.js\";\n\n/**\n * Encode payment payload for the X-PAYMENT header: standard Base64 of UTF-8 JSON.\n */\nexport function encodePaymentHeader(payload: PaymentPayload): string {\n return Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64\");\n}\n\nfunction normalizeBase64(b64: string): string {\n const normalized = b64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const pad = (4 - (normalized.length % 4)) % 4;\n return normalized + \"=\".repeat(pad);\n}\n\nexport function decodePaymentHeader(header: string): PaymentPayload {\n const trimmed = header.trim();\n const json = Buffer.from(normalizeBase64(trimmed), \"base64\").toString(\"utf8\");\n return JSON.parse(json) as PaymentPayload;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Address, Hex, TypedDataParameter, TypedDataDomain } from 'viem';
|
|
2
|
+
|
|
3
|
+
/** x402 scheme id for HyperCore sendAsset payments */
|
|
4
|
+
declare const HYPERLIQUID_SENDASSET_SCHEME: "hyperliquid-sendasset-v1";
|
|
5
|
+
type HyperliquidChainName = "mainnet" | "testnet";
|
|
6
|
+
interface HyperliquidChainConfig {
|
|
7
|
+
/** HyperEVM chain id — must match wallet EIP-712 domain chainId */
|
|
8
|
+
chainId: bigint;
|
|
9
|
+
/** Hex chain id sent on the exchange action (e.g. 0x3e7) */
|
|
10
|
+
signatureChainId: Hex;
|
|
11
|
+
/** Mainnet / Testnet label used in EIP-712 message and API action */
|
|
12
|
+
hyperliquidLabel: "Mainnet" | "Testnet";
|
|
13
|
+
/** Public exchange HTTP API */
|
|
14
|
+
exchangeUrl: string;
|
|
15
|
+
/** Network string echoed in PaymentRequirements */
|
|
16
|
+
network: string;
|
|
17
|
+
key: HyperliquidChainName;
|
|
18
|
+
}
|
|
19
|
+
declare const EIP712_VERifyingContract: Address;
|
|
20
|
+
declare const mainnet: HyperliquidChainConfig;
|
|
21
|
+
declare const testnet: HyperliquidChainConfig;
|
|
22
|
+
declare function getChainConfig(chain: HyperliquidChainName): HyperliquidChainConfig;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Hyperliquid publishes spot token metadata via POST `{ "type": "spotMeta" }` to `/info`:
|
|
26
|
+
* - Mainnet: https://api.hyperliquid.xyz/info
|
|
27
|
+
* - Testnet: https://api.hyperliquid-testnet.xyz/info
|
|
28
|
+
*
|
|
29
|
+
* Each token entry includes `szDecimals` (display / size precision) and `weiDecimals` (unit for
|
|
30
|
+
* balances and for `amount` in EIP-712 `HyperliquidTransaction:SendAsset`). **Verification must
|
|
31
|
+
* parse decimal `amount` strings using `weiDecimals`**, not assumptions from EVM USDC (6) or from
|
|
32
|
+
* `szDecimals` alone.
|
|
33
|
+
*
|
|
34
|
+
* Last cross-check (automated): USDC on mainnet + testnet both reported `weiDecimals: 8` and
|
|
35
|
+
* `szDecimals: 8`. If `spotMeta` changes, update `DEFAULT_TOKEN_AMOUNT_DECIMALS` and/or run your
|
|
36
|
+
* own `spotMeta` fetch before production deploys.
|
|
37
|
+
*/
|
|
38
|
+
declare const SPOT_META_INFO_ENDPOINTS: Record<HyperliquidChainName, string>;
|
|
39
|
+
/** Default USDC spot token ids from Hyperliquid spotMeta (`tokenId` field). */
|
|
40
|
+
declare const DEFAULT_USDC_TOKEN: Record<HyperliquidChainName, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Register how many fractional digits the `amount` field uses for this full token string
|
|
43
|
+
* (must match `weiDecimals` from `spotMeta` for that token).
|
|
44
|
+
*/
|
|
45
|
+
declare function registerTokenAmountDecimals(fullTokenString: string, weiDecimals: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Decimals used when interpreting `action.amount` / `maxAmountRequired` decimal strings for this
|
|
48
|
+
* token (Hyperliquid `weiDecimals`).
|
|
49
|
+
*/
|
|
50
|
+
declare function getAmountDecimalsForToken(fullTokenString: string): number;
|
|
51
|
+
/**
|
|
52
|
+
* Register a custom token string for a chain (e.g. HIP-1 spot assets).
|
|
53
|
+
* Symbol is matched case-insensitively.
|
|
54
|
+
* Pass `amountDecimals` (weiDecimals from spotMeta) so verification can parse amounts.
|
|
55
|
+
*/
|
|
56
|
+
declare function registerToken(chain: HyperliquidChainName, symbol: string, tokenString: string, amountDecimals?: number): void;
|
|
57
|
+
declare function getTokenString(chain: HyperliquidChainName, symbol: string): string | undefined;
|
|
58
|
+
/** Resolve USDC or a previously registered custom symbol. */
|
|
59
|
+
declare function resolveTokenString(chain: HyperliquidChainName, symbol: string): string;
|
|
60
|
+
|
|
61
|
+
/** Extra Hyperliquid fields carried in PaymentRequirements.extra */
|
|
62
|
+
interface HyperliquidPaymentExtra {
|
|
63
|
+
chain: "mainnet" | "testnet";
|
|
64
|
+
/** Full HL token string e.g. USDC:0x... */
|
|
65
|
+
token: string;
|
|
66
|
+
/** "" = perps / default USDC DEX, "spot" = spot balance */
|
|
67
|
+
sourceDex: "spot" | "";
|
|
68
|
+
destinationDex: "spot" | "";
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Payment requirements for a Hyperliquid sendAsset payment (x402-compatible shape).
|
|
72
|
+
*/
|
|
73
|
+
interface PaymentRequirements {
|
|
74
|
+
scheme: typeof HYPERLIQUID_SENDASSET_SCHEME;
|
|
75
|
+
network: string;
|
|
76
|
+
maxAmountRequired: string;
|
|
77
|
+
resource: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
mimeType?: string;
|
|
80
|
+
payTo: Hex;
|
|
81
|
+
maxTimeoutSeconds: number;
|
|
82
|
+
/** Human-readable asset label (e.g. USDC) */
|
|
83
|
+
asset: string;
|
|
84
|
+
extra: HyperliquidPaymentExtra;
|
|
85
|
+
}
|
|
86
|
+
/** EIP-712 message body for HyperliquidTransaction:SendAsset (signed fields only). */
|
|
87
|
+
interface SendAssetEip712Message {
|
|
88
|
+
hyperliquidChain: "Mainnet" | "Testnet";
|
|
89
|
+
destination: string;
|
|
90
|
+
sourceDex: string;
|
|
91
|
+
destinationDex: string;
|
|
92
|
+
token: string;
|
|
93
|
+
amount: string;
|
|
94
|
+
fromSubAccount: string;
|
|
95
|
+
nonce: bigint;
|
|
96
|
+
}
|
|
97
|
+
/** Full exchange action including fields not present in the EIP-712 hash. */
|
|
98
|
+
interface SendAssetExchangeAction {
|
|
99
|
+
type: "sendAsset";
|
|
100
|
+
signatureChainId: Hex;
|
|
101
|
+
hyperliquidChain: "Mainnet" | "Testnet";
|
|
102
|
+
destination: string;
|
|
103
|
+
sourceDex: string;
|
|
104
|
+
destinationDex: string;
|
|
105
|
+
token: string;
|
|
106
|
+
amount: string;
|
|
107
|
+
fromSubAccount: string;
|
|
108
|
+
nonce: number;
|
|
109
|
+
}
|
|
110
|
+
interface HyperliquidSignatureComponents {
|
|
111
|
+
r: Hex;
|
|
112
|
+
s: Hex;
|
|
113
|
+
v: number;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Signed payment payload sent in the X-PAYMENT header.
|
|
117
|
+
* Servers must validate `action` against requirements — never trust `accepted`.
|
|
118
|
+
*/
|
|
119
|
+
interface PaymentPayload {
|
|
120
|
+
x402Version?: number;
|
|
121
|
+
scheme: typeof HYPERLIQUID_SENDASSET_SCHEME;
|
|
122
|
+
network: string;
|
|
123
|
+
action: SendAssetExchangeAction;
|
|
124
|
+
signature: HyperliquidSignatureComponents;
|
|
125
|
+
/** Timestamp ms; must match action.nonce */
|
|
126
|
+
nonce: number;
|
|
127
|
+
signatureChainId: Hex;
|
|
128
|
+
/** Echo of what the client claims it accepted — verify against `action` only */
|
|
129
|
+
accepted: PaymentRequirements;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Primary type — must match Hyperliquid's signer exactly */
|
|
133
|
+
declare const SEND_ASSET_PRIMARY_TYPE: "HyperliquidTransaction:SendAsset";
|
|
134
|
+
/** Frozen EIP-712 types — do not modify field order or names */
|
|
135
|
+
declare const EIP712_DOMAIN_TYPES: TypedDataParameter[];
|
|
136
|
+
declare const SEND_ASSET_TYPES: TypedDataParameter[];
|
|
137
|
+
declare const ALL_SEND_ASSET_EIP712_TYPES: {
|
|
138
|
+
readonly EIP712Domain: TypedDataParameter[];
|
|
139
|
+
readonly "HyperliquidTransaction:SendAsset": TypedDataParameter[];
|
|
140
|
+
};
|
|
141
|
+
/** Use with viem/ethers signTypedData — omit EIP712Domain (domain is passed separately). */
|
|
142
|
+
declare const VIEM_SEND_ASSET_TYPES: {
|
|
143
|
+
readonly "HyperliquidTransaction:SendAsset": TypedDataParameter[];
|
|
144
|
+
};
|
|
145
|
+
interface BuildSendAssetTypedDataParams {
|
|
146
|
+
/** HyperEVM chain id (999 mainnet / 998 testnet) — wallet must be on this chain */
|
|
147
|
+
chainId: bigint;
|
|
148
|
+
message: SendAssetEip712Message;
|
|
149
|
+
}
|
|
150
|
+
interface SendAssetTypedData {
|
|
151
|
+
domain: TypedDataDomain;
|
|
152
|
+
types: typeof ALL_SEND_ASSET_EIP712_TYPES;
|
|
153
|
+
primaryType: typeof SEND_ASSET_PRIMARY_TYPE;
|
|
154
|
+
message: SendAssetEip712Message;
|
|
155
|
+
}
|
|
156
|
+
declare function buildDomain(chainId: bigint): TypedDataDomain;
|
|
157
|
+
/**
|
|
158
|
+
* Builds EIP-712 typed data for HyperCore sendAsset — domain, types, and message
|
|
159
|
+
* match Hyperliquid's signing spec exactly.
|
|
160
|
+
*/
|
|
161
|
+
declare function buildSendAssetTypedData(params: BuildSendAssetTypedDataParams): SendAssetTypedData;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Encode payment payload for the X-PAYMENT header: standard Base64 of UTF-8 JSON.
|
|
165
|
+
*/
|
|
166
|
+
declare function encodePaymentHeader(payload: PaymentPayload): string;
|
|
167
|
+
declare function decodePaymentHeader(header: string): PaymentPayload;
|
|
168
|
+
|
|
169
|
+
export { ALL_SEND_ASSET_EIP712_TYPES, type BuildSendAssetTypedDataParams, DEFAULT_USDC_TOKEN, EIP712_DOMAIN_TYPES, EIP712_VERifyingContract, HYPERLIQUID_SENDASSET_SCHEME, type HyperliquidChainConfig, type HyperliquidChainName, type HyperliquidPaymentExtra, type HyperliquidSignatureComponents, type PaymentPayload, type PaymentRequirements, SEND_ASSET_PRIMARY_TYPE, SEND_ASSET_TYPES, SPOT_META_INFO_ENDPOINTS, type SendAssetEip712Message, type SendAssetExchangeAction, type SendAssetTypedData, VIEM_SEND_ASSET_TYPES, buildDomain, buildSendAssetTypedData, decodePaymentHeader, encodePaymentHeader, getAmountDecimalsForToken, getChainConfig, getTokenString, mainnet, registerToken, registerTokenAmountDecimals, resolveTokenString, testnet };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Address, Hex, TypedDataParameter, TypedDataDomain } from 'viem';
|
|
2
|
+
|
|
3
|
+
/** x402 scheme id for HyperCore sendAsset payments */
|
|
4
|
+
declare const HYPERLIQUID_SENDASSET_SCHEME: "hyperliquid-sendasset-v1";
|
|
5
|
+
type HyperliquidChainName = "mainnet" | "testnet";
|
|
6
|
+
interface HyperliquidChainConfig {
|
|
7
|
+
/** HyperEVM chain id — must match wallet EIP-712 domain chainId */
|
|
8
|
+
chainId: bigint;
|
|
9
|
+
/** Hex chain id sent on the exchange action (e.g. 0x3e7) */
|
|
10
|
+
signatureChainId: Hex;
|
|
11
|
+
/** Mainnet / Testnet label used in EIP-712 message and API action */
|
|
12
|
+
hyperliquidLabel: "Mainnet" | "Testnet";
|
|
13
|
+
/** Public exchange HTTP API */
|
|
14
|
+
exchangeUrl: string;
|
|
15
|
+
/** Network string echoed in PaymentRequirements */
|
|
16
|
+
network: string;
|
|
17
|
+
key: HyperliquidChainName;
|
|
18
|
+
}
|
|
19
|
+
declare const EIP712_VERifyingContract: Address;
|
|
20
|
+
declare const mainnet: HyperliquidChainConfig;
|
|
21
|
+
declare const testnet: HyperliquidChainConfig;
|
|
22
|
+
declare function getChainConfig(chain: HyperliquidChainName): HyperliquidChainConfig;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Hyperliquid publishes spot token metadata via POST `{ "type": "spotMeta" }` to `/info`:
|
|
26
|
+
* - Mainnet: https://api.hyperliquid.xyz/info
|
|
27
|
+
* - Testnet: https://api.hyperliquid-testnet.xyz/info
|
|
28
|
+
*
|
|
29
|
+
* Each token entry includes `szDecimals` (display / size precision) and `weiDecimals` (unit for
|
|
30
|
+
* balances and for `amount` in EIP-712 `HyperliquidTransaction:SendAsset`). **Verification must
|
|
31
|
+
* parse decimal `amount` strings using `weiDecimals`**, not assumptions from EVM USDC (6) or from
|
|
32
|
+
* `szDecimals` alone.
|
|
33
|
+
*
|
|
34
|
+
* Last cross-check (automated): USDC on mainnet + testnet both reported `weiDecimals: 8` and
|
|
35
|
+
* `szDecimals: 8`. If `spotMeta` changes, update `DEFAULT_TOKEN_AMOUNT_DECIMALS` and/or run your
|
|
36
|
+
* own `spotMeta` fetch before production deploys.
|
|
37
|
+
*/
|
|
38
|
+
declare const SPOT_META_INFO_ENDPOINTS: Record<HyperliquidChainName, string>;
|
|
39
|
+
/** Default USDC spot token ids from Hyperliquid spotMeta (`tokenId` field). */
|
|
40
|
+
declare const DEFAULT_USDC_TOKEN: Record<HyperliquidChainName, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Register how many fractional digits the `amount` field uses for this full token string
|
|
43
|
+
* (must match `weiDecimals` from `spotMeta` for that token).
|
|
44
|
+
*/
|
|
45
|
+
declare function registerTokenAmountDecimals(fullTokenString: string, weiDecimals: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Decimals used when interpreting `action.amount` / `maxAmountRequired` decimal strings for this
|
|
48
|
+
* token (Hyperliquid `weiDecimals`).
|
|
49
|
+
*/
|
|
50
|
+
declare function getAmountDecimalsForToken(fullTokenString: string): number;
|
|
51
|
+
/**
|
|
52
|
+
* Register a custom token string for a chain (e.g. HIP-1 spot assets).
|
|
53
|
+
* Symbol is matched case-insensitively.
|
|
54
|
+
* Pass `amountDecimals` (weiDecimals from spotMeta) so verification can parse amounts.
|
|
55
|
+
*/
|
|
56
|
+
declare function registerToken(chain: HyperliquidChainName, symbol: string, tokenString: string, amountDecimals?: number): void;
|
|
57
|
+
declare function getTokenString(chain: HyperliquidChainName, symbol: string): string | undefined;
|
|
58
|
+
/** Resolve USDC or a previously registered custom symbol. */
|
|
59
|
+
declare function resolveTokenString(chain: HyperliquidChainName, symbol: string): string;
|
|
60
|
+
|
|
61
|
+
/** Extra Hyperliquid fields carried in PaymentRequirements.extra */
|
|
62
|
+
interface HyperliquidPaymentExtra {
|
|
63
|
+
chain: "mainnet" | "testnet";
|
|
64
|
+
/** Full HL token string e.g. USDC:0x... */
|
|
65
|
+
token: string;
|
|
66
|
+
/** "" = perps / default USDC DEX, "spot" = spot balance */
|
|
67
|
+
sourceDex: "spot" | "";
|
|
68
|
+
destinationDex: "spot" | "";
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Payment requirements for a Hyperliquid sendAsset payment (x402-compatible shape).
|
|
72
|
+
*/
|
|
73
|
+
interface PaymentRequirements {
|
|
74
|
+
scheme: typeof HYPERLIQUID_SENDASSET_SCHEME;
|
|
75
|
+
network: string;
|
|
76
|
+
maxAmountRequired: string;
|
|
77
|
+
resource: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
mimeType?: string;
|
|
80
|
+
payTo: Hex;
|
|
81
|
+
maxTimeoutSeconds: number;
|
|
82
|
+
/** Human-readable asset label (e.g. USDC) */
|
|
83
|
+
asset: string;
|
|
84
|
+
extra: HyperliquidPaymentExtra;
|
|
85
|
+
}
|
|
86
|
+
/** EIP-712 message body for HyperliquidTransaction:SendAsset (signed fields only). */
|
|
87
|
+
interface SendAssetEip712Message {
|
|
88
|
+
hyperliquidChain: "Mainnet" | "Testnet";
|
|
89
|
+
destination: string;
|
|
90
|
+
sourceDex: string;
|
|
91
|
+
destinationDex: string;
|
|
92
|
+
token: string;
|
|
93
|
+
amount: string;
|
|
94
|
+
fromSubAccount: string;
|
|
95
|
+
nonce: bigint;
|
|
96
|
+
}
|
|
97
|
+
/** Full exchange action including fields not present in the EIP-712 hash. */
|
|
98
|
+
interface SendAssetExchangeAction {
|
|
99
|
+
type: "sendAsset";
|
|
100
|
+
signatureChainId: Hex;
|
|
101
|
+
hyperliquidChain: "Mainnet" | "Testnet";
|
|
102
|
+
destination: string;
|
|
103
|
+
sourceDex: string;
|
|
104
|
+
destinationDex: string;
|
|
105
|
+
token: string;
|
|
106
|
+
amount: string;
|
|
107
|
+
fromSubAccount: string;
|
|
108
|
+
nonce: number;
|
|
109
|
+
}
|
|
110
|
+
interface HyperliquidSignatureComponents {
|
|
111
|
+
r: Hex;
|
|
112
|
+
s: Hex;
|
|
113
|
+
v: number;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Signed payment payload sent in the X-PAYMENT header.
|
|
117
|
+
* Servers must validate `action` against requirements — never trust `accepted`.
|
|
118
|
+
*/
|
|
119
|
+
interface PaymentPayload {
|
|
120
|
+
x402Version?: number;
|
|
121
|
+
scheme: typeof HYPERLIQUID_SENDASSET_SCHEME;
|
|
122
|
+
network: string;
|
|
123
|
+
action: SendAssetExchangeAction;
|
|
124
|
+
signature: HyperliquidSignatureComponents;
|
|
125
|
+
/** Timestamp ms; must match action.nonce */
|
|
126
|
+
nonce: number;
|
|
127
|
+
signatureChainId: Hex;
|
|
128
|
+
/** Echo of what the client claims it accepted — verify against `action` only */
|
|
129
|
+
accepted: PaymentRequirements;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Primary type — must match Hyperliquid's signer exactly */
|
|
133
|
+
declare const SEND_ASSET_PRIMARY_TYPE: "HyperliquidTransaction:SendAsset";
|
|
134
|
+
/** Frozen EIP-712 types — do not modify field order or names */
|
|
135
|
+
declare const EIP712_DOMAIN_TYPES: TypedDataParameter[];
|
|
136
|
+
declare const SEND_ASSET_TYPES: TypedDataParameter[];
|
|
137
|
+
declare const ALL_SEND_ASSET_EIP712_TYPES: {
|
|
138
|
+
readonly EIP712Domain: TypedDataParameter[];
|
|
139
|
+
readonly "HyperliquidTransaction:SendAsset": TypedDataParameter[];
|
|
140
|
+
};
|
|
141
|
+
/** Use with viem/ethers signTypedData — omit EIP712Domain (domain is passed separately). */
|
|
142
|
+
declare const VIEM_SEND_ASSET_TYPES: {
|
|
143
|
+
readonly "HyperliquidTransaction:SendAsset": TypedDataParameter[];
|
|
144
|
+
};
|
|
145
|
+
interface BuildSendAssetTypedDataParams {
|
|
146
|
+
/** HyperEVM chain id (999 mainnet / 998 testnet) — wallet must be on this chain */
|
|
147
|
+
chainId: bigint;
|
|
148
|
+
message: SendAssetEip712Message;
|
|
149
|
+
}
|
|
150
|
+
interface SendAssetTypedData {
|
|
151
|
+
domain: TypedDataDomain;
|
|
152
|
+
types: typeof ALL_SEND_ASSET_EIP712_TYPES;
|
|
153
|
+
primaryType: typeof SEND_ASSET_PRIMARY_TYPE;
|
|
154
|
+
message: SendAssetEip712Message;
|
|
155
|
+
}
|
|
156
|
+
declare function buildDomain(chainId: bigint): TypedDataDomain;
|
|
157
|
+
/**
|
|
158
|
+
* Builds EIP-712 typed data for HyperCore sendAsset — domain, types, and message
|
|
159
|
+
* match Hyperliquid's signing spec exactly.
|
|
160
|
+
*/
|
|
161
|
+
declare function buildSendAssetTypedData(params: BuildSendAssetTypedDataParams): SendAssetTypedData;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Encode payment payload for the X-PAYMENT header: standard Base64 of UTF-8 JSON.
|
|
165
|
+
*/
|
|
166
|
+
declare function encodePaymentHeader(payload: PaymentPayload): string;
|
|
167
|
+
declare function decodePaymentHeader(header: string): PaymentPayload;
|
|
168
|
+
|
|
169
|
+
export { ALL_SEND_ASSET_EIP712_TYPES, type BuildSendAssetTypedDataParams, DEFAULT_USDC_TOKEN, EIP712_DOMAIN_TYPES, EIP712_VERifyingContract, HYPERLIQUID_SENDASSET_SCHEME, type HyperliquidChainConfig, type HyperliquidChainName, type HyperliquidPaymentExtra, type HyperliquidSignatureComponents, type PaymentPayload, type PaymentRequirements, SEND_ASSET_PRIMARY_TYPE, SEND_ASSET_TYPES, SPOT_META_INFO_ENDPOINTS, type SendAssetEip712Message, type SendAssetExchangeAction, type SendAssetTypedData, VIEM_SEND_ASSET_TYPES, buildDomain, buildSendAssetTypedData, decodePaymentHeader, encodePaymentHeader, getAmountDecimalsForToken, getChainConfig, getTokenString, mainnet, registerToken, registerTokenAmountDecimals, resolveTokenString, testnet };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// src/chains.ts
|
|
2
|
+
var HYPERLIQUID_SENDASSET_SCHEME = "hyperliquid-sendasset-v1";
|
|
3
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
4
|
+
var EIP712_VERifyingContract = ZERO_ADDRESS;
|
|
5
|
+
var mainnet = {
|
|
6
|
+
key: "mainnet",
|
|
7
|
+
chainId: 999n,
|
|
8
|
+
signatureChainId: "0x3e7",
|
|
9
|
+
hyperliquidLabel: "Mainnet",
|
|
10
|
+
exchangeUrl: "https://api.hyperliquid.xyz/exchange",
|
|
11
|
+
network: "hyperliquid-mainnet"
|
|
12
|
+
};
|
|
13
|
+
var testnet = {
|
|
14
|
+
key: "testnet",
|
|
15
|
+
chainId: 998n,
|
|
16
|
+
signatureChainId: "0x3e6",
|
|
17
|
+
hyperliquidLabel: "Testnet",
|
|
18
|
+
exchangeUrl: "https://api.hyperliquid-testnet.xyz/exchange",
|
|
19
|
+
network: "hyperliquid-testnet"
|
|
20
|
+
};
|
|
21
|
+
function getChainConfig(chain) {
|
|
22
|
+
return chain === "mainnet" ? mainnet : testnet;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/tokens.ts
|
|
26
|
+
var SPOT_META_INFO_ENDPOINTS = {
|
|
27
|
+
mainnet: "https://api.hyperliquid.xyz/info",
|
|
28
|
+
testnet: "https://api.hyperliquid-testnet.xyz/info"
|
|
29
|
+
};
|
|
30
|
+
var DEFAULT_USDC_TOKEN = {
|
|
31
|
+
mainnet: "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
|
|
32
|
+
testnet: "USDC:0xeb62eee3685fc4c43992febcd9e75443"
|
|
33
|
+
};
|
|
34
|
+
var amountDecimalsByFullToken = /* @__PURE__ */ new Map([
|
|
35
|
+
[DEFAULT_USDC_TOKEN.mainnet, 8],
|
|
36
|
+
[DEFAULT_USDC_TOKEN.testnet, 8]
|
|
37
|
+
]);
|
|
38
|
+
var custom = /* @__PURE__ */ new Map();
|
|
39
|
+
function registryKey(chain, symbol) {
|
|
40
|
+
return `${chain}:${symbol.toUpperCase()}`;
|
|
41
|
+
}
|
|
42
|
+
function registerTokenAmountDecimals(fullTokenString, weiDecimals) {
|
|
43
|
+
amountDecimalsByFullToken.set(fullTokenString, weiDecimals);
|
|
44
|
+
}
|
|
45
|
+
function getAmountDecimalsForToken(fullTokenString) {
|
|
46
|
+
const d = amountDecimalsByFullToken.get(fullTokenString);
|
|
47
|
+
if (d === void 0) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`No amount decimals registered for token "${fullTokenString}". Call registerTokenAmountDecimals() (weiDecimals from spotMeta).`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return d;
|
|
53
|
+
}
|
|
54
|
+
function registerToken(chain, symbol, tokenString, amountDecimals) {
|
|
55
|
+
custom.set(registryKey(chain, symbol), tokenString);
|
|
56
|
+
if (amountDecimals !== void 0) {
|
|
57
|
+
registerTokenAmountDecimals(tokenString, amountDecimals);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function getTokenString(chain, symbol) {
|
|
61
|
+
return custom.get(registryKey(chain, symbol));
|
|
62
|
+
}
|
|
63
|
+
function resolveTokenString(chain, symbol) {
|
|
64
|
+
const upper = symbol.toUpperCase();
|
|
65
|
+
const customHit = getTokenString(chain, upper);
|
|
66
|
+
if (customHit) return customHit;
|
|
67
|
+
if (upper === "USDC") return DEFAULT_USDC_TOKEN[chain];
|
|
68
|
+
throw new Error(`Unknown token symbol "${symbol}" for ${chain}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/eip712.ts
|
|
72
|
+
var SEND_ASSET_PRIMARY_TYPE = "HyperliquidTransaction:SendAsset";
|
|
73
|
+
var EIP712_DOMAIN_TYPES = [
|
|
74
|
+
{ name: "name", type: "string" },
|
|
75
|
+
{ name: "version", type: "string" },
|
|
76
|
+
{ name: "chainId", type: "uint256" },
|
|
77
|
+
{ name: "verifyingContract", type: "address" }
|
|
78
|
+
];
|
|
79
|
+
var SEND_ASSET_TYPES = [
|
|
80
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
81
|
+
{ name: "destination", type: "string" },
|
|
82
|
+
{ name: "sourceDex", type: "string" },
|
|
83
|
+
{ name: "destinationDex", type: "string" },
|
|
84
|
+
{ name: "token", type: "string" },
|
|
85
|
+
{ name: "amount", type: "string" },
|
|
86
|
+
{ name: "fromSubAccount", type: "string" },
|
|
87
|
+
{ name: "nonce", type: "uint64" }
|
|
88
|
+
];
|
|
89
|
+
var ALL_SEND_ASSET_EIP712_TYPES = {
|
|
90
|
+
EIP712Domain: EIP712_DOMAIN_TYPES,
|
|
91
|
+
[SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES
|
|
92
|
+
};
|
|
93
|
+
var VIEM_SEND_ASSET_TYPES = {
|
|
94
|
+
[SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES
|
|
95
|
+
};
|
|
96
|
+
function buildDomain(chainId) {
|
|
97
|
+
return {
|
|
98
|
+
name: "HyperliquidSignTransaction",
|
|
99
|
+
version: "1",
|
|
100
|
+
chainId,
|
|
101
|
+
verifyingContract: EIP712_VERifyingContract
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function buildSendAssetTypedData(params) {
|
|
105
|
+
return {
|
|
106
|
+
domain: buildDomain(params.chainId),
|
|
107
|
+
types: ALL_SEND_ASSET_EIP712_TYPES,
|
|
108
|
+
primaryType: SEND_ASSET_PRIMARY_TYPE,
|
|
109
|
+
message: params.message
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/encode.ts
|
|
114
|
+
import { Buffer } from "buffer";
|
|
115
|
+
function encodePaymentHeader(payload) {
|
|
116
|
+
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
|
|
117
|
+
}
|
|
118
|
+
function normalizeBase64(b64) {
|
|
119
|
+
const normalized = b64.replace(/-/g, "+").replace(/_/g, "/");
|
|
120
|
+
const pad = (4 - normalized.length % 4) % 4;
|
|
121
|
+
return normalized + "=".repeat(pad);
|
|
122
|
+
}
|
|
123
|
+
function decodePaymentHeader(header) {
|
|
124
|
+
const trimmed = header.trim();
|
|
125
|
+
const json = Buffer.from(normalizeBase64(trimmed), "base64").toString("utf8");
|
|
126
|
+
return JSON.parse(json);
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
ALL_SEND_ASSET_EIP712_TYPES,
|
|
130
|
+
DEFAULT_USDC_TOKEN,
|
|
131
|
+
EIP712_DOMAIN_TYPES,
|
|
132
|
+
EIP712_VERifyingContract,
|
|
133
|
+
HYPERLIQUID_SENDASSET_SCHEME,
|
|
134
|
+
SEND_ASSET_PRIMARY_TYPE,
|
|
135
|
+
SEND_ASSET_TYPES,
|
|
136
|
+
SPOT_META_INFO_ENDPOINTS,
|
|
137
|
+
VIEM_SEND_ASSET_TYPES,
|
|
138
|
+
buildDomain,
|
|
139
|
+
buildSendAssetTypedData,
|
|
140
|
+
decodePaymentHeader,
|
|
141
|
+
encodePaymentHeader,
|
|
142
|
+
getAmountDecimalsForToken,
|
|
143
|
+
getChainConfig,
|
|
144
|
+
getTokenString,
|
|
145
|
+
mainnet,
|
|
146
|
+
registerToken,
|
|
147
|
+
registerTokenAmountDecimals,
|
|
148
|
+
resolveTokenString,
|
|
149
|
+
testnet
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chains.ts","../src/tokens.ts","../src/eip712.ts","../src/encode.ts"],"sourcesContent":["import type { Address, Hex } from \"viem\";\n\n/** x402 scheme id for HyperCore sendAsset payments */\nexport const HYPERLIQUID_SENDASSET_SCHEME = \"hyperliquid-sendasset-v1\" as const;\n\nexport type HyperliquidChainName = \"mainnet\" | \"testnet\";\n\nexport interface HyperliquidChainConfig {\n /** HyperEVM chain id — must match wallet EIP-712 domain chainId */\n chainId: bigint;\n /** Hex chain id sent on the exchange action (e.g. 0x3e7) */\n signatureChainId: Hex;\n /** Mainnet / Testnet label used in EIP-712 message and API action */\n hyperliquidLabel: \"Mainnet\" | \"Testnet\";\n /** Public exchange HTTP API */\n exchangeUrl: string;\n /** Network string echoed in PaymentRequirements */\n network: string;\n key: HyperliquidChainName;\n}\n\nconst ZERO_ADDRESS =\n \"0x0000000000000000000000000000000000000000\" as const satisfies Address;\n\nexport const EIP712_VERifyingContract: Address = ZERO_ADDRESS;\n\nexport const mainnet: HyperliquidChainConfig = {\n key: \"mainnet\",\n chainId: 999n,\n signatureChainId: \"0x3e7\",\n hyperliquidLabel: \"Mainnet\",\n exchangeUrl: \"https://api.hyperliquid.xyz/exchange\",\n network: \"hyperliquid-mainnet\",\n};\n\nexport const testnet: HyperliquidChainConfig = {\n key: \"testnet\",\n chainId: 998n,\n signatureChainId: \"0x3e6\",\n hyperliquidLabel: \"Testnet\",\n exchangeUrl: \"https://api.hyperliquid-testnet.xyz/exchange\",\n network: \"hyperliquid-testnet\",\n};\n\nexport function getChainConfig(\n chain: HyperliquidChainName,\n): HyperliquidChainConfig {\n return chain === \"mainnet\" ? mainnet : testnet;\n}\n","import type { HyperliquidChainName } from \"./chains.js\";\n\n/**\n * Hyperliquid publishes spot token metadata via POST `{ \"type\": \"spotMeta\" }` to `/info`:\n * - Mainnet: https://api.hyperliquid.xyz/info\n * - Testnet: https://api.hyperliquid-testnet.xyz/info\n *\n * Each token entry includes `szDecimals` (display / size precision) and `weiDecimals` (unit for\n * balances and for `amount` in EIP-712 `HyperliquidTransaction:SendAsset`). **Verification must\n * parse decimal `amount` strings using `weiDecimals`**, not assumptions from EVM USDC (6) or from\n * `szDecimals` alone.\n *\n * Last cross-check (automated): USDC on mainnet + testnet both reported `weiDecimals: 8` and\n * `szDecimals: 8`. If `spotMeta` changes, update `DEFAULT_TOKEN_AMOUNT_DECIMALS` and/or run your\n * own `spotMeta` fetch before production deploys.\n */\nexport const SPOT_META_INFO_ENDPOINTS: Record<HyperliquidChainName, string> = {\n mainnet: \"https://api.hyperliquid.xyz/info\",\n testnet: \"https://api.hyperliquid-testnet.xyz/info\",\n};\n\n/** Default USDC spot token ids from Hyperliquid spotMeta (`tokenId` field). */\nexport const DEFAULT_USDC_TOKEN: Record<HyperliquidChainName, string> = {\n mainnet: \"USDC:0x6d1e7cde53ba9467b783cb7c530ce054\",\n testnet: \"USDC:0xeb62eee3685fc4c43992febcd9e75443\",\n};\n\n/**\n * `amount` string precision for `parseUnits` / server-side comparisons, keyed by full HL token\n * string (`SYMBOL:0x…`). Values must match **`weiDecimals`** from `spotMeta` for that token.\n */\nconst amountDecimalsByFullToken = new Map<string, number>([\n [DEFAULT_USDC_TOKEN.mainnet, 8],\n [DEFAULT_USDC_TOKEN.testnet, 8],\n]);\n\n/** Custom HIP-1 style token strings: SYMBOL:0x... */\nconst custom = new Map<string, string>();\n\nfunction registryKey(chain: HyperliquidChainName, symbol: string): string {\n return `${chain}:${symbol.toUpperCase()}`;\n}\n\n/**\n * Register how many fractional digits the `amount` field uses for this full token string\n * (must match `weiDecimals` from `spotMeta` for that token).\n */\nexport function registerTokenAmountDecimals(\n fullTokenString: string,\n weiDecimals: number,\n): void {\n amountDecimalsByFullToken.set(fullTokenString, weiDecimals);\n}\n\n/**\n * Decimals used when interpreting `action.amount` / `maxAmountRequired` decimal strings for this\n * token (Hyperliquid `weiDecimals`).\n */\nexport function getAmountDecimalsForToken(fullTokenString: string): number {\n const d = amountDecimalsByFullToken.get(fullTokenString);\n if (d === undefined) {\n throw new Error(\n `No amount decimals registered for token \"${fullTokenString}\". Call registerTokenAmountDecimals() (weiDecimals from spotMeta).`,\n );\n }\n return d;\n}\n\n/**\n * Register a custom token string for a chain (e.g. HIP-1 spot assets).\n * Symbol is matched case-insensitively.\n * Pass `amountDecimals` (weiDecimals from spotMeta) so verification can parse amounts.\n */\nexport function registerToken(\n chain: HyperliquidChainName,\n symbol: string,\n tokenString: string,\n amountDecimals?: number,\n): void {\n custom.set(registryKey(chain, symbol), tokenString);\n if (amountDecimals !== undefined) {\n registerTokenAmountDecimals(tokenString, amountDecimals);\n }\n}\n\nexport function getTokenString(\n chain: HyperliquidChainName,\n symbol: string,\n): string | undefined {\n return custom.get(registryKey(chain, symbol));\n}\n\n/** Resolve USDC or a previously registered custom symbol. */\nexport function resolveTokenString(\n chain: HyperliquidChainName,\n symbol: string,\n): string {\n const upper = symbol.toUpperCase();\n const customHit = getTokenString(chain, upper);\n if (customHit) return customHit;\n if (upper === \"USDC\") return DEFAULT_USDC_TOKEN[chain];\n throw new Error(`Unknown token symbol \"${symbol}\" for ${chain}`);\n}\n","import type { TypedDataDomain, TypedDataParameter } from \"viem\";\n\nimport { EIP712_VERifyingContract } from \"./chains.js\";\nimport type { SendAssetEip712Message } from \"./types.js\";\n\n/** Primary type — must match Hyperliquid's signer exactly */\nexport const SEND_ASSET_PRIMARY_TYPE = \"HyperliquidTransaction:SendAsset\" as const;\n\n/** Frozen EIP-712 types — do not modify field order or names */\nexport const EIP712_DOMAIN_TYPES: TypedDataParameter[] = [\n { name: \"name\", type: \"string\" },\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n];\n\nexport const SEND_ASSET_TYPES: TypedDataParameter[] = [\n { name: \"hyperliquidChain\", type: \"string\" },\n { name: \"destination\", type: \"string\" },\n { name: \"sourceDex\", type: \"string\" },\n { name: \"destinationDex\", type: \"string\" },\n { name: \"token\", type: \"string\" },\n { name: \"amount\", type: \"string\" },\n { name: \"fromSubAccount\", type: \"string\" },\n { name: \"nonce\", type: \"uint64\" },\n];\n\nexport const ALL_SEND_ASSET_EIP712_TYPES = {\n EIP712Domain: EIP712_DOMAIN_TYPES,\n [SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES,\n} as const;\n\n/** Use with viem/ethers signTypedData — omit EIP712Domain (domain is passed separately). */\nexport const VIEM_SEND_ASSET_TYPES = {\n [SEND_ASSET_PRIMARY_TYPE]: SEND_ASSET_TYPES,\n} as const;\n\nexport interface BuildSendAssetTypedDataParams {\n /** HyperEVM chain id (999 mainnet / 998 testnet) — wallet must be on this chain */\n chainId: bigint;\n message: SendAssetEip712Message;\n}\n\nexport interface SendAssetTypedData {\n domain: TypedDataDomain;\n types: typeof ALL_SEND_ASSET_EIP712_TYPES;\n primaryType: typeof SEND_ASSET_PRIMARY_TYPE;\n message: SendAssetEip712Message;\n}\n\nexport function buildDomain(chainId: bigint): TypedDataDomain {\n return {\n name: \"HyperliquidSignTransaction\",\n version: \"1\",\n chainId,\n verifyingContract: EIP712_VERifyingContract,\n };\n}\n\n/**\n * Builds EIP-712 typed data for HyperCore sendAsset — domain, types, and message\n * match Hyperliquid's signing spec exactly.\n */\nexport function buildSendAssetTypedData(\n params: BuildSendAssetTypedDataParams,\n): SendAssetTypedData {\n return {\n domain: buildDomain(params.chainId),\n types: ALL_SEND_ASSET_EIP712_TYPES,\n primaryType: SEND_ASSET_PRIMARY_TYPE,\n message: params.message,\n };\n}\n","import { Buffer } from \"node:buffer\";\n\nimport type { PaymentPayload } from \"./types.js\";\n\n/**\n * Encode payment payload for the X-PAYMENT header: standard Base64 of UTF-8 JSON.\n */\nexport function encodePaymentHeader(payload: PaymentPayload): string {\n return Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64\");\n}\n\nfunction normalizeBase64(b64: string): string {\n const normalized = b64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const pad = (4 - (normalized.length % 4)) % 4;\n return normalized + \"=\".repeat(pad);\n}\n\nexport function decodePaymentHeader(header: string): PaymentPayload {\n const trimmed = header.trim();\n const json = Buffer.from(normalizeBase64(trimmed), \"base64\").toString(\"utf8\");\n return JSON.parse(json) as PaymentPayload;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ampvaleo/x402-hyperliquid-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Types, EIP-712, and encoding for x402 on Hyperliquid HyperCore",
|
|
5
|
+
"author": "Valeo Protocol",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/valeo-cash/x402-hyperliquid.git",
|
|
10
|
+
"directory": "packages/core"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.cjs",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"require": "./dist/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"viem": "^2.21.54"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.10.2",
|
|
35
|
+
"tsup": "^8.3.5",
|
|
36
|
+
"typescript": "^5.7.2",
|
|
37
|
+
"vitest": "^2.1.8"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"test": "vitest run"
|
|
42
|
+
}
|
|
43
|
+
}
|