@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 +21 -0
- package/README.md +153 -0
- package/dist/client/baseClient.d.ts +93 -0
- package/dist/client/baseClient.js +374 -0
- package/dist/client/baseClient.js.map +1 -0
- package/dist/client/lifecycleClient.d.ts +48 -0
- package/dist/client/lifecycleClient.js +163 -0
- package/dist/client/lifecycleClient.js.map +1 -0
- package/dist/client/publicClient.d.ts +44 -0
- package/dist/client/publicClient.js +127 -0
- package/dist/client/publicClient.js.map +1 -0
- package/dist/client/tradingClient.d.ts +15 -0
- package/dist/client/tradingClient.js +75 -0
- package/dist/client/tradingClient.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +31 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/constants.d.ts +142 -0
- package/dist/internal/constants.js +84 -0
- package/dist/internal/constants.js.map +1 -0
- package/dist/internal/utils.d.ts +26 -0
- package/dist/internal/utils.js +115 -0
- package/dist/internal/utils.js.map +1 -0
- package/dist/speculiteClobClient.d.ts +16 -0
- package/dist/speculiteClobClient.js +17 -0
- package/dist/speculiteClobClient.js.map +1 -0
- package/dist/types.d.ts +353 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -0
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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"}
|