@speculite/clob-client 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Speculite
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,153 @@
1
+ # @speculite/clob-client
2
+
3
+ Official TypeScript SDK for Speculite market data and developer trading APIs.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @speculite/clob-client ethers viem
9
+ ```
10
+
11
+ ## SDK Architecture
12
+
13
+ The SDK is now split by concern so it is easier to maintain and extend:
14
+
15
+ - `src/types.ts`: public types and enums
16
+ - `src/errors.ts`: API error types
17
+ - `src/internal/*`: reusable constants and pure helpers
18
+ - `src/client/baseClient.ts`: transport/auth/signing shared logic
19
+ - `src/client/publicClient.ts`: public + developer REST methods
20
+ - `src/client/tradingClient.ts`: order creation/signing flow
21
+ - `src/client/lifecycleClient.ts`: on-chain lifecycle transaction helpers
22
+ - `src/speculiteClobClient.ts`: public facade class + re-exports
23
+
24
+ ## Quickstart
25
+
26
+ ```ts
27
+ import { Wallet } from 'ethers';
28
+ import { SpeculiteClobClient, Side, OrderType } from '@speculite/clob-client';
29
+
30
+ const HOST = 'https://api.speculite.com';
31
+ const CHAIN_ID = 10143;
32
+
33
+ const signer = new Wallet(process.env.PRIVATE_KEY!);
34
+
35
+ const client = new SpeculiteClobClient(
36
+ HOST,
37
+ CHAIN_ID,
38
+ signer,
39
+ {
40
+ apiKey: process.env.SPECULITE_API_KEY!,
41
+ apiSecret: process.env.SPECULITE_API_SECRET!
42
+ }
43
+ );
44
+
45
+ const markets = await client.getMarkets({ statusFilter: 'active', limit: 1 });
46
+ const marketId = markets.markets[0].market_id;
47
+
48
+ const order = await client.createAndPostOrder({
49
+ marketId,
50
+ outcome: 'YES',
51
+ side: Side.BUY,
52
+ price: 0.5,
53
+ size: 10,
54
+ orderType: OrderType.LIMIT
55
+ });
56
+
57
+ console.log(order.order_id, order.lifecycle_status);
58
+ ```
59
+
60
+ ## API Coverage
61
+
62
+ ### Public market data
63
+
64
+ - `getMarkets(query)`
65
+ - `getMarket(marketId)`
66
+ - `getMarketData(marketId)`
67
+ - `getMarketDataBatch(marketIds)`
68
+ - `getOrderbook(marketId)`
69
+
70
+ ### Developer trading
71
+
72
+ - `getAuthMe()`
73
+ - `postOrder(order)`
74
+ - `createOrder(args, marketInfo?)`
75
+ - `createAndPostOrder(args, marketInfo?)`
76
+ - `cancelOrder(orderId)`
77
+ - `resolveExpiredMarket(marketId)`
78
+ - `getOpenOrders(marketId?)`
79
+ - `getOrderHistory({ marketId?, limit?, offset? })`
80
+ - `getTrades({ marketId?, limit?, offset? })`
81
+ - `getPositions({ marketId?, includeClosed?, limit?, offset? })`
82
+
83
+ ### On-chain lifecycle (self-gas)
84
+
85
+ - `prepareApproveUsdcTx({ spender, amount, usdcAddress })`
86
+ - `prepareMintTx({ marketId, amount })`
87
+ - `prepareMergeTx({ marketId, pairs, holder })`
88
+ - `prepareClaimTx({ marketId })`
89
+ - `prepareResolveTx({ marketId, pythAddress, rpcUrl? })`
90
+ - `sendPreparedTransaction(tx, account?)`
91
+ - `approveUsdc(...)`
92
+ - `mintTokens(...)`
93
+ - `mergeTokens(...)`
94
+ - `claimWinnings(...)`
95
+ - `resolveMarket(...)`
96
+
97
+ ### API key management (app-authenticated)
98
+
99
+ - `listApiKeys(authToken)`
100
+ - `revokeApiKey(apiKeyId, authToken)`
101
+ - `getWalletActivity(authToken)`
102
+
103
+ ## Notes
104
+
105
+ - Developer API keys are created in the Speculite web app settings.
106
+ - The SDK signs developer API requests with `SPECULITE-API-KEY`, `SPECULITE-TIMESTAMP`, `SPECULITE-SIGNATURE`.
107
+ - On-chain lifecycle methods are wallet-native and paid by the user's wallet (no sponsored gas).
108
+ - `resolveExpiredMarket` is an API-key endpoint that triggers backend/operator resolution for expired markets.
109
+ - Keep API secret and private keys out of source control.
110
+
111
+ ## Wallet-Native Lifecycle Example
112
+
113
+ ```ts
114
+ import { privateKeyToAccount } from 'viem/accounts';
115
+ import { createWalletClient, http } from 'viem';
116
+ import { SpeculiteClobClient } from '@speculite/clob-client';
117
+
118
+ const HOST = 'https://api.speculite.com';
119
+ const CHAIN_ID = 10143;
120
+ const RPC_URL = process.env.RPC_URL!;
121
+
122
+ const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
123
+ const walletClient = createWalletClient({
124
+ account,
125
+ transport: http(RPC_URL)
126
+ });
127
+
128
+ const client = new SpeculiteClobClient(
129
+ HOST,
130
+ CHAIN_ID,
131
+ account as any,
132
+ {
133
+ apiKey: process.env.SPECULITE_API_KEY!,
134
+ apiSecret: process.env.SPECULITE_API_SECRET!
135
+ },
136
+ {
137
+ walletClient,
138
+ rpcUrl: RPC_URL,
139
+ pythAddress: process.env.PYTH_ADDRESS as `0x${string}`
140
+ }
141
+ );
142
+
143
+ const mint = await client.mintTokens({
144
+ marketId: 'MARKET_UUID',
145
+ amount: '25'
146
+ });
147
+ console.log('mint tx:', mint.hash);
148
+
149
+ const claim = await client.claimWinnings({
150
+ marketId: 'MARKET_UUID'
151
+ });
152
+ console.log('claim tx:', claim.hash);
153
+ ```
@@ -0,0 +1,93 @@
1
+ import { type Address, type Hex, type PublicClient, type WalletClient } from 'viem';
2
+ import type { ApiCredentials, ClientConstructorOptions, Market, MarketResponse, MarketSigningInfo, OnchainMarketInfo, RequestOptions, RuntimeOptions, SignerLike } from '../types.js';
3
+ /**
4
+ * Shared SDK core:
5
+ * - request transport + auth header signing
6
+ * - signer/wallet resolution helpers
7
+ * - market metadata normalization
8
+ * - typed-data signing primitives
9
+ *
10
+ * Feature-specific APIs are implemented in subclasses.
11
+ */
12
+ export declare abstract class BaseClient {
13
+ protected readonly host: string;
14
+ protected readonly chainId: number;
15
+ protected readonly signatureType: number;
16
+ protected readonly fetchImpl: typeof fetch;
17
+ protected readonly now: () => number;
18
+ protected readonly publicClient?: PublicClient;
19
+ protected walletClient?: WalletClient;
20
+ protected readonly rpcUrl?: string;
21
+ protected readonly defaultPythAddress?: Address;
22
+ protected readonly pythPriceServiceUrl: string;
23
+ protected signer?: SignerLike;
24
+ protected funderAddress?: string;
25
+ protected credentials?: ApiCredentials;
26
+ protected nonceCounter: number;
27
+ protected abstract getMarket(marketId: string): Promise<MarketResponse>;
28
+ /**
29
+ * Creates a client with backward-compatible constructor forms:
30
+ * - legacy positional: `(host, chainId, signer, creds, signatureType?, funderAddress?, runtimeOptions?)`
31
+ * - preferred options: `(host, chainId, signer, creds, { signatureType?, funderAddress?, ...runtimeOptions })`
32
+ */
33
+ constructor(host: string, chainId: number, signer?: SignerLike, credentials?: ApiCredentials, signatureTypeOrOptions?: number | ClientConstructorOptions, funderAddress?: string, runtimeOptions?: RuntimeOptions);
34
+ /** Signature strategy identifier used by upstream systems. */
35
+ getSignatureType(): number;
36
+ /**
37
+ * Replaces signer and optional funder address at runtime.
38
+ */
39
+ setSigner(signer: SignerLike, funderAddress?: string): void;
40
+ /** Replaces developer API credentials used for HMAC-auth endpoints. */
41
+ setApiCredentials(credentials: ApiCredentials): void;
42
+ /** Replaces wallet client used for on-chain transaction submission. */
43
+ setWalletClient(walletClient: WalletClient): void;
44
+ /** Returns currently configured developer API credentials, if set. */
45
+ getApiCredentials(): ApiCredentials | null;
46
+ /** Ensures signer exists and can sign typed data. */
47
+ protected requireSigner(): SignerLike;
48
+ /** Ensures developer API credentials are configured. */
49
+ protected requireCredentials(): ApiCredentials;
50
+ /** Ensures wallet client is configured for on-chain tx sending. */
51
+ protected requireWalletClient(): WalletClient;
52
+ /**
53
+ * Resolves sender address for on-chain txs.
54
+ *
55
+ * Resolution order:
56
+ * 1. explicit `account` argument
57
+ * 2. wallet client's default account / first address
58
+ * 3. signer/funder-derived address
59
+ */
60
+ protected resolveWalletAccount(walletClient: WalletClient, account?: Address): Promise<Address>;
61
+ /** Returns explicit public client or builds one from RPC URL. */
62
+ protected resolvePublicClient(overrideRpcUrl?: string): PublicClient;
63
+ /** Converts API market payload into normalized on-chain metadata. */
64
+ protected mapMarketToOnchainInfo(marketId: string, market: Market): OnchainMarketInfo;
65
+ /**
66
+ * Resolves required on-chain market metadata from override or API lookup.
67
+ */
68
+ protected resolveOnchainMarketInfo(marketId: string, override?: Partial<OnchainMarketInfo>): Promise<OnchainMarketInfo>;
69
+ /**
70
+ * Fetches Pyth update payload(s) for market expiry.
71
+ * Falls back to latest endpoint when allowed.
72
+ */
73
+ protected fetchPythUpdateData(pythFeedId: Hex, expiryTimestamp: number, priceServiceUrl: string, allowLatestFallback: boolean): Promise<Hex[]>;
74
+ /**
75
+ * Resolves maker/funder address used for signing orders.
76
+ */
77
+ protected resolveMakerAddress(explicitMaker?: string): Promise<string>;
78
+ /**
79
+ * Signs EIP-712 payload, supporting both ethers-style and viem-style signers.
80
+ */
81
+ protected signTypedData(signer: SignerLike, domain: Record<string, unknown>, message: Record<string, unknown>, makerAddress: string): Promise<string>;
82
+ /** Generates a monotonic nonce derived from current timestamp. */
83
+ protected nextNonce(): string;
84
+ /** Fetches/validates market data needed for order signing. */
85
+ protected fetchMarketSigningInfo(marketId: string): Promise<MarketSigningInfo>;
86
+ /** Builds HMAC headers for developer-authenticated API requests. */
87
+ protected buildDeveloperAuthHeaders(method: string, pathWithQuery: string, bodyText: string): Record<string, string>;
88
+ /**
89
+ * Executes an HTTP request and parses JSON/text payload.
90
+ * Throws `SpeculiteApiError` on non-2xx responses.
91
+ */
92
+ protected request<T = unknown>(method: string, path: string, options?: RequestOptions): Promise<T>;
93
+ }
@@ -0,0 +1,374 @@
1
+ import crypto from 'crypto';
2
+ import { createPublicClient, http } from 'viem';
3
+ import { SpeculiteApiError } from '../errors.js';
4
+ import { DEFAULT_PYTH_PRICE_SERVICE_URL, ORDER_TYPES, } from '../internal/constants.js';
5
+ import { buildUrl, bytesToHex, normalizeAddress, normalizeHost, normalizePythFeedId, parseExpiryTimestamp, } from '../internal/utils.js';
6
+ /**
7
+ * Shared SDK core:
8
+ * - request transport + auth header signing
9
+ * - signer/wallet resolution helpers
10
+ * - market metadata normalization
11
+ * - typed-data signing primitives
12
+ *
13
+ * Feature-specific APIs are implemented in subclasses.
14
+ */
15
+ export class BaseClient {
16
+ host;
17
+ chainId;
18
+ signatureType;
19
+ fetchImpl;
20
+ now;
21
+ publicClient;
22
+ walletClient;
23
+ rpcUrl;
24
+ defaultPythAddress;
25
+ pythPriceServiceUrl;
26
+ signer;
27
+ funderAddress;
28
+ credentials;
29
+ nonceCounter = 0;
30
+ /**
31
+ * Creates a client with backward-compatible constructor forms:
32
+ * - legacy positional: `(host, chainId, signer, creds, signatureType?, funderAddress?, runtimeOptions?)`
33
+ * - preferred options: `(host, chainId, signer, creds, { signatureType?, funderAddress?, ...runtimeOptions })`
34
+ */
35
+ constructor(host, chainId, signer, credentials, signatureTypeOrOptions = 0, funderAddress, runtimeOptions = {}) {
36
+ let signatureType = 0;
37
+ let resolvedFunderAddress = funderAddress;
38
+ let resolvedRuntimeOptions = runtimeOptions;
39
+ if (typeof signatureTypeOrOptions === 'number') {
40
+ signatureType = signatureTypeOrOptions;
41
+ }
42
+ else {
43
+ const { signatureType: optionsSignatureType = 0, funderAddress: optionsFunderAddress, ...runtimeFromOptions } = signatureTypeOrOptions;
44
+ signatureType = optionsSignatureType;
45
+ resolvedFunderAddress = optionsFunderAddress ?? funderAddress;
46
+ resolvedRuntimeOptions = {
47
+ ...runtimeFromOptions,
48
+ ...runtimeOptions
49
+ };
50
+ }
51
+ this.host = normalizeHost(host);
52
+ this.chainId = chainId;
53
+ this.signer = signer;
54
+ this.credentials = credentials;
55
+ this.signatureType = signatureType;
56
+ this.funderAddress = resolvedFunderAddress;
57
+ this.fetchImpl = resolvedRuntimeOptions.fetch || fetch;
58
+ this.now = resolvedRuntimeOptions.now || (() => Date.now());
59
+ this.publicClient = resolvedRuntimeOptions.publicClient;
60
+ this.walletClient = resolvedRuntimeOptions.walletClient;
61
+ this.rpcUrl = resolvedRuntimeOptions.rpcUrl;
62
+ this.defaultPythAddress = resolvedRuntimeOptions.pythAddress;
63
+ this.pythPriceServiceUrl = resolvedRuntimeOptions.pythPriceServiceUrl || DEFAULT_PYTH_PRICE_SERVICE_URL;
64
+ }
65
+ /** Signature strategy identifier used by upstream systems. */
66
+ getSignatureType() {
67
+ return this.signatureType;
68
+ }
69
+ /**
70
+ * Replaces signer and optional funder address at runtime.
71
+ */
72
+ setSigner(signer, funderAddress) {
73
+ this.signer = signer;
74
+ if (funderAddress)
75
+ this.funderAddress = funderAddress;
76
+ }
77
+ /** Replaces developer API credentials used for HMAC-auth endpoints. */
78
+ setApiCredentials(credentials) {
79
+ this.credentials = credentials;
80
+ }
81
+ /** Replaces wallet client used for on-chain transaction submission. */
82
+ setWalletClient(walletClient) {
83
+ this.walletClient = walletClient;
84
+ }
85
+ /** Returns currently configured developer API credentials, if set. */
86
+ getApiCredentials() {
87
+ return this.credentials || null;
88
+ }
89
+ /** Ensures signer exists and can sign typed data. */
90
+ requireSigner() {
91
+ if (!this.signer) {
92
+ throw new Error('A signer is required for order creation');
93
+ }
94
+ if (typeof this.signer.signTypedData !== 'function') {
95
+ throw new Error('Signer must implement signTypedData');
96
+ }
97
+ return this.signer;
98
+ }
99
+ /** Ensures developer API credentials are configured. */
100
+ requireCredentials() {
101
+ if (!this.credentials) {
102
+ throw new Error('Developer API credentials are required');
103
+ }
104
+ return this.credentials;
105
+ }
106
+ /** Ensures wallet client is configured for on-chain tx sending. */
107
+ requireWalletClient() {
108
+ if (!this.walletClient) {
109
+ throw new Error('walletClient is required for on-chain transaction execution');
110
+ }
111
+ return this.walletClient;
112
+ }
113
+ /**
114
+ * Resolves sender address for on-chain txs.
115
+ *
116
+ * Resolution order:
117
+ * 1. explicit `account` argument
118
+ * 2. wallet client's default account / first address
119
+ * 3. signer/funder-derived address
120
+ */
121
+ async resolveWalletAccount(walletClient, account) {
122
+ if (account)
123
+ return account;
124
+ if (walletClient.account?.address)
125
+ return walletClient.account.address;
126
+ if (typeof walletClient.getAddresses === 'function') {
127
+ const addresses = await walletClient.getAddresses();
128
+ if (addresses.length > 0)
129
+ return addresses[0];
130
+ }
131
+ try {
132
+ return normalizeAddress(await this.resolveMakerAddress(), 'signer.address');
133
+ }
134
+ catch {
135
+ throw new Error('No wallet account available; pass account explicitly or provide signer/funderAddress');
136
+ }
137
+ }
138
+ /** Returns explicit public client or builds one from RPC URL. */
139
+ resolvePublicClient(overrideRpcUrl) {
140
+ if (this.publicClient)
141
+ return this.publicClient;
142
+ const rpcUrl = overrideRpcUrl || this.rpcUrl;
143
+ if (!rpcUrl) {
144
+ throw new Error('rpcUrl is required when publicClient is not configured');
145
+ }
146
+ return createPublicClient({ transport: http(rpcUrl) });
147
+ }
148
+ /** Converts API market payload into normalized on-chain metadata. */
149
+ mapMarketToOnchainInfo(marketId, market) {
150
+ const exchangeAddress = normalizeAddress(market.exchange_address, 'market.exchange_address');
151
+ const marketIdOnchain = Number(market.market_id_onchain);
152
+ if (!Number.isFinite(marketIdOnchain)) {
153
+ throw new Error('Market is missing market_id_onchain');
154
+ }
155
+ return {
156
+ marketId,
157
+ marketIdOnchain: Math.floor(marketIdOnchain),
158
+ exchangeAddress,
159
+ pythFeedId: normalizePythFeedId(market.pyth_feed_id),
160
+ expiryTimestamp: parseExpiryTimestamp(market.expiration_timestamp)
161
+ };
162
+ }
163
+ /**
164
+ * Resolves required on-chain market metadata from override or API lookup.
165
+ */
166
+ async resolveOnchainMarketInfo(marketId, override) {
167
+ const needsFetch = !override?.exchangeAddress || !override?.marketIdOnchain;
168
+ const fetched = needsFetch
169
+ ? this.mapMarketToOnchainInfo(marketId, (await this.getMarket(marketId)).market)
170
+ : null;
171
+ const exchangeAddress = normalizeAddress(override?.exchangeAddress || fetched?.exchangeAddress, 'market.exchangeAddress');
172
+ const marketIdOnchainRaw = override?.marketIdOnchain ?? fetched?.marketIdOnchain;
173
+ if (!Number.isFinite(Number(marketIdOnchainRaw))) {
174
+ throw new Error('market.marketIdOnchain is required');
175
+ }
176
+ return {
177
+ marketId,
178
+ marketIdOnchain: Math.floor(Number(marketIdOnchainRaw)),
179
+ exchangeAddress,
180
+ pythFeedId: normalizePythFeedId(override?.pythFeedId) ?? fetched?.pythFeedId ?? null,
181
+ expiryTimestamp: override?.expiryTimestamp ?? fetched?.expiryTimestamp ?? null
182
+ };
183
+ }
184
+ /**
185
+ * Fetches Pyth update payload(s) for market expiry.
186
+ * Falls back to latest endpoint when allowed.
187
+ */
188
+ async fetchPythUpdateData(pythFeedId, expiryTimestamp, priceServiceUrl, allowLatestFallback) {
189
+ const normalizedBase = priceServiceUrl.replace(/\/+$/, '');
190
+ const feedId = pythFeedId.startsWith('0x') ? pythFeedId : `0x${pythFeedId}`;
191
+ const endpoints = [
192
+ `${normalizedBase}/v2/updates/price/${expiryTimestamp}?ids[]=${feedId}&encoding=hex`,
193
+ ...(allowLatestFallback
194
+ ? [`${normalizedBase}/v2/updates/price/latest?ids[]=${feedId}&encoding=hex`]
195
+ : [])
196
+ ];
197
+ let lastError = null;
198
+ for (const endpoint of endpoints) {
199
+ try {
200
+ const response = await this.fetchImpl(endpoint);
201
+ if (!response.ok) {
202
+ lastError = `Pyth API ${response.status} ${response.statusText}`;
203
+ continue;
204
+ }
205
+ const contentType = response.headers.get('content-type') || '';
206
+ if (contentType.includes('application/json')) {
207
+ const payload = await response.json();
208
+ const hexValues = payload?.binary?.data;
209
+ if (Array.isArray(hexValues) && hexValues.length > 0) {
210
+ return hexValues.map((raw) => {
211
+ const value = raw.startsWith('0x') ? raw : `0x${raw}`;
212
+ if (!/^0x[0-9a-fA-F]+$/.test(value)) {
213
+ throw new Error('Pyth API returned non-hex updateData payload');
214
+ }
215
+ return value;
216
+ });
217
+ }
218
+ lastError = 'Pyth API returned JSON without binary.data';
219
+ continue;
220
+ }
221
+ const raw = new Uint8Array(await response.arrayBuffer());
222
+ if (raw.length > 0) {
223
+ return [bytesToHex(raw)];
224
+ }
225
+ lastError = 'Pyth API returned empty binary response';
226
+ }
227
+ catch (error) {
228
+ lastError = error instanceof Error ? error.message : String(error);
229
+ }
230
+ }
231
+ throw new Error(`Failed to fetch Pyth update data: ${lastError || 'unknown error'}`);
232
+ }
233
+ /**
234
+ * Resolves maker/funder address used for signing orders.
235
+ */
236
+ async resolveMakerAddress(explicitMaker) {
237
+ if (explicitMaker && explicitMaker.trim())
238
+ return explicitMaker.trim();
239
+ if (this.funderAddress && this.funderAddress.trim())
240
+ return this.funderAddress.trim();
241
+ if (!this.signer)
242
+ throw new Error('No signer configured');
243
+ if (typeof this.signer.getAddress === 'function') {
244
+ const address = await this.signer.getAddress();
245
+ if (address && String(address).trim())
246
+ return String(address).trim();
247
+ }
248
+ if (typeof this.signer.address === 'string' && this.signer.address.trim()) {
249
+ return this.signer.address.trim();
250
+ }
251
+ if (this.signer.account?.address && this.signer.account.address.trim()) {
252
+ return this.signer.account.address.trim();
253
+ }
254
+ throw new Error('Unable to resolve maker address from signer; pass args.maker explicitly');
255
+ }
256
+ /**
257
+ * Signs EIP-712 payload, supporting both ethers-style and viem-style signers.
258
+ */
259
+ async signTypedData(signer, domain, message, makerAddress) {
260
+ const signTypedData = signer.signTypedData.bind(signer);
261
+ const prefersViemStyle = Boolean(signer.account?.address) && signTypedData.length < 2;
262
+ if (prefersViemStyle) {
263
+ try {
264
+ return await signTypedData({
265
+ account: makerAddress,
266
+ domain,
267
+ types: ORDER_TYPES,
268
+ primaryType: 'Order',
269
+ message
270
+ });
271
+ }
272
+ catch {
273
+ return signTypedData(domain, ORDER_TYPES, message);
274
+ }
275
+ }
276
+ return signTypedData(domain, ORDER_TYPES, message);
277
+ }
278
+ /** Generates a monotonic nonce derived from current timestamp. */
279
+ nextNonce() {
280
+ this.nonceCounter = (this.nonceCounter + 1) % 1000;
281
+ const base = BigInt(this.now());
282
+ return (base * 1000n + BigInt(this.nonceCounter)).toString();
283
+ }
284
+ /** Fetches/validates market data needed for order signing. */
285
+ async fetchMarketSigningInfo(marketId) {
286
+ const response = await this.getMarket(marketId);
287
+ const market = response?.market;
288
+ if (!market || typeof market !== 'object') {
289
+ throw new Error('Missing market object in response');
290
+ }
291
+ const exchangeAddress = market.exchange_address;
292
+ const marketIdOnchain = market.market_id_onchain;
293
+ const takerFeeBps = market.taker_fee_bps ?? 0;
294
+ if (typeof exchangeAddress !== 'string' || !exchangeAddress) {
295
+ throw new Error('Market is missing exchange_address');
296
+ }
297
+ const parsedMarketIdOnchain = Number(marketIdOnchain);
298
+ if (!Number.isFinite(parsedMarketIdOnchain)) {
299
+ throw new Error('Market is missing market_id_onchain');
300
+ }
301
+ const parsedTakerFeeBps = Number(takerFeeBps);
302
+ if (!Number.isFinite(parsedTakerFeeBps) || parsedTakerFeeBps < 0) {
303
+ throw new Error('Invalid taker_fee_bps value');
304
+ }
305
+ return {
306
+ marketId,
307
+ exchangeAddress,
308
+ marketIdOnchain: Math.floor(parsedMarketIdOnchain),
309
+ takerFeeBps: Math.floor(parsedTakerFeeBps)
310
+ };
311
+ }
312
+ /** Builds HMAC headers for developer-authenticated API requests. */
313
+ buildDeveloperAuthHeaders(method, pathWithQuery, bodyText) {
314
+ const creds = this.requireCredentials();
315
+ const timestamp = String(Math.floor(this.now() / 1000));
316
+ const payload = `${timestamp}${method.toUpperCase()}${pathWithQuery}${bodyText}`;
317
+ const signature = crypto
318
+ .createHmac('sha256', creds.apiSecret)
319
+ .update(payload)
320
+ .digest('hex');
321
+ return {
322
+ 'SPECULITE-API-KEY': creds.apiKey,
323
+ 'SPECULITE-TIMESTAMP': timestamp,
324
+ 'SPECULITE-SIGNATURE': signature
325
+ };
326
+ }
327
+ /**
328
+ * Executes an HTTP request and parses JSON/text payload.
329
+ * Throws `SpeculiteApiError` on non-2xx responses.
330
+ */
331
+ async request(method, path, options = {}) {
332
+ const url = buildUrl(this.host, path, options.query);
333
+ const pathWithQuery = `${url.pathname}${url.search}`;
334
+ const headers = new Headers(options.headers || {});
335
+ let bodyText = '';
336
+ if (options.body !== undefined && options.body !== null) {
337
+ bodyText = typeof options.body === 'string'
338
+ ? options.body
339
+ : JSON.stringify(options.body);
340
+ if (!headers.has('content-type')) {
341
+ headers.set('Content-Type', 'application/json');
342
+ }
343
+ }
344
+ if (options.auth === 'bearer') {
345
+ if (!options.authToken)
346
+ throw new Error('authToken is required');
347
+ headers.set('Authorization', options.authToken.startsWith('Bearer ')
348
+ ? options.authToken
349
+ : `Bearer ${options.authToken}`);
350
+ }
351
+ else if (options.auth === 'developer') {
352
+ const authHeaders = this.buildDeveloperAuthHeaders(method, pathWithQuery, bodyText);
353
+ for (const [key, value] of Object.entries(authHeaders)) {
354
+ headers.set(key, value);
355
+ }
356
+ }
357
+ const response = await this.fetchImpl(url.toString(), {
358
+ method,
359
+ headers,
360
+ body: bodyText || undefined
361
+ });
362
+ if (response.status === 204) {
363
+ return undefined;
364
+ }
365
+ const contentType = response.headers.get('content-type') || '';
366
+ const isJson = contentType.includes('application/json');
367
+ const payload = isJson ? await response.json() : await response.text();
368
+ if (!response.ok) {
369
+ throw new SpeculiteApiError(response.status, payload);
370
+ }
371
+ return payload;
372
+ }
373
+ }
374
+ //# sourceMappingURL=baseClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseClient.js","sourceRoot":"","sources":["../../src/client/baseClient.ts"],"names":[],"mappings":"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"}