@indexing/jiti 0.1.12 → 0.1.14

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/dist/module.js CHANGED
@@ -3,9 +3,14 @@ import {sha256 as $hgUW1$sha256, keccak256 as $hgUW1$keccak256, decodeEventLog a
3
3
  import $hgUW1$tronweb from "tronweb";
4
4
  import {decodeTxRaw as $hgUW1$decodeTxRaw, Registry as $hgUW1$Registry} from "@cosmjs/proto-signing";
5
5
  import {defaultRegistryTypes as $hgUW1$defaultRegistryTypes} from "@cosmjs/stargate";
6
+ import {Address as $hgUW1$Address, Cell as $hgUW1$Cell} from "@ton/core";
6
7
  import $hgUW1$bs58 from "bs58";
7
8
 
8
9
 
10
+ function $parcel$export(e, n, v, s) {
11
+ Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
12
+ }
13
+
9
14
  function $parcel$exportWildcard(dest, source) {
10
15
  Object.keys(source).forEach(function(key) {
11
16
  if (key === 'default' || key === '__esModule' || Object.prototype.hasOwnProperty.call(dest, key)) {
@@ -23,9 +28,106 @@ function $parcel$exportWildcard(dest, source) {
23
28
  return dest;
24
29
  }
25
30
 
26
- function $parcel$export(e, n, v, s) {
27
- Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
31
+ var $parcel$global = globalThis;
32
+
33
+ var $parcel$modules = {};
34
+ var $parcel$inits = {};
35
+
36
+ var parcelRequire = $parcel$global["parcelRequire3fdc"];
37
+
38
+ if (parcelRequire == null) {
39
+ parcelRequire = function(id) {
40
+ if (id in $parcel$modules) {
41
+ return $parcel$modules[id].exports;
42
+ }
43
+ if (id in $parcel$inits) {
44
+ var init = $parcel$inits[id];
45
+ delete $parcel$inits[id];
46
+ var module = {id: id, exports: {}};
47
+ $parcel$modules[id] = module;
48
+ init.call(module.exports, module, module.exports);
49
+ return module.exports;
50
+ }
51
+ var err = new Error("Cannot find module '" + id + "'");
52
+ err.code = 'MODULE_NOT_FOUND';
53
+ throw err;
54
+ };
55
+
56
+ parcelRequire.register = function register(id, init) {
57
+ $parcel$inits[id] = init;
58
+ };
59
+
60
+ $parcel$global["parcelRequire3fdc"] = parcelRequire;
28
61
  }
62
+
63
+ var parcelRegister = parcelRequire.register;
64
+ parcelRegister("cP1H0", function(module, exports) {
65
+
66
+ $parcel$export(module.exports, "createPostgresCacheStorage", () => createPostgresCacheStorage);
67
+ function createPostgresCacheStorage(opts) {
68
+ const table = (opts.table ?? "jiti_cache").replace(/[^a-zA-Z0-9_]/g, "");
69
+ let pool = opts.pool;
70
+ function getPool() {
71
+ if (!pool) {
72
+ // Obscure the require so jiti's bundler leaves `pg` external (loaded from the consumer).
73
+ const requirePg = eval("require");
74
+ const pg = requirePg("pg");
75
+ pool = new pg.Pool({
76
+ connectionString: opts.connectionUri
77
+ });
78
+ }
79
+ return pool;
80
+ }
81
+ let ready;
82
+ function ensureTable() {
83
+ if (!ready) ready = (async ()=>{
84
+ const p = getPool();
85
+ await p.query(`CREATE TABLE IF NOT EXISTS ${table} (
86
+ namespace text NOT NULL,
87
+ key text NOT NULL,
88
+ value jsonb,
89
+ found boolean NOT NULL DEFAULT true,
90
+ resolved_at timestamptz NOT NULL DEFAULT now(),
91
+ expires_at timestamptz,
92
+ PRIMARY KEY (namespace, key)
93
+ );`);
94
+ await p.query(`CREATE INDEX IF NOT EXISTS ${table}_expires_idx ON ${table} (expires_at) WHERE expires_at IS NOT NULL;`);
95
+ })();
96
+ return ready;
97
+ }
98
+ return {
99
+ async get (namespace, key) {
100
+ await ensureTable();
101
+ const { rows } = await getPool().query(`SELECT value, found, expires_at FROM ${table} WHERE namespace = $1 AND key = $2`, [
102
+ namespace,
103
+ key
104
+ ]);
105
+ if (!rows.length) return null;
106
+ const row = rows[0];
107
+ return {
108
+ value: row.value ?? null,
109
+ found: row.found,
110
+ expiresAt: row.expires_at ? new Date(row.expires_at).getTime() : null
111
+ };
112
+ },
113
+ async set (namespace, key, row) {
114
+ await ensureTable();
115
+ await getPool().query(`INSERT INTO ${table} (namespace, key, value, found, resolved_at, expires_at)
116
+ VALUES ($1, $2, $3::jsonb, $4, now(), $5)
117
+ ON CONFLICT (namespace, key) DO UPDATE
118
+ SET value = EXCLUDED.value, found = EXCLUDED.found, resolved_at = now(), expires_at = EXCLUDED.expires_at`, [
119
+ namespace,
120
+ key,
121
+ row.value === null || row.value === undefined ? null : JSON.stringify(row.value),
122
+ row.found,
123
+ row.expiresAt ? new Date(row.expiresAt).toISOString() : null
124
+ ]);
125
+ }
126
+ };
127
+ }
128
+
129
+ });
130
+
29
131
  var $fde9406d76ec24a9$exports = {};
30
132
  var $82293038337e7b3f$exports = {};
31
133
 
@@ -1350,6 +1452,219 @@ const $548ae36ea3681b01$export$d7ac970e8e789607 = {
1350
1452
 
1351
1453
 
1352
1454
 
1455
+ // Per-namespace policy registry. Namespaces differ only here: immutable vs TTL
1456
+ // (`ttlSeconds`), and resolve-on-miss vs externally-populated (presence of `resolve`).
1457
+ // jiti registers the namespaces it can resolve itself (e.g. ton-jetton-wallet); a consumer
1458
+ // may register its own (e.g. token-price with no resolver, populated via cacheSet).
1459
+ const $caa0db003a346aa2$var$REGISTRY = new Map();
1460
+ function $caa0db003a346aa2$export$2b845901f37b4099(namespace, policy) {
1461
+ $caa0db003a346aa2$var$REGISTRY.set(namespace, policy);
1462
+ }
1463
+ function $caa0db003a346aa2$export$d23e4dbc7b86eaca(namespace) {
1464
+ return $caa0db003a346aa2$var$REGISTRY.get(namespace) ?? {};
1465
+ }
1466
+
1467
+
1468
+ // cache-or-lookup core. jiti owns the orchestration — in-process L1, single-flight, negative
1469
+ // caching, TTL/immutability, read-through/write-through — and the per-namespace resolvers.
1470
+ // The consumer injects only durable storage (see createPostgresCacheStorage for a ready-made
1471
+ // Postgres adapter). With no storage available, callers simply don't invoke cacheGet.
1472
+ const $692184cb0ed76c37$var$L1_MAX = 50000;
1473
+ const $692184cb0ed76c37$var$L1 = new Map();
1474
+ function $692184cb0ed76c37$var$l1Get(id) {
1475
+ const e = $692184cb0ed76c37$var$L1.get(id);
1476
+ if (!e) return undefined;
1477
+ if (e.expiresAt !== null && e.expiresAt <= Date.now()) {
1478
+ $692184cb0ed76c37$var$L1.delete(id);
1479
+ return undefined;
1480
+ }
1481
+ $692184cb0ed76c37$var$L1.delete(id);
1482
+ $692184cb0ed76c37$var$L1.set(id, e); // bump recency
1483
+ return e;
1484
+ }
1485
+ function $692184cb0ed76c37$var$l1Set(id, value, expiresAt) {
1486
+ if ($692184cb0ed76c37$var$L1.size >= $692184cb0ed76c37$var$L1_MAX) {
1487
+ const oldest = $692184cb0ed76c37$var$L1.keys().next().value;
1488
+ if (oldest !== undefined) $692184cb0ed76c37$var$L1.delete(oldest);
1489
+ }
1490
+ $692184cb0ed76c37$var$L1.set(id, {
1491
+ value: value,
1492
+ expiresAt: expiresAt
1493
+ });
1494
+ }
1495
+ const $692184cb0ed76c37$var$inflight = new Map();
1496
+ function $692184cb0ed76c37$var$cacheId(namespace, key) {
1497
+ return `${namespace} ${key}`;
1498
+ }
1499
+ async function $692184cb0ed76c37$export$2aca74ef9665e35d(storage, namespace, key) {
1500
+ const id = $692184cb0ed76c37$var$cacheId(namespace, key);
1501
+ const l1 = $692184cb0ed76c37$var$l1Get(id);
1502
+ if (l1) return l1.value;
1503
+ const existing = $692184cb0ed76c37$var$inflight.get(id);
1504
+ if (existing !== undefined) return existing;
1505
+ const p = (async ()=>{
1506
+ const row = await storage.get(namespace, key);
1507
+ if (row && (row.expiresAt === null || row.expiresAt > Date.now())) {
1508
+ const value = row.found ? row.value : null;
1509
+ $692184cb0ed76c37$var$l1Set(id, value, row.expiresAt);
1510
+ return value;
1511
+ }
1512
+ const policy = (0, $caa0db003a346aa2$export$d23e4dbc7b86eaca)(namespace);
1513
+ if (!policy.resolve) return null; // externally-populated namespace: miss ⇒ null (no write)
1514
+ let resolved = null;
1515
+ try {
1516
+ resolved = await policy.resolve(key);
1517
+ } catch {
1518
+ // Transient resolver failure (e.g. RPC) — do NOT cache so it retries next time.
1519
+ return null;
1520
+ }
1521
+ const found = resolved !== null && resolved !== undefined;
1522
+ const negativeTtl = policy.negativeTtlSeconds ?? 3600;
1523
+ if (!found && negativeTtl === 0) return null; // negative caching disabled for this namespace
1524
+ const ttlSeconds = found ? policy.ttlSeconds : negativeTtl;
1525
+ const expiresAt = ttlSeconds === null || ttlSeconds === undefined ? null : Date.now() + ttlSeconds * 1000;
1526
+ await storage.set(namespace, key, {
1527
+ value: found ? resolved : null,
1528
+ found: found,
1529
+ expiresAt: expiresAt
1530
+ });
1531
+ $692184cb0ed76c37$var$l1Set(id, found ? resolved : null, expiresAt);
1532
+ return found ? resolved : null;
1533
+ })().finally(()=>$692184cb0ed76c37$var$inflight.delete(id));
1534
+ $692184cb0ed76c37$var$inflight.set(id, p);
1535
+ return p;
1536
+ }
1537
+ async function $692184cb0ed76c37$export$59c69e19e33761f6(storage, namespace, key, value, ttlSecondsOverride) {
1538
+ const policy = (0, $caa0db003a346aa2$export$d23e4dbc7b86eaca)(namespace);
1539
+ const ttlSeconds = ttlSecondsOverride !== undefined ? ttlSecondsOverride : policy.ttlSeconds;
1540
+ const expiresAt = ttlSeconds === null || ttlSeconds === undefined ? null : Date.now() + ttlSeconds * 1000;
1541
+ await storage.set(namespace, key, {
1542
+ value: value,
1543
+ found: true,
1544
+ expiresAt: expiresAt
1545
+ });
1546
+ $692184cb0ed76c37$var$l1Set($692184cb0ed76c37$var$cacheId(namespace, key), value, expiresAt);
1547
+ }
1548
+
1549
+
1550
+
1551
+ const $cfe9a1176e32c0c3$export$a0a0f70252f1386f = "ton-jetton-wallet";
1552
+ const $cfe9a1176e32c0c3$var$ORBS_MANAGER_URL = "https://ton.access.orbs.network/mngr/nodes";
1553
+ const $cfe9a1176e32c0c3$var$ORBS_REFRESH_MS = 300000;
1554
+ let $cfe9a1176e32c0c3$var$orbsHosts = [];
1555
+ let $cfe9a1176e32c0c3$var$orbsRefreshedAt = 0;
1556
+ function $cfe9a1176e32c0c3$var$shuffled(hosts) {
1557
+ const a = [
1558
+ ...hosts
1559
+ ];
1560
+ for(let i = a.length - 1; i > 0; i--){
1561
+ const j = Math.floor(Math.random() * (i + 1));
1562
+ [a[i], a[j]] = [
1563
+ a[j],
1564
+ a[i]
1565
+ ];
1566
+ }
1567
+ return a;
1568
+ }
1569
+ async function $cfe9a1176e32c0c3$var$getHosts() {
1570
+ if ($cfe9a1176e32c0c3$var$orbsHosts.length && Date.now() - $cfe9a1176e32c0c3$var$orbsRefreshedAt < $cfe9a1176e32c0c3$var$ORBS_REFRESH_MS) return $cfe9a1176e32c0c3$var$shuffled($cfe9a1176e32c0c3$var$orbsHosts);
1571
+ try {
1572
+ const resp = await fetch($cfe9a1176e32c0c3$var$ORBS_MANAGER_URL, {
1573
+ signal: AbortSignal.timeout(8000)
1574
+ });
1575
+ const nodes = await resp.json();
1576
+ const healthy = nodes.filter((n)=>n.Healthy === "1" && n.Mngr?.health?.["v2-mainnet"]).map((n)=>`https://ton.access.orbs.network/${n.NodeId}/1/mainnet/toncenter-api-v2/jsonRPC`);
1577
+ if (healthy.length) {
1578
+ $cfe9a1176e32c0c3$var$orbsHosts = healthy;
1579
+ $cfe9a1176e32c0c3$var$orbsRefreshedAt = Date.now();
1580
+ }
1581
+ } catch {
1582
+ // keep prior cached set
1583
+ }
1584
+ return $cfe9a1176e32c0c3$var$shuffled($cfe9a1176e32c0c3$var$orbsHosts);
1585
+ }
1586
+ function $cfe9a1176e32c0c3$export$938b62d04991c792(addr) {
1587
+ try {
1588
+ return (0, $hgUW1$Address).parse(addr).toString({
1589
+ urlSafe: true,
1590
+ bounceable: true,
1591
+ testOnly: false
1592
+ });
1593
+ } catch {
1594
+ return addr;
1595
+ }
1596
+ }
1597
+ function $cfe9a1176e32c0c3$var$parseAddressFromStackEntry(entry) {
1598
+ // toncenter v2 runGetMethod returns slice/cell results as ['cell', { bytes: <base64 BoC> }].
1599
+ const value = entry?.[1];
1600
+ const b64 = typeof value === "string" ? value : value?.bytes;
1601
+ if (!b64) return null;
1602
+ return $cfe9a1176e32c0c3$export$938b62d04991c792((0, $hgUW1$Cell).fromBase64(b64).beginParse().loadAddress().toString());
1603
+ }
1604
+ async function $cfe9a1176e32c0c3$var$runGetMethod(host, address, method, stack) {
1605
+ const resp = await fetch(host, {
1606
+ method: "POST",
1607
+ headers: {
1608
+ "content-type": "application/json"
1609
+ },
1610
+ body: JSON.stringify({
1611
+ jsonrpc: "2.0",
1612
+ id: 1,
1613
+ method: "runGetMethod",
1614
+ params: {
1615
+ address: address,
1616
+ method: method,
1617
+ stack: stack
1618
+ }
1619
+ }),
1620
+ signal: AbortSignal.timeout(15000)
1621
+ });
1622
+ const json = await resp.json();
1623
+ if (!json.ok || !json.result) throw new Error(`TON runGetMethod ${method} error: ${json.error || "unknown"}`);
1624
+ return {
1625
+ exitCode: json.result.exit_code,
1626
+ stack: json.result.stack
1627
+ };
1628
+ }
1629
+ async function $cfe9a1176e32c0c3$export$cef9e9799d863462(wallet) {
1630
+ const hosts = await $cfe9a1176e32c0c3$var$getHosts();
1631
+ if (!hosts.length) throw new Error("TON: no Orbs hosts available for get_wallet_data");
1632
+ let sawDefiniteMiss = false;
1633
+ let lastErr;
1634
+ for(let attempt = 0; attempt < 2; attempt++){
1635
+ for (const host of hosts)try {
1636
+ const { exitCode: exitCode, stack: stack } = await $cfe9a1176e32c0c3$var$runGetMethod(host, wallet, "get_wallet_data", []);
1637
+ if (exitCode !== 0) {
1638
+ sawDefiniteMiss = true; // no get_wallet_data → not a jetton wallet
1639
+ continue;
1640
+ }
1641
+ const owner = $cfe9a1176e32c0c3$var$parseAddressFromStackEntry(stack[1]);
1642
+ const master = $cfe9a1176e32c0c3$var$parseAddressFromStackEntry(stack[2]);
1643
+ if (owner && master) return {
1644
+ owner: owner,
1645
+ master: master
1646
+ };
1647
+ sawDefiniteMiss = true;
1648
+ } catch (e) {
1649
+ lastErr = e;
1650
+ }
1651
+ }
1652
+ if (sawDefiniteMiss) return null; // definitive: not a jetton wallet → negative-cache
1653
+ throw new Error(`TON: get_wallet_data failed for ${wallet}: ${lastErr?.message}`); // transient → don't cache
1654
+ }
1655
+ async function $cfe9a1176e32c0c3$export$77ffdf974cb300ec(storage, wallet) {
1656
+ return await (0, $692184cb0ed76c37$export$2aca74ef9665e35d)(storage, $cfe9a1176e32c0c3$export$a0a0f70252f1386f, $cfe9a1176e32c0c3$export$938b62d04991c792(wallet));
1657
+ }
1658
+ // Register on import: immutable mapping, resolve-on-miss via get_wallet_data; non-jetton
1659
+ // accounts negative-cached for a day.
1660
+ (0, $caa0db003a346aa2$export$2b845901f37b4099)($cfe9a1176e32c0c3$export$a0a0f70252f1386f, {
1661
+ resolve: (key)=>$cfe9a1176e32c0c3$export$cef9e9799d863462(key),
1662
+ ttlSeconds: null,
1663
+ negativeTtlSeconds: 86400
1664
+ });
1665
+
1666
+
1667
+
1353
1668
  const $07b3982e2fc4c8b2$export$400f08bfae9ee97f = {
1354
1669
  match: (block)=>(0, $09654dffcb68affa$export$ae001c77434c5340)(block) === "RIPPLE",
1355
1670
  transform (block) {
@@ -3524,65 +3839,150 @@ const $13c3ff41f568666f$export$bc6c7ab7e0727dd7 = {
3524
3839
 
3525
3840
 
3526
3841
 
3842
+
3843
+
3844
+ var $e97546fe39f2692a$require$Buffer = $hgUW1$Buffer;
3845
+ // TEP-74 jetton `internal_transfer` op-code. This is the message a recipient's
3846
+ // jetton wallet receives when it is credited, so it is the canonical signal of a
3847
+ // jetton deposit landing — and the only jetton message whose executing account
3848
+ // (`tx.address`) is the recipient jetton wallet itself.
3849
+ const $e97546fe39f2692a$var$JETTON_INTERNAL_TRANSFER_OP = 0x178d4519;
3850
+ // Decode a jetton `internal_transfer` message body (a base64-encoded BoC).
3851
+ // Returns null when the body is absent, is not a BoC, or carries a different
3852
+ // op-code (text comments, other jetton ops, arbitrary contract calls) — the
3853
+ // caller then falls back to the native path. Body layout (TEP-74):
3854
+ // internal_transfer#0x178d4519 query_id:uint64 amount:(VarUInteger 16)
3855
+ // from:MsgAddress response_address:MsgAddress ...
3856
+ function $e97546fe39f2692a$var$decodeJettonInternalTransfer(body) {
3857
+ if (!body) return null;
3858
+ try {
3859
+ const slice = (0, $hgUW1$Cell).fromBoc($e97546fe39f2692a$require$Buffer.from(body, "base64"))[0].beginParse();
3860
+ if (slice.loadUint(32) !== $e97546fe39f2692a$var$JETTON_INTERNAL_TRANSFER_OP) return null;
3861
+ slice.loadUintBig(64); // query_id
3862
+ const amount = slice.loadCoins();
3863
+ // `from` is the sending owner, read best-effort: it can be addr_none on some
3864
+ // mints/airdrops, and rare non-standard address encodings can throw. In
3865
+ // either case keep the (valid) amount and let the caller fall back to the
3866
+ // message source rather than dropping a real jetton transfer.
3867
+ let from;
3868
+ try {
3869
+ const fromAddress = slice.loadMaybeAddress();
3870
+ from = fromAddress ? fromAddress.toString({
3871
+ urlSafe: true,
3872
+ bounceable: true,
3873
+ testOnly: false
3874
+ }) : undefined;
3875
+ } catch {
3876
+ from = undefined;
3877
+ }
3878
+ return {
3879
+ amount: amount,
3880
+ from: from
3881
+ };
3882
+ } catch {
3883
+ return null;
3884
+ }
3885
+ }
3527
3886
  const $e97546fe39f2692a$export$608f3f42810b9879 = {
3528
3887
  match: (block)=>(0, $09654dffcb68affa$export$ae001c77434c5340)(block) === "TON",
3529
3888
  transform (block) {
3530
- let transfers = [];
3889
+ const transfers = [];
3531
3890
  const typedBlock = block;
3532
3891
  const blockNumber = typedBlock.seqno;
3533
- const blockTimestamp = new Date(typedBlock.shards?.[0]?.gen_utime * 1000).toISOString();
3534
3892
  for (const shard of typedBlock.shards || [])for (const tx of shard.transactions || []){
3535
- const transactionLT = tx.transaction_id.lt;
3536
- const transactionHash = tx.transaction_id.hash;
3537
- const transactionFee = BigInt(tx.fee || "0");
3538
- const inVal = BigInt(tx.in_msg?.value || "0");
3539
- if (inVal > 0n) transfers.push({
3893
+ const inMsg = tx.in_msg;
3894
+ if (!inMsg) continue;
3895
+ const transactionHash = tx.transaction_id?.hash;
3896
+ const transactionGasFee = BigInt(tx.fee || "0");
3897
+ // Per-transaction time. shards[0].gen_utime — the previous source — is
3898
+ // wrong for any transaction outside the first shard and is undefined for
3899
+ // empty shards (producing `Invalid Date`).
3900
+ const timestamp = new Date((tx.utime || 0) * 1000).toISOString();
3901
+ // The account this transaction executed on: the recipient account for a
3902
+ // native transfer, or the recipient's jetton wallet for a jetton one
3903
+ // (== in_msg.destination).
3904
+ const to = tx.address?.account_address;
3905
+ // Walk `in_msg` only: every transfer is recorded once, at the
3906
+ // recipient's transaction, with `from` carried on the row so sender
3907
+ // queries still match. Walking `out_msgs` too would double-emit each hop
3908
+ // — the sender's and the recipient's transactions both fall in range.
3909
+ const jetton = $e97546fe39f2692a$var$decodeJettonInternalTransfer(inMsg.msg_data?.body);
3910
+ if (jetton) {
3911
+ // Jetton and native value are mutually exclusive per message: a jetton
3912
+ // `internal_transfer` also carries forwarded gas as `in_msg.value`, so
3913
+ // emitting a native transfer here too would surface a phantom TON hop.
3914
+ transfers.push({
3915
+ blockNumber: blockNumber,
3916
+ from: jetton.from || inMsg.source?.account_address,
3917
+ to: to,
3918
+ amount: jetton.amount,
3919
+ // The jetton master is not carried in the wallet-to-wallet
3920
+ // `internal_transfer`; a stateless template can't resolve it without
3921
+ // an RPC call, so `token` is intentionally left undefined.
3922
+ tokenType: "TOKEN",
3923
+ timestamp: timestamp,
3924
+ transactionHash: transactionHash,
3925
+ transactionGasFee: transactionGasFee
3926
+ });
3927
+ continue;
3928
+ }
3929
+ const inValue = BigInt(inMsg.value || "0");
3930
+ if (inValue > 0n) transfers.push({
3540
3931
  blockNumber: blockNumber,
3541
- from: tx.in_msg?.source?.account_address,
3542
- to: tx.address?.account_address,
3543
- amount: inVal,
3932
+ from: inMsg.source?.account_address,
3933
+ to: to,
3934
+ amount: inValue,
3544
3935
  token: "TON",
3545
3936
  tokenType: "NATIVE",
3546
- timestamp: blockTimestamp,
3937
+ timestamp: timestamp,
3547
3938
  transactionHash: transactionHash,
3548
- transactionGasFee: transactionFee
3939
+ transactionGasFee: transactionGasFee
3549
3940
  });
3550
- for (const outMsg of tx.out_msgs || []){
3551
- const outVal = BigInt(outMsg.value || "0");
3552
- if (outVal > 0n) transfers.push({
3553
- blockNumber: blockNumber,
3554
- from: outMsg.source?.account_address,
3555
- to: outMsg.destination?.account_address,
3556
- amount: outVal,
3557
- token: "TON",
3558
- tokenType: "NATIVE",
3559
- timestamp: blockTimestamp,
3560
- transactionHash: transactionHash,
3561
- transactionGasFee: transactionFee
3562
- });
3563
- }
3564
3941
  }
3565
3942
  return transfers;
3566
3943
  },
3567
3944
  tests: [
3568
3945
  {
3946
+ // Native TON transfer — `in_msg` carries value and no jetton body.
3569
3947
  params: {
3570
3948
  network: "TON",
3571
- walletAddress: "EQAFukUyzmHjUvOYDOjNE-wbZFFl2FWas1rFJoh8IiTsWD40",
3572
- contractAddress: ""
3949
+ transactionHash: "rwDRQeWniNdxBayFcDavE/Wo35B+MsfO4lJJmvz5Edk="
3573
3950
  },
3574
- payload: "https://jiti.indexing.co/networks/ton/44919328",
3951
+ payload: "https://jiti.indexing.co/networks/ton/71399000",
3575
3952
  output: [
3576
3953
  {
3577
- blockNumber: 44919328,
3578
- from: "EQAFukUyzmHjUvOYDOjNE-wbZFFl2FWas1rFJoh8IiTsWD40",
3579
- to: "EQCFTFAHOU3vFt2NiZhRD5dwuS0k7GS59vIg3WfCKwfaQGW2",
3580
- amount: 10000000n,
3954
+ blockNumber: 71399000,
3955
+ from: "EQBkhlXTyZjri7SfyZcgFbRkjlLvq4kU3UjBTtiTtwLITn0H",
3956
+ to: "EQABGo8KCza3ea8DNHMnSWZmbRzW-05332eTdfvW-XDQEjQM",
3957
+ amount: 203686310466n,
3581
3958
  token: "TON",
3582
3959
  tokenType: "NATIVE",
3583
- timestamp: "2025-02-13T23:10:18.000Z",
3584
- transactionHash: "Vh5cWr2uvCsdhoouBQ+EiUcF54os9oqvh8A/62EroQc=",
3585
- transactionGasFee: 2355233n
3960
+ timestamp: "2026-06-05T15:31:47.000Z",
3961
+ transactionHash: "rwDRQeWniNdxBayFcDavE/Wo35B+MsfO4lJJmvz5Edk=",
3962
+ transactionGasFee: 6668n
3963
+ }
3964
+ ]
3965
+ },
3966
+ {
3967
+ // Jetton transfer — `in_msg` is an internal_transfer (op 0x178d4519). The
3968
+ // message also carries 49740664 nanoTON of forwarded gas, which must NOT
3969
+ // surface as a phantom native transfer. `token` is left undefined (the
3970
+ // jetton master is not in the wallet-to-wallet message).
3971
+ params: {
3972
+ network: "TON",
3973
+ transactionHash: "Tx+nOxUzqo8kYpNkX20C2OTg6Dd9d6MHadQsknv4620="
3974
+ },
3975
+ payload: "https://jiti.indexing.co/networks/ton/71399000",
3976
+ output: [
3977
+ {
3978
+ blockNumber: 71399000,
3979
+ from: "EQDshc_H_RAJNi5CG1oBQfUQ1lQBB6tz54Kf2h756Xp14_Cv",
3980
+ to: "EQBMzIc7YUB_WkSkmaIooZyONQDayNfipt3PQ4IJRsGXsPGI",
3981
+ amount: 2800000000n,
3982
+ tokenType: "TOKEN",
3983
+ timestamp: "2026-06-05T15:31:47.000Z",
3984
+ transactionHash: "Tx+nOxUzqo8kYpNkX20C2OTg6Dd9d6MHadQsknv4620=",
3985
+ transactionGasFee: 233386n
3586
3986
  }
3587
3987
  ]
3588
3988
  }
@@ -3680,6 +4080,27 @@ const $0ab1acc1eff391f6$var$UNIVERSAL_SUB_TEMPLATES = [
3680
4080
  (0, $8d6646508fb2fa58$export$b5fd4920e8b7d913),
3681
4081
  (0, $5ec62a2088d070a8$export$5beebc5708fabf3c)
3682
4082
  ];
4083
+ // Drops zero-amount + duplicate transfers and applies the optional contractAddress /
4084
+ // walletAddress / transactionHash param filters. Runs AFTER any jetton enrichment so the
4085
+ // filters see the resolved owner/master.
4086
+ function $0ab1acc1eff391f6$var$applyTransferFilters(transfers, _ctx) {
4087
+ const seenTransfers = new Set();
4088
+ return transfers.filter((txfer)=>{
4089
+ if (txfer.amount <= BigInt(0)) return false;
4090
+ if (_ctx?.params) {
4091
+ if (_ctx.params.contractAddress && _ctx.params.contractAddress !== txfer.token) return false;
4092
+ if (_ctx.params.walletAddress && ![
4093
+ txfer.from,
4094
+ txfer.to
4095
+ ].includes(_ctx.params.walletAddress)) return false;
4096
+ if (_ctx.params.transactionHash && txfer.transactionHash !== _ctx.params.transactionHash) return false;
4097
+ }
4098
+ const key = `${txfer.transactionHash}-${txfer.from}-${txfer.to}-${txfer.amount}-${txfer.token}-${txfer.index}`;
4099
+ if (seenTransfers.has(key)) return false;
4100
+ seenTransfers.add(key);
4101
+ return true;
4102
+ });
4103
+ }
3683
4104
  const $0ab1acc1eff391f6$var$tokenTransfersTemplate = {
3684
4105
  key: "token_transfers",
3685
4106
  name: "Token Transfers",
@@ -3732,23 +4153,27 @@ const $0ab1acc1eff391f6$var$tokenTransfersTemplate = {
3732
4153
  transfers = sub.transform(block, _ctx);
3733
4154
  break;
3734
4155
  }
3735
- const seenTransfers = new Set();
3736
- transfers = transfers.filter((txfer)=>{
3737
- if (txfer.amount <= BigInt(0)) return false;
3738
- if (_ctx?.params) {
3739
- if (_ctx.params.contractAddress && _ctx.params.contractAddress !== txfer.token) return false;
3740
- if (_ctx.params.walletAddress && ![
3741
- txfer.from,
3742
- txfer.to
3743
- ].includes(_ctx.params.walletAddress)) return false;
3744
- if (_ctx.params.transactionHash && txfer.transactionHash !== _ctx.params.transactionHash) return false;
3745
- }
3746
- const key = `${txfer.transactionHash}-${txfer.from}-${txfer.to}-${txfer.amount}-${txfer.token}-${txfer.index}`;
3747
- if (seenTransfers.has(key)) return false;
3748
- seenTransfers.add(key);
3749
- return true;
3750
- });
3751
- return transfers;
4156
+ // Optional enrichment for account-model token transfers (TON jettons) where the block
4157
+ // only carries the token-WALLET address and no master: they come out as
4158
+ // `tokenType: 'TOKEN'`, `to` = wallet, `token` = undefined. When the caller injects a
4159
+ // `_ctx.cacheStorage` (durable cache), jiti resolves the wallet → { owner, master } via
4160
+ // its own cache+RPC and rewrites `to`/`token` BEFORE filtering, so contractAddress /
4161
+ // walletAddress filters match the real owner + master. jiti owns the cache + resolver
4162
+ // (get_wallet_data over Orbs); the consumer injects only storage. Async only when storage
4163
+ // is provided; the sync path is unchanged for every existing caller.
4164
+ const cacheStorage = _ctx?.cacheStorage;
4165
+ if (cacheStorage) return (async ()=>{
4166
+ await Promise.all(transfers.map(async (txfer)=>{
4167
+ if (txfer.tokenType !== "TOKEN" || txfer.token || !txfer.to) return;
4168
+ const info = await (0, $cfe9a1176e32c0c3$export$77ffdf974cb300ec)(cacheStorage, txfer.to);
4169
+ if (info) {
4170
+ txfer.to = info.owner;
4171
+ txfer.token = info.master;
4172
+ }
4173
+ }));
4174
+ return $0ab1acc1eff391f6$var$applyTransferFilters(transfers, _ctx);
4175
+ })();
4176
+ return $0ab1acc1eff391f6$var$applyTransferFilters(transfers, _ctx);
3752
4177
  },
3753
4178
  tests: $0ab1acc1eff391f6$var$SUB_TEMPLATES.concat($0ab1acc1eff391f6$var$UNIVERSAL_SUB_TEMPLATES).map((v)=>v.tests).flat()
3754
4179
  };
@@ -11505,6 +11930,10 @@ $parcel$exportWildcard($a4e0e4b4a62175c4$exports, $f3761421850600fb$exports);
11505
11930
  $parcel$exportWildcard($a4e0e4b4a62175c4$exports, $e64a550a52a9d690$exports);
11506
11931
 
11507
11932
 
11933
+
11934
+
11935
+ var $cP1H0 = parcelRequire("cP1H0");
11936
+
11508
11937
  const $149c1bd638913645$export$eab97d15b1788b8d = {
11509
11938
  ...$fde9406d76ec24a9$exports
11510
11939
  };
@@ -11519,5 +11948,6 @@ function $149c1bd638913645$export$a07bfd14bbc36e4b(key) {
11519
11948
  }
11520
11949
 
11521
11950
 
11522
- export {$149c1bd638913645$export$eab97d15b1788b8d as utils, $149c1bd638913645$export$a8fc3402335b0b04 as templates, $149c1bd638913645$export$cceb5167b935aafb as getAllTemplates, $149c1bd638913645$export$a07bfd14bbc36e4b as getTemplateByKey};
11951
+ var createPostgresCacheStorage = parcelRequire("cP1H0").createPostgresCacheStorage;
11952
+ export {$149c1bd638913645$export$eab97d15b1788b8d as utils, $149c1bd638913645$export$a8fc3402335b0b04 as templates, $149c1bd638913645$export$cceb5167b935aafb as getAllTemplates, $149c1bd638913645$export$a07bfd14bbc36e4b as getTemplateByKey, $692184cb0ed76c37$export$2aca74ef9665e35d as cacheGet, $692184cb0ed76c37$export$59c69e19e33761f6 as cacheSet, $caa0db003a346aa2$export$2b845901f37b4099 as registerCacheNamespace, createPostgresCacheStorage as createPostgresCacheStorage, $cfe9a1176e32c0c3$export$77ffdf974cb300ec as lookupJettonWallet, $cfe9a1176e32c0c3$export$cef9e9799d863462 as resolveJettonWalletData, $cfe9a1176e32c0c3$export$a0a0f70252f1386f as TON_JETTON_NAMESPACE};
11523
11953
  //# sourceMappingURL=module.js.map