@coinlist-co/react 0.10.1 → 0.11.1-rc.10770e8
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/README.md +32 -0
- package/dist/chunk-7CTH4KPU.js +2399 -0
- package/dist/chunk-7CTH4KPU.js.map +1 -0
- package/dist/{chunk-AQVCOWOV.js → chunk-LSPZETDH.js} +249 -317
- package/dist/chunk-LSPZETDH.js.map +1 -0
- package/dist/chunk-UZUQALFY.js +279 -0
- package/dist/chunk-UZUQALFY.js.map +1 -0
- package/dist/client/index.cjs +13430 -3308
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +5486 -899
- package/dist/client/index.d.ts +5486 -899
- package/dist/client/index.js +11025 -2388
- package/dist/client/index.js.map +1 -1
- package/dist/collections-BBI_XydI.d.cts +116 -0
- package/dist/collections-BrX9rRWc.d.ts +116 -0
- package/dist/config-CMl1bR3F.d.cts +2959 -0
- package/dist/config-CMl1bR3F.d.ts +2959 -0
- package/dist/server/index.cjs +1768 -511
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +266 -162
- package/dist/server/index.d.ts +266 -162
- package/dist/server/index.js +235 -169
- package/dist/server/index.js.map +1 -1
- package/dist/shared/index.cjs +2423 -926
- package/dist/shared/index.cjs.map +1 -1
- package/dist/shared/index.d.cts +325 -132
- package/dist/shared/index.d.ts +325 -132
- package/dist/shared/index.js +112 -28
- package/package.json +12 -8
- package/dist/chunk-AQVCOWOV.js.map +0 -1
- package/dist/chunk-TBU3EBNM.js +0 -442
- package/dist/chunk-TBU3EBNM.js.map +0 -1
- package/dist/chunk-UOHD7US2.js +0 -855
- package/dist/chunk-UOHD7US2.js.map +0 -1
- package/dist/collections-Bv1Oxzu_.d.ts +0 -28
- package/dist/collections-DDyxbOPZ.d.cts +0 -28
- package/dist/requirement-oVZA1INj.d.cts +0 -1040
- package/dist/requirement-oVZA1INj.d.ts +0 -1040
package/dist/server/index.cjs
CHANGED
|
@@ -20,8 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/server/index.ts
|
|
21
21
|
var server_exports = {};
|
|
22
22
|
__export(server_exports, {
|
|
23
|
+
ServerAuthNamespaceImpl: () => ServerAuthNamespaceImpl,
|
|
24
|
+
ServerOffersNamespaceImpl: () => ServerOffersNamespaceImpl,
|
|
25
|
+
ServerRequirementsNamespaceImpl: () => ServerRequirementsNamespaceImpl,
|
|
23
26
|
WritableSessionStoreRequiredError: () => WritableSessionStoreRequiredError,
|
|
24
|
-
createCoinListServer: () => createCoinListServer
|
|
27
|
+
createCoinListServer: () => createCoinListServer,
|
|
28
|
+
emptySessionStore: () => emptySessionStore,
|
|
29
|
+
pinoServerLogger: () => pinoServerLogger
|
|
25
30
|
});
|
|
26
31
|
module.exports = __toCommonJS(server_exports);
|
|
27
32
|
|
|
@@ -52,6 +57,8 @@ var retryAttempt = (attempt) => ({
|
|
|
52
57
|
var renewAttempted = (value) => ({
|
|
53
58
|
renewAttempted: value
|
|
54
59
|
});
|
|
60
|
+
var requestId = (id) => ({ requestId: id });
|
|
61
|
+
var getRequestId = (attrs) => attrs?.requestId ?? null;
|
|
55
62
|
var isProtected = (attrs) => attrs?.protected === true;
|
|
56
63
|
var needUserAgent = (attrs) => attrs?.userAgent === true;
|
|
57
64
|
var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
|
|
@@ -73,7 +80,9 @@ var Attributes = {
|
|
|
73
80
|
renewAttempted,
|
|
74
81
|
wasRenewAttempted,
|
|
75
82
|
clientCredentials,
|
|
76
|
-
getClientCredentials
|
|
83
|
+
getClientCredentials,
|
|
84
|
+
requestId,
|
|
85
|
+
getRequestId
|
|
77
86
|
};
|
|
78
87
|
|
|
79
88
|
// src/shared/api/http.ts
|
|
@@ -83,7 +92,24 @@ var HttpError = class extends Error {
|
|
|
83
92
|
this.name = "HttpError";
|
|
84
93
|
this.response = response;
|
|
85
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Correlates this failure with the `[HTTP]` log lines for the same request,
|
|
97
|
+
* which carry the method, the URL, the duration and every retry. `null` when
|
|
98
|
+
* the response did not come from an {@link HttpClient}.
|
|
99
|
+
*
|
|
100
|
+
* Worth quoting in a bug report: it is what makes a log excerpt readable.
|
|
101
|
+
*/
|
|
102
|
+
get requestId() {
|
|
103
|
+
return this.response.requestId ?? null;
|
|
104
|
+
}
|
|
86
105
|
};
|
|
106
|
+
function apiErrorCode(error) {
|
|
107
|
+
if (!(error instanceof HttpError)) return null;
|
|
108
|
+
const body = error.response.body;
|
|
109
|
+
if (typeof body !== "object" || body === null) return null;
|
|
110
|
+
const code = body.code;
|
|
111
|
+
return typeof code === "string" ? code : null;
|
|
112
|
+
}
|
|
87
113
|
async function makeRequest(request) {
|
|
88
114
|
const headers = {
|
|
89
115
|
Accept: "application/json",
|
|
@@ -119,7 +145,16 @@ async function makeRequest(request) {
|
|
|
119
145
|
};
|
|
120
146
|
}
|
|
121
147
|
const text = await response.text();
|
|
122
|
-
|
|
148
|
+
let body;
|
|
149
|
+
try {
|
|
150
|
+
body = text ? JSON.parse(text) : null;
|
|
151
|
+
} catch (_) {
|
|
152
|
+
throw new HttpError({
|
|
153
|
+
status: response.status,
|
|
154
|
+
headers: responseHeaders,
|
|
155
|
+
body: text
|
|
156
|
+
});
|
|
157
|
+
}
|
|
123
158
|
return {
|
|
124
159
|
status: response.status,
|
|
125
160
|
body,
|
|
@@ -180,11 +215,194 @@ var HEADER_API_VERSION = "X-API-Version";
|
|
|
180
215
|
var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
|
|
181
216
|
var API_VERSION = "2025-10-17";
|
|
182
217
|
|
|
218
|
+
// src/shared/types/errors.ts
|
|
219
|
+
var NotImplementedError = class extends Error {
|
|
220
|
+
constructor(message = "Not implemented yet") {
|
|
221
|
+
super(message);
|
|
222
|
+
this.name = "NotImplementedError";
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
var NotAuthenticatedError = class extends Error {
|
|
226
|
+
constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
|
|
227
|
+
super(message);
|
|
228
|
+
this.name = "NotAuthenticatedError";
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
var ValidationError = class extends Error {
|
|
232
|
+
constructor(message) {
|
|
233
|
+
super(message);
|
|
234
|
+
this.name = "ValidationError";
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
var InvariantError = class extends Error {
|
|
238
|
+
constructor(message) {
|
|
239
|
+
super(message);
|
|
240
|
+
this.name = "InvariantError";
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
var MathError = class extends Error {
|
|
244
|
+
constructor(message) {
|
|
245
|
+
super(message);
|
|
246
|
+
this.name = "MathError";
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// src/shared/core/observability/log-cause.ts
|
|
251
|
+
function classifyLogCause(error) {
|
|
252
|
+
if (error instanceof HttpError) {
|
|
253
|
+
return httpCause(error);
|
|
254
|
+
}
|
|
255
|
+
if (error instanceof ValidationError) {
|
|
256
|
+
return { type: "validation", message: error.message };
|
|
257
|
+
}
|
|
258
|
+
if (error instanceof InvariantError) {
|
|
259
|
+
return { type: "invariant", message: error.message };
|
|
260
|
+
}
|
|
261
|
+
if (error instanceof MathError) {
|
|
262
|
+
return { type: "math", message: error.message };
|
|
263
|
+
}
|
|
264
|
+
if (error instanceof NotAuthenticatedError) {
|
|
265
|
+
return { type: "not-authenticated" };
|
|
266
|
+
}
|
|
267
|
+
if (error instanceof NotImplementedError) {
|
|
268
|
+
return { type: "not-implemented" };
|
|
269
|
+
}
|
|
270
|
+
return { type: "generic-error", name: errorName(error) };
|
|
271
|
+
}
|
|
272
|
+
function describeErrorUnredacted(error) {
|
|
273
|
+
if (error instanceof HttpError) {
|
|
274
|
+
return describeHttpErrorRedacted(error);
|
|
275
|
+
}
|
|
276
|
+
if (error instanceof Error) {
|
|
277
|
+
return `${error.name}: ${error.message}`;
|
|
278
|
+
}
|
|
279
|
+
return `thrown non-error: ${stringifyUnredacted(error)}`;
|
|
280
|
+
}
|
|
281
|
+
function stringifyUnredacted(value) {
|
|
282
|
+
if (value === void 0) return "";
|
|
283
|
+
try {
|
|
284
|
+
return JSON.stringify(
|
|
285
|
+
value,
|
|
286
|
+
(_key, item) => typeof item === "bigint" ? `${item}` : item
|
|
287
|
+
) ?? String(value);
|
|
288
|
+
} catch (_) {
|
|
289
|
+
return "<unserializable>";
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function describeHttpErrorRedacted(error) {
|
|
293
|
+
const code = apiErrorCode(error);
|
|
294
|
+
const status = error.response.status;
|
|
295
|
+
return code === null ? `HttpError ${status}` : `HttpError ${status} (${code})`;
|
|
296
|
+
}
|
|
297
|
+
function errorName(error) {
|
|
298
|
+
return error instanceof Error ? error.name : `non-error ${typeof error}`;
|
|
299
|
+
}
|
|
300
|
+
function httpCause(error) {
|
|
301
|
+
return {
|
|
302
|
+
type: "http",
|
|
303
|
+
requestId: error.requestId,
|
|
304
|
+
status: error.response.status,
|
|
305
|
+
code: apiErrorCode(error),
|
|
306
|
+
eventId: apiErrorEventId(error)
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function apiErrorEventId(error) {
|
|
310
|
+
const body = error.response.body;
|
|
311
|
+
if (typeof body !== "object" || body === null) return null;
|
|
312
|
+
const eventId = body.event_id;
|
|
313
|
+
return typeof eventId === "string" ? eventId : null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/shared/core/observability/internal-logger.ts
|
|
317
|
+
function internalLogger(logger, scope) {
|
|
318
|
+
return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;
|
|
319
|
+
}
|
|
320
|
+
var LEVEL_RANK = {
|
|
321
|
+
none: 0,
|
|
322
|
+
error: 1,
|
|
323
|
+
warn: 2,
|
|
324
|
+
info: 3,
|
|
325
|
+
debug: 4
|
|
326
|
+
};
|
|
327
|
+
function scopedLogger(logger, scope, bindings) {
|
|
328
|
+
const admits = (level) => LEVEL_RANK[logger.level()] >= LEVEL_RANK[level];
|
|
329
|
+
const safe = (event) => ({
|
|
330
|
+
msg: event.msg,
|
|
331
|
+
scope,
|
|
332
|
+
bindings,
|
|
333
|
+
fields: event.fields ?? {},
|
|
334
|
+
...event.cause === void 0 ? {} : { cause: event.cause }
|
|
335
|
+
});
|
|
336
|
+
const unredacted = (event) => ({
|
|
337
|
+
msg: event.msg,
|
|
338
|
+
scope,
|
|
339
|
+
bindings,
|
|
340
|
+
fields: event.fields ?? {}
|
|
341
|
+
});
|
|
342
|
+
const self = {
|
|
343
|
+
child: (binding) => scopedLogger(logger, scope, { ...bindings, ...binding }),
|
|
344
|
+
debug: (event) => {
|
|
345
|
+
if (admits("debug")) logger.debug(() => unredacted(event()));
|
|
346
|
+
},
|
|
347
|
+
info: (event) => {
|
|
348
|
+
if (admits("info")) logger.info(() => safe(event()));
|
|
349
|
+
},
|
|
350
|
+
warn: (event) => {
|
|
351
|
+
if (admits("warn")) logger.warn(() => safe(event()));
|
|
352
|
+
},
|
|
353
|
+
error: (event) => {
|
|
354
|
+
if (admits("error")) logger.error(() => safe(event()));
|
|
355
|
+
},
|
|
356
|
+
failure: (event, error) => {
|
|
357
|
+
if (admits("debug"))
|
|
358
|
+
logger.debug(() => unredacted(verbatim(event(), error)));
|
|
359
|
+
if (admits("error")) logger.error(() => safe(classified(event(), error)));
|
|
360
|
+
},
|
|
361
|
+
warning: (event, error) => {
|
|
362
|
+
if (admits("debug"))
|
|
363
|
+
logger.debug(() => unredacted(verbatim(event(), error)));
|
|
364
|
+
if (admits("warn")) logger.warn(() => safe(classified(event(), error)));
|
|
365
|
+
},
|
|
366
|
+
wrap: async (op, params, run) => {
|
|
367
|
+
const opLog = self.child({ op });
|
|
368
|
+
opLog.debug(() => ({ msg: "call", fields: { params } }));
|
|
369
|
+
try {
|
|
370
|
+
return await run();
|
|
371
|
+
} catch (error) {
|
|
372
|
+
opLog.failure(() => ({ msg: "call failed" }), error);
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
return self;
|
|
378
|
+
}
|
|
379
|
+
function verbatim(event, error) {
|
|
380
|
+
return {
|
|
381
|
+
msg: event.msg,
|
|
382
|
+
fields: { ...event.fields, error: describeErrorUnredacted(error) }
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function classified(event, error) {
|
|
386
|
+
return { ...event, cause: event.cause ?? classifyLogCause(error) };
|
|
387
|
+
}
|
|
388
|
+
var noopInternalLogger = {
|
|
389
|
+
child: () => noopInternalLogger,
|
|
390
|
+
debug: () => void 0,
|
|
391
|
+
info: () => void 0,
|
|
392
|
+
warn: () => void 0,
|
|
393
|
+
error: () => void 0,
|
|
394
|
+
failure: () => void 0,
|
|
395
|
+
warning: () => void 0,
|
|
396
|
+
wrap: (_op, _params, run) => run()
|
|
397
|
+
};
|
|
398
|
+
|
|
183
399
|
// src/shared/api/http-client.ts
|
|
184
400
|
var HttpClient = class {
|
|
185
|
-
constructor(config, middleware = {}) {
|
|
401
|
+
constructor(config, middleware = {}, logger = null, options = {}) {
|
|
186
402
|
this.config = config;
|
|
187
403
|
this.middleware = middleware;
|
|
404
|
+
this.log = internalLogger(logger, "HTTP");
|
|
405
|
+
this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;
|
|
188
406
|
}
|
|
189
407
|
async send(request) {
|
|
190
408
|
return this.runRequestWithAfterMiddleware(request);
|
|
@@ -215,12 +433,18 @@ var HttpClient = class {
|
|
|
215
433
|
const url = this.resolveUrl(request.url);
|
|
216
434
|
const headers = {
|
|
217
435
|
...request.headers ?? {},
|
|
218
|
-
[HEADER_API_VERSION]: this.config.xApiVersion
|
|
436
|
+
...this.config.xApiVersion !== void 0 ? { [HEADER_API_VERSION]: this.config.xApiVersion } : {}
|
|
219
437
|
};
|
|
220
438
|
return {
|
|
221
439
|
...request,
|
|
222
440
|
url,
|
|
223
|
-
headers
|
|
441
|
+
headers,
|
|
442
|
+
// Only when absent: a retry or a post-renewal re-send arrives with the
|
|
443
|
+
// first attempt's id already on it, and keeping it is the whole point.
|
|
444
|
+
attributes: Attributes.getRequestId(request.attributes) === null ? Attributes.concat(
|
|
445
|
+
request.attributes ?? Attributes.empty,
|
|
446
|
+
Attributes.requestId(this.makeRequestId())
|
|
447
|
+
) : request.attributes
|
|
224
448
|
};
|
|
225
449
|
}
|
|
226
450
|
/**
|
|
@@ -244,10 +468,89 @@ var HttpClient = class {
|
|
|
244
468
|
}
|
|
245
469
|
return request;
|
|
246
470
|
}
|
|
247
|
-
|
|
248
|
-
|
|
471
|
+
/**
|
|
472
|
+
* One physical attempt, logged as one line.
|
|
473
|
+
*
|
|
474
|
+
* A non-2xx is a `warn` rather than an `error` because the wire does not
|
|
475
|
+
* know whether it is a failure: the retry middleware may turn a 503 into a
|
|
476
|
+
* success, and the token registry reads a 404 as "not listed". The namespace
|
|
477
|
+
* above decides, and logs the `error` when it does.
|
|
478
|
+
*/
|
|
479
|
+
async executeRequest(request) {
|
|
480
|
+
const requestId2 = Attributes.getRequestId(request.attributes);
|
|
481
|
+
const log = requestId2 === null ? this.log : this.log.child({ requestId: requestId2 });
|
|
482
|
+
const attempt = Attributes.getRetryAttempt(request.attributes) + 1;
|
|
483
|
+
const startedAt = Date.now();
|
|
484
|
+
log.debug(() => ({
|
|
485
|
+
msg: "request sent",
|
|
486
|
+
fields: describeRequestUnredacted(request)
|
|
487
|
+
}));
|
|
488
|
+
try {
|
|
489
|
+
const response = await makeRequest(request);
|
|
490
|
+
const elapsed = Date.now() - startedAt;
|
|
491
|
+
const outcome = () => ({
|
|
492
|
+
msg: "request completed",
|
|
493
|
+
fields: {
|
|
494
|
+
...identifyRequest(request),
|
|
495
|
+
"http.response.status_code": response.status,
|
|
496
|
+
duration_ms: elapsed,
|
|
497
|
+
attempt
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
if (response.status >= 200 && response.status < 300) {
|
|
501
|
+
log.info(outcome);
|
|
502
|
+
} else {
|
|
503
|
+
log.warn(outcome);
|
|
504
|
+
}
|
|
505
|
+
log.debug(() => ({
|
|
506
|
+
msg: "response received",
|
|
507
|
+
fields: { body: response.body }
|
|
508
|
+
}));
|
|
509
|
+
return requestId2 === null ? response : { ...response, requestId: requestId2 };
|
|
510
|
+
} catch (error) {
|
|
511
|
+
const elapsed = Date.now() - startedAt;
|
|
512
|
+
log.warning(
|
|
513
|
+
() => ({
|
|
514
|
+
msg: "request threw",
|
|
515
|
+
fields: {
|
|
516
|
+
...identifyRequest(request),
|
|
517
|
+
duration_ms: elapsed,
|
|
518
|
+
attempt
|
|
519
|
+
}
|
|
520
|
+
}),
|
|
521
|
+
error
|
|
522
|
+
);
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
249
525
|
}
|
|
250
526
|
};
|
|
527
|
+
function identifyRequest(request) {
|
|
528
|
+
const { host, path } = splitUrl(request.url);
|
|
529
|
+
return {
|
|
530
|
+
"http.request.method": request.method,
|
|
531
|
+
"server.address": host,
|
|
532
|
+
"url.path": path
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function splitUrl(url) {
|
|
536
|
+
try {
|
|
537
|
+
const parsed = new URL(url);
|
|
538
|
+
return { host: parsed.host, path: parsed.pathname };
|
|
539
|
+
} catch (_) {
|
|
540
|
+
return { host: null, path: url };
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
function defaultMakeRequestId() {
|
|
544
|
+
return Math.random().toString(36).slice(2, 10).padEnd(8, "0");
|
|
545
|
+
}
|
|
546
|
+
function describeRequestUnredacted(request) {
|
|
547
|
+
return {
|
|
548
|
+
"http.request.method": request.method,
|
|
549
|
+
"url.full": buildUrlWithQueryParams(request.url, request.queryParams),
|
|
550
|
+
headers: request.headers,
|
|
551
|
+
...request.method === "POST" ? { body: request.body } : {}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
251
554
|
|
|
252
555
|
// src/shared/api/middleware/attach-session-middleware.ts
|
|
253
556
|
function attachSessionMiddleware(fetchAccessToken) {
|
|
@@ -275,7 +578,7 @@ function attachSessionMiddleware(fetchAccessToken) {
|
|
|
275
578
|
};
|
|
276
579
|
}
|
|
277
580
|
|
|
278
|
-
// src/shared/utils.ts
|
|
581
|
+
// src/shared/core/utils/crypto.ts
|
|
279
582
|
function getUUIDv4() {
|
|
280
583
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
281
584
|
return crypto.randomUUID();
|
|
@@ -378,18 +681,22 @@ function renewSessionMiddleware(fetchAccessToken) {
|
|
|
378
681
|
|
|
379
682
|
// src/shared/api/authenticated-api-client.ts
|
|
380
683
|
var AuthenticatedApiClient = class {
|
|
381
|
-
constructor(config, fetchAccessToken, additionalBeforeRequest = []) {
|
|
382
|
-
this.httpClient = new HttpClient(
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
684
|
+
constructor(config, fetchAccessToken, additionalBeforeRequest = [], logger = null) {
|
|
685
|
+
this.httpClient = new HttpClient(
|
|
686
|
+
config,
|
|
687
|
+
{
|
|
688
|
+
beforeRequest: [
|
|
689
|
+
attachSessionMiddleware(fetchAccessToken),
|
|
690
|
+
...additionalBeforeRequest,
|
|
691
|
+
idempotencyKeyMiddleware
|
|
692
|
+
],
|
|
693
|
+
afterRequest: [
|
|
694
|
+
renewSessionMiddleware(fetchAccessToken),
|
|
695
|
+
requestRetryMiddleware
|
|
696
|
+
]
|
|
697
|
+
},
|
|
698
|
+
logger
|
|
699
|
+
);
|
|
393
700
|
}
|
|
394
701
|
async send(request) {
|
|
395
702
|
const response = await this.httpClient.send(request);
|
|
@@ -401,10 +708,15 @@ var AuthenticatedApiClient = class {
|
|
|
401
708
|
}
|
|
402
709
|
};
|
|
403
710
|
|
|
404
|
-
// src/server/api/api.
|
|
405
|
-
var
|
|
406
|
-
constructor(config, fetchAccessToken) {
|
|
407
|
-
this.client = new AuthenticatedApiClient(
|
|
711
|
+
// src/server/core/api/api-client.ts
|
|
712
|
+
var ApiClient = class {
|
|
713
|
+
constructor(config, fetchAccessToken, logger = null) {
|
|
714
|
+
this.client = new AuthenticatedApiClient(
|
|
715
|
+
config,
|
|
716
|
+
fetchAccessToken,
|
|
717
|
+
[],
|
|
718
|
+
logger
|
|
719
|
+
);
|
|
408
720
|
}
|
|
409
721
|
async send(request) {
|
|
410
722
|
return this.client.send(request);
|
|
@@ -419,48 +731,168 @@ var WritableSessionStoreRequiredError = class extends Error {
|
|
|
419
731
|
}
|
|
420
732
|
};
|
|
421
733
|
|
|
422
|
-
// src/shared/types/
|
|
423
|
-
var
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
734
|
+
// src/shared/types/oauth-session.ts
|
|
735
|
+
var ClientCredentialsOAuth = (value) => value;
|
|
736
|
+
var OAuthRefreshToken = (value) => value;
|
|
737
|
+
var OAuthSession = {
|
|
738
|
+
fromDto: (dto) => {
|
|
739
|
+
const expiresAt = new Date(Date.now() + dto.expires_in * 1e3);
|
|
740
|
+
return {
|
|
741
|
+
accessToken: {
|
|
742
|
+
value: dto.access_token,
|
|
743
|
+
expiresAt
|
|
744
|
+
},
|
|
745
|
+
...dto.refresh_token != null && dto.refresh_token !== "" ? { refreshToken: OAuthRefreshToken(dto.refresh_token) } : void 0
|
|
746
|
+
};
|
|
747
|
+
}
|
|
428
748
|
};
|
|
429
749
|
|
|
430
|
-
// src/
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
method: "POST",
|
|
434
|
-
url: `/v1/documents/${documentType}/submission`,
|
|
435
|
-
body: fields,
|
|
436
|
-
attributes: Attributes.protected()
|
|
437
|
-
});
|
|
438
|
-
return DocumentSubmission.fromDto(dto);
|
|
750
|
+
// src/server/core/server-auth-namespace.ts
|
|
751
|
+
function emptySessionStore() {
|
|
752
|
+
return { getSession: async () => null };
|
|
439
753
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
754
|
+
var ServerAuthNamespaceImpl = class {
|
|
755
|
+
constructor(api, config) {
|
|
756
|
+
this.api = api;
|
|
757
|
+
this.config = config;
|
|
758
|
+
this.log = internalLogger(config.logger ?? null, "AUTH");
|
|
759
|
+
}
|
|
760
|
+
async completeOAuth(params) {
|
|
761
|
+
return this.log.wrap("completeOAuth", void 0, async () => {
|
|
762
|
+
const setSession = this.writableSessionStore();
|
|
763
|
+
const sessionDto = await this.api.send({
|
|
764
|
+
method: "POST",
|
|
765
|
+
url: `/oauth/token`,
|
|
766
|
+
body: {
|
|
767
|
+
grant_type: "authorization_code",
|
|
768
|
+
code: params.code,
|
|
769
|
+
redirect_uri: this.config.redirectUri,
|
|
770
|
+
client_id: this.config.clientId,
|
|
771
|
+
client_secret: this.config.clientSecret,
|
|
772
|
+
code_verifier: params.codeVerifier
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
const session = OAuthSession.fromDto(sessionDto);
|
|
776
|
+
await setSession(session);
|
|
777
|
+
return session;
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
async getAccessToken() {
|
|
781
|
+
return this.log.wrap(
|
|
782
|
+
"getAccessToken",
|
|
783
|
+
void 0,
|
|
784
|
+
() => this.readAccessToken()
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
async readAccessToken() {
|
|
788
|
+
const sessionStore = this.config.sessionStore;
|
|
789
|
+
const session = await sessionStore.getSession();
|
|
790
|
+
if (session == null) return null;
|
|
791
|
+
const now = Date.now();
|
|
792
|
+
const expiresAt = session.accessToken.expiresAt.getTime();
|
|
793
|
+
const bufferMs = this.config.accessTokenExpiryBufferSeconds * 1e3;
|
|
794
|
+
if (expiresAt > now + bufferMs) {
|
|
795
|
+
return session.accessToken;
|
|
796
|
+
}
|
|
797
|
+
const setSession = sessionStore.setSession?.bind(sessionStore);
|
|
798
|
+
if (!setSession) {
|
|
799
|
+
this.log.child({ op: "getAccessToken" }).warn(() => ({
|
|
800
|
+
msg: "serving an expired token: the session store is read-only, so it cannot be refreshed"
|
|
801
|
+
}));
|
|
802
|
+
return session.accessToken;
|
|
803
|
+
}
|
|
804
|
+
return this.refreshSession(session.refreshToken, setSession);
|
|
805
|
+
}
|
|
806
|
+
async refreshSession(refreshToken, setSession) {
|
|
807
|
+
const log = this.log.child({ op: "refresh" });
|
|
808
|
+
if (!refreshToken) {
|
|
809
|
+
log.warn(() => ({
|
|
810
|
+
msg: "clearing the session: it carries no refresh token"
|
|
811
|
+
}));
|
|
812
|
+
await setSession(null);
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
try {
|
|
816
|
+
const sessionDto = await this.api.send({
|
|
817
|
+
method: "POST",
|
|
818
|
+
url: `/oauth/token`,
|
|
819
|
+
body: {
|
|
820
|
+
grant_type: "refresh_token",
|
|
821
|
+
refresh_token: refreshToken,
|
|
822
|
+
client_id: this.config.clientId,
|
|
823
|
+
client_secret: this.config.clientSecret
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
const newSession = OAuthSession.fromDto(sessionDto);
|
|
827
|
+
await setSession(newSession);
|
|
828
|
+
log.info(() => ({ msg: "session renewed" }));
|
|
829
|
+
return newSession.accessToken;
|
|
830
|
+
} catch (error) {
|
|
831
|
+
log.failure(
|
|
832
|
+
() => ({ msg: "refresh failed; clearing the session" }),
|
|
833
|
+
error
|
|
834
|
+
);
|
|
835
|
+
await setSession(null);
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
async clientCredentials() {
|
|
840
|
+
return this.log.wrap("clientCredentials", void 0, async () => {
|
|
841
|
+
const sessionDto = await this.api.send({
|
|
842
|
+
method: "POST",
|
|
843
|
+
url: `/oauth/token`,
|
|
844
|
+
body: {
|
|
845
|
+
grant_type: "client_credentials",
|
|
846
|
+
client_id: this.config.clientId,
|
|
847
|
+
client_secret: this.config.clientSecret
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
const session = OAuthSession.fromDto(sessionDto);
|
|
851
|
+
return ClientCredentialsOAuth(session.accessToken);
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
async logout() {
|
|
855
|
+
return this.log.wrap("logout", void 0, () => this.revokeAndClear());
|
|
856
|
+
}
|
|
857
|
+
async revokeAndClear() {
|
|
858
|
+
const setSession = this.writableSessionStore();
|
|
859
|
+
const session = await this.config.sessionStore.getSession();
|
|
860
|
+
if (session == null) return;
|
|
861
|
+
try {
|
|
862
|
+
await this.api.send({
|
|
863
|
+
method: "POST",
|
|
864
|
+
url: `/oauth/revoke`,
|
|
865
|
+
body: {
|
|
866
|
+
token: session.accessToken.value,
|
|
867
|
+
client_id: this.config.clientId,
|
|
868
|
+
client_secret: this.config.clientSecret
|
|
869
|
+
}
|
|
870
|
+
});
|
|
871
|
+
} catch (err) {
|
|
872
|
+
if (!(err instanceof HttpError) || this.config.strict) {
|
|
873
|
+
throw err;
|
|
874
|
+
}
|
|
875
|
+
this.log.child({ op: "logout" }).warn(() => ({
|
|
876
|
+
msg: "the token was not revoked upstream; the local session is cleared regardless"
|
|
877
|
+
}));
|
|
878
|
+
}
|
|
879
|
+
await setSession(null);
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Returns the store's `setSession`, or throws — the guard every
|
|
883
|
+
* session-writing operation shares.
|
|
884
|
+
*/
|
|
885
|
+
writableSessionStore() {
|
|
886
|
+
const sessionStore = this.config.sessionStore;
|
|
887
|
+
const setSession = sessionStore.setSession?.bind(sessionStore);
|
|
888
|
+
if (!setSession) {
|
|
889
|
+
throw new WritableSessionStoreRequiredError();
|
|
890
|
+
}
|
|
891
|
+
return setSession;
|
|
892
|
+
}
|
|
446
893
|
};
|
|
447
894
|
|
|
448
|
-
// src/shared/api/frontline/kyc.ts
|
|
449
|
-
async function createKycToken(api, levelName, reset) {
|
|
450
|
-
const dto = await api.send({
|
|
451
|
-
method: "POST",
|
|
452
|
-
url: "/v1/kyc-token",
|
|
453
|
-
body: {
|
|
454
|
-
...levelName === void 0 ? {} : { level_name: levelName },
|
|
455
|
-
...reset === void 0 ? {} : { reset }
|
|
456
|
-
},
|
|
457
|
-
attributes: Attributes.protected()
|
|
458
|
-
});
|
|
459
|
-
return KycToken.fromDto(dto);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
895
|
// src/shared/api/pagination.ts
|
|
463
|
-
var Cursor = (value) => value;
|
|
464
896
|
async function fetchAllPages(fetchPage, baseParams) {
|
|
465
897
|
const items = [];
|
|
466
898
|
let cursor = null;
|
|
@@ -475,55 +907,135 @@ async function fetchAllPages(fetchPage, baseParams) {
|
|
|
475
907
|
} while (cursor);
|
|
476
908
|
return items;
|
|
477
909
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
910
|
+
|
|
911
|
+
// src/shared/types/blockchain/core.ts
|
|
912
|
+
var ETHEREUM_CHAINS = {
|
|
913
|
+
ethereum_mainnet: true,
|
|
914
|
+
ethereum_sepolia: true,
|
|
915
|
+
base_mainnet: true,
|
|
916
|
+
base_sepolia: true
|
|
484
917
|
};
|
|
485
|
-
var
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (params.after) {
|
|
489
|
-
queryParams.starting_after = params.after;
|
|
490
|
-
}
|
|
491
|
-
if (params.before) {
|
|
492
|
-
queryParams.starting_before = params.before;
|
|
493
|
-
}
|
|
494
|
-
if (params.limit) {
|
|
495
|
-
queryParams.limit = params.limit;
|
|
496
|
-
}
|
|
497
|
-
return queryParams;
|
|
918
|
+
var EthereumChain = (value) => {
|
|
919
|
+
if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {
|
|
920
|
+
throw new ValidationError(`Unsupported Ethereum chain: "${value}"`);
|
|
498
921
|
}
|
|
922
|
+
return value;
|
|
499
923
|
};
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
var OfferSlug = (value) => value;
|
|
504
|
-
var Offer = {
|
|
505
|
-
fromDto: (dto) => ({
|
|
506
|
-
id: OfferId(dto.id),
|
|
507
|
-
slug: OfferSlug(dto.slug),
|
|
508
|
-
type: dto.type,
|
|
509
|
-
tagline: dto.tagline,
|
|
510
|
-
bannerUrl: dto.banner_url,
|
|
511
|
-
logoUrl: dto.logo_url,
|
|
512
|
-
startsAt: new Date(dto.starts_at),
|
|
513
|
-
endsAt: dto.ends_at ? new Date(dto.ends_at) : null
|
|
514
|
-
})
|
|
924
|
+
var SOLANA_CHAINS = {
|
|
925
|
+
solana_mainnet: true,
|
|
926
|
+
solana_devnet: true
|
|
515
927
|
};
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
928
|
+
var Chain = (value) => {
|
|
929
|
+
if (!Object.keys(ETHEREUM_CHAINS).includes(value) && !Object.keys(SOLANA_CHAINS).includes(value)) {
|
|
930
|
+
throw new ValidationError(`Unsupported chain: "${value}"`);
|
|
931
|
+
}
|
|
932
|
+
return value;
|
|
933
|
+
};
|
|
934
|
+
var EvmWalletAddress = (value) => value;
|
|
935
|
+
var EvmContractAddress = (value) => value;
|
|
936
|
+
var HexEncodedTransactionData = (value) => value;
|
|
937
|
+
var MAX_ASSET_DECIMALS = 77;
|
|
938
|
+
var AssetDecimals = (value) => {
|
|
939
|
+
if (!Number.isInteger(value)) {
|
|
940
|
+
throw new ValidationError(`Asset decimals must be an integer: ${value}`);
|
|
941
|
+
}
|
|
942
|
+
if (value < 0 || value > MAX_ASSET_DECIMALS) {
|
|
943
|
+
throw new ValidationError(
|
|
944
|
+
`Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
return value;
|
|
948
|
+
};
|
|
949
|
+
var STABLE_DECIMALS = AssetDecimals(6);
|
|
950
|
+
var DecimalString = (value) => value;
|
|
951
|
+
var MAX_UINT_256 = 2n ** 256n - 1n;
|
|
952
|
+
var assertUint256 = (value) => {
|
|
953
|
+
if (isUint256(value)) return value;
|
|
954
|
+
throw new InvariantError(`Value out of uint256 bounds: ${value}`);
|
|
955
|
+
};
|
|
956
|
+
var parseUint256 = (value, label) => {
|
|
957
|
+
if (isUint256(value)) return value;
|
|
958
|
+
throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
|
|
959
|
+
};
|
|
960
|
+
var isUint256 = (value) => value >= 0n && value <= MAX_UINT_256;
|
|
961
|
+
var BlockchainAmount = Object.assign(
|
|
962
|
+
(value) => value,
|
|
963
|
+
{
|
|
964
|
+
add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
|
|
965
|
+
sub: (a, b) => combineAmounts(a, b, (x, y) => x - y),
|
|
966
|
+
mul: multiplyAmounts,
|
|
967
|
+
div: divideAmounts
|
|
968
|
+
}
|
|
969
|
+
);
|
|
970
|
+
function multiplyAmounts(a, b) {
|
|
971
|
+
const product = a.raw * b.raw;
|
|
972
|
+
return BlockchainAmount({
|
|
973
|
+
raw: product / 10n ** BigInt(b.decimals),
|
|
974
|
+
decimals: a.decimals
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
function divideAmounts(a, b) {
|
|
978
|
+
if (b.raw === 0n) {
|
|
979
|
+
throw new MathError("Cannot divide a BlockchainAmount by zero");
|
|
980
|
+
}
|
|
981
|
+
const scaled = a.raw * 10n ** BigInt(b.decimals);
|
|
982
|
+
return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });
|
|
983
|
+
}
|
|
984
|
+
function combineAmounts(a, b, op) {
|
|
985
|
+
if (a.decimals !== b.decimals) {
|
|
986
|
+
throw new InvariantError(
|
|
987
|
+
`Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
const raw = op(a.raw, b.raw);
|
|
991
|
+
if (raw < 0n || raw > MAX_UINT_256) {
|
|
992
|
+
throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);
|
|
993
|
+
}
|
|
994
|
+
return BlockchainAmount({ raw, decimals: a.decimals });
|
|
995
|
+
}
|
|
996
|
+
var AssetSymbol = (value) => value;
|
|
997
|
+
|
|
998
|
+
// src/shared/types/offer.ts
|
|
999
|
+
var OfferId = (value) => value;
|
|
1000
|
+
var OfferSlug = (value) => value;
|
|
1001
|
+
var Offer = {
|
|
1002
|
+
fromDto: (dto) => {
|
|
1003
|
+
if (!Array.isArray(dto.tokens)) {
|
|
1004
|
+
throw new ValidationError(
|
|
1005
|
+
`Offer.tokens: expected an array, got ${typeof dto.tokens}`
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
return {
|
|
1009
|
+
id: OfferId(dto.id),
|
|
1010
|
+
slug: OfferSlug(dto.slug),
|
|
1011
|
+
type: dto.type,
|
|
1012
|
+
tagline: dto.tagline,
|
|
1013
|
+
bannerUrl: dto.banner_url,
|
|
1014
|
+
logoUrl: dto.logo_url,
|
|
1015
|
+
startsAt: new Date(dto.starts_at),
|
|
1016
|
+
endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
|
|
1017
|
+
tokens: dto.tokens.map(OfferToken.fromDto)
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
var OfferToken = {
|
|
1022
|
+
fromDto: (dto) => ({
|
|
1023
|
+
role: dto.role,
|
|
1024
|
+
chain: Chain(dto.chain),
|
|
1025
|
+
address: EvmContractAddress(dto.address)
|
|
1026
|
+
})
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
// src/shared/types/asset.ts
|
|
1030
|
+
var AssetId = (value) => value;
|
|
1031
|
+
var AssetCode = (value) => value;
|
|
1032
|
+
var Asset = {
|
|
1033
|
+
fromDto: (dto) => ({
|
|
1034
|
+
id: AssetId(dto.id),
|
|
1035
|
+
code: AssetCode(dto.code),
|
|
1036
|
+
name: dto.name,
|
|
1037
|
+
fractionalDigits: dto.fractional_digits
|
|
1038
|
+
})
|
|
527
1039
|
};
|
|
528
1040
|
|
|
529
1041
|
// src/shared/types/offer-detail.ts
|
|
@@ -532,22 +1044,39 @@ var OfferOptionSlug = (value) => value;
|
|
|
532
1044
|
var OfferDetail = {
|
|
533
1045
|
fromDto: (dto) => {
|
|
534
1046
|
if (!Array.isArray(dto.funding_assets)) {
|
|
535
|
-
throw new
|
|
1047
|
+
throw new ValidationError(
|
|
1048
|
+
`OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`
|
|
1049
|
+
);
|
|
536
1050
|
}
|
|
537
1051
|
if (!Array.isArray(dto.options)) {
|
|
538
|
-
throw new
|
|
1052
|
+
throw new ValidationError(
|
|
1053
|
+
`OfferDetail.options: expected an array, got ${typeof dto.options}`
|
|
1054
|
+
);
|
|
539
1055
|
}
|
|
540
1056
|
if (!Array.isArray(dto.terms)) {
|
|
541
|
-
throw new
|
|
1057
|
+
throw new ValidationError(
|
|
1058
|
+
`OfferDetail.terms: expected an array, got ${typeof dto.terms}`
|
|
1059
|
+
);
|
|
542
1060
|
}
|
|
543
1061
|
if (!Array.isArray(dto.links)) {
|
|
544
|
-
throw new
|
|
1062
|
+
throw new ValidationError(
|
|
1063
|
+
`OfferDetail.links: expected an array, got ${typeof dto.links}`
|
|
1064
|
+
);
|
|
545
1065
|
}
|
|
546
1066
|
if (!Array.isArray(dto.faqs)) {
|
|
547
|
-
throw new
|
|
1067
|
+
throw new ValidationError(
|
|
1068
|
+
`OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`
|
|
1069
|
+
);
|
|
548
1070
|
}
|
|
549
1071
|
if (!Array.isArray(dto.milestones)) {
|
|
550
|
-
throw new
|
|
1072
|
+
throw new ValidationError(
|
|
1073
|
+
`OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
if (!Array.isArray(dto.tokens)) {
|
|
1077
|
+
throw new ValidationError(
|
|
1078
|
+
`OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`
|
|
1079
|
+
);
|
|
551
1080
|
}
|
|
552
1081
|
return {
|
|
553
1082
|
id: OfferId(dto.id),
|
|
@@ -556,6 +1085,7 @@ var OfferDetail = {
|
|
|
556
1085
|
name: dto.name,
|
|
557
1086
|
asset: Asset.fromDto(dto.asset),
|
|
558
1087
|
fundingAssets: dto.funding_assets.map(Asset.fromDto),
|
|
1088
|
+
tokens: dto.tokens.map(OfferToken.fromDto),
|
|
559
1089
|
about: notBlankStringOrNull(dto.about),
|
|
560
1090
|
tagline: dto.tagline,
|
|
561
1091
|
bannerUrl: dto.banner_url,
|
|
@@ -609,6 +1139,31 @@ var Milestone = {
|
|
|
609
1139
|
})
|
|
610
1140
|
};
|
|
611
1141
|
|
|
1142
|
+
// src/shared/types/pagination.ts
|
|
1143
|
+
var Cursor = (value) => value;
|
|
1144
|
+
var PaginatedResponse = {
|
|
1145
|
+
fromDto: (dto, itemMapper) => ({
|
|
1146
|
+
data: dto.data.map(itemMapper),
|
|
1147
|
+
startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
|
|
1148
|
+
startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
|
|
1149
|
+
})
|
|
1150
|
+
};
|
|
1151
|
+
var PaginationParams = {
|
|
1152
|
+
toQueryParams: (params) => {
|
|
1153
|
+
const queryParams = {};
|
|
1154
|
+
if (params.after) {
|
|
1155
|
+
queryParams.starting_after = params.after;
|
|
1156
|
+
}
|
|
1157
|
+
if (params.before) {
|
|
1158
|
+
queryParams.starting_before = params.before;
|
|
1159
|
+
}
|
|
1160
|
+
if (params.limit) {
|
|
1161
|
+
queryParams.limit = params.limit;
|
|
1162
|
+
}
|
|
1163
|
+
return queryParams;
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
|
|
612
1167
|
// src/shared/api/frontline/offers.ts
|
|
613
1168
|
async function fetchOffers(api, clientCreds) {
|
|
614
1169
|
return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
|
|
@@ -638,44 +1193,32 @@ async function fetchOfferDetails(api, id, clientCreds) {
|
|
|
638
1193
|
return OfferDetail.fromDto(dto);
|
|
639
1194
|
}
|
|
640
1195
|
|
|
641
|
-
// src/
|
|
642
|
-
var
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
};
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
permanentAddress: PiiAddress.fromDto(dto.permanent_address)
|
|
666
|
-
})
|
|
1196
|
+
// src/server/core/server-offers-namespace.ts
|
|
1197
|
+
var ServerOffersNamespaceImpl = class {
|
|
1198
|
+
constructor(ctx) {
|
|
1199
|
+
this.ctx = ctx;
|
|
1200
|
+
this.log = internalLogger(ctx.logger, "OFFERS");
|
|
1201
|
+
}
|
|
1202
|
+
async list(clientCreds) {
|
|
1203
|
+
return this.log.wrap("list", clientCreds, async () => {
|
|
1204
|
+
await this.ctx.ensureAuthenticated(clientCreds);
|
|
1205
|
+
return fetchOffers(this.ctx.api, clientCreds);
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
async listPage(params, clientCreds) {
|
|
1209
|
+
return this.log.wrap("listPage", { params, clientCreds }, async () => {
|
|
1210
|
+
await this.ctx.ensureAuthenticated(clientCreds);
|
|
1211
|
+
return fetchOffersPage(this.ctx.api, params, clientCreds);
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
async get(id, clientCreds) {
|
|
1215
|
+
return this.log.wrap("get", { id, clientCreds }, async () => {
|
|
1216
|
+
await this.ctx.ensureAuthenticated(clientCreds);
|
|
1217
|
+
return fetchOfferDetails(this.ctx.api, id, clientCreds);
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
667
1220
|
};
|
|
668
1221
|
|
|
669
|
-
// src/shared/api/frontline/pii.ts
|
|
670
|
-
async function fetchPii(api) {
|
|
671
|
-
const dto = await api.send({
|
|
672
|
-
method: "GET",
|
|
673
|
-
url: "/v1/pii",
|
|
674
|
-
attributes: Attributes.protected()
|
|
675
|
-
});
|
|
676
|
-
return Pii.fromDto(dto);
|
|
677
|
-
}
|
|
678
|
-
|
|
679
1222
|
// src/shared/types/requirement.ts
|
|
680
1223
|
var RequirementId = (value) => value;
|
|
681
1224
|
var Requirement = {
|
|
@@ -723,138 +1266,156 @@ async function fetchRequirementStatuses(api, offerId) {
|
|
|
723
1266
|
return RequirementStatusInfo.fromStatusesDto(response);
|
|
724
1267
|
}
|
|
725
1268
|
|
|
726
|
-
// src/shared/types/
|
|
727
|
-
var
|
|
728
|
-
var EvmContractAddress = (value) => value;
|
|
729
|
-
var HexEncodedTransactionData = (value) => value;
|
|
730
|
-
var AssetDecimals = (value) => value;
|
|
731
|
-
var MAX_UINT_256 = 2n ** 256n - 1n;
|
|
732
|
-
var assertUint256 = (value) => {
|
|
733
|
-
if (value < 0n || value > MAX_UINT_256) {
|
|
734
|
-
throw new Error(`Value out of uint256 bounds: ${value}`);
|
|
735
|
-
}
|
|
736
|
-
return value;
|
|
737
|
-
};
|
|
738
|
-
var BlockchainAmount = Object.assign(
|
|
739
|
-
(value) => value,
|
|
740
|
-
{
|
|
741
|
-
add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
|
|
742
|
-
sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
|
|
743
|
-
}
|
|
744
|
-
);
|
|
745
|
-
function combineAmounts(a, b, op) {
|
|
746
|
-
if (a.decimals !== b.decimals) {
|
|
747
|
-
throw new Error(
|
|
748
|
-
`Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
|
|
749
|
-
);
|
|
750
|
-
}
|
|
751
|
-
const raw = op(a.raw, b.raw);
|
|
752
|
-
if (raw < 0n || raw > MAX_UINT_256) {
|
|
753
|
-
throw new Error(`BlockchainAmount out of uint256 bounds: ${raw}`);
|
|
754
|
-
}
|
|
755
|
-
return BlockchainAmount({ raw, decimals: a.decimals });
|
|
756
|
-
}
|
|
757
|
-
var AssetSymbol = (value) => value;
|
|
758
|
-
|
|
759
|
-
// src/shared/types/offer-option-address.ts
|
|
760
|
-
var OfferOptionAddressId = (value) => value;
|
|
761
|
-
var OfferOptionAddress = {
|
|
762
|
-
/** Maps the API DTO into the SDK offer-option-address domain model. */
|
|
1269
|
+
// src/shared/types/document-submission.ts
|
|
1270
|
+
var DocumentSubmission = {
|
|
763
1271
|
fromDto: (dto) => ({
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
address: EvmWalletAddress(dto.address),
|
|
767
|
-
protocol: dto.protocol,
|
|
768
|
-
createdAt: new Date(dto.created_at)
|
|
769
|
-
})
|
|
770
|
-
};
|
|
771
|
-
var ConnectExternalWalletParams = {
|
|
772
|
-
/** Maps connect-wallet params into the API DTO payload. */
|
|
773
|
-
toDto: (params) => ({
|
|
774
|
-
offer_option_id: params.offerOptionId,
|
|
775
|
-
wallet_address: params.walletAddress,
|
|
776
|
-
chain: params.chain,
|
|
777
|
-
signature: params.signature
|
|
1272
|
+
status: dto.status,
|
|
1273
|
+
formType: dto.form_type
|
|
778
1274
|
})
|
|
779
1275
|
};
|
|
780
1276
|
|
|
781
|
-
// src/shared/
|
|
782
|
-
|
|
783
|
-
|
|
1277
|
+
// src/shared/api/frontline/documents.ts
|
|
1278
|
+
async function submitDocument(api, documentType, fields) {
|
|
1279
|
+
const dto = await api.send({
|
|
1280
|
+
method: "POST",
|
|
1281
|
+
url: `/v1/documents/${documentType}/submission`,
|
|
1282
|
+
body: fields,
|
|
1283
|
+
attributes: Attributes.protected()
|
|
1284
|
+
});
|
|
1285
|
+
return DocumentSubmission.fromDto(dto);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// src/shared/types/kyc.ts
|
|
1289
|
+
var KycToken = {
|
|
784
1290
|
fromDto: (dto) => ({
|
|
785
|
-
|
|
786
|
-
expiresAt: new Date(dto.expires_at)
|
|
1291
|
+
token: dto.token
|
|
787
1292
|
})
|
|
788
1293
|
};
|
|
789
|
-
var CreateWalletOwnershipChallengeParams = {
|
|
790
|
-
/**
|
|
791
|
-
* Maps challenge-request params into the API DTO payload. The discriminated
|
|
792
|
-
* union guarantees SIWE fields are present exactly when `challengeType` is
|
|
793
|
-
* `siwe`, so the mapping narrows on the discriminant.
|
|
794
|
-
*/
|
|
795
|
-
toDto: (params) => {
|
|
796
|
-
switch (params.challengeType) {
|
|
797
|
-
case "plain":
|
|
798
|
-
return {
|
|
799
|
-
wallet_address: params.walletAddress,
|
|
800
|
-
chain: params.chain,
|
|
801
|
-
challenge_type: "plain"
|
|
802
|
-
};
|
|
803
|
-
case "siwe":
|
|
804
|
-
return {
|
|
805
|
-
wallet_address: params.walletAddress,
|
|
806
|
-
chain: params.chain,
|
|
807
|
-
challenge_type: "siwe",
|
|
808
|
-
domain: params.domain,
|
|
809
|
-
uri: params.uri,
|
|
810
|
-
statement: params.statement
|
|
811
|
-
};
|
|
812
|
-
default: {
|
|
813
|
-
const _exhaustive = params;
|
|
814
|
-
return _exhaustive;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
};
|
|
819
1294
|
|
|
820
|
-
// src/shared/api/frontline/
|
|
821
|
-
async function
|
|
1295
|
+
// src/shared/api/frontline/kyc.ts
|
|
1296
|
+
async function createKycToken(api, levelName, reset) {
|
|
822
1297
|
const dto = await api.send({
|
|
823
1298
|
method: "POST",
|
|
824
|
-
url: "/v1/
|
|
825
|
-
body:
|
|
1299
|
+
url: "/v1/kyc-token",
|
|
1300
|
+
body: {
|
|
1301
|
+
...levelName === void 0 ? {} : { level_name: levelName },
|
|
1302
|
+
...reset === void 0 ? {} : { reset }
|
|
1303
|
+
},
|
|
826
1304
|
attributes: Attributes.protected()
|
|
827
1305
|
});
|
|
828
|
-
return
|
|
1306
|
+
return KycToken.fromDto(dto);
|
|
829
1307
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
}
|
|
848
|
-
|
|
1308
|
+
|
|
1309
|
+
// src/shared/types/pii.ts
|
|
1310
|
+
var Iso2CountryCode = (value) => value;
|
|
1311
|
+
var PiiJurisdiction = {
|
|
1312
|
+
fromDto: (dto) => ({
|
|
1313
|
+
iso2: Iso2CountryCode(dto.iso_2),
|
|
1314
|
+
name: dto.name
|
|
1315
|
+
})
|
|
1316
|
+
};
|
|
1317
|
+
var PiiAddress = {
|
|
1318
|
+
fromDto: (dto) => ({
|
|
1319
|
+
street: dto.street,
|
|
1320
|
+
city: dto.city,
|
|
1321
|
+
state: dto.state,
|
|
1322
|
+
postalCode: dto.postal_code,
|
|
1323
|
+
country: dto.country
|
|
1324
|
+
})
|
|
1325
|
+
};
|
|
1326
|
+
var Pii = {
|
|
1327
|
+
fromDto: (dto) => ({
|
|
1328
|
+
kind: dto.kind,
|
|
1329
|
+
fullLegalName: dto.full_legal_name,
|
|
1330
|
+
dateOfBirth: dto.date_of_birth,
|
|
1331
|
+
jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
|
|
1332
|
+
taxId: dto.tax_id,
|
|
1333
|
+
permanentAddress: PiiAddress.fromDto(dto.permanent_address)
|
|
1334
|
+
})
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
// src/shared/api/frontline/pii.ts
|
|
1338
|
+
async function fetchPii(api) {
|
|
849
1339
|
const dto = await api.send({
|
|
850
|
-
method: "
|
|
851
|
-
url:
|
|
1340
|
+
method: "GET",
|
|
1341
|
+
url: "/v1/pii",
|
|
852
1342
|
attributes: Attributes.protected()
|
|
853
1343
|
});
|
|
854
|
-
return
|
|
1344
|
+
return Pii.fromDto(dto);
|
|
855
1345
|
}
|
|
856
1346
|
|
|
857
|
-
// src/shared/
|
|
1347
|
+
// src/shared/core/requirements/requirements-namespace.ts
|
|
1348
|
+
var RequirementsNamespaceImpl = class {
|
|
1349
|
+
constructor(ctx) {
|
|
1350
|
+
this.ctx = ctx;
|
|
1351
|
+
this.log = internalLogger(ctx.logger, "REQUIREMENTS");
|
|
1352
|
+
}
|
|
1353
|
+
async forOffer(offerId) {
|
|
1354
|
+
return this.log.wrap("forOffer", offerId, async () => {
|
|
1355
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1356
|
+
return fetchOfferRequirements(
|
|
1357
|
+
this.ctx.api,
|
|
1358
|
+
offerId,
|
|
1359
|
+
void 0
|
|
1360
|
+
);
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
async statuses(offerId) {
|
|
1364
|
+
return this.log.wrap("statuses", offerId, async () => {
|
|
1365
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1366
|
+
return fetchRequirementStatuses(this.ctx.api, offerId);
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
async createKycToken(params) {
|
|
1370
|
+
return this.log.wrap("createKycToken", params, async () => {
|
|
1371
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1372
|
+
return createKycToken(
|
|
1373
|
+
this.ctx.api,
|
|
1374
|
+
params?.levelName,
|
|
1375
|
+
params?.reset
|
|
1376
|
+
);
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
async getPii() {
|
|
1380
|
+
return this.log.wrap("getPii", void 0, async () => {
|
|
1381
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1382
|
+
return fetchPii(this.ctx.api);
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
async submitDocument(params) {
|
|
1386
|
+
return this.log.wrap("submitDocument", params, async () => {
|
|
1387
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1388
|
+
return submitDocument(
|
|
1389
|
+
this.ctx.api,
|
|
1390
|
+
params.documentType,
|
|
1391
|
+
params.fields
|
|
1392
|
+
);
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
|
|
1397
|
+
// src/server/core/server-requirements-namespace.ts
|
|
1398
|
+
var ServerRequirementsNamespaceImpl = class extends RequirementsNamespaceImpl {
|
|
1399
|
+
constructor(serverCtx) {
|
|
1400
|
+
super(serverCtx);
|
|
1401
|
+
this.serverCtx = serverCtx;
|
|
1402
|
+
}
|
|
1403
|
+
async forOffer(offerId, clientCreds) {
|
|
1404
|
+
return this.log.wrap("forOffer", { offerId, clientCreds }, async () => {
|
|
1405
|
+
await this.serverCtx.ensureAuthenticated(clientCreds);
|
|
1406
|
+
return fetchOfferRequirements(
|
|
1407
|
+
this.serverCtx.api,
|
|
1408
|
+
offerId,
|
|
1409
|
+
clientCreds
|
|
1410
|
+
);
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1415
|
+
// src/shared/api/nabu/config.ts
|
|
1416
|
+
var NABU_BASE_URL = "https://asset.coinlist.co";
|
|
1417
|
+
|
|
1418
|
+
// src/shared/types/providers/superstate/swap.ts
|
|
858
1419
|
var SwapAuthorization = {
|
|
859
1420
|
fromDto: (dto) => ({
|
|
860
1421
|
authorized: dto.authorized
|
|
@@ -862,25 +1423,31 @@ var SwapAuthorization = {
|
|
|
862
1423
|
};
|
|
863
1424
|
var SwapPreview = {
|
|
864
1425
|
fromDto: (dto) => ({
|
|
865
|
-
inputAmount:
|
|
866
|
-
|
|
867
|
-
|
|
1426
|
+
inputAmount: parseUint256(
|
|
1427
|
+
BigInt(dto.pay_input_amount),
|
|
1428
|
+
"SwapPreview.pay_input_amount"
|
|
1429
|
+
),
|
|
1430
|
+
fee: parseUint256(BigInt(dto.fee), "SwapPreview.fee"),
|
|
1431
|
+
outputAmount: parseUint256(
|
|
1432
|
+
BigInt(dto.receive_output_amount),
|
|
1433
|
+
"SwapPreview.receive_output_amount"
|
|
1434
|
+
)
|
|
868
1435
|
})
|
|
869
1436
|
};
|
|
870
1437
|
var SwapStatus = {
|
|
871
1438
|
fromDto: (dto) => ({
|
|
872
|
-
stopped:
|
|
873
|
-
swapLevel:
|
|
1439
|
+
stopped: parseUint256(BigInt(dto.stopped), "SwapStatus.stopped"),
|
|
1440
|
+
swapLevel: parseUint256(BigInt(dto.swap_level), "SwapStatus.swap_level")
|
|
874
1441
|
})
|
|
875
1442
|
};
|
|
876
1443
|
var TokenAllowance = {
|
|
877
1444
|
fromDto: (dto) => ({
|
|
878
|
-
allowance:
|
|
1445
|
+
allowance: parseUint256(BigInt(dto.allowance), "TokenAllowance.allowance")
|
|
879
1446
|
})
|
|
880
1447
|
};
|
|
881
1448
|
var TokenBalance = {
|
|
882
1449
|
fromDto: (dto) => ({
|
|
883
|
-
balance:
|
|
1450
|
+
balance: parseUint256(BigInt(dto.balance), "TokenBalance.balance")
|
|
884
1451
|
})
|
|
885
1452
|
};
|
|
886
1453
|
var AllowWalletResponse = {
|
|
@@ -905,7 +1472,7 @@ var AllowWalletResponse = {
|
|
|
905
1472
|
}
|
|
906
1473
|
};
|
|
907
1474
|
|
|
908
|
-
// src/shared/api/frontline/swap.ts
|
|
1475
|
+
// src/shared/api/frontline/providers/superstate/swap.ts
|
|
909
1476
|
async function getSwapAuthorization(api, params) {
|
|
910
1477
|
const dto = await api.send({
|
|
911
1478
|
method: "GET",
|
|
@@ -1005,53 +1572,27 @@ function toErc20Asset(dto) {
|
|
|
1005
1572
|
};
|
|
1006
1573
|
}
|
|
1007
1574
|
|
|
1008
|
-
// src/shared/core/erc20-namespace.ts
|
|
1575
|
+
// src/shared/core/blockchain/erc20/erc20-namespace.ts
|
|
1009
1576
|
var Erc20NamespaceImpl = class {
|
|
1010
1577
|
constructor(ctx) {
|
|
1011
1578
|
this.ctx = ctx;
|
|
1579
|
+
this.log = internalLogger(ctx.logger, "ERC20");
|
|
1012
1580
|
}
|
|
1013
|
-
async
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
await this.ctx.ensureUserAuthenticated();
|
|
1019
|
-
return getTokenBalance(this.ctx.api, params);
|
|
1020
|
-
}
|
|
1021
|
-
};
|
|
1022
|
-
|
|
1023
|
-
// src/shared/core/swap-namespace.ts
|
|
1024
|
-
var SwapNamespaceImpl = class {
|
|
1025
|
-
constructor(ctx) {
|
|
1026
|
-
this.ctx = ctx;
|
|
1027
|
-
}
|
|
1028
|
-
async getAuthorization(params) {
|
|
1029
|
-
await this.ctx.ensureUserAuthenticated();
|
|
1030
|
-
return getSwapAuthorization(this.ctx.api, params);
|
|
1031
|
-
}
|
|
1032
|
-
async getPreview(params) {
|
|
1033
|
-
await this.ctx.ensureUserAuthenticated();
|
|
1034
|
-
return getSwapPreview(this.ctx.api, params);
|
|
1035
|
-
}
|
|
1036
|
-
async getStatus(params) {
|
|
1037
|
-
await this.ctx.ensureUserAuthenticated();
|
|
1038
|
-
return getSwapStatus(this.ctx.api, params);
|
|
1039
|
-
}
|
|
1040
|
-
async getOutputToken(params) {
|
|
1041
|
-
await this.ctx.ensureUserAuthenticated();
|
|
1042
|
-
return getSwapOutputToken(this.ctx.api, params);
|
|
1043
|
-
}
|
|
1044
|
-
async requestWalletOwnershipChallenge(params) {
|
|
1045
|
-
await this.ctx.ensureUserAuthenticated();
|
|
1046
|
-
return createWalletOwnershipChallenge(this.ctx.api, params);
|
|
1581
|
+
async getAllowance(params) {
|
|
1582
|
+
return this.log.wrap("getAllowance", params, async () => {
|
|
1583
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1584
|
+
return getTokenAllowance(this.ctx.api, params);
|
|
1585
|
+
});
|
|
1047
1586
|
}
|
|
1048
|
-
async
|
|
1049
|
-
|
|
1050
|
-
|
|
1587
|
+
async getBalance(params) {
|
|
1588
|
+
return this.log.wrap("getBalance", params, async () => {
|
|
1589
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1590
|
+
return getTokenBalance(this.ctx.api, params);
|
|
1591
|
+
});
|
|
1051
1592
|
}
|
|
1052
1593
|
};
|
|
1053
1594
|
|
|
1054
|
-
// src/shared/types/
|
|
1595
|
+
// src/shared/types/providers/coin-list/token-sale.ts
|
|
1055
1596
|
var ParticipationId = (value) => value;
|
|
1056
1597
|
var Blockchain = (value) => value;
|
|
1057
1598
|
var WalletAddress = (value) => value;
|
|
@@ -1098,7 +1639,7 @@ var CreateParticipationParams = {
|
|
|
1098
1639
|
})
|
|
1099
1640
|
};
|
|
1100
1641
|
|
|
1101
|
-
// src/shared/api/frontline/
|
|
1642
|
+
// src/shared/api/frontline/providers/coin-list/token-sale.ts
|
|
1102
1643
|
async function fetchParticipations(api, offerId) {
|
|
1103
1644
|
return fetchAllPages(
|
|
1104
1645
|
(params) => fetchParticipationsPage(api, params),
|
|
@@ -1132,261 +1673,977 @@ async function createParticipation(api, params) {
|
|
|
1132
1673
|
return Participation.fromDto(dto);
|
|
1133
1674
|
}
|
|
1134
1675
|
|
|
1135
|
-
// src/shared/core/token-sale-namespace.ts
|
|
1136
|
-
var
|
|
1676
|
+
// src/shared/core/checkout/coin-list/token-sale-namespace.ts
|
|
1677
|
+
var CoinListTokenSaleNamespaceImpl = class {
|
|
1137
1678
|
constructor(ctx) {
|
|
1138
1679
|
this.ctx = ctx;
|
|
1680
|
+
this.log = internalLogger(ctx.logger, "TOKEN_SALE");
|
|
1139
1681
|
}
|
|
1140
|
-
async
|
|
1141
|
-
|
|
1142
|
-
|
|
1682
|
+
async list(offerId) {
|
|
1683
|
+
return this.log.wrap("list", offerId, async () => {
|
|
1684
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1685
|
+
return fetchParticipations(this.ctx.api, offerId);
|
|
1686
|
+
});
|
|
1143
1687
|
}
|
|
1144
|
-
async
|
|
1145
|
-
|
|
1146
|
-
|
|
1688
|
+
async listPage(params) {
|
|
1689
|
+
return this.log.wrap("listPage", params, async () => {
|
|
1690
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1691
|
+
return fetchParticipationsPage(this.ctx.api, params);
|
|
1692
|
+
});
|
|
1147
1693
|
}
|
|
1148
|
-
async
|
|
1149
|
-
|
|
1150
|
-
|
|
1694
|
+
async get(id) {
|
|
1695
|
+
return this.log.wrap("get", id, async () => {
|
|
1696
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1697
|
+
return fetchParticipation(this.ctx.api, id);
|
|
1698
|
+
});
|
|
1151
1699
|
}
|
|
1152
1700
|
async createParticipation(params) {
|
|
1153
|
-
|
|
1154
|
-
|
|
1701
|
+
return this.log.wrap("createParticipation", params, async () => {
|
|
1702
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1703
|
+
return createParticipation(this.ctx.api, params);
|
|
1704
|
+
});
|
|
1155
1705
|
}
|
|
1156
1706
|
};
|
|
1157
1707
|
|
|
1158
|
-
// src/shared/
|
|
1159
|
-
var
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1708
|
+
// src/shared/core/blockchain/formatters.ts
|
|
1709
|
+
var import_viem = require("viem");
|
|
1710
|
+
|
|
1711
|
+
// src/shared/types/blockchain/ui.ts
|
|
1712
|
+
var FormattedAmountAssetUi = (value) => value;
|
|
1713
|
+
|
|
1714
|
+
// src/shared/core/blockchain/formatters.ts
|
|
1715
|
+
function formatRawAmount(amount) {
|
|
1716
|
+
return (0, import_viem.formatUnits)(amount.raw, amount.decimals);
|
|
1717
|
+
}
|
|
1718
|
+
var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
|
|
1719
|
+
var USD_FRACTION_DIGITS = AssetDecimals(2);
|
|
1720
|
+
|
|
1721
|
+
// src/shared/core/blockchain/chain.ts
|
|
1722
|
+
var CHAIN_IDS = {
|
|
1723
|
+
ethereum_mainnet: 1,
|
|
1724
|
+
ethereum_sepolia: 11155111,
|
|
1725
|
+
base_mainnet: 8453,
|
|
1726
|
+
base_sepolia: 84532
|
|
1164
1727
|
};
|
|
1728
|
+
function chainFromId(chainId) {
|
|
1729
|
+
const chains = Object.keys(CHAIN_IDS);
|
|
1730
|
+
const chain = chains.find((c) => String(CHAIN_IDS[c]) === chainId);
|
|
1731
|
+
if (!chain) {
|
|
1732
|
+
throw new ValidationError(`Unsupported EIP-155 chain id: "${chainId}"`);
|
|
1733
|
+
}
|
|
1734
|
+
return chain;
|
|
1735
|
+
}
|
|
1165
1736
|
|
|
1166
|
-
// src/shared/
|
|
1167
|
-
var
|
|
1168
|
-
|
|
1169
|
-
|
|
1737
|
+
// src/shared/core/blockchain/math.ts
|
|
1738
|
+
var import_viem2 = require("viem");
|
|
1739
|
+
function blockchainAmountFromRawOrThrow({
|
|
1740
|
+
label,
|
|
1741
|
+
raw,
|
|
1742
|
+
decimals
|
|
1743
|
+
}) {
|
|
1744
|
+
const trimmed = raw.trim();
|
|
1745
|
+
if (trimmed === "") {
|
|
1746
|
+
throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
|
|
1747
|
+
}
|
|
1748
|
+
let value;
|
|
1749
|
+
try {
|
|
1750
|
+
value = BigInt(trimmed);
|
|
1751
|
+
} catch {
|
|
1752
|
+
throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
|
|
1753
|
+
}
|
|
1754
|
+
try {
|
|
1755
|
+
return BlockchainAmount({ raw: assertUint256(value), decimals });
|
|
1756
|
+
} catch {
|
|
1757
|
+
throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
// src/shared/types/trading.ts
|
|
1762
|
+
var Ticker = (value) => value;
|
|
1763
|
+
|
|
1764
|
+
// src/shared/types/providers/ondo/ondo.ts
|
|
1765
|
+
var OndoTradingStatus = {
|
|
1170
1766
|
fromDto: (dto) => {
|
|
1171
|
-
|
|
1767
|
+
if (!dto.tradable) return { type: "not-tradable", side: dto.side };
|
|
1172
1768
|
return {
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1769
|
+
type: "tradable",
|
|
1770
|
+
side: dto.side,
|
|
1771
|
+
grossMaxTokens: decimalOrNull(dto.gross_max_tokens),
|
|
1772
|
+
grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),
|
|
1773
|
+
grossMaxActiveNotionalValue: decimalOrNull(
|
|
1774
|
+
dto.gross_max_active_notional_value
|
|
1775
|
+
)
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
};
|
|
1779
|
+
var decimalOrNull = (value) => value === null ? null : DecimalString(value);
|
|
1780
|
+
var OndoQuote = {
|
|
1781
|
+
fromDto: (dto) => {
|
|
1782
|
+
const assetDecimals = AssetDecimals(dto.asset_decimals);
|
|
1783
|
+
return {
|
|
1784
|
+
chain: chainFromId(dto.chain_id),
|
|
1785
|
+
ticker: Ticker(dto.ticker),
|
|
1786
|
+
assetAddress: EvmContractAddress(dto.asset_address),
|
|
1787
|
+
asset: {
|
|
1788
|
+
name: dto.ticker,
|
|
1789
|
+
symbol: AssetSymbol(dto.symbol),
|
|
1790
|
+
decimals: assetDecimals
|
|
1176
1791
|
},
|
|
1177
|
-
|
|
1792
|
+
side: dto.side,
|
|
1793
|
+
tokenBaseUnits: blockchainAmountFromRawOrThrow({
|
|
1794
|
+
label: "tokenBaseUnits",
|
|
1795
|
+
raw: dto.token_base_units,
|
|
1796
|
+
decimals: assetDecimals
|
|
1797
|
+
}),
|
|
1798
|
+
price: DecimalString(dto.price)
|
|
1178
1799
|
};
|
|
1179
1800
|
}
|
|
1180
1801
|
};
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1802
|
+
var OndoBuyTransaction = {
|
|
1803
|
+
fromDto: (dto) => {
|
|
1804
|
+
const spendDecimals = AssetDecimals(dto.spend_input_decimals);
|
|
1805
|
+
const outputDecimals = AssetDecimals(dto.receive_output_decimals);
|
|
1806
|
+
return {
|
|
1807
|
+
...parseSwapCore(dto, spendDecimals),
|
|
1808
|
+
side: "buy",
|
|
1809
|
+
fee: blockchainAmountFromRawOrThrow({
|
|
1810
|
+
label: "fee",
|
|
1811
|
+
raw: dto.fee,
|
|
1812
|
+
decimals: spendDecimals
|
|
1813
|
+
}),
|
|
1814
|
+
notionalValue: blockchainAmountFromRawOrThrow({
|
|
1815
|
+
label: "notional_value",
|
|
1816
|
+
raw: dto.notional_value,
|
|
1817
|
+
decimals: spendDecimals
|
|
1818
|
+
}),
|
|
1819
|
+
receiveOutputAmount: parsePositiveAmount({
|
|
1820
|
+
label: "receive_output_amount",
|
|
1821
|
+
raw: dto.receive_output_amount,
|
|
1822
|
+
decimals: outputDecimals,
|
|
1823
|
+
// A transaction that yields nothing is not one to sign - the user
|
|
1824
|
+
// would pay the deposit and receive no asset - and frontline refuses
|
|
1825
|
+
// to emit one. A zero here is a changed encoding, not a small order.
|
|
1826
|
+
// Rejecting it at the boundary is also what lets `computeOndoBuyPrice`
|
|
1827
|
+
// divide by it without a fallible result: the failure surfaces as the
|
|
1828
|
+
// data hook's ERROR state rather than as a division during render.
|
|
1829
|
+
reason: "a buy that yields nothing is not fillable"
|
|
1830
|
+
})
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
var OndoSellTransaction = {
|
|
1835
|
+
fromDto: (dto) => {
|
|
1836
|
+
const spendDecimals = AssetDecimals(dto.spend_input_decimals);
|
|
1837
|
+
const outputDecimals = AssetDecimals(dto.receive_output_decimals);
|
|
1838
|
+
const expectedQuantity = parsePositiveAmount({
|
|
1839
|
+
label: "expected_quantity",
|
|
1840
|
+
raw: dto.expected_quantity,
|
|
1841
|
+
decimals: outputDecimals,
|
|
1842
|
+
reason: "a sale that yields nothing is not fillable"
|
|
1843
|
+
});
|
|
1844
|
+
return {
|
|
1845
|
+
...parseSwapCore(dto, spendDecimals),
|
|
1846
|
+
side: "sell",
|
|
1847
|
+
expected: {
|
|
1848
|
+
quantity: expectedQuantity,
|
|
1849
|
+
fee: blockchainAmountFromRawOrThrow({
|
|
1850
|
+
label: "expected_fee",
|
|
1851
|
+
raw: dto.expected_fee,
|
|
1852
|
+
decimals: outputDecimals
|
|
1853
|
+
})
|
|
1194
1854
|
},
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1855
|
+
minimum: {
|
|
1856
|
+
quantity: parseMinimumQuantity(
|
|
1857
|
+
dto.minimum_quantity,
|
|
1858
|
+
outputDecimals,
|
|
1859
|
+
expectedQuantity
|
|
1860
|
+
),
|
|
1861
|
+
fee: blockchainAmountFromRawOrThrow({
|
|
1862
|
+
label: "minimum_fee",
|
|
1863
|
+
raw: dto.minimum_fee,
|
|
1864
|
+
decimals: outputDecimals
|
|
1865
|
+
})
|
|
1866
|
+
}
|
|
1204
1867
|
};
|
|
1205
|
-
this.erc20 = new Erc20NamespaceImpl(ctx);
|
|
1206
|
-
this.tokenSale = new TokenSaleNamespaceImpl(ctx);
|
|
1207
|
-
this.swap = new SwapNamespaceImpl(ctx);
|
|
1208
1868
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1869
|
+
};
|
|
1870
|
+
function parseSwapCore(dto, spendDecimals) {
|
|
1871
|
+
return {
|
|
1872
|
+
tx: {
|
|
1873
|
+
to: EvmContractAddress(dto.to),
|
|
1874
|
+
data: HexEncodedTransactionData(dto.data)
|
|
1875
|
+
},
|
|
1876
|
+
expiresAt: parseExpiresAt(dto.expires_at),
|
|
1877
|
+
spendInputAmount: parsePositiveAmount({
|
|
1878
|
+
label: "spend_input_amount",
|
|
1879
|
+
raw: dto.spend_input_amount,
|
|
1880
|
+
decimals: spendDecimals,
|
|
1881
|
+
// A transaction that takes nothing from the wallet is not one to sign:
|
|
1882
|
+
// it would settle one leg of a trade and skip the other. Frontline
|
|
1883
|
+
// refuses an `amount` of zero whichever way the trade runs, so this is a
|
|
1884
|
+
// changed encoding rather than a small order.
|
|
1885
|
+
//
|
|
1886
|
+
// Guarded on both sides rather than on the sale alone, because which
|
|
1887
|
+
// amount becomes the divisor in the price flips with the direction: a
|
|
1888
|
+
// guard placed by that would be a rule about the arithmetic rather than
|
|
1889
|
+
// about the trade.
|
|
1890
|
+
reason: "a swap that spends nothing is not fillable"
|
|
1891
|
+
})
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
function parseMinimumQuantity(raw, decimals, expectedQuantity) {
|
|
1895
|
+
const amount = parsePositiveAmount({
|
|
1896
|
+
label: "minimum_quantity",
|
|
1897
|
+
raw,
|
|
1898
|
+
decimals,
|
|
1899
|
+
reason: "a floor of zero guarantees nothing"
|
|
1900
|
+
});
|
|
1901
|
+
if (amount.raw > expectedQuantity.raw) {
|
|
1902
|
+
throw new ValidationError(
|
|
1903
|
+
`minimum_quantity: must not exceed expected_quantity ("${raw}" > "${expectedQuantity.raw}")`
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
return amount;
|
|
1907
|
+
}
|
|
1908
|
+
function parsePositiveAmount({
|
|
1909
|
+
label,
|
|
1910
|
+
raw,
|
|
1911
|
+
decimals,
|
|
1912
|
+
reason
|
|
1913
|
+
}) {
|
|
1914
|
+
const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });
|
|
1915
|
+
if (amount.raw <= 0n) {
|
|
1916
|
+
throw new ValidationError(
|
|
1917
|
+
`${label}: must be greater than zero ("${raw}") - ${reason}`
|
|
1918
|
+
);
|
|
1919
|
+
}
|
|
1920
|
+
return amount;
|
|
1921
|
+
}
|
|
1922
|
+
function parseExpiresAt(value) {
|
|
1923
|
+
const date = new Date(value);
|
|
1924
|
+
if (Number.isNaN(date.getTime())) {
|
|
1925
|
+
throw new ValidationError(`expires_at: not a date ("${value}")`);
|
|
1926
|
+
}
|
|
1927
|
+
return date;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
// src/shared/api/frontline/providers/ondo/ondo.ts
|
|
1931
|
+
async function getOndoTradingStatus(api, params) {
|
|
1932
|
+
const dto = await api.send({
|
|
1933
|
+
method: "GET",
|
|
1934
|
+
url: "/v1/ondo/swap/trading-status",
|
|
1935
|
+
queryParams: { symbol: params.symbol, side: params.side },
|
|
1936
|
+
attributes: Attributes.protected()
|
|
1937
|
+
});
|
|
1938
|
+
return OndoTradingStatus.fromDto(dto);
|
|
1939
|
+
}
|
|
1940
|
+
async function getOndoQuote(api, params) {
|
|
1941
|
+
const dto = await api.send({
|
|
1942
|
+
method: "GET",
|
|
1943
|
+
url: "/v1/ondo/swap/quote",
|
|
1944
|
+
queryParams: {
|
|
1945
|
+
symbol: params.symbol,
|
|
1946
|
+
side: params.side,
|
|
1947
|
+
duration: params.duration,
|
|
1948
|
+
...sizeParam(params)
|
|
1949
|
+
},
|
|
1950
|
+
attributes: Attributes.protected()
|
|
1951
|
+
});
|
|
1952
|
+
return OndoQuote.fromDto(dto);
|
|
1953
|
+
}
|
|
1954
|
+
async function buildOndoBuy(api, params) {
|
|
1955
|
+
const dto = await api.send({
|
|
1956
|
+
method: "POST",
|
|
1957
|
+
url: "/v1/ondo/swap/buy",
|
|
1958
|
+
body: swapBody(params),
|
|
1959
|
+
attributes: Attributes.protected()
|
|
1960
|
+
});
|
|
1961
|
+
assertSpendScaleAgrees({
|
|
1962
|
+
published: dto.spend_input_decimals,
|
|
1963
|
+
sized: params.amount,
|
|
1964
|
+
trade: "purchase"
|
|
1965
|
+
});
|
|
1966
|
+
return OndoBuyTransaction.fromDto(dto);
|
|
1967
|
+
}
|
|
1968
|
+
async function buildOndoSell(api, params) {
|
|
1969
|
+
const dto = await api.send({
|
|
1970
|
+
method: "POST",
|
|
1971
|
+
url: "/v1/ondo/swap/sell",
|
|
1972
|
+
body: swapBody(params),
|
|
1973
|
+
attributes: Attributes.protected()
|
|
1974
|
+
});
|
|
1975
|
+
assertSpendScaleAgrees({
|
|
1976
|
+
published: dto.spend_input_decimals,
|
|
1977
|
+
sized: params.amount,
|
|
1978
|
+
trade: "sale",
|
|
1979
|
+
// The two answers come from two chains, so on a testnet they can disagree
|
|
1980
|
+
// for a reason that is neither the caller's nor a corrupt response. Say so,
|
|
1981
|
+
// or a QA run reads as a puzzle rather than a diagnosis.
|
|
1982
|
+
note: "the quote resolves the asset on Ethereum mainnet while the swap executes on the chain requested, so these disagree until frontline serves a chain-scoped quote"
|
|
1983
|
+
});
|
|
1984
|
+
return OndoSellTransaction.fromDto(dto);
|
|
1985
|
+
}
|
|
1986
|
+
function swapBody(params) {
|
|
1987
|
+
return {
|
|
1988
|
+
symbol: params.symbol,
|
|
1989
|
+
chain: params.chain,
|
|
1990
|
+
wallet_address: params.walletAddress,
|
|
1991
|
+
amount: params.amount.raw.toString()
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
function assertSpendScaleAgrees({
|
|
1995
|
+
published,
|
|
1996
|
+
sized,
|
|
1997
|
+
trade,
|
|
1998
|
+
note
|
|
1999
|
+
}) {
|
|
2000
|
+
if (published === sized.decimals) return;
|
|
2001
|
+
const because = note === void 0 ? "" : ` - ${note}`;
|
|
2002
|
+
throw new ValidationError(
|
|
2003
|
+
`spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
function sizeParam(params) {
|
|
2007
|
+
const tokenAmount = "tokenAmount" in params ? params.tokenAmount : void 0;
|
|
2008
|
+
const notionalValue = "notionalValue" in params ? params.notionalValue : void 0;
|
|
2009
|
+
if (tokenAmount !== void 0) {
|
|
2010
|
+
if (notionalValue !== void 0) {
|
|
2011
|
+
throw new ValidationError(
|
|
2012
|
+
"An Ondo quote takes tokenAmount or notionalValue, not both"
|
|
2013
|
+
);
|
|
1214
2014
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
2015
|
+
return { token_amount: formatRawAmount(tokenAmount) };
|
|
2016
|
+
}
|
|
2017
|
+
if (notionalValue === void 0) {
|
|
2018
|
+
throw new ValidationError(
|
|
2019
|
+
"An Ondo quote must be sized by tokenAmount or notionalValue"
|
|
2020
|
+
);
|
|
2021
|
+
}
|
|
2022
|
+
return { notional_value: notionalValue };
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
// src/shared/core/checkout/ondo/ondo-namespace.ts
|
|
2026
|
+
var OndoNamespaceImpl = class {
|
|
2027
|
+
constructor(ctx) {
|
|
2028
|
+
this.ctx = ctx;
|
|
2029
|
+
this.log = internalLogger(ctx.logger, "ONDO");
|
|
2030
|
+
}
|
|
2031
|
+
async getTradingStatus(params) {
|
|
2032
|
+
return this.log.wrap("getTradingStatus", params, async () => {
|
|
2033
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2034
|
+
return getOndoTradingStatus(this.ctx.api, params);
|
|
1226
2035
|
});
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
return
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
const sessionDto = await this.api.send({
|
|
1233
|
-
method: "POST",
|
|
1234
|
-
url: `/oauth/token`,
|
|
1235
|
-
body: {
|
|
1236
|
-
grant_type: "client_credentials",
|
|
1237
|
-
client_id: this._config.clientId,
|
|
1238
|
-
client_secret: this._config.clientSecret
|
|
1239
|
-
}
|
|
2036
|
+
}
|
|
2037
|
+
async getQuote(params) {
|
|
2038
|
+
return this.log.wrap("getQuote", params, async () => {
|
|
2039
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2040
|
+
return getOndoQuote(this.ctx.api, params);
|
|
1240
2041
|
});
|
|
1241
|
-
const session = OAuthSession.fromDto(sessionDto);
|
|
1242
|
-
return ClientCredentialsOAuth(session.accessToken);
|
|
1243
2042
|
}
|
|
1244
|
-
async
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
const expiresAt = session.accessToken.expiresAt.getTime();
|
|
1250
|
-
const bufferMs = this.accessTokenExpiryBufferSeconds * 1e3;
|
|
1251
|
-
if (expiresAt > now + bufferMs) {
|
|
1252
|
-
return session.accessToken;
|
|
1253
|
-
}
|
|
1254
|
-
const setSession = sessionStore.setSession?.bind(sessionStore);
|
|
1255
|
-
if (!setSession) {
|
|
1256
|
-
return session.accessToken;
|
|
1257
|
-
} else {
|
|
1258
|
-
return this.refreshSession(session.refreshToken, setSession);
|
|
1259
|
-
}
|
|
2043
|
+
async buildBuyTransaction(params) {
|
|
2044
|
+
return this.log.wrap("buildBuyTransaction", params, async () => {
|
|
2045
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2046
|
+
return buildOndoBuy(this.ctx.api, params);
|
|
2047
|
+
});
|
|
1260
2048
|
}
|
|
1261
|
-
async
|
|
1262
|
-
|
|
1263
|
-
await
|
|
1264
|
-
return
|
|
1265
|
-
}
|
|
1266
|
-
try {
|
|
1267
|
-
const sessionDto = await this.api.send({
|
|
1268
|
-
method: "POST",
|
|
1269
|
-
url: `/oauth/token`,
|
|
1270
|
-
body: {
|
|
1271
|
-
grant_type: "refresh_token",
|
|
1272
|
-
refresh_token: refreshToken,
|
|
1273
|
-
client_id: this._config.clientId,
|
|
1274
|
-
client_secret: this._config.clientSecret
|
|
1275
|
-
}
|
|
1276
|
-
});
|
|
1277
|
-
const newSession = OAuthSession.fromDto(sessionDto);
|
|
1278
|
-
await setSession(newSession);
|
|
1279
|
-
return newSession.accessToken;
|
|
1280
|
-
} catch {
|
|
1281
|
-
await setSession(null);
|
|
1282
|
-
return null;
|
|
1283
|
-
}
|
|
2049
|
+
async buildSellTransaction(params) {
|
|
2050
|
+
return this.log.wrap("buildSellTransaction", params, async () => {
|
|
2051
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2052
|
+
return buildOndoSell(this.ctx.api, params);
|
|
2053
|
+
});
|
|
1284
2054
|
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
2055
|
+
};
|
|
2056
|
+
|
|
2057
|
+
// src/shared/core/checkout/superstate/swap-namespace.ts
|
|
2058
|
+
var SuperstateSwapNamespaceImpl = class {
|
|
2059
|
+
constructor(ctx) {
|
|
2060
|
+
this.ctx = ctx;
|
|
2061
|
+
this.log = internalLogger(ctx.logger, "SUPERSTATE");
|
|
2062
|
+
}
|
|
2063
|
+
async getAuthorization(params) {
|
|
2064
|
+
return this.log.wrap("getAuthorization", params, async () => {
|
|
2065
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2066
|
+
return getSwapAuthorization(this.ctx.api, params);
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
async getPreview(params) {
|
|
2070
|
+
return this.log.wrap("getPreview", params, async () => {
|
|
2071
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2072
|
+
return getSwapPreview(this.ctx.api, params);
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
async getStatus(params) {
|
|
2076
|
+
return this.log.wrap("getStatus", params, async () => {
|
|
2077
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2078
|
+
return getSwapStatus(this.ctx.api, params);
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
async getOutputToken(params) {
|
|
2082
|
+
return this.log.wrap("getOutputToken", params, async () => {
|
|
2083
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2084
|
+
return getSwapOutputToken(this.ctx.api, params);
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
async allowWallet(params) {
|
|
2088
|
+
return this.log.wrap("allowWallet", params, async () => {
|
|
2089
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2090
|
+
return allowWallet(this.ctx.api, params);
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2093
|
+
};
|
|
2094
|
+
|
|
2095
|
+
// src/shared/api/nabu/tokens.ts
|
|
2096
|
+
var import_viem3 = require("viem");
|
|
2097
|
+
|
|
2098
|
+
// src/shared/types/token-metadata.ts
|
|
2099
|
+
var TokenLogoUrl = (value) => value;
|
|
2100
|
+
var TokenLogo = {
|
|
2101
|
+
/** `baseUrl` is the registry origin; registry URLs are root-relative. */
|
|
2102
|
+
fromDto: (dto, baseUrl) => dto.kind === "VECTOR" ? { kind: "VECTOR", url: resolveLogoUrl(dto.url, baseUrl) } : {
|
|
2103
|
+
kind: "RASTER",
|
|
2104
|
+
original: logoImageFromDto(dto.original, baseUrl),
|
|
2105
|
+
variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl))
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
var TokenMetadata = {
|
|
2109
|
+
/** `baseUrl` is the registry origin; registry logo URLs are root-relative. */
|
|
2110
|
+
fromDto: (dto, baseUrl) => {
|
|
2111
|
+
assertSupportedSchemaVersion(dto.schema_version);
|
|
2112
|
+
return {
|
|
2113
|
+
identifier: {
|
|
2114
|
+
chain: EthereumChain(dto.chain),
|
|
2115
|
+
address: EvmContractAddress(dto.address)
|
|
2116
|
+
},
|
|
2117
|
+
name: dto.name,
|
|
2118
|
+
symbol: AssetSymbol(dto.symbol),
|
|
2119
|
+
decimals: AssetDecimals(dto.decimals),
|
|
2120
|
+
logo: TokenLogo.fromDto(dto.logo, baseUrl),
|
|
2121
|
+
logoDark: dto.logo_dark === void 0 ? null : TokenLogo.fromDto(dto.logo_dark, baseUrl)
|
|
2122
|
+
};
|
|
2123
|
+
},
|
|
2124
|
+
/**
|
|
2125
|
+
* Maps the complete registry snapshot to every token it lists across the
|
|
2126
|
+
* chains this SDK models, skipping native coins and chains outside
|
|
2127
|
+
* {@link EthereumChain} (e.g. Solana) rather than failing on them — the
|
|
2128
|
+
* registry may serve chains ahead of the SDK's type surface.
|
|
2129
|
+
*/
|
|
2130
|
+
fromRegistryDto: (dto, baseUrl) => {
|
|
2131
|
+
assertSupportedSchemaVersion(dto.schema_version);
|
|
2132
|
+
return dto.chains.flatMap((chainDto) => {
|
|
2133
|
+
let chain;
|
|
1294
2134
|
try {
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
body: {
|
|
1299
|
-
token: tokenToRevoke,
|
|
1300
|
-
client_id: this._config.clientId,
|
|
1301
|
-
client_secret: this._config.clientSecret
|
|
1302
|
-
}
|
|
1303
|
-
});
|
|
1304
|
-
} catch (err) {
|
|
1305
|
-
if (err instanceof HttpError) {
|
|
1306
|
-
if (this.strict) {
|
|
1307
|
-
throw err;
|
|
1308
|
-
}
|
|
1309
|
-
} else {
|
|
1310
|
-
throw err;
|
|
1311
|
-
}
|
|
2135
|
+
chain = EthereumChain(chainDto.chain);
|
|
2136
|
+
} catch {
|
|
2137
|
+
return [];
|
|
1312
2138
|
}
|
|
1313
|
-
|
|
2139
|
+
return tokensOfChain(chain, chainDto.assets, baseUrl);
|
|
2140
|
+
});
|
|
2141
|
+
},
|
|
2142
|
+
/**
|
|
2143
|
+
* Maps a chain snapshot to the tokens it lists, skipping the chain's native
|
|
2144
|
+
* coin (`kind: 'COIN'`, no contract address).
|
|
2145
|
+
*/
|
|
2146
|
+
fromChainAssetsDto: (dto, baseUrl) => {
|
|
2147
|
+
assertSupportedSchemaVersion(dto.schema_version);
|
|
2148
|
+
return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
function tokensOfChain(chain, assets, baseUrl) {
|
|
2152
|
+
return assets.filter((asset) => asset.kind === "TOKEN" && asset.address !== void 0).map((asset) => ({
|
|
2153
|
+
identifier: {
|
|
2154
|
+
chain,
|
|
2155
|
+
// The filter above cannot narrow `address` for the type checker.
|
|
2156
|
+
address: EvmContractAddress(asset.address)
|
|
2157
|
+
},
|
|
2158
|
+
name: asset.name,
|
|
2159
|
+
symbol: AssetSymbol(asset.symbol),
|
|
2160
|
+
decimals: AssetDecimals(asset.decimals),
|
|
2161
|
+
logo: TokenLogo.fromDto(asset.logo, baseUrl),
|
|
2162
|
+
logoDark: asset.logo_dark === void 0 ? null : TokenLogo.fromDto(asset.logo_dark, baseUrl)
|
|
2163
|
+
}));
|
|
2164
|
+
}
|
|
2165
|
+
function assertSupportedSchemaVersion(version) {
|
|
2166
|
+
if (version !== 1) {
|
|
2167
|
+
throw new ValidationError(
|
|
2168
|
+
`Unsupported token registry schema_version: ${version}`
|
|
2169
|
+
);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
var logoImageFromDto = (dto, baseUrl) => ({
|
|
2173
|
+
url: resolveLogoUrl(dto.url, baseUrl),
|
|
2174
|
+
width: dto.width,
|
|
2175
|
+
height: dto.height
|
|
2176
|
+
});
|
|
2177
|
+
var resolveLogoUrl = (url, baseUrl) => TokenLogoUrl(
|
|
2178
|
+
url.startsWith("http") ? url : `${baseUrl.replace(/\/$/, "")}${url}`
|
|
2179
|
+
);
|
|
2180
|
+
|
|
2181
|
+
// src/shared/api/nabu/tokens.ts
|
|
2182
|
+
function createNabuApiClient(baseUrl, logger = null) {
|
|
2183
|
+
return new HttpClient({ baseUrl }, {}, logger);
|
|
2184
|
+
}
|
|
2185
|
+
async function fetchTokenMetadata(client, token) {
|
|
2186
|
+
const address = checksummed(token.address);
|
|
2187
|
+
let response;
|
|
2188
|
+
try {
|
|
2189
|
+
response = await client.send({
|
|
2190
|
+
method: "GET",
|
|
2191
|
+
url: `/${token.chain}/token/${address}`
|
|
2192
|
+
});
|
|
2193
|
+
} catch (error) {
|
|
2194
|
+
if (isRegistryHtmlFallback(error)) {
|
|
2195
|
+
return null;
|
|
1314
2196
|
}
|
|
2197
|
+
throw error;
|
|
1315
2198
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
return fetchOffers(this.api, clientCreds);
|
|
2199
|
+
if (response.status === 404) {
|
|
2200
|
+
return null;
|
|
1319
2201
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
2202
|
+
assertOk(response);
|
|
2203
|
+
if (response.body === null) {
|
|
2204
|
+
throw new ValidationError(
|
|
2205
|
+
`Token registry returned an empty body for token "${address}" on "${token.chain}"`
|
|
2206
|
+
);
|
|
1323
2207
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
2208
|
+
return TokenMetadata.fromDto(response.body, client.config.baseUrl);
|
|
2209
|
+
}
|
|
2210
|
+
async function fetchTokensMetadata(client, chain) {
|
|
2211
|
+
let response;
|
|
2212
|
+
try {
|
|
2213
|
+
response = await client.send({
|
|
2214
|
+
method: "GET",
|
|
2215
|
+
url: `/${chain}/assets.json`
|
|
2216
|
+
});
|
|
2217
|
+
} catch (error) {
|
|
2218
|
+
if (isRegistryHtmlFallback(error)) {
|
|
2219
|
+
throw new ValidationError(
|
|
2220
|
+
`Token registry returned non-JSON for the "${chain}" snapshot`
|
|
2221
|
+
);
|
|
2222
|
+
}
|
|
2223
|
+
throw error;
|
|
1327
2224
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
2225
|
+
assertOk(response);
|
|
2226
|
+
if (response.body === null) {
|
|
2227
|
+
throw new ValidationError(
|
|
2228
|
+
`Token registry returned an empty "${chain}" snapshot`
|
|
2229
|
+
);
|
|
1331
2230
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
2231
|
+
return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);
|
|
2232
|
+
}
|
|
2233
|
+
async function fetchAllTokensMetadata(client) {
|
|
2234
|
+
let response;
|
|
2235
|
+
try {
|
|
2236
|
+
response = await client.send({
|
|
2237
|
+
method: "GET",
|
|
2238
|
+
url: `/assets.json`
|
|
2239
|
+
});
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
if (isRegistryHtmlFallback(error)) {
|
|
2242
|
+
throw new ValidationError(
|
|
2243
|
+
"Token registry returned non-JSON for the complete snapshot"
|
|
2244
|
+
);
|
|
2245
|
+
}
|
|
2246
|
+
throw error;
|
|
1335
2247
|
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
offerId,
|
|
1341
|
-
offerOptionId
|
|
2248
|
+
assertOk(response);
|
|
2249
|
+
if (response.body === null) {
|
|
2250
|
+
throw new ValidationError(
|
|
2251
|
+
"Token registry returned an empty complete snapshot"
|
|
1342
2252
|
);
|
|
1343
2253
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
2254
|
+
return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);
|
|
2255
|
+
}
|
|
2256
|
+
function isRegistryHtmlFallback(error) {
|
|
2257
|
+
return error instanceof HttpError && error.response.status >= 200 && error.response.status < 300;
|
|
2258
|
+
}
|
|
2259
|
+
function assertOk(response) {
|
|
2260
|
+
if (response.status < 200 || response.status >= 300) {
|
|
2261
|
+
throw new HttpError(response);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
function checksummed(address) {
|
|
2265
|
+
try {
|
|
2266
|
+
return (0, import_viem3.getAddress)(address);
|
|
2267
|
+
} catch (_) {
|
|
2268
|
+
throw new ValidationError(`Invalid EVM contract address: "${address}"`);
|
|
1347
2269
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
// src/shared/core/tokens/tokens-namespace.ts
|
|
2273
|
+
var TokensNamespaceImpl = class {
|
|
2274
|
+
/**
|
|
2275
|
+
* Takes the registry origin rather than a `SharedNamespaceContext`: the
|
|
2276
|
+
* registry is unauthenticated and on its own host, so the frontline sender
|
|
2277
|
+
* and the auth check would both be dead weight here.
|
|
2278
|
+
*/
|
|
2279
|
+
constructor(baseUrl, logger = null) {
|
|
2280
|
+
this.api = createNabuApiClient(baseUrl, logger);
|
|
2281
|
+
this.log = internalLogger(logger, "TOKENS");
|
|
2282
|
+
}
|
|
2283
|
+
get(token) {
|
|
2284
|
+
return this.log.wrap(
|
|
2285
|
+
"get",
|
|
2286
|
+
token,
|
|
2287
|
+
() => fetchTokenMetadata(this.api, token)
|
|
1354
2288
|
);
|
|
1355
2289
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
2290
|
+
list(chain) {
|
|
2291
|
+
return this.log.wrap(
|
|
2292
|
+
"list",
|
|
2293
|
+
chain,
|
|
2294
|
+
() => chain === void 0 ? fetchAllTokensMetadata(this.api) : fetchTokensMetadata(this.api, chain)
|
|
2295
|
+
);
|
|
1359
2296
|
}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
2297
|
+
};
|
|
2298
|
+
|
|
2299
|
+
// src/shared/types/offer-option-address.ts
|
|
2300
|
+
var OfferOptionAddressId = (value) => value;
|
|
2301
|
+
var OfferOptionAddress = {
|
|
2302
|
+
/** Maps the API DTO into the SDK offer-option-address domain model. */
|
|
2303
|
+
fromDto: (dto) => ({
|
|
2304
|
+
id: OfferOptionAddressId(dto.id),
|
|
2305
|
+
offerOptionId: OfferOptionId(dto.offer_option_id),
|
|
2306
|
+
address: EvmWalletAddress(dto.address),
|
|
2307
|
+
protocol: dto.protocol,
|
|
2308
|
+
createdAt: new Date(dto.created_at)
|
|
2309
|
+
})
|
|
2310
|
+
};
|
|
2311
|
+
var ConnectExternalWalletParams = {
|
|
2312
|
+
/** Maps connect-wallet params into the API DTO payload. */
|
|
2313
|
+
toDto: (params) => ({
|
|
2314
|
+
offer_option_id: params.offerOptionId,
|
|
2315
|
+
wallet_address: params.walletAddress,
|
|
2316
|
+
chain: params.chain,
|
|
2317
|
+
signature: params.signature
|
|
2318
|
+
})
|
|
2319
|
+
};
|
|
2320
|
+
|
|
2321
|
+
// src/shared/types/wallet-ownership-challenge.ts
|
|
2322
|
+
var WalletOwnershipChallenge = {
|
|
2323
|
+
/** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
|
|
2324
|
+
fromDto: (dto) => ({
|
|
2325
|
+
message: dto.message,
|
|
2326
|
+
expiresAt: new Date(dto.expires_at)
|
|
2327
|
+
})
|
|
2328
|
+
};
|
|
2329
|
+
var CreateWalletOwnershipChallengeParams = {
|
|
2330
|
+
/**
|
|
2331
|
+
* Maps challenge-request params into the API DTO payload. The discriminated
|
|
2332
|
+
* union guarantees SIWE fields are present exactly when `challengeType` is
|
|
2333
|
+
* `siwe`, so the mapping narrows on the discriminant.
|
|
2334
|
+
*/
|
|
2335
|
+
toDto: (params) => {
|
|
2336
|
+
switch (params.challengeType) {
|
|
2337
|
+
case "plain":
|
|
2338
|
+
return {
|
|
2339
|
+
wallet_address: params.walletAddress,
|
|
2340
|
+
chain: params.chain,
|
|
2341
|
+
challenge_type: "plain"
|
|
2342
|
+
};
|
|
2343
|
+
case "siwe":
|
|
2344
|
+
return {
|
|
2345
|
+
wallet_address: params.walletAddress,
|
|
2346
|
+
chain: params.chain,
|
|
2347
|
+
challenge_type: "siwe",
|
|
2348
|
+
domain: params.domain,
|
|
2349
|
+
uri: params.uri,
|
|
2350
|
+
statement: params.statement
|
|
2351
|
+
};
|
|
2352
|
+
default: {
|
|
2353
|
+
const _exhaustive = params;
|
|
2354
|
+
return _exhaustive;
|
|
2355
|
+
}
|
|
1363
2356
|
}
|
|
1364
2357
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
2358
|
+
};
|
|
2359
|
+
|
|
2360
|
+
// src/shared/api/frontline/wallet-connect.ts
|
|
2361
|
+
async function createWalletOwnershipChallenge(api, params) {
|
|
2362
|
+
const dto = await api.send({
|
|
2363
|
+
method: "POST",
|
|
2364
|
+
url: "/v1/wallet-ownership",
|
|
2365
|
+
body: CreateWalletOwnershipChallengeParams.toDto(params),
|
|
2366
|
+
attributes: Attributes.protected()
|
|
2367
|
+
});
|
|
2368
|
+
return WalletOwnershipChallenge.fromDto(dto);
|
|
2369
|
+
}
|
|
2370
|
+
async function connectExternalWallet(api, params) {
|
|
2371
|
+
const dto = await api.send({
|
|
2372
|
+
method: "POST",
|
|
2373
|
+
url: `/v1/offers/${params.offerId}/addresses`,
|
|
2374
|
+
body: ConnectExternalWalletParams.toDto(params),
|
|
2375
|
+
attributes: Attributes.protected()
|
|
2376
|
+
});
|
|
2377
|
+
return OfferOptionAddress.fromDto(dto);
|
|
2378
|
+
}
|
|
2379
|
+
async function listOptionAddresses(api, offerId, offerOptionId) {
|
|
2380
|
+
const { data } = await api.send({
|
|
2381
|
+
method: "GET",
|
|
2382
|
+
url: `/v1/offers/${offerId}/addresses`,
|
|
2383
|
+
queryParams: { offer_option_id: offerOptionId },
|
|
2384
|
+
attributes: Attributes.protected()
|
|
2385
|
+
});
|
|
2386
|
+
return data.map(OfferOptionAddress.fromDto);
|
|
2387
|
+
}
|
|
2388
|
+
async function removeOptionAddress(api, offerId, addressId) {
|
|
2389
|
+
const dto = await api.send({
|
|
2390
|
+
method: "DELETE",
|
|
2391
|
+
url: `/v1/offers/${offerId}/addresses/${addressId}`,
|
|
2392
|
+
attributes: Attributes.protected()
|
|
2393
|
+
});
|
|
2394
|
+
return OfferOptionAddress.fromDto(dto);
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
// src/shared/core/wallets/wallets-namespace.ts
|
|
2398
|
+
var WalletsNamespaceImpl = class {
|
|
2399
|
+
constructor(ctx) {
|
|
2400
|
+
this.ctx = ctx;
|
|
2401
|
+
this.log = internalLogger(ctx.logger, "WALLETS");
|
|
2402
|
+
}
|
|
2403
|
+
async createOwnershipChallenge(params) {
|
|
2404
|
+
return this.log.wrap("createOwnershipChallenge", params, async () => {
|
|
2405
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2406
|
+
return createWalletOwnershipChallenge(
|
|
2407
|
+
this.ctx.api,
|
|
2408
|
+
params
|
|
2409
|
+
);
|
|
2410
|
+
});
|
|
1370
2411
|
}
|
|
1371
|
-
async
|
|
1372
|
-
|
|
1373
|
-
|
|
2412
|
+
async connectExternal(params) {
|
|
2413
|
+
return this.log.wrap("connectExternal", params, async () => {
|
|
2414
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2415
|
+
return connectExternalWallet(this.ctx.api, params);
|
|
2416
|
+
});
|
|
2417
|
+
}
|
|
2418
|
+
async list(params) {
|
|
2419
|
+
return this.log.wrap("list", params, async () => {
|
|
2420
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2421
|
+
return listOptionAddresses(
|
|
2422
|
+
this.ctx.api,
|
|
2423
|
+
params.offerId,
|
|
2424
|
+
params.offerOptionId
|
|
2425
|
+
);
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
async remove(params) {
|
|
2429
|
+
return this.log.wrap("remove", params, async () => {
|
|
2430
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2431
|
+
return removeOptionAddress(
|
|
2432
|
+
this.ctx.api,
|
|
2433
|
+
params.offerId,
|
|
2434
|
+
params.addressId
|
|
2435
|
+
);
|
|
2436
|
+
});
|
|
1374
2437
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
2438
|
+
};
|
|
2439
|
+
|
|
2440
|
+
// src/server/core/coinlist-server.ts
|
|
2441
|
+
var ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
2442
|
+
var CoinListServerImpl = class {
|
|
2443
|
+
constructor(_config) {
|
|
2444
|
+
this._config = _config;
|
|
2445
|
+
const logger = _config.logger ?? null;
|
|
2446
|
+
this.api = new ApiClient(
|
|
2447
|
+
{
|
|
2448
|
+
baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,
|
|
2449
|
+
xApiVersion: API_VERSION
|
|
2450
|
+
},
|
|
2451
|
+
// When refresh=true the renewal middleware has received a 401 and wants a
|
|
2452
|
+
// fresh token. A read-only store cannot persist a new session, so return
|
|
2453
|
+
// null immediately — this tells the middleware to skip the retry rather
|
|
2454
|
+
// than re-sending with the same expired token and wasting a round-trip.
|
|
2455
|
+
(refresh) => refresh && !this._config.sessionStore.setSession ? Promise.resolve(null) : this.auth.getAccessToken(),
|
|
2456
|
+
logger
|
|
2457
|
+
);
|
|
2458
|
+
this.auth = new ServerAuthNamespaceImpl(this.api, {
|
|
2459
|
+
..._config,
|
|
2460
|
+
accessTokenExpiryBufferSeconds: _config.accessTokenExpiryBufferSeconds ?? ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS,
|
|
2461
|
+
strict: _config.strict ?? false
|
|
2462
|
+
});
|
|
2463
|
+
const ctx = {
|
|
2464
|
+
api: this.api,
|
|
2465
|
+
logger,
|
|
2466
|
+
ensureUserAuthenticated: () => this.ensureAuthenticated(void 0),
|
|
2467
|
+
ensureAuthenticated: (clientCreds) => this.ensureAuthenticated(clientCreds)
|
|
2468
|
+
};
|
|
2469
|
+
this.offers = new ServerOffersNamespaceImpl(ctx);
|
|
2470
|
+
this.requirements = new ServerRequirementsNamespaceImpl(ctx);
|
|
2471
|
+
this.wallets = new WalletsNamespaceImpl(ctx);
|
|
2472
|
+
this.erc20 = new Erc20NamespaceImpl(ctx);
|
|
2473
|
+
this.tokenSale = new CoinListTokenSaleNamespaceImpl(ctx);
|
|
2474
|
+
this.superstate = new SuperstateSwapNamespaceImpl(ctx);
|
|
2475
|
+
this.ondo = new OndoNamespaceImpl(ctx);
|
|
2476
|
+
this.tokens = new TokensNamespaceImpl(
|
|
2477
|
+
_config.tokensBaseUrl ?? NABU_BASE_URL,
|
|
2478
|
+
logger
|
|
2479
|
+
);
|
|
1378
2480
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
2481
|
+
/**
|
|
2482
|
+
* An app-level token authenticates a request on its own; without one the
|
|
2483
|
+
* caller needs a user session.
|
|
2484
|
+
*/
|
|
2485
|
+
async ensureAuthenticated(clientCreds) {
|
|
2486
|
+
if (clientCreds) return;
|
|
2487
|
+
const token = await this.auth.getAccessToken();
|
|
2488
|
+
if (token === null) {
|
|
2489
|
+
throw new NotAuthenticatedError();
|
|
2490
|
+
}
|
|
1382
2491
|
}
|
|
1383
2492
|
};
|
|
1384
2493
|
function createCoinListServer(config) {
|
|
1385
2494
|
return new CoinListServerImpl(config);
|
|
1386
2495
|
}
|
|
2496
|
+
|
|
2497
|
+
// src/server/core/observability/pino-server-logger.ts
|
|
2498
|
+
var import_pino = require("pino");
|
|
2499
|
+
|
|
2500
|
+
// src/shared/core/observability/pino-logger.ts
|
|
2501
|
+
function toPinoRecord(event) {
|
|
2502
|
+
try {
|
|
2503
|
+
const record = {};
|
|
2504
|
+
for (const key of ownKeys(event.fields)) {
|
|
2505
|
+
record[key] = readProperty(event.fields, key, 0, /* @__PURE__ */ new WeakSet());
|
|
2506
|
+
}
|
|
2507
|
+
const cause = "cause" in event ? event.cause : void 0;
|
|
2508
|
+
if (cause !== void 0) {
|
|
2509
|
+
record.cause = sanitize(cause, 0, /* @__PURE__ */ new WeakSet());
|
|
2510
|
+
}
|
|
2511
|
+
return { ...record, scope: event.scope, ...event.bindings };
|
|
2512
|
+
} catch (_) {
|
|
2513
|
+
return { "log.render": "<unrenderable event>" };
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
var PINO_LEVEL = {
|
|
2517
|
+
none: "silent",
|
|
2518
|
+
error: "error",
|
|
2519
|
+
warn: "warn",
|
|
2520
|
+
info: "info",
|
|
2521
|
+
debug: "debug"
|
|
2522
|
+
};
|
|
2523
|
+
var MAX_DEPTH = 8;
|
|
2524
|
+
function sanitize(value, depth, seen) {
|
|
2525
|
+
switch (typeof value) {
|
|
2526
|
+
case "string":
|
|
2527
|
+
case "boolean":
|
|
2528
|
+
return value;
|
|
2529
|
+
case "number":
|
|
2530
|
+
return Number.isFinite(value) ? value : String(value);
|
|
2531
|
+
case "bigint":
|
|
2532
|
+
return value.toString();
|
|
2533
|
+
case "undefined":
|
|
2534
|
+
return "<undefined>";
|
|
2535
|
+
case "function":
|
|
2536
|
+
return "<function>";
|
|
2537
|
+
case "symbol":
|
|
2538
|
+
return value.toString();
|
|
2539
|
+
case "object":
|
|
2540
|
+
return value === null ? null : sanitizeObject(value, depth, seen);
|
|
2541
|
+
default:
|
|
2542
|
+
return "<unrenderable>";
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
function sanitizeObject(value, depth, seen) {
|
|
2546
|
+
if (seen.has(value)) return "<circular>";
|
|
2547
|
+
if (depth >= MAX_DEPTH) return "<max depth>";
|
|
2548
|
+
if (value instanceof Error) return describeError(value);
|
|
2549
|
+
if (value instanceof Date) return describeDate(value);
|
|
2550
|
+
seen.add(value);
|
|
2551
|
+
try {
|
|
2552
|
+
if (Array.isArray(value)) {
|
|
2553
|
+
return value.map(
|
|
2554
|
+
(_item, index) => readProperty(value, String(index), depth, seen)
|
|
2555
|
+
);
|
|
2556
|
+
}
|
|
2557
|
+
const out = {};
|
|
2558
|
+
for (const key of ownKeys(value)) {
|
|
2559
|
+
out[key] = readProperty(value, key, depth, seen);
|
|
2560
|
+
}
|
|
2561
|
+
return out;
|
|
2562
|
+
} finally {
|
|
2563
|
+
seen.delete(value);
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
function readProperty(owner, key, depth, seen) {
|
|
2567
|
+
try {
|
|
2568
|
+
return sanitize(owner[key], depth + 1, seen);
|
|
2569
|
+
} catch (_) {
|
|
2570
|
+
return "<unreadable>";
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
function ownKeys(value) {
|
|
2574
|
+
try {
|
|
2575
|
+
return Object.keys(value);
|
|
2576
|
+
} catch (_) {
|
|
2577
|
+
return [];
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
function describeError(error) {
|
|
2581
|
+
return {
|
|
2582
|
+
name: safeRead(() => error.name),
|
|
2583
|
+
message: safeRead(() => error.message),
|
|
2584
|
+
stack: safeRead(() => error.stack)
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
function describeDate(date) {
|
|
2588
|
+
return safeRead(() => date.toISOString());
|
|
2589
|
+
}
|
|
2590
|
+
function safeRead(read) {
|
|
2591
|
+
try {
|
|
2592
|
+
const value = read();
|
|
2593
|
+
return typeof value === "string" ? value : "<unreadable>";
|
|
2594
|
+
} catch (_) {
|
|
2595
|
+
return "<unreadable>";
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
var SDK_LOGGER_NAME = "@coinlist-co/react";
|
|
2599
|
+
function loggerOverPino(sink, level) {
|
|
2600
|
+
return {
|
|
2601
|
+
level: () => level,
|
|
2602
|
+
debug: (event) => emit(sink, "debug", event),
|
|
2603
|
+
info: (event) => emit(sink, "info", event),
|
|
2604
|
+
warn: (event) => emit(sink, "warn", event),
|
|
2605
|
+
error: (event) => emit(sink, "error", event)
|
|
2606
|
+
};
|
|
2607
|
+
}
|
|
2608
|
+
function emit(sink, method, event) {
|
|
2609
|
+
try {
|
|
2610
|
+
const value = event();
|
|
2611
|
+
sink[method](toPinoRecord(value), value.msg);
|
|
2612
|
+
} catch (error) {
|
|
2613
|
+
reportRenderFailure(sink, error);
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
function reportRenderFailure(sink, error) {
|
|
2617
|
+
try {
|
|
2618
|
+
sink.error(
|
|
2619
|
+
{ "error.type": error instanceof Error ? error.name : typeof error },
|
|
2620
|
+
"log event failed to render"
|
|
2621
|
+
);
|
|
2622
|
+
} catch (_) {
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
// src/server/core/observability/pino-server-logger.ts
|
|
2627
|
+
function pinoServerLogger(options) {
|
|
2628
|
+
return loggerOverPino(
|
|
2629
|
+
// `name` as a child binding rather than pino's `name` option: the option
|
|
2630
|
+
// is honoured by pino's node build and silently dropped by its browser
|
|
2631
|
+
// build, so a binding is the only spelling that identifies the SDK in
|
|
2632
|
+
// both environments.
|
|
2633
|
+
(0, import_pino.pino)({
|
|
2634
|
+
level: PINO_LEVEL[options.level]
|
|
2635
|
+
}).child({ name: SDK_LOGGER_NAME }),
|
|
2636
|
+
options.level
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
1387
2639
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1388
2640
|
0 && (module.exports = {
|
|
2641
|
+
ServerAuthNamespaceImpl,
|
|
2642
|
+
ServerOffersNamespaceImpl,
|
|
2643
|
+
ServerRequirementsNamespaceImpl,
|
|
1389
2644
|
WritableSessionStoreRequiredError,
|
|
1390
|
-
createCoinListServer
|
|
2645
|
+
createCoinListServer,
|
|
2646
|
+
emptySessionStore,
|
|
2647
|
+
pinoServerLogger
|
|
1391
2648
|
});
|
|
1392
2649
|
//# sourceMappingURL=index.cjs.map
|