@olympex-io/olympex-sdk 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 +11 -0
- package/README.md +157 -0
- package/dist/index.d.mts +824 -0
- package/dist/index.d.ts +824 -0
- package/dist/index.js +863 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +817 -0
- package/dist/index.mjs.map +1 -0
- package/docs/authentication.md +166 -0
- package/docs/contributing-jsdoc.md +184 -0
- package/docs/errors.md +61 -0
- package/docs/fees.md +64 -0
- package/docs/getting-started.md +107 -0
- package/docs/logging.md +85 -0
- package/docs/methods/README.md +25 -0
- package/docs/methods/create-account.md +62 -0
- package/docs/methods/quote.md +84 -0
- package/docs/methods/swap.md +69 -0
- package/package.json +88 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,863 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
OlympexConfigError: () => OlympexConfigError,
|
|
34
|
+
OlympexDomainError: () => OlympexDomainError,
|
|
35
|
+
OlympexGraphQLError: () => OlympexGraphQLError,
|
|
36
|
+
OlympexNetworkError: () => OlympexNetworkError,
|
|
37
|
+
OlympexNotImplementedError: () => OlympexNotImplementedError,
|
|
38
|
+
OlympexSdkError: () => OlympexSdkError,
|
|
39
|
+
createAccount: () => createAccount,
|
|
40
|
+
createConsoleLogger: () => createConsoleLogger,
|
|
41
|
+
getVersion: () => getVersion,
|
|
42
|
+
initialize: () => initialize
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(index_exports);
|
|
45
|
+
|
|
46
|
+
// src/errors/base-error.ts
|
|
47
|
+
var OlympexSdkError = class extends Error {
|
|
48
|
+
code;
|
|
49
|
+
metadata;
|
|
50
|
+
constructor(message, code = "OLYMPEX_SDK_ERROR", metadata) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = new.target.name;
|
|
53
|
+
this.code = code;
|
|
54
|
+
this.metadata = metadata;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/errors/graphql-error.ts
|
|
59
|
+
var OlympexGraphQLError = class extends OlympexSdkError {
|
|
60
|
+
constructor(message, metadata) {
|
|
61
|
+
super(message, "OLYMPEX_GRAPHQL_ERROR", metadata);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/errors/network-error.ts
|
|
66
|
+
var OlympexNetworkError = class extends OlympexSdkError {
|
|
67
|
+
constructor(message, metadata) {
|
|
68
|
+
super(message, "OLYMPEX_NETWORK_ERROR", metadata);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/errors/redact.ts
|
|
73
|
+
var SENSITIVE_KEY_PATTERN = /api[-_]?key|authorization|cookie|token|secret|password/i;
|
|
74
|
+
function isPlainObject(value) {
|
|
75
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
76
|
+
}
|
|
77
|
+
function redact(value) {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
return value.map((item) => redact(item));
|
|
80
|
+
}
|
|
81
|
+
if (!isPlainObject(value)) {
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
return Object.fromEntries(
|
|
85
|
+
Object.entries(value).map(([key, entry]) => [
|
|
86
|
+
key,
|
|
87
|
+
SENSITIVE_KEY_PATTERN.test(key) ? "<REDACTED>" : redact(entry)
|
|
88
|
+
])
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/client/request-signing.ts
|
|
93
|
+
var import_crypto = __toESM(require("crypto"));
|
|
94
|
+
function generateBodySignature(body) {
|
|
95
|
+
const hashBuffer = import_crypto.default.createHash("sha256").update(body).digest();
|
|
96
|
+
return hashBuffer.toString("base64url");
|
|
97
|
+
}
|
|
98
|
+
function getTimestamp() {
|
|
99
|
+
return Math.floor(Date.now() / 1e3).toString();
|
|
100
|
+
}
|
|
101
|
+
function generateNonce() {
|
|
102
|
+
return import_crypto.default.randomBytes(12).toString("hex");
|
|
103
|
+
}
|
|
104
|
+
function sign({ message, secret }) {
|
|
105
|
+
return import_crypto.default.createHmac("sha256", secret).update(message).digest("hex");
|
|
106
|
+
}
|
|
107
|
+
function buildSignedHeaders({
|
|
108
|
+
apiKey,
|
|
109
|
+
apiSecret,
|
|
110
|
+
passphrase,
|
|
111
|
+
body,
|
|
112
|
+
timestamp,
|
|
113
|
+
nonce
|
|
114
|
+
}) {
|
|
115
|
+
const bodyHash = generateBodySignature(body);
|
|
116
|
+
const resolvedTimestamp = timestamp ?? getTimestamp();
|
|
117
|
+
const resolvedNonce = nonce ?? generateNonce();
|
|
118
|
+
const message = `${resolvedTimestamp}
|
|
119
|
+
${resolvedNonce}
|
|
120
|
+
${bodyHash}`;
|
|
121
|
+
const headerData = Buffer.from(message).toString("base64");
|
|
122
|
+
return {
|
|
123
|
+
"x-api-key-id": apiKey,
|
|
124
|
+
"x-value-info": headerData,
|
|
125
|
+
"x-passphrase": passphrase,
|
|
126
|
+
"x-signature": sign({ message, secret: apiSecret })
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/client/graphql-client.ts
|
|
131
|
+
var OlympexGraphQLClient = class {
|
|
132
|
+
apiKey;
|
|
133
|
+
apiSecret;
|
|
134
|
+
passphrase;
|
|
135
|
+
endpoint;
|
|
136
|
+
headers;
|
|
137
|
+
logger;
|
|
138
|
+
timeoutMs;
|
|
139
|
+
constructor(options) {
|
|
140
|
+
this.apiKey = options.apiKey;
|
|
141
|
+
this.apiSecret = options.apiSecret;
|
|
142
|
+
this.passphrase = options.passphrase;
|
|
143
|
+
this.endpoint = options.endpoint;
|
|
144
|
+
this.headers = options.headers ?? {};
|
|
145
|
+
this.logger = options.logger;
|
|
146
|
+
this.timeoutMs = options.timeoutMs;
|
|
147
|
+
}
|
|
148
|
+
async request(document, variables) {
|
|
149
|
+
const controller = new AbortController();
|
|
150
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
151
|
+
try {
|
|
152
|
+
this.logger?.log(
|
|
153
|
+
"debug",
|
|
154
|
+
"Sending Olympex GraphQL request",
|
|
155
|
+
redact({
|
|
156
|
+
endpoint: this.endpoint,
|
|
157
|
+
variables
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
const bodyToFetch = JSON.stringify({ query: document, variables });
|
|
161
|
+
const signedHeaders = buildSignedHeaders({
|
|
162
|
+
apiKey: this.apiKey,
|
|
163
|
+
apiSecret: this.apiSecret,
|
|
164
|
+
body: bodyToFetch,
|
|
165
|
+
passphrase: this.passphrase
|
|
166
|
+
});
|
|
167
|
+
const response = await fetch(this.endpoint, {
|
|
168
|
+
body: bodyToFetch,
|
|
169
|
+
headers: {
|
|
170
|
+
accept: "application/json",
|
|
171
|
+
"content-type": "application/json",
|
|
172
|
+
...this.headers,
|
|
173
|
+
...signedHeaders
|
|
174
|
+
},
|
|
175
|
+
method: "POST",
|
|
176
|
+
signal: controller.signal
|
|
177
|
+
});
|
|
178
|
+
let body;
|
|
179
|
+
try {
|
|
180
|
+
body = await response.json();
|
|
181
|
+
} catch {
|
|
182
|
+
this.logger?.log(
|
|
183
|
+
"error",
|
|
184
|
+
"Olympex GraphQL response was not valid JSON",
|
|
185
|
+
redact({
|
|
186
|
+
contentType: response.headers.get("content-type") ?? void 0,
|
|
187
|
+
endpoint: this.endpoint,
|
|
188
|
+
status: response.status
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
throw new OlympexNetworkError("GraphQL response was not valid JSON", {
|
|
192
|
+
contentType: response.headers.get("content-type") ?? void 0,
|
|
193
|
+
status: response.status,
|
|
194
|
+
statusText: response.statusText
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (!response.ok) {
|
|
198
|
+
this.logger?.log(
|
|
199
|
+
"error",
|
|
200
|
+
"Olympex GraphQL request failed with HTTP status",
|
|
201
|
+
redact({
|
|
202
|
+
endpoint: this.endpoint,
|
|
203
|
+
status: response.status,
|
|
204
|
+
statusText: response.statusText
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
throw new OlympexNetworkError(`GraphQL request failed with status ${response.status}`, {
|
|
208
|
+
status: response.status,
|
|
209
|
+
statusText: response.statusText
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
if (body?.errors?.length) {
|
|
213
|
+
const firstError = body.errors[0];
|
|
214
|
+
this.logger?.log(
|
|
215
|
+
"warn",
|
|
216
|
+
"Olympex GraphQL response contains errors",
|
|
217
|
+
redact({
|
|
218
|
+
endpoint: this.endpoint,
|
|
219
|
+
errorCount: body.errors.length,
|
|
220
|
+
extensions: firstError?.extensions,
|
|
221
|
+
firstMessage: firstError?.message
|
|
222
|
+
})
|
|
223
|
+
);
|
|
224
|
+
throw new OlympexGraphQLError(body.errors[0]?.message ?? "GraphQL request failed", {
|
|
225
|
+
errors: body.errors.map((error) => ({
|
|
226
|
+
extensions: error.extensions,
|
|
227
|
+
message: error.message,
|
|
228
|
+
path: error.path
|
|
229
|
+
}))
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
if (!body?.data) {
|
|
233
|
+
throw new OlympexGraphQLError("GraphQL response did not include data");
|
|
234
|
+
}
|
|
235
|
+
return body.data;
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (error instanceof OlympexGraphQLError || error instanceof OlympexNetworkError) {
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
const errorName = error instanceof Error ? error.name : "UnknownError";
|
|
241
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown network error";
|
|
242
|
+
this.logger?.log(
|
|
243
|
+
"error",
|
|
244
|
+
"Olympex GraphQL network failure",
|
|
245
|
+
redact({
|
|
246
|
+
endpoint: this.endpoint,
|
|
247
|
+
errorMessage,
|
|
248
|
+
errorName
|
|
249
|
+
})
|
|
250
|
+
);
|
|
251
|
+
throw new OlympexNetworkError(errorMessage);
|
|
252
|
+
} finally {
|
|
253
|
+
clearTimeout(timeout);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// src/errors/config-error.ts
|
|
259
|
+
var OlympexConfigError = class extends OlympexSdkError {
|
|
260
|
+
constructor(message, metadata) {
|
|
261
|
+
super(message, "OLYMPEX_CONFIG_ERROR", metadata);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// src/fees/validation.ts
|
|
266
|
+
var import_ethers = require("ethers");
|
|
267
|
+
|
|
268
|
+
// src/fees/constants.ts
|
|
269
|
+
var FEE_BPS_MIN = 0;
|
|
270
|
+
var FEE_BPS_MAX = 100;
|
|
271
|
+
|
|
272
|
+
// src/fees/validation.ts
|
|
273
|
+
function validateFeeOptions(fees) {
|
|
274
|
+
if (!fees) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (fees.feeBps !== void 0) {
|
|
278
|
+
if (!Number.isFinite(fees.feeBps) || fees.feeBps < FEE_BPS_MIN || fees.feeBps > FEE_BPS_MAX) {
|
|
279
|
+
throw new OlympexConfigError(`feeBps must be between ${FEE_BPS_MIN} and ${FEE_BPS_MAX}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (fees.feeRecipient !== void 0 && !(0, import_ethers.isAddress)(fees.feeRecipient)) {
|
|
283
|
+
throw new OlympexConfigError("feeRecipient must be a valid Ethereum address");
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// src/config/backend-url.ts
|
|
288
|
+
var DEFAULT_BACKEND_URL = "https://back.olympex.io/graphql";
|
|
289
|
+
var BACKEND_URL_ENV = "OLYMPEX_BACKEND_URL";
|
|
290
|
+
var GRAPHQL_PATH = "/graphql";
|
|
291
|
+
function readBackendUrlEnv() {
|
|
292
|
+
const raw = process.env[BACKEND_URL_ENV];
|
|
293
|
+
if (raw === void 0) {
|
|
294
|
+
return void 0;
|
|
295
|
+
}
|
|
296
|
+
const trimmed = raw.trim();
|
|
297
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
298
|
+
}
|
|
299
|
+
function validateBackendUrl(url) {
|
|
300
|
+
let parsed;
|
|
301
|
+
try {
|
|
302
|
+
parsed = new URL(url);
|
|
303
|
+
} catch {
|
|
304
|
+
throw new OlympexConfigError(`Invalid ${BACKEND_URL_ENV}: ${url}`);
|
|
305
|
+
}
|
|
306
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
307
|
+
throw new OlympexConfigError(`Invalid ${BACKEND_URL_ENV}: ${url}`);
|
|
308
|
+
}
|
|
309
|
+
if (parsed.search || parsed.hash) {
|
|
310
|
+
throw new OlympexConfigError(`Invalid ${BACKEND_URL_ENV}: ${url}`);
|
|
311
|
+
}
|
|
312
|
+
const pathname = parsed.pathname.replace(/\/$/, "") || "/";
|
|
313
|
+
if (pathname !== "/" && pathname !== GRAPHQL_PATH) {
|
|
314
|
+
throw new OlympexConfigError(`Invalid ${BACKEND_URL_ENV}: ${url}`);
|
|
315
|
+
}
|
|
316
|
+
return parsed;
|
|
317
|
+
}
|
|
318
|
+
function normalizeBase(baseUrl) {
|
|
319
|
+
return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
320
|
+
}
|
|
321
|
+
function toGraphqlEndpoint(url) {
|
|
322
|
+
const parsed = validateBackendUrl(url);
|
|
323
|
+
const pathname = parsed.pathname.replace(/\/$/, "") || "/";
|
|
324
|
+
if (pathname === GRAPHQL_PATH) {
|
|
325
|
+
return `${parsed.origin}${GRAPHQL_PATH}`;
|
|
326
|
+
}
|
|
327
|
+
return `${parsed.origin}${GRAPHQL_PATH}`;
|
|
328
|
+
}
|
|
329
|
+
function resolveBackendBaseUrl() {
|
|
330
|
+
const configured = readBackendUrlEnv();
|
|
331
|
+
const candidate = configured ?? DEFAULT_BACKEND_URL;
|
|
332
|
+
return toGraphqlEndpoint(candidate);
|
|
333
|
+
}
|
|
334
|
+
function getGraphqlEndpoint() {
|
|
335
|
+
return normalizeBase(resolveBackendBaseUrl());
|
|
336
|
+
}
|
|
337
|
+
function getRestBaseUrl() {
|
|
338
|
+
const graphqlEndpoint = normalizeBase(resolveBackendBaseUrl());
|
|
339
|
+
if (graphqlEndpoint.endsWith(GRAPHQL_PATH)) {
|
|
340
|
+
return graphqlEndpoint.slice(0, -GRAPHQL_PATH.length);
|
|
341
|
+
}
|
|
342
|
+
return graphqlEndpoint;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// src/methods/account.ts
|
|
346
|
+
var CREATE_ACCOUNT_PATH = "/api/v1/accounts";
|
|
347
|
+
function extractCredentials(payload) {
|
|
348
|
+
if (!payload || typeof payload !== "object") {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
const directPayload = payload;
|
|
352
|
+
const candidatePayloads = [directPayload];
|
|
353
|
+
if (directPayload.data !== void 0) {
|
|
354
|
+
candidatePayloads.push(directPayload.data);
|
|
355
|
+
}
|
|
356
|
+
for (const candidate of candidatePayloads) {
|
|
357
|
+
if (!candidate || typeof candidate !== "object") {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const values = candidate;
|
|
361
|
+
if (typeof values.apiKey === "string" && typeof values.secretKey === "string") {
|
|
362
|
+
return {
|
|
363
|
+
apiKey: values.apiKey,
|
|
364
|
+
secretKey: values.secretKey
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
function parseResponseMessage(payload) {
|
|
371
|
+
if (!payload || typeof payload !== "object") {
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
const maybeMessage = payload.message;
|
|
375
|
+
return typeof maybeMessage === "string" ? maybeMessage : void 0;
|
|
376
|
+
}
|
|
377
|
+
async function createAccount({
|
|
378
|
+
name,
|
|
379
|
+
password
|
|
380
|
+
}) {
|
|
381
|
+
const normalizedName = name.trim();
|
|
382
|
+
const normalizedPassword = password.trim();
|
|
383
|
+
if (!normalizedName) {
|
|
384
|
+
throw new OlympexConfigError("name is required");
|
|
385
|
+
}
|
|
386
|
+
if (!normalizedPassword) {
|
|
387
|
+
throw new OlympexConfigError("password is required");
|
|
388
|
+
}
|
|
389
|
+
const endpoint = `${getRestBaseUrl()}${CREATE_ACCOUNT_PATH}`;
|
|
390
|
+
const response = await fetch(endpoint, {
|
|
391
|
+
body: JSON.stringify({ name: normalizedName, password: normalizedPassword }),
|
|
392
|
+
headers: {
|
|
393
|
+
accept: "application/json",
|
|
394
|
+
"content-type": "application/json"
|
|
395
|
+
},
|
|
396
|
+
method: "POST"
|
|
397
|
+
});
|
|
398
|
+
let responseBody;
|
|
399
|
+
try {
|
|
400
|
+
responseBody = await response.json();
|
|
401
|
+
} catch {
|
|
402
|
+
throw new OlympexNetworkError("createAccount response was not valid JSON", {
|
|
403
|
+
contentType: response.headers.get("content-type") ?? void 0,
|
|
404
|
+
endpoint,
|
|
405
|
+
status: response.status,
|
|
406
|
+
statusText: response.statusText
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
if (!response.ok) {
|
|
410
|
+
throw new OlympexNetworkError(`createAccount request failed with status ${response.status}`, {
|
|
411
|
+
endpoint,
|
|
412
|
+
responseMessage: parseResponseMessage(responseBody),
|
|
413
|
+
status: response.status,
|
|
414
|
+
statusText: response.statusText
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
const credentials = extractCredentials(responseBody);
|
|
418
|
+
if (!credentials) {
|
|
419
|
+
throw new OlympexNetworkError("createAccount response did not include credentials", {
|
|
420
|
+
endpoint,
|
|
421
|
+
status: response.status
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return credentials;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// src/methods/get-version.ts
|
|
428
|
+
var VERSION = "0.0.0";
|
|
429
|
+
function getVersion() {
|
|
430
|
+
return VERSION;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/errors/domain-error.ts
|
|
434
|
+
var OlympexDomainError = class extends OlympexSdkError {
|
|
435
|
+
constructor(message, metadata) {
|
|
436
|
+
super(message, "OLYMPEX_DOMAIN_ERROR", metadata);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// src/client/domain-response.ts
|
|
441
|
+
function requireSuccessfulDomainResponse(response, payloadName) {
|
|
442
|
+
if (response === null || response === void 0) {
|
|
443
|
+
throw new OlympexDomainError(`Missing ${payloadName} response`);
|
|
444
|
+
}
|
|
445
|
+
if (response.success === false) {
|
|
446
|
+
throw new OlympexDomainError(response.message ?? `${payloadName} failed`, {
|
|
447
|
+
code: response.code,
|
|
448
|
+
success: response.success
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
return response;
|
|
452
|
+
}
|
|
453
|
+
function requirePayload(payload, payloadName) {
|
|
454
|
+
if (payload === null || payload === void 0) {
|
|
455
|
+
throw new OlympexDomainError(`Missing ${payloadName} payload`);
|
|
456
|
+
}
|
|
457
|
+
return payload;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/fees/defaults.ts
|
|
461
|
+
function resolveFeeOptions(callFees, clientDefaultFees) {
|
|
462
|
+
if (!callFees && !clientDefaultFees) {
|
|
463
|
+
return void 0;
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
...clientDefaultFees,
|
|
467
|
+
...callFees
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/fees/serialize.ts
|
|
472
|
+
function serializeFeeOptions(fees) {
|
|
473
|
+
if (!fees) {
|
|
474
|
+
return void 0;
|
|
475
|
+
}
|
|
476
|
+
const serialized = {};
|
|
477
|
+
if (fees.feeBps !== void 0) {
|
|
478
|
+
serialized.feeBps = fees.feeBps;
|
|
479
|
+
}
|
|
480
|
+
if (fees.feeRecipient !== void 0) {
|
|
481
|
+
serialized.feeRecipient = fees.feeRecipient;
|
|
482
|
+
}
|
|
483
|
+
return Object.keys(serialized).length > 0 ? serialized : void 0;
|
|
484
|
+
}
|
|
485
|
+
function mergeParamsWithFees(params, fees) {
|
|
486
|
+
const serialized = serializeFeeOptions(fees);
|
|
487
|
+
if (!serialized) {
|
|
488
|
+
return params;
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
...params,
|
|
492
|
+
...serialized
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/graphql/operations.ts
|
|
497
|
+
var GET_ENABLED_CHAINS = (
|
|
498
|
+
/* GraphQL */
|
|
499
|
+
`
|
|
500
|
+
query GetEnabledChains {
|
|
501
|
+
getEnabledChains {
|
|
502
|
+
chainIds
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
`
|
|
506
|
+
);
|
|
507
|
+
var GET_QUOTE = (
|
|
508
|
+
/* GraphQL */
|
|
509
|
+
`
|
|
510
|
+
query GetQuote($getQuoteParams: QuoteInput!) {
|
|
511
|
+
getQuote(params: $getQuoteParams) {
|
|
512
|
+
outAmount
|
|
513
|
+
estimatedGas
|
|
514
|
+
aggregatorId
|
|
515
|
+
aggregatorOrder
|
|
516
|
+
market {
|
|
517
|
+
dexName
|
|
518
|
+
swapAmount
|
|
519
|
+
dexImageURL
|
|
520
|
+
}
|
|
521
|
+
routes {
|
|
522
|
+
percentage
|
|
523
|
+
subRoutes {
|
|
524
|
+
from
|
|
525
|
+
to
|
|
526
|
+
dexes {
|
|
527
|
+
name
|
|
528
|
+
percentage
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
dataFeeTransaction {
|
|
533
|
+
effectiveGasPrice
|
|
534
|
+
nativePrice
|
|
535
|
+
transactionFee
|
|
536
|
+
transactionFeeInUSD
|
|
537
|
+
tokenPrice
|
|
538
|
+
transactionFeeInTokenIn
|
|
539
|
+
valueToApprove
|
|
540
|
+
}
|
|
541
|
+
gasMultiplier
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
`
|
|
545
|
+
);
|
|
546
|
+
var GET_QUOTE_SWAP = (
|
|
547
|
+
/* GraphQL */
|
|
548
|
+
`
|
|
549
|
+
mutation GetQuoteSwap($getQuoteSwapParams: QuoteSwapInput!) {
|
|
550
|
+
getQuoteSwap(params: $getQuoteSwapParams) {
|
|
551
|
+
code
|
|
552
|
+
message
|
|
553
|
+
quoteSwap {
|
|
554
|
+
data
|
|
555
|
+
estimatedGas
|
|
556
|
+
minOutAmount
|
|
557
|
+
outAmount
|
|
558
|
+
value
|
|
559
|
+
approveTransaction
|
|
560
|
+
}
|
|
561
|
+
success
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
`
|
|
565
|
+
);
|
|
566
|
+
var GET_CROSS_CHAIN_QUOTE = (
|
|
567
|
+
/* GraphQL */
|
|
568
|
+
`
|
|
569
|
+
query GetCrossChainQuote($params: CrossChainQuoteInput!) {
|
|
570
|
+
getCrossChainQuote(params: $params) {
|
|
571
|
+
code
|
|
572
|
+
message
|
|
573
|
+
success
|
|
574
|
+
crossChainQuote {
|
|
575
|
+
aggregatorId
|
|
576
|
+
estimatedGas
|
|
577
|
+
estimatedTime
|
|
578
|
+
estimateCostInUSD
|
|
579
|
+
fromTokenAmount
|
|
580
|
+
toTokenAmount
|
|
581
|
+
minimumReceived
|
|
582
|
+
bridgeInfo {
|
|
583
|
+
icon
|
|
584
|
+
displayName
|
|
585
|
+
}
|
|
586
|
+
middlewareRoute {
|
|
587
|
+
chainFrom {
|
|
588
|
+
fromAsset {
|
|
589
|
+
address
|
|
590
|
+
decimals
|
|
591
|
+
symbol
|
|
592
|
+
}
|
|
593
|
+
toAsset {
|
|
594
|
+
address
|
|
595
|
+
decimals
|
|
596
|
+
symbol
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
chainTo {
|
|
600
|
+
fromAsset {
|
|
601
|
+
address
|
|
602
|
+
decimals
|
|
603
|
+
symbol
|
|
604
|
+
}
|
|
605
|
+
toAsset {
|
|
606
|
+
address
|
|
607
|
+
decimals
|
|
608
|
+
symbol
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
`
|
|
616
|
+
);
|
|
617
|
+
var GET_CROSS_CHAIN_SWAP = (
|
|
618
|
+
/* GraphQL */
|
|
619
|
+
`
|
|
620
|
+
mutation GetCrossChainSwap($params: CrossChainSwapInput!) {
|
|
621
|
+
getCrossChainSwap(params: $params) {
|
|
622
|
+
code
|
|
623
|
+
message
|
|
624
|
+
success
|
|
625
|
+
crossChainSwap {
|
|
626
|
+
calldata
|
|
627
|
+
value
|
|
628
|
+
approveTransaction
|
|
629
|
+
dexHash
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
`
|
|
634
|
+
);
|
|
635
|
+
var GET_CROSS_CHAIN_TX_STATUS = (
|
|
636
|
+
/* GraphQL */
|
|
637
|
+
`
|
|
638
|
+
query GetCrossChainTxStatus($hash: String!, $chainId: String!, $dexHash: String!) {
|
|
639
|
+
getCrossChainTxStatus(txHash: $hash, chainId: $chainId, dexHash: $dexHash) {
|
|
640
|
+
message
|
|
641
|
+
success
|
|
642
|
+
txStatus {
|
|
643
|
+
toChainId
|
|
644
|
+
fromChainId
|
|
645
|
+
detailStatus
|
|
646
|
+
status
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
`
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
// src/methods/quote.ts
|
|
654
|
+
function createQuoteMethod(graphqlClient, defaultFees, logger) {
|
|
655
|
+
return async function quote(input) {
|
|
656
|
+
const fees = resolveFeeOptions(input.fees, defaultFees);
|
|
657
|
+
validateFeeOptions(fees);
|
|
658
|
+
if (input.mode === "single-chain") {
|
|
659
|
+
logger?.log(
|
|
660
|
+
"info",
|
|
661
|
+
"Olympex quote requested",
|
|
662
|
+
redact({
|
|
663
|
+
chainId: input.params.chainId,
|
|
664
|
+
mode: "single-chain"
|
|
665
|
+
})
|
|
666
|
+
);
|
|
667
|
+
const data2 = await graphqlClient.request(
|
|
668
|
+
GET_QUOTE,
|
|
669
|
+
{
|
|
670
|
+
getQuoteParams: mergeParamsWithFees(input.params, fees)
|
|
671
|
+
}
|
|
672
|
+
);
|
|
673
|
+
return {
|
|
674
|
+
mode: "single-chain",
|
|
675
|
+
quote: requirePayload(data2.getQuote, "getQuote")
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
logger?.log(
|
|
679
|
+
"info",
|
|
680
|
+
"Olympex quote requested",
|
|
681
|
+
redact({
|
|
682
|
+
fromChainId: input.params.fromChainId,
|
|
683
|
+
mode: "cross-chain",
|
|
684
|
+
toChainId: input.params.toChainId
|
|
685
|
+
})
|
|
686
|
+
);
|
|
687
|
+
const data = await graphqlClient.request(
|
|
688
|
+
GET_CROSS_CHAIN_QUOTE,
|
|
689
|
+
{
|
|
690
|
+
params: mergeParamsWithFees(input.params, fees)
|
|
691
|
+
}
|
|
692
|
+
);
|
|
693
|
+
const response = requireSuccessfulDomainResponse(data.getCrossChainQuote, "getCrossChainQuote");
|
|
694
|
+
return {
|
|
695
|
+
mode: "cross-chain",
|
|
696
|
+
quote: requirePayload(response.crossChainQuote, "crossChainQuote")
|
|
697
|
+
};
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// src/methods/support-chain.ts
|
|
702
|
+
function createSupportChainMethod(graphqlClient) {
|
|
703
|
+
return async function supportChain(chainId) {
|
|
704
|
+
const data = await graphqlClient.request(
|
|
705
|
+
GET_ENABLED_CHAINS,
|
|
706
|
+
{}
|
|
707
|
+
);
|
|
708
|
+
const enabledChains = requirePayload(data.getEnabledChains, "getEnabledChains");
|
|
709
|
+
return enabledChains.chainIds.includes(String(chainId));
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// src/methods/swap.ts
|
|
714
|
+
function createSwapMethod(graphqlClient, defaultFees, logger) {
|
|
715
|
+
return async function swap(input) {
|
|
716
|
+
const fees = resolveFeeOptions(input.fees, defaultFees);
|
|
717
|
+
validateFeeOptions(fees);
|
|
718
|
+
if (input.mode === "single-chain") {
|
|
719
|
+
logger?.log(
|
|
720
|
+
"info",
|
|
721
|
+
"Olympex swap requested",
|
|
722
|
+
redact({
|
|
723
|
+
chainId: input.params.chainId,
|
|
724
|
+
mode: "single-chain"
|
|
725
|
+
})
|
|
726
|
+
);
|
|
727
|
+
const data2 = await graphqlClient.request(
|
|
728
|
+
GET_QUOTE_SWAP,
|
|
729
|
+
{
|
|
730
|
+
getQuoteSwapParams: mergeParamsWithFees(input.params, fees)
|
|
731
|
+
}
|
|
732
|
+
);
|
|
733
|
+
const response2 = requireSuccessfulDomainResponse(data2.getQuoteSwap, "getQuoteSwap");
|
|
734
|
+
return {
|
|
735
|
+
mode: "single-chain",
|
|
736
|
+
swap: requirePayload(response2.quoteSwap, "quoteSwap")
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
logger?.log(
|
|
740
|
+
"info",
|
|
741
|
+
"Olympex swap requested",
|
|
742
|
+
redact({
|
|
743
|
+
fromChainId: input.params.fromChainId,
|
|
744
|
+
mode: "cross-chain",
|
|
745
|
+
toChainId: input.params.toChainId
|
|
746
|
+
})
|
|
747
|
+
);
|
|
748
|
+
const data = await graphqlClient.request(
|
|
749
|
+
GET_CROSS_CHAIN_SWAP,
|
|
750
|
+
{
|
|
751
|
+
params: mergeParamsWithFees(input.params, fees)
|
|
752
|
+
}
|
|
753
|
+
);
|
|
754
|
+
const response = requireSuccessfulDomainResponse(data.getCrossChainSwap, "getCrossChainSwap");
|
|
755
|
+
return {
|
|
756
|
+
mode: "cross-chain",
|
|
757
|
+
swap: requirePayload(response.crossChainSwap, "crossChainSwap")
|
|
758
|
+
};
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// src/methods/tx-status.ts
|
|
763
|
+
function createTxStatusMethod(graphqlClient) {
|
|
764
|
+
return async function txStatus(input) {
|
|
765
|
+
const data = await graphqlClient.request(
|
|
766
|
+
GET_CROSS_CHAIN_TX_STATUS,
|
|
767
|
+
input
|
|
768
|
+
);
|
|
769
|
+
const response = requireSuccessfulDomainResponse(
|
|
770
|
+
data.getCrossChainTxStatus,
|
|
771
|
+
"getCrossChainTxStatus"
|
|
772
|
+
);
|
|
773
|
+
return requirePayload(response.txStatus, "txStatus");
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// src/config/initialize.ts
|
|
778
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
779
|
+
function initialize(options) {
|
|
780
|
+
const apiKey = options.apiKey.trim();
|
|
781
|
+
const apiSecret = options.apiSecret.trim();
|
|
782
|
+
const passphrase = options.passphrase.trim();
|
|
783
|
+
if (!apiKey) {
|
|
784
|
+
throw new OlympexConfigError("apiKey is required");
|
|
785
|
+
}
|
|
786
|
+
if (!apiSecret) {
|
|
787
|
+
throw new OlympexConfigError("apiSecret is required");
|
|
788
|
+
}
|
|
789
|
+
if (!passphrase) {
|
|
790
|
+
throw new OlympexConfigError("passphrase is required");
|
|
791
|
+
}
|
|
792
|
+
validateFeeOptions(options.defaultFees);
|
|
793
|
+
const graphqlClient = new OlympexGraphQLClient({
|
|
794
|
+
apiKey,
|
|
795
|
+
apiSecret,
|
|
796
|
+
endpoint: getGraphqlEndpoint(),
|
|
797
|
+
headers: options.headers,
|
|
798
|
+
logger: options.logger,
|
|
799
|
+
passphrase,
|
|
800
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS
|
|
801
|
+
});
|
|
802
|
+
return {
|
|
803
|
+
apiKey,
|
|
804
|
+
createAccount,
|
|
805
|
+
getVersion,
|
|
806
|
+
quote: createQuoteMethod(graphqlClient, options.defaultFees, options.logger),
|
|
807
|
+
supportChain: createSupportChainMethod(graphqlClient),
|
|
808
|
+
swap: createSwapMethod(graphqlClient, options.defaultFees, options.logger),
|
|
809
|
+
txStatus: createTxStatusMethod(graphqlClient)
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// src/logging/console-logger.ts
|
|
814
|
+
var LEVEL_RANK = {
|
|
815
|
+
debug: 10,
|
|
816
|
+
info: 20,
|
|
817
|
+
warn: 30,
|
|
818
|
+
error: 40
|
|
819
|
+
};
|
|
820
|
+
function createConsoleLogger(options = {}) {
|
|
821
|
+
const minRank = LEVEL_RANK[options.minLevel ?? "info"];
|
|
822
|
+
const target = (level) => {
|
|
823
|
+
const method = globalThis.console[level];
|
|
824
|
+
return typeof method === "function" ? method.bind(globalThis.console) : globalThis.console.log.bind(globalThis.console);
|
|
825
|
+
};
|
|
826
|
+
return Object.freeze({
|
|
827
|
+
log(level, message, metadata) {
|
|
828
|
+
if (LEVEL_RANK[level] < minRank) {
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
try {
|
|
832
|
+
const write = target(level);
|
|
833
|
+
if (metadata === void 0) {
|
|
834
|
+
write(message);
|
|
835
|
+
} else {
|
|
836
|
+
write(message, metadata);
|
|
837
|
+
}
|
|
838
|
+
} catch {
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// src/errors/not-implemented-error.ts
|
|
845
|
+
var OlympexNotImplementedError = class extends OlympexSdkError {
|
|
846
|
+
constructor(message, metadata) {
|
|
847
|
+
super(message, "OLYMPEX_NOT_IMPLEMENTED", metadata);
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
851
|
+
0 && (module.exports = {
|
|
852
|
+
OlympexConfigError,
|
|
853
|
+
OlympexDomainError,
|
|
854
|
+
OlympexGraphQLError,
|
|
855
|
+
OlympexNetworkError,
|
|
856
|
+
OlympexNotImplementedError,
|
|
857
|
+
OlympexSdkError,
|
|
858
|
+
createAccount,
|
|
859
|
+
createConsoleLogger,
|
|
860
|
+
getVersion,
|
|
861
|
+
initialize
|
|
862
|
+
});
|
|
863
|
+
//# sourceMappingURL=index.js.map
|