@secondlayer/sdk 3.3.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -0
- package/dist/index.d.ts +270 -1
- package/dist/index.js +481 -1
- package/dist/index.js.map +11 -4
- package/dist/streams/index.d.ts +183 -0
- package/dist/streams/index.js +378 -0
- package/dist/streams/index.js.map +15 -0
- package/dist/subgraphs/index.d.ts +87 -0
- package/dist/subgraphs/index.js +108 -1
- package/dist/subgraphs/index.js.map +5 -4
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -276,6 +276,111 @@ class Subgraphs extends BaseClient {
|
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
|
+
// src/index-api/client.ts
|
|
280
|
+
function appendSearchParam(params, name, value) {
|
|
281
|
+
if (value === undefined || value === null)
|
|
282
|
+
return;
|
|
283
|
+
params.set(name, String(value));
|
|
284
|
+
}
|
|
285
|
+
function firstWalkFromHeight(params) {
|
|
286
|
+
if (params.fromHeight !== undefined)
|
|
287
|
+
return params.fromHeight;
|
|
288
|
+
if (params.cursor || params.fromCursor)
|
|
289
|
+
return;
|
|
290
|
+
return 0;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
class Index extends BaseClient {
|
|
294
|
+
constructor(options = {}) {
|
|
295
|
+
super(options);
|
|
296
|
+
}
|
|
297
|
+
ftTransfers = {
|
|
298
|
+
list: (params = {}) => this.listFtTransfers(params),
|
|
299
|
+
walk: (params = {}) => this.walkFtTransfers(params)
|
|
300
|
+
};
|
|
301
|
+
nftTransfers = {
|
|
302
|
+
list: (params = {}) => this.listNftTransfers(params),
|
|
303
|
+
walk: (params = {}) => this.walkNftTransfers(params)
|
|
304
|
+
};
|
|
305
|
+
async listFtTransfers(params = {}) {
|
|
306
|
+
const searchParams = new URLSearchParams;
|
|
307
|
+
appendSearchParam(searchParams, "cursor", params.cursor);
|
|
308
|
+
appendSearchParam(searchParams, "from_cursor", params.fromCursor);
|
|
309
|
+
appendSearchParam(searchParams, "limit", params.limit);
|
|
310
|
+
appendSearchParam(searchParams, "contract_id", params.contractId);
|
|
311
|
+
appendSearchParam(searchParams, "sender", params.sender);
|
|
312
|
+
appendSearchParam(searchParams, "recipient", params.recipient);
|
|
313
|
+
appendSearchParam(searchParams, "from_height", params.fromHeight);
|
|
314
|
+
appendSearchParam(searchParams, "to_height", params.toHeight);
|
|
315
|
+
const query = searchParams.toString();
|
|
316
|
+
return this.request("GET", `/v1/index/ft-transfers${query ? `?${query}` : ""}`);
|
|
317
|
+
}
|
|
318
|
+
async listNftTransfers(params = {}) {
|
|
319
|
+
const searchParams = new URLSearchParams;
|
|
320
|
+
appendSearchParam(searchParams, "cursor", params.cursor);
|
|
321
|
+
appendSearchParam(searchParams, "from_cursor", params.fromCursor);
|
|
322
|
+
appendSearchParam(searchParams, "limit", params.limit);
|
|
323
|
+
appendSearchParam(searchParams, "contract_id", params.contractId);
|
|
324
|
+
appendSearchParam(searchParams, "asset_identifier", params.assetIdentifier);
|
|
325
|
+
appendSearchParam(searchParams, "sender", params.sender);
|
|
326
|
+
appendSearchParam(searchParams, "recipient", params.recipient);
|
|
327
|
+
appendSearchParam(searchParams, "from_height", params.fromHeight);
|
|
328
|
+
appendSearchParam(searchParams, "to_height", params.toHeight);
|
|
329
|
+
const query = searchParams.toString();
|
|
330
|
+
return this.request("GET", `/v1/index/nft-transfers${query ? `?${query}` : ""}`);
|
|
331
|
+
}
|
|
332
|
+
async* walkFtTransfers(params = {}) {
|
|
333
|
+
const batchSize = params.batchSize ?? 200;
|
|
334
|
+
let cursor = params.cursor ?? params.fromCursor ?? null;
|
|
335
|
+
let firstPage = true;
|
|
336
|
+
while (!params.signal?.aborted) {
|
|
337
|
+
const envelope = await this.listFtTransfers({
|
|
338
|
+
...params,
|
|
339
|
+
limit: batchSize,
|
|
340
|
+
cursor: firstPage ? params.cursor : cursor,
|
|
341
|
+
fromCursor: firstPage ? params.fromCursor : undefined,
|
|
342
|
+
fromHeight: firstPage ? firstWalkFromHeight(params) : undefined
|
|
343
|
+
});
|
|
344
|
+
for (const event of envelope.events) {
|
|
345
|
+
if (params.signal?.aborted)
|
|
346
|
+
return;
|
|
347
|
+
yield event;
|
|
348
|
+
}
|
|
349
|
+
const nextCursor = envelope.next_cursor;
|
|
350
|
+
if (!nextCursor || nextCursor === cursor || envelope.events.length < batchSize) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
cursor = nextCursor;
|
|
354
|
+
firstPage = false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async* walkNftTransfers(params = {}) {
|
|
358
|
+
const batchSize = params.batchSize ?? 200;
|
|
359
|
+
let cursor = params.cursor ?? params.fromCursor ?? null;
|
|
360
|
+
let firstPage = true;
|
|
361
|
+
while (!params.signal?.aborted) {
|
|
362
|
+
const envelope = await this.listNftTransfers({
|
|
363
|
+
...params,
|
|
364
|
+
limit: batchSize,
|
|
365
|
+
cursor: firstPage ? params.cursor : cursor,
|
|
366
|
+
fromCursor: firstPage ? params.fromCursor : undefined,
|
|
367
|
+
fromHeight: firstPage ? firstWalkFromHeight(params) : undefined
|
|
368
|
+
});
|
|
369
|
+
for (const event of envelope.events) {
|
|
370
|
+
if (params.signal?.aborted)
|
|
371
|
+
return;
|
|
372
|
+
yield event;
|
|
373
|
+
}
|
|
374
|
+
const nextCursor = envelope.next_cursor;
|
|
375
|
+
if (!nextCursor || nextCursor === cursor || envelope.events.length < batchSize) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
cursor = nextCursor;
|
|
379
|
+
firstPage = false;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
279
384
|
// src/subscriptions/client.ts
|
|
280
385
|
class Subscriptions extends BaseClient {
|
|
281
386
|
async list() {
|
|
@@ -318,10 +423,12 @@ class Subscriptions extends BaseClient {
|
|
|
318
423
|
|
|
319
424
|
// src/client.ts
|
|
320
425
|
class SecondLayer extends BaseClient {
|
|
426
|
+
index;
|
|
321
427
|
subgraphs;
|
|
322
428
|
subscriptions;
|
|
323
429
|
constructor(options = {}) {
|
|
324
430
|
super(options);
|
|
431
|
+
this.index = new Index(options);
|
|
325
432
|
this.subgraphs = new Subgraphs(options);
|
|
326
433
|
this.subscriptions = new Subscriptions(options);
|
|
327
434
|
}
|
|
@@ -337,6 +444,369 @@ function getSubgraph(def, options = {}) {
|
|
|
337
444
|
}
|
|
338
445
|
return new Subgraphs(options).typed(def);
|
|
339
446
|
}
|
|
447
|
+
// src/streams/consumer.ts
|
|
448
|
+
async function defaultSleep(ms, signal) {
|
|
449
|
+
if (signal?.aborted)
|
|
450
|
+
return;
|
|
451
|
+
await new Promise((resolve) => {
|
|
452
|
+
const timeout = setTimeout(resolve, ms);
|
|
453
|
+
if (!signal)
|
|
454
|
+
return;
|
|
455
|
+
signal.addEventListener("abort", () => {
|
|
456
|
+
clearTimeout(timeout);
|
|
457
|
+
resolve();
|
|
458
|
+
}, { once: true });
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
async function consumeStreamsEvents(opts) {
|
|
462
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
463
|
+
const mode = opts.mode ?? "tail";
|
|
464
|
+
const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
|
|
465
|
+
const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
|
|
466
|
+
const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
|
|
467
|
+
let cursor = opts.fromCursor ?? null;
|
|
468
|
+
let pages = 0;
|
|
469
|
+
let emptyPolls = 0;
|
|
470
|
+
while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
|
|
471
|
+
const envelope = await opts.fetchEvents({
|
|
472
|
+
cursor,
|
|
473
|
+
limit: opts.batchSize,
|
|
474
|
+
types: opts.types
|
|
475
|
+
});
|
|
476
|
+
pages++;
|
|
477
|
+
const returnedCursor = await opts.onBatch(envelope.events, envelope);
|
|
478
|
+
const nextCursor = returnedCursor ?? envelope.next_cursor;
|
|
479
|
+
if (nextCursor && nextCursor !== cursor) {
|
|
480
|
+
cursor = nextCursor;
|
|
481
|
+
emptyPolls = 0;
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (envelope.events.length === 0) {
|
|
485
|
+
emptyPolls++;
|
|
486
|
+
if (mode === "bounded") {
|
|
487
|
+
return { cursor, pages, emptyPolls };
|
|
488
|
+
}
|
|
489
|
+
await sleep(emptyBackoffMs, opts.signal);
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
return { cursor, pages, emptyPolls };
|
|
493
|
+
}
|
|
494
|
+
return { cursor, pages, emptyPolls };
|
|
495
|
+
}
|
|
496
|
+
async function* streamStreamsEvents(opts) {
|
|
497
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
498
|
+
const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
|
|
499
|
+
const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
|
|
500
|
+
const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
|
|
501
|
+
let cursor = opts.fromCursor ?? null;
|
|
502
|
+
let pages = 0;
|
|
503
|
+
let emptyPolls = 0;
|
|
504
|
+
while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
|
|
505
|
+
const envelope = await opts.fetchEvents({
|
|
506
|
+
cursor,
|
|
507
|
+
limit: opts.batchSize,
|
|
508
|
+
types: opts.types
|
|
509
|
+
});
|
|
510
|
+
pages++;
|
|
511
|
+
for (const event of envelope.events) {
|
|
512
|
+
if (opts.signal?.aborted)
|
|
513
|
+
return;
|
|
514
|
+
yield event;
|
|
515
|
+
}
|
|
516
|
+
const nextCursor = envelope.next_cursor;
|
|
517
|
+
if (nextCursor && nextCursor !== cursor) {
|
|
518
|
+
cursor = nextCursor;
|
|
519
|
+
emptyPolls = 0;
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
if (envelope.events.length === 0) {
|
|
523
|
+
emptyPolls++;
|
|
524
|
+
if (emptyPolls >= maxEmptyPolls || pages >= maxPages)
|
|
525
|
+
return;
|
|
526
|
+
await sleep(emptyBackoffMs, opts.signal);
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/streams/errors.ts
|
|
534
|
+
class AuthError extends Error {
|
|
535
|
+
status = 401;
|
|
536
|
+
constructor(message = "API key invalid or expired.") {
|
|
537
|
+
super(message);
|
|
538
|
+
this.name = "AuthError";
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
class RateLimitError extends Error {
|
|
543
|
+
retryAfter;
|
|
544
|
+
status = 429;
|
|
545
|
+
constructor(message = "Rate limited. Try again later.", retryAfter) {
|
|
546
|
+
super(message);
|
|
547
|
+
this.retryAfter = retryAfter;
|
|
548
|
+
this.name = "RateLimitError";
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
class ValidationError extends Error {
|
|
553
|
+
status;
|
|
554
|
+
body;
|
|
555
|
+
constructor(message, status, body) {
|
|
556
|
+
super(message);
|
|
557
|
+
this.status = status;
|
|
558
|
+
this.body = body;
|
|
559
|
+
this.name = "ValidationError";
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
class StreamsServerError extends Error {
|
|
564
|
+
status;
|
|
565
|
+
body;
|
|
566
|
+
constructor(message, status, body) {
|
|
567
|
+
super(message);
|
|
568
|
+
this.status = status;
|
|
569
|
+
this.body = body;
|
|
570
|
+
this.name = "StreamsServerError";
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// src/streams/client.ts
|
|
575
|
+
var DEFAULT_STREAMS_BASE_URL = "https://api.secondlayer.tools";
|
|
576
|
+
function normalizeBaseUrl(baseUrl) {
|
|
577
|
+
return baseUrl.replace(/\/+$/, "");
|
|
578
|
+
}
|
|
579
|
+
function appendSearchParam2(params, name, value) {
|
|
580
|
+
if (value === undefined || value === null)
|
|
581
|
+
return;
|
|
582
|
+
params.set(name, String(value));
|
|
583
|
+
}
|
|
584
|
+
async function responseBody(response) {
|
|
585
|
+
const text = await response.text();
|
|
586
|
+
if (text.length === 0)
|
|
587
|
+
return;
|
|
588
|
+
try {
|
|
589
|
+
return JSON.parse(text);
|
|
590
|
+
} catch {
|
|
591
|
+
return text;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
function errorMessage(body, fallback) {
|
|
595
|
+
if (body && typeof body === "object") {
|
|
596
|
+
const record = body;
|
|
597
|
+
const message = record.error ?? record.message;
|
|
598
|
+
if (typeof message === "string" && message.length > 0)
|
|
599
|
+
return message;
|
|
600
|
+
}
|
|
601
|
+
if (typeof body === "string" && body.length > 0)
|
|
602
|
+
return body;
|
|
603
|
+
return fallback;
|
|
604
|
+
}
|
|
605
|
+
async function mapStreamsError(response) {
|
|
606
|
+
const body = await responseBody(response);
|
|
607
|
+
if (response.status === 401) {
|
|
608
|
+
throw new AuthError(errorMessage(body, "API key invalid or expired."));
|
|
609
|
+
}
|
|
610
|
+
if (response.status === 429) {
|
|
611
|
+
const retryAfter = response.headers.get("Retry-After") ?? undefined;
|
|
612
|
+
throw new RateLimitError(errorMessage(body, "Rate limited. Try again later."), retryAfter);
|
|
613
|
+
}
|
|
614
|
+
if (response.status >= 500) {
|
|
615
|
+
throw new StreamsServerError(errorMessage(body, `Streams server returned ${response.status}.`), response.status, body);
|
|
616
|
+
}
|
|
617
|
+
throw new ValidationError(errorMessage(body, `Streams request returned ${response.status}.`), response.status, body);
|
|
618
|
+
}
|
|
619
|
+
function createStreamsClient(options) {
|
|
620
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_STREAMS_BASE_URL);
|
|
621
|
+
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
622
|
+
async function request(path) {
|
|
623
|
+
const response = await fetchImpl(`${baseUrl}${path}`, {
|
|
624
|
+
headers: { Authorization: `Bearer ${options.apiKey}` }
|
|
625
|
+
});
|
|
626
|
+
if (!response.ok)
|
|
627
|
+
await mapStreamsError(response);
|
|
628
|
+
return await response.json();
|
|
629
|
+
}
|
|
630
|
+
const fetchEvents = async ({
|
|
631
|
+
cursor,
|
|
632
|
+
limit,
|
|
633
|
+
types
|
|
634
|
+
}) => {
|
|
635
|
+
return listEvents({ cursor, limit, types });
|
|
636
|
+
};
|
|
637
|
+
async function listEvents(params = {}) {
|
|
638
|
+
const searchParams = new URLSearchParams;
|
|
639
|
+
appendSearchParam2(searchParams, "cursor", params.cursor);
|
|
640
|
+
appendSearchParam2(searchParams, "from_height", params.fromHeight);
|
|
641
|
+
appendSearchParam2(searchParams, "to_height", params.toHeight);
|
|
642
|
+
appendSearchParam2(searchParams, "limit", params.limit);
|
|
643
|
+
if (params.types?.length) {
|
|
644
|
+
searchParams.set("types", params.types.join(","));
|
|
645
|
+
}
|
|
646
|
+
const query = searchParams.toString();
|
|
647
|
+
return request(`/v1/streams/events${query ? `?${query}` : ""}`);
|
|
648
|
+
}
|
|
649
|
+
return {
|
|
650
|
+
events: {
|
|
651
|
+
list: listEvents,
|
|
652
|
+
consume(params) {
|
|
653
|
+
return consumeStreamsEvents({
|
|
654
|
+
fromCursor: params.fromCursor,
|
|
655
|
+
mode: params.mode,
|
|
656
|
+
types: params.types,
|
|
657
|
+
batchSize: params.batchSize ?? 100,
|
|
658
|
+
fetchEvents,
|
|
659
|
+
onBatch: params.onBatch,
|
|
660
|
+
emptyBackoffMs: params.emptyBackoffMs,
|
|
661
|
+
maxPages: params.maxPages,
|
|
662
|
+
maxEmptyPolls: params.maxEmptyPolls,
|
|
663
|
+
signal: params.signal
|
|
664
|
+
});
|
|
665
|
+
},
|
|
666
|
+
stream(params = {}) {
|
|
667
|
+
return streamStreamsEvents({
|
|
668
|
+
fromCursor: params.fromCursor,
|
|
669
|
+
types: params.types,
|
|
670
|
+
batchSize: params.batchSize ?? 100,
|
|
671
|
+
emptyBackoffMs: params.emptyBackoffMs,
|
|
672
|
+
maxPages: params.maxPages,
|
|
673
|
+
maxEmptyPolls: params.maxEmptyPolls,
|
|
674
|
+
signal: params.signal,
|
|
675
|
+
fetchEvents
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
tip() {
|
|
680
|
+
return request("/v1/streams/tip");
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
// src/streams/ft-transfer.ts
|
|
685
|
+
function requireString(payload, field) {
|
|
686
|
+
const value = payload[field];
|
|
687
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
688
|
+
throw new Error(`ft_transfer payload missing ${field}`);
|
|
689
|
+
}
|
|
690
|
+
return value;
|
|
691
|
+
}
|
|
692
|
+
function parseAssetIdentifier(assetIdentifier) {
|
|
693
|
+
const [contractId, tokenName] = assetIdentifier.split("::");
|
|
694
|
+
if (!contractId) {
|
|
695
|
+
throw new Error("ft_transfer payload has malformed asset_identifier");
|
|
696
|
+
}
|
|
697
|
+
return {
|
|
698
|
+
contract_id: contractId,
|
|
699
|
+
token_name: tokenName && tokenName.length > 0 ? tokenName : null
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
function isFtTransfer(event) {
|
|
703
|
+
return event.event_type === "ft_transfer";
|
|
704
|
+
}
|
|
705
|
+
function decodeFtTransfer(event) {
|
|
706
|
+
if (!isFtTransfer(event)) {
|
|
707
|
+
throw new Error(`Expected ft_transfer event, got ${event.event_type}`);
|
|
708
|
+
}
|
|
709
|
+
const payload = event.payload;
|
|
710
|
+
const assetIdentifier = requireString(payload, "asset_identifier");
|
|
711
|
+
const sender = requireString(payload, "sender");
|
|
712
|
+
const recipient = requireString(payload, "recipient");
|
|
713
|
+
const amount = requireString(payload, "amount");
|
|
714
|
+
if (!/^(0|[1-9]\d*)$/.test(amount)) {
|
|
715
|
+
throw new Error("ft_transfer payload has malformed amount");
|
|
716
|
+
}
|
|
717
|
+
const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier);
|
|
718
|
+
return {
|
|
719
|
+
cursor: event.cursor,
|
|
720
|
+
block_height: event.block_height,
|
|
721
|
+
tx_id: event.tx_id,
|
|
722
|
+
tx_index: event.tx_index,
|
|
723
|
+
event_index: event.event_index,
|
|
724
|
+
event_type: event.event_type,
|
|
725
|
+
decoded_payload: {
|
|
726
|
+
asset_identifier: assetIdentifier,
|
|
727
|
+
contract_id: event.contract_id ?? contract_id,
|
|
728
|
+
token_name,
|
|
729
|
+
sender,
|
|
730
|
+
recipient,
|
|
731
|
+
amount
|
|
732
|
+
},
|
|
733
|
+
source_cursor: event.cursor
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
// src/streams/nft-transfer.ts
|
|
737
|
+
function requireString2(payload, field) {
|
|
738
|
+
const value = payload[field];
|
|
739
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
740
|
+
throw new Error(`nft_transfer payload missing ${field}`);
|
|
741
|
+
}
|
|
742
|
+
return value;
|
|
743
|
+
}
|
|
744
|
+
function requireHexValue(payload) {
|
|
745
|
+
const value = payload.value;
|
|
746
|
+
const hex = typeof value === "string" ? value : value && typeof value === "object" && typeof value.hex === "string" ? value.hex : null;
|
|
747
|
+
if (!hex) {
|
|
748
|
+
throw new Error("nft_transfer payload missing value");
|
|
749
|
+
}
|
|
750
|
+
if (!/^0x[0-9a-fA-F]*$/.test(hex)) {
|
|
751
|
+
throw new Error("nft_transfer payload has malformed value");
|
|
752
|
+
}
|
|
753
|
+
return hex;
|
|
754
|
+
}
|
|
755
|
+
function parseAssetIdentifier2(assetIdentifier) {
|
|
756
|
+
const [contractId, tokenName] = assetIdentifier.split("::");
|
|
757
|
+
if (!contractId) {
|
|
758
|
+
throw new Error("nft_transfer payload has malformed asset_identifier");
|
|
759
|
+
}
|
|
760
|
+
return {
|
|
761
|
+
contract_id: contractId,
|
|
762
|
+
token_name: tokenName && tokenName.length > 0 ? tokenName : null
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
function isNftTransfer(event) {
|
|
766
|
+
return event.event_type === "nft_transfer";
|
|
767
|
+
}
|
|
768
|
+
function decodeNftTransfer(event) {
|
|
769
|
+
if (!isNftTransfer(event)) {
|
|
770
|
+
throw new Error(`Expected nft_transfer event, got ${event.event_type}`);
|
|
771
|
+
}
|
|
772
|
+
const payload = event.payload;
|
|
773
|
+
const assetIdentifier = requireString2(payload, "asset_identifier");
|
|
774
|
+
const sender = requireString2(payload, "sender");
|
|
775
|
+
const recipient = requireString2(payload, "recipient");
|
|
776
|
+
const value = requireHexValue(payload);
|
|
777
|
+
const { contract_id, token_name } = parseAssetIdentifier2(assetIdentifier);
|
|
778
|
+
return {
|
|
779
|
+
cursor: event.cursor,
|
|
780
|
+
block_height: event.block_height,
|
|
781
|
+
tx_id: event.tx_id,
|
|
782
|
+
tx_index: event.tx_index,
|
|
783
|
+
event_index: event.event_index,
|
|
784
|
+
event_type: event.event_type,
|
|
785
|
+
decoded_payload: {
|
|
786
|
+
asset_identifier: assetIdentifier,
|
|
787
|
+
contract_id: event.contract_id ?? contract_id,
|
|
788
|
+
token_name,
|
|
789
|
+
sender,
|
|
790
|
+
recipient,
|
|
791
|
+
value
|
|
792
|
+
},
|
|
793
|
+
source_cursor: event.cursor
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
// src/streams/types.ts
|
|
797
|
+
var STREAMS_EVENT_TYPES = [
|
|
798
|
+
"stx_transfer",
|
|
799
|
+
"stx_mint",
|
|
800
|
+
"stx_burn",
|
|
801
|
+
"stx_lock",
|
|
802
|
+
"ft_transfer",
|
|
803
|
+
"ft_mint",
|
|
804
|
+
"ft_burn",
|
|
805
|
+
"nft_transfer",
|
|
806
|
+
"nft_mint",
|
|
807
|
+
"nft_burn",
|
|
808
|
+
"print"
|
|
809
|
+
];
|
|
340
810
|
// src/webhooks.ts
|
|
341
811
|
import { verifySignatureHeader } from "@secondlayer/shared/crypto/hmac";
|
|
342
812
|
function verifyWebhookSignature(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
|
|
@@ -344,13 +814,23 @@ function verifyWebhookSignature(rawBody, signatureHeader, secret, toleranceSecon
|
|
|
344
814
|
}
|
|
345
815
|
export {
|
|
346
816
|
verifyWebhookSignature,
|
|
817
|
+
isNftTransfer,
|
|
818
|
+
isFtTransfer,
|
|
347
819
|
getSubgraph,
|
|
820
|
+
decodeNftTransfer,
|
|
821
|
+
decodeFtTransfer,
|
|
822
|
+
createStreamsClient,
|
|
348
823
|
VersionConflictError,
|
|
824
|
+
ValidationError,
|
|
349
825
|
Subscriptions,
|
|
350
826
|
Subgraphs,
|
|
827
|
+
StreamsServerError,
|
|
351
828
|
SecondLayer,
|
|
829
|
+
RateLimitError,
|
|
830
|
+
Index,
|
|
831
|
+
AuthError,
|
|
352
832
|
ApiError
|
|
353
833
|
};
|
|
354
834
|
|
|
355
|
-
//# debugId=
|
|
835
|
+
//# debugId=2771C8998C150B3F64756E2164756E21
|
|
356
836
|
//# sourceMappingURL=index.js.map
|