@anywalletkit/wallet-ton 0.0.0-stage → 0.2.1

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.
@@ -0,0 +1,480 @@
1
+ // src/history.ts
2
+ import { Address } from "@ton/core";
3
+ import { Buffer } from "buffer";
4
+
5
+ // src/types.ts
6
+ var CAIP2 = { mainnet: "ton:-239", testnet: "ton:-3" };
7
+
8
+ // src/history.ts
9
+ var HistoryUnavailableError = class extends Error {
10
+ chain;
11
+ reason;
12
+ attempts;
13
+ constructor(chain, reason, attempts = []) {
14
+ super(`History unavailable for ${chain}: ${reason}`);
15
+ this.name = "HistoryUnavailableError";
16
+ this.chain = chain;
17
+ this.reason = reason;
18
+ this.attempts = attempts;
19
+ }
20
+ };
21
+ var DEFAULT_LIMIT = 25;
22
+ var MAX_LIMIT = 100;
23
+ var DEFAULT_TIMEOUT_MS = 15e3;
24
+ function encodeCursor(c) {
25
+ return Buffer.from(JSON.stringify(c), "utf8").toString("base64");
26
+ }
27
+ function decodeCursor(s) {
28
+ let parsed;
29
+ try {
30
+ parsed = JSON.parse(Buffer.from(s, "base64").toString("utf8"));
31
+ } catch {
32
+ throw new Error("@anywalletkit/wallet-ton: malformed history cursor");
33
+ }
34
+ const c = parsed;
35
+ if (!c || c.v !== 1 || c.b !== "tonapi" && c.b !== "toncenter" || typeof c.lt !== "string" || !/^\d+$/.test(c.lt)) {
36
+ throw new Error("@anywalletkit/wallet-ton: malformed history cursor");
37
+ }
38
+ return { v: 1, b: c.b, lt: c.lt };
39
+ }
40
+ var TokenBucket = class {
41
+ constructor(rate, burst = Math.max(1, Math.ceil(rate))) {
42
+ this.rate = rate;
43
+ this.burst = burst;
44
+ this.tokens = burst;
45
+ }
46
+ rate;
47
+ burst;
48
+ tokens;
49
+ last = Date.now();
50
+ chain = Promise.resolve();
51
+ acquire() {
52
+ const next = this.chain.then(() => this.take());
53
+ this.chain = next.catch(() => void 0);
54
+ return next;
55
+ }
56
+ refill() {
57
+ const now = Date.now();
58
+ this.tokens = Math.min(this.burst, this.tokens + (now - this.last) / 1e3 * this.rate);
59
+ this.last = now;
60
+ }
61
+ async take() {
62
+ this.refill();
63
+ if (this.tokens >= 1) {
64
+ this.tokens -= 1;
65
+ return;
66
+ }
67
+ await new Promise((r) => setTimeout(r, Math.ceil((1 - this.tokens) / this.rate * 1e3)));
68
+ this.refill();
69
+ this.tokens = Math.max(0, this.tokens - 1);
70
+ }
71
+ };
72
+ function timeoutSignal(ms) {
73
+ const ctor = globalThis.AbortSignal;
74
+ return typeof ctor?.timeout === "function" ? ctor.timeout(ms) : void 0;
75
+ }
76
+ function rawTonAddress(a) {
77
+ try {
78
+ return Address.parse(a).toRawString().toLowerCase();
79
+ } catch {
80
+ return a.toLowerCase();
81
+ }
82
+ }
83
+ var big = (v) => {
84
+ if (typeof v === "bigint") return v;
85
+ if (typeof v === "number" && Number.isFinite(v)) return BigInt(Math.trunc(v));
86
+ if (typeof v === "string" && /^-?\d+$/.test(v)) return BigInt(v);
87
+ return 0n;
88
+ };
89
+ var isHexOp = (s) => typeof s === "string" && /^0x[0-9a-f]{1,8}$/i.test(s);
90
+ var jettonMeta = (j) => {
91
+ const m = {};
92
+ if (j?.symbol !== void 0) m.symbol = j.symbol;
93
+ if (j?.decimals !== void 0) m.decimals = j.decimals;
94
+ return m;
95
+ };
96
+ var addr = (a) => typeof a === "object" && a !== null && typeof a.address === "string" ? a.address.toLowerCase() : typeof a === "string" ? a.toLowerCase() : void 0;
97
+ var isWallet = (a) => typeof a === "object" && a !== null && a.is_wallet === true;
98
+ function mapActions(actions) {
99
+ const out = { transfers: [] };
100
+ const native = (from, to, amount) => {
101
+ if (from === void 0 || to === void 0 || amount <= 0n) return;
102
+ out.transfers.push({ token: null, from, to, amount });
103
+ };
104
+ const jetton = (j, from, to, amount) => {
105
+ if (!j || from === void 0 || to === void 0 || amount <= 0n) return;
106
+ out.transfers.push({ token: j.address.toLowerCase(), from, to, amount, standard: "jetton", ...jettonMeta(j) });
107
+ };
108
+ const setCall = (c) => {
109
+ if (c && !out.call) out.call = c;
110
+ };
111
+ const init = (a) => {
112
+ if (out.initiator === void 0 && a !== void 0) out.initiator = a;
113
+ };
114
+ for (const a of actions) {
115
+ const b = a[a.type] ?? {};
116
+ const ok = a.status === "ok";
117
+ switch (a.type) {
118
+ case "TonTransfer": {
119
+ const from = addr(b.sender), to = addr(b.recipient);
120
+ init(from);
121
+ if (ok) native(from, to, big(b.amount));
122
+ break;
123
+ }
124
+ case "JettonTransfer": {
125
+ const from = addr(b.sender) ?? addr(b.senders_wallet), to = addr(b.recipient) ?? addr(b.recipients_wallet);
126
+ init(from);
127
+ if (ok) jetton(b.jetton, from, to, big(b.amount));
128
+ if (to !== void 0 && b.recipient !== void 0 && !isWallet(b.recipient)) {
129
+ const c = { to, method: "jetton_transfer" };
130
+ const m = typeof b.comment === "string" ? /^Call:\s*(0x[0-9a-f]+)/i.exec(b.comment) : null;
131
+ if (m) c.data = m[1].toLowerCase();
132
+ setCall(c);
133
+ }
134
+ break;
135
+ }
136
+ case "JettonMint": {
137
+ const j = b.jetton;
138
+ if (ok) jetton(j, j?.address.toLowerCase(), addr(b.recipient) ?? addr(b.recipients_wallet), big(b.amount));
139
+ break;
140
+ }
141
+ case "JettonBurn": {
142
+ const j = b.jetton;
143
+ const from = addr(b.sender) ?? addr(b.senders_wallet);
144
+ init(from);
145
+ if (ok) jetton(j, from, j?.address.toLowerCase(), big(b.amount));
146
+ setCall(j ? { to: j.address.toLowerCase(), method: "jetton_burn" } : void 0);
147
+ break;
148
+ }
149
+ case "JettonSwap": {
150
+ const user = addr(b.user_wallet), router = addr(b.router);
151
+ init(user);
152
+ if (ok) {
153
+ native(user, router, big(b.ton_in));
154
+ jetton(b.jetton_master_in, user, router, big(b.amount_in));
155
+ native(router, user, big(b.ton_out));
156
+ jetton(b.jetton_master_out, router, user, big(b.amount_out));
157
+ }
158
+ if (router !== void 0) setCall({ to: router, method: "swap" });
159
+ break;
160
+ }
161
+ case "SmartContractExec": {
162
+ const executor = addr(b.executor), contract = addr(b.contract);
163
+ init(executor);
164
+ if (ok) native(executor, contract, big(b.ton_attached));
165
+ if (contract !== void 0) {
166
+ const c = { to: contract };
167
+ if (isHexOp(b.operation)) c.data = b.operation.toLowerCase();
168
+ else if (typeof b.operation === "string" && b.operation) c.method = b.operation;
169
+ setCall(c);
170
+ }
171
+ break;
172
+ }
173
+ case "DepositStake": {
174
+ const staker = addr(b.staker), pool = addr(b.pool);
175
+ init(staker);
176
+ if (ok) native(staker, pool, big(b.amount));
177
+ if (pool !== void 0) setCall({ to: pool, method: "stake" });
178
+ break;
179
+ }
180
+ case "WithdrawStakeRequest": {
181
+ const staker = addr(b.staker), pool = addr(b.pool);
182
+ init(staker);
183
+ if (ok && b.amount !== void 0) native(staker, pool, big(b.amount));
184
+ if (pool !== void 0) {
185
+ setCall({ to: pool, method: "unstake" });
186
+ if (ok) out.needsValueFlow ??= { counterparty: pool };
187
+ }
188
+ break;
189
+ }
190
+ case "WithdrawStake": {
191
+ const staker = addr(b.staker), pool = addr(b.pool);
192
+ init(pool);
193
+ if (ok) native(pool, staker, big(b.amount));
194
+ if (pool !== void 0) setCall({ to: pool, method: "withdraw_stake" });
195
+ break;
196
+ }
197
+ case "ElectionsDepositStake":
198
+ case "ElectionsRecoverStake": {
199
+ const staker = addr(b.staker);
200
+ init(staker);
201
+ if (ok) a.type === "ElectionsDepositStake" ? native(staker, "-1:3333333333333333333333333333333333333333333333333333333333333333", big(b.amount)) : native("-1:3333333333333333333333333333333333333333333333333333333333333333", staker, big(b.amount));
202
+ break;
203
+ }
204
+ case "Subscribe":
205
+ case "UnSubscribe": {
206
+ const subscriber = addr(b.subscriber), beneficiary = addr(b.beneficiary), subscription = addr(b.subscription);
207
+ init(subscriber);
208
+ if (ok && a.type === "Subscribe") native(subscriber, beneficiary, big(b.amount));
209
+ if (subscription !== void 0) setCall({ to: subscription, method: a.type === "Subscribe" ? "subscribe" : "unsubscribe" });
210
+ break;
211
+ }
212
+ case "NftPurchase": {
213
+ const buyer = addr(b.buyer), seller = addr(b.seller), nft = addr(b.nft);
214
+ init(buyer);
215
+ if (ok) native(buyer, seller, big(b.amount?.value ?? b.amount));
216
+ if (nft !== void 0) setCall({ to: nft, method: "nft_purchase" });
217
+ break;
218
+ }
219
+ case "ContractDeploy": {
220
+ const deployed = addr(b.address);
221
+ if (deployed !== void 0) setCall({ to: deployed, method: "deploy" });
222
+ break;
223
+ }
224
+ default:
225
+ break;
226
+ }
227
+ }
228
+ return out;
229
+ }
230
+ function valueFlowTransfers(event, own, counterparty) {
231
+ const flow = event.value_flow?.find((v) => addr(v.account) === own);
232
+ const out = [];
233
+ for (const j of flow?.jettons ?? []) {
234
+ const q = big(j.quantity);
235
+ if (q === 0n) continue;
236
+ const t = { token: j.jetton.address.toLowerCase(), from: q < 0n ? own : counterparty, to: q < 0n ? counterparty : own, amount: q < 0n ? -q : q, standard: "jetton", ...jettonMeta(j.jetton) };
237
+ out.push(t);
238
+ }
239
+ return out;
240
+ }
241
+ function mapTonapiEvent(chain, address, own, event, valueFlow) {
242
+ const mapped = mapActions(event.actions ?? []);
243
+ const transfers = mapped.transfers;
244
+ const raw = { backend: "tonapi", event };
245
+ if (mapped.needsValueFlow && valueFlow) {
246
+ raw.valueFlow = valueFlow.value_flow;
247
+ const extra = valueFlowTransfers(valueFlow, own, mapped.needsValueFlow.counterparty);
248
+ for (const t of extra) if (!transfers.some((x) => x.token === t.token && x.from === t.from && x.to === t.to && x.amount === t.amount)) transfers.push(t);
249
+ }
250
+ const from = mapped.initiator ?? own;
251
+ const involves = (t) => t.from === own || t.to === own;
252
+ const primary = transfers.find((t) => t.token !== null && involves(t)) ?? transfers.find(involves) ?? transfers[0];
253
+ const to = mapped.call?.to ?? primary?.to ?? null;
254
+ let nativeValue = 0n;
255
+ for (const t of transfers) if (t.token === null && t.from === from) nativeValue += t.amount;
256
+ const actions = event.actions ?? [];
257
+ const status = event.in_progress ? "pending" : actions.length > 0 && actions.every((a) => a.status !== "ok") ? "failed" : "confirmed";
258
+ const out = {
259
+ chain,
260
+ hash: event.event_id,
261
+ time: event.timestamp,
262
+ status,
263
+ address,
264
+ from,
265
+ to,
266
+ nativeValue,
267
+ transfers,
268
+ block: big(event.lt),
269
+ raw
270
+ };
271
+ if (typeof event.extra === "number" && event.extra < 0) out.fee = BigInt(-event.extra);
272
+ if (mapped.call) out.call = mapped.call;
273
+ if (event.is_scam) {
274
+ out.scam = true;
275
+ raw.scam = true;
276
+ }
277
+ return out;
278
+ }
279
+ var TEXT_COMMENT_OP = "0x00000000";
280
+ function mapToncenterTransaction(chain, address, row) {
281
+ const own = row.account.toLowerCase();
282
+ const hash = Buffer.from(row.hash, "base64").toString("hex");
283
+ const d = row.description;
284
+ const failed = d?.aborted === true || d?.compute_ph?.skipped !== true && d?.compute_ph?.success === false || d?.action?.success === false;
285
+ const transfers = [];
286
+ let from = own;
287
+ let to = null;
288
+ let call;
289
+ const source = row.in_msg?.source ? row.in_msg.source.toLowerCase() : void 0;
290
+ if (source === void 0) {
291
+ for (const m of row.out_msgs ?? []) {
292
+ const dest = m.destination?.toLowerCase();
293
+ if (!dest) continue;
294
+ const value = big(m.value);
295
+ if (value > 0n) transfers.push({ token: null, from: own, to: dest, amount: value });
296
+ if (!call && m.opcode && m.opcode !== TEXT_COMMENT_OP) {
297
+ call = { to: dest, data: m.opcode.toLowerCase() };
298
+ if (m.decoded_opcode) call.method = m.decoded_opcode;
299
+ }
300
+ to ??= dest;
301
+ }
302
+ } else {
303
+ from = source;
304
+ to = own;
305
+ const value = big(row.in_msg?.value);
306
+ if (value > 0n) transfers.push({ token: null, from: source, to: own, amount: value });
307
+ const op = row.in_msg?.opcode;
308
+ if (op && op !== TEXT_COMMENT_OP) {
309
+ call = { to: own, data: op.toLowerCase() };
310
+ if (row.in_msg?.decoded_opcode) call.method = row.in_msg.decoded_opcode;
311
+ }
312
+ }
313
+ let nativeValue = 0n;
314
+ for (const t of transfers) if (t.token === null && t.from === from) nativeValue += t.amount;
315
+ const out = {
316
+ chain,
317
+ hash,
318
+ time: row.now,
319
+ status: failed ? "failed" : "confirmed",
320
+ address,
321
+ from,
322
+ to: call?.to ?? to,
323
+ nativeValue,
324
+ transfers,
325
+ fee: big(row.total_fees),
326
+ block: big(row.lt),
327
+ raw: { backend: "toncenter", event: row }
328
+ };
329
+ if (call) out.call = call;
330
+ return out;
331
+ }
332
+ function tonExplorerTxUrl(hash, network = "mainnet") {
333
+ return `https://${network === "testnet" ? "testnet." : ""}tonviewer.com/transaction/${hash}`;
334
+ }
335
+ function createTonHistory(options = {}) {
336
+ const network = options.network ?? "mainnet";
337
+ const chain = CAIP2[network];
338
+ const fetchFn = options.fetch ?? globalThis.fetch;
339
+ if (typeof fetchFn !== "function") throw new Error("@anywalletkit/wallet-ton: no global fetch; pass `fetch` in the options");
340
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
341
+ const tonapiUrl = options.tonapiUrl === null ? void 0 : (options.tonapiUrl ?? (network === "testnet" ? "https://testnet.tonapi.io" : "https://tonapi.io")).replace(/\/+$/, "");
342
+ const toncenterUrl = options.toncenterUrl === null ? void 0 : (options.toncenterUrl ?? (network === "testnet" ? "https://testnet.toncenter.com" : "https://toncenter.com")).replace(/\/+$/, "");
343
+ if (!tonapiUrl && !toncenterUrl) throw new Error("@anywalletkit/wallet-ton: createTonHistory needs tonapi or toncenter");
344
+ const tonapiBucket = new TokenBucket(options.rateLimit ?? (options.apiKey ? 10 : 1));
345
+ const toncenterBucket = new TokenBucket(options.toncenterApiKey ? 10 : 1);
346
+ async function getJson(backend, url, headers) {
347
+ await (backend === "tonapi" ? tonapiBucket : toncenterBucket).acquire();
348
+ let res;
349
+ try {
350
+ const signal = timeoutSignal(timeoutMs);
351
+ res = await fetchFn(url, { headers: { accept: "application/json", ...headers }, ...signal ? { signal } : {} });
352
+ } catch (e) {
353
+ throw new Error(`${backend}: ${e instanceof Error ? e.message : String(e)}`);
354
+ }
355
+ let body;
356
+ try {
357
+ body = await res.json();
358
+ } catch {
359
+ body = void 0;
360
+ }
361
+ return { status: res.status, body };
362
+ }
363
+ const tonapiHeaders = () => options.apiKey ? { authorization: `Bearer ${options.apiKey}` } : {};
364
+ const toncenterHeaders = () => options.toncenterApiKey ? { "x-api-key": options.toncenterApiKey } : {};
365
+ const fail = (backend, r) => {
366
+ const msg = typeof r.body === "object" && r.body !== null && typeof r.body.error === "string" ? r.body.error : "";
367
+ throw new Error(`${backend}: HTTP ${r.status}${msg ? ` ${msg}` : ""}`);
368
+ };
369
+ async function tonapiEventFull(eventId) {
370
+ const r = await getJson("tonapi", `${tonapiUrl}/v2/events/${eventId}`, tonapiHeaders());
371
+ if (r.status === 404) return void 0;
372
+ if (r.status !== 200) fail("tonapi", r);
373
+ return r.body;
374
+ }
375
+ async function finishTonapi(address, own, event) {
376
+ const probe = mapActions(event.actions ?? []);
377
+ let flow;
378
+ if (probe.needsValueFlow) {
379
+ try {
380
+ flow = await tonapiEventFull(event.event_id);
381
+ } catch {
382
+ flow = void 0;
383
+ }
384
+ }
385
+ return mapTonapiEvent(chain, address, own, event, flow);
386
+ }
387
+ async function tonapiPage(address, own, limit, before) {
388
+ if (!tonapiUrl) throw new Error("tonapi: disabled");
389
+ const q = `limit=${limit}${before ? `&before_lt=${before}` : ""}`;
390
+ const r = await getJson("tonapi", `${tonapiUrl}/v2/accounts/${encodeURIComponent(address)}/events?${q}`, tonapiHeaders());
391
+ if (r.status !== 200) fail("tonapi", r);
392
+ const body = r.body;
393
+ const events = body?.events ?? [];
394
+ const items = [];
395
+ for (const e of events) items.push(await finishTonapi(address, own, e));
396
+ const page = { items, backend: "tonapi" };
397
+ if (events.length >= limit) {
398
+ const last = events[events.length - 1];
399
+ page.cursor = encodeCursor({ v: 1, b: "tonapi", lt: String(body?.next_from ?? last.lt) });
400
+ }
401
+ return page;
402
+ }
403
+ async function toncenterPage(address, limit, before) {
404
+ if (!toncenterUrl) throw new Error("toncenter: disabled");
405
+ const endLt = before ? (BigInt(before) - 1n).toString() : void 0;
406
+ const q = `account=${encodeURIComponent(address)}&limit=${limit}&sort=desc${endLt ? `&end_lt=${endLt}` : ""}`;
407
+ const r = await getJson("toncenter", `${toncenterUrl}/api/v3/transactions?${q}`, toncenterHeaders());
408
+ if (r.status !== 200) fail("toncenter", r);
409
+ const rows = r.body?.transactions ?? [];
410
+ const items = rows.map((row) => mapToncenterTransaction(chain, address, row));
411
+ const page = { items, backend: "toncenter" };
412
+ if (rows.length >= limit) page.cursor = encodeCursor({ v: 1, b: "toncenter", lt: rows[rows.length - 1].lt });
413
+ return page;
414
+ }
415
+ const backends = [...tonapiUrl ? ["tonapi"] : [], ...toncenterUrl ? ["toncenter"] : []];
416
+ return {
417
+ chain,
418
+ async listActivity(address, query = {}) {
419
+ const limit = Math.min(MAX_LIMIT, Math.max(1, Math.floor(query.limit ?? DEFAULT_LIMIT)));
420
+ const cursor = query.cursor ? decodeCursor(query.cursor) : void 0;
421
+ const own = rawTonAddress(address);
422
+ const ordered = cursor ? [...backends].sort((a, b) => a === cursor.b ? -1 : b === cursor.b ? 1 : 0) : backends;
423
+ const attempts = [];
424
+ for (const b of ordered) {
425
+ try {
426
+ let page = b === "tonapi" ? await tonapiPage(address, own, limit, cursor?.lt) : await toncenterPage(address, limit, cursor?.lt);
427
+ if (query.since !== void 0) {
428
+ const since = query.since;
429
+ if (page.items.some((t) => t.time < since)) delete page.cursor;
430
+ page = { ...page, items: page.items.filter((t) => t.time >= since) };
431
+ }
432
+ return page;
433
+ } catch (e) {
434
+ attempts.push(e instanceof Error ? e.message : String(e));
435
+ }
436
+ }
437
+ throw new HistoryUnavailableError(chain, attempts[attempts.length - 1] ?? "no backend configured", attempts);
438
+ },
439
+ async getTransaction(hash, address) {
440
+ const own = rawTonAddress(address);
441
+ const attempts = [];
442
+ for (const b of backends) {
443
+ try {
444
+ if (b === "tonapi") {
445
+ const r2 = await getJson("tonapi", `${tonapiUrl}/v2/accounts/${encodeURIComponent(address)}/events/${encodeURIComponent(hash)}`, tonapiHeaders());
446
+ if (r2.status === 404) return void 0;
447
+ if (r2.status !== 200) fail("tonapi", r2);
448
+ return await finishTonapi(address, own, r2.body);
449
+ }
450
+ const r = await getJson("toncenter", `${toncenterUrl}/api/v3/transactions?hash=${encodeURIComponent(hash)}`, toncenterHeaders());
451
+ if (r.status !== 200) fail("toncenter", r);
452
+ const rows = r.body?.transactions ?? [];
453
+ const row = rows.find((x) => x.account.toLowerCase() === own) ?? rows[0];
454
+ return row ? mapToncenterTransaction(chain, address, row) : void 0;
455
+ } catch (e) {
456
+ attempts.push(e instanceof Error ? e.message : String(e));
457
+ }
458
+ }
459
+ throw new HistoryUnavailableError(chain, attempts[attempts.length - 1] ?? "no backend configured", attempts);
460
+ },
461
+ explorerTxUrl(hash) {
462
+ return tonExplorerTxUrl(hash, network);
463
+ }
464
+ };
465
+ }
466
+
467
+ export {
468
+ CAIP2,
469
+ HistoryUnavailableError,
470
+ encodeCursor,
471
+ decodeCursor,
472
+ rawTonAddress,
473
+ mapActions,
474
+ valueFlowTransfers,
475
+ mapTonapiEvent,
476
+ mapToncenterTransaction,
477
+ tonExplorerTxUrl,
478
+ createTonHistory
479
+ };
480
+ //# sourceMappingURL=chunk-BLWBC6L2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/history.ts","../src/types.ts"],"sourcesContent":["/**\n * Activity history for TON: a `HistorySource` over tonapi account events\n * (`/v2/accounts/{a}/events`, keyless or with a Bearer key) with toncenter v3\n * (`/api/v3/transactions`) as a reduced fallback.\n *\n * tonapi groups a whole trace (the wallet's message and everything it caused)\n * into one event with typed actions; each action becomes native / jetton\n * transfers and the first contract-level action becomes `call`. The fee is\n * tonapi's `extra` (what the account lost beyond its actions). toncenter sees\n * only the account's own transactions: TON in / out and op codes, no jettons.\n * Addresses are kept raw (`0:…`, lowercase) as both indexers return them;\n * recognizers normalize. `fetch` + `AbortSignal.timeout` only — Hermes-safe.\n */\nimport { Address } from '@ton/core'\nimport { Buffer } from 'buffer'\nimport type { ChainCall, ChainTransfer, ChainTx, HistoryPage, HistoryQuery, HistorySource } from '@anywalletkit/core'\nimport { CAIP2 } from './types.js'\n\n// ── Public types ─────────────────────────────────────────────────────────────\n\nexport type HistoryFetch = (\n input: string,\n init?: { method?: string; headers?: Record<string, string>; signal?: AbortSignal },\n) => Promise<{ ok: boolean; status: number; json(): Promise<unknown> }>\n\n/** Which indexer answered: tonapi events or toncenter v3 transactions. */\nexport type TonHistoryBackend = 'tonapi' | 'toncenter'\n\n/** Options for `createTonHistory`: tonapi first, toncenter v3 as the fallback. */\nexport interface TonHistoryOptions {\n /** tonapi root. Default `https://tonapi.io` (`https://testnet.tonapi.io` on testnet). `null` disables tonapi. */\n tonapiUrl?: string | null\n /** tonapi Bearer key. Keyless tonapi allows ~1 request/s. */\n apiKey?: string\n /** toncenter root for the v3 fallback. Default `https://toncenter.com` (`https://testnet.toncenter.com`). `null` disables it. */\n toncenterUrl?: string | null\n /** toncenter `X-API-Key`. */\n toncenterApiKey?: string\n network?: 'mainnet' | 'testnet'\n fetch?: HistoryFetch\n /** tonapi requests per second. Default 1 without a key, 10 with one. */\n rateLimit?: number\n /** Per request, ms. Default 15 000. */\n timeoutMs?: number\n}\n\nexport interface TonHistoryRaw {\n backend: TonHistoryBackend\n /** The tonapi account event, or the toncenter v3 transaction row. */\n event: unknown\n /** tonapi flagged the event as scam. */\n scam?: boolean\n /** tonapi `value_flow` for the account when it had to be fetched to recover jetton movements. */\n valueFlow?: unknown\n}\n\nexport interface TonChainTx extends ChainTx {\n /** Mirrors `raw.scam`; the app hides these by default. */\n scam?: boolean\n raw: TonHistoryRaw\n}\n\nexport interface TonHistoryPage extends HistoryPage {\n items: TonChainTx[]\n backend?: TonHistoryBackend\n}\n\n/**\n * TON history from tonapi events with a toncenter v3 fallback. Build it with `createTonHistory`.\n */\nexport interface TonHistorySource extends HistorySource {\n listActivity(address: string, query?: HistoryQuery): Promise<TonHistoryPage>\n getTransaction(hash: string, address: string): Promise<TonChainTx | undefined>\n}\n\n/** Every configured history backend failed (or none was configured). */\nexport class HistoryUnavailableError extends Error {\n readonly chain: string\n readonly reason: string\n readonly attempts: readonly string[]\n constructor(chain: string, reason: string, attempts: readonly string[] = []) {\n super(`History unavailable for ${chain}: ${reason}`)\n this.name = 'HistoryUnavailableError'\n this.chain = chain\n this.reason = reason\n this.attempts = attempts\n }\n}\n\nconst DEFAULT_LIMIT = 25\nconst MAX_LIMIT = 100\nconst DEFAULT_TIMEOUT_MS = 15_000\n\n// ── Cursor: an exclusive `lt` upper bound, base64 JSON ───────────────────────\n\nexport interface TonHistoryCursor {\n v: 1\n b: TonHistoryBackend\n /** Next page = events / transactions with `lt < this` (decimal string). */\n lt: string\n}\n\nexport function encodeCursor(c: TonHistoryCursor): string {\n return Buffer.from(JSON.stringify(c), 'utf8').toString('base64')\n}\n\nexport function decodeCursor(s: string): TonHistoryCursor {\n let parsed: unknown\n try {\n parsed = JSON.parse(Buffer.from(s, 'base64').toString('utf8'))\n } catch {\n throw new Error('@anywalletkit/wallet-ton: malformed history cursor')\n }\n const c = parsed as Partial<TonHistoryCursor> | null\n if (!c || c.v !== 1 || (c.b !== 'tonapi' && c.b !== 'toncenter') || typeof c.lt !== 'string' || !/^\\d+$/.test(c.lt)) {\n throw new Error('@anywalletkit/wallet-ton: malformed history cursor')\n }\n return { v: 1, b: c.b, lt: c.lt }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nclass TokenBucket {\n private tokens: number\n private last = Date.now()\n private chain: Promise<void> = Promise.resolve()\n constructor(private readonly rate: number, private readonly burst = Math.max(1, Math.ceil(rate))) {\n this.tokens = burst\n }\n acquire(): Promise<void> {\n const next = this.chain.then(() => this.take())\n this.chain = next.catch(() => undefined)\n return next\n }\n private refill(): void {\n const now = Date.now()\n this.tokens = Math.min(this.burst, this.tokens + ((now - this.last) / 1000) * this.rate)\n this.last = now\n }\n private async take(): Promise<void> {\n this.refill()\n if (this.tokens >= 1) {\n this.tokens -= 1\n return\n }\n await new Promise((r) => setTimeout(r, Math.ceil(((1 - this.tokens) / this.rate) * 1000)))\n this.refill()\n this.tokens = Math.max(0, this.tokens - 1)\n }\n}\n\nfunction timeoutSignal(ms: number): AbortSignal | undefined {\n const ctor = (globalThis as { AbortSignal?: { timeout?: (ms: number) => AbortSignal } }).AbortSignal\n return typeof ctor?.timeout === 'function' ? ctor.timeout(ms) : undefined\n}\n\n/** Any spelling → raw lowercase `wc:hex`; unparsable input is returned as-is. */\nexport function rawTonAddress(a: string): string {\n try {\n return Address.parse(a).toRawString().toLowerCase()\n } catch {\n return a.toLowerCase()\n }\n}\n\nconst big = (v: unknown): bigint => {\n if (typeof v === 'bigint') return v\n if (typeof v === 'number' && Number.isFinite(v)) return BigInt(Math.trunc(v))\n if (typeof v === 'string' && /^-?\\d+$/.test(v)) return BigInt(v)\n return 0n\n}\n\nconst isHexOp = (s: unknown): s is string => typeof s === 'string' && /^0x[0-9a-f]{1,8}$/i.test(s)\n\n// ── tonapi shapes (what the mapper reads) ────────────────────────────────────\n\ninterface TonapiAccount { address: string; is_wallet?: boolean; is_scam?: boolean; name?: string }\ninterface TonapiJetton { address: string; symbol?: string; decimals?: number; name?: string }\nexport interface TonapiAction {\n type: string\n status: 'ok' | 'failed' | string\n [body: string]: unknown\n}\nexport interface TonapiEvent {\n event_id: string\n account?: TonapiAccount\n timestamp: number\n lt: number | string\n in_progress: boolean\n is_scam: boolean\n actions: TonapiAction[]\n /** Account-scoped events only: TON the account lost beyond its actions (negative = fees). */\n extra?: number\n value_flow?: Array<{ account: TonapiAccount; ton: number; jettons?: Array<{ jetton: TonapiJetton; quantity: number | string }> }>\n}\n\ninterface MappedActions {\n transfers: ChainTransfer[]\n call?: ChainCall\n /** Who initiated the event as far as the first action tells. */\n initiator?: string\n /** The event needs `value_flow` to recover a jetton movement tonapi did not spell out (unstake requests). */\n needsValueFlow?: { counterparty: string }\n}\n\nconst jettonMeta = (j: TonapiJetton | undefined): Pick<ChainTransfer, 'symbol' | 'decimals'> => {\n const m: Pick<ChainTransfer, 'symbol' | 'decimals'> = {}\n if (j?.symbol !== undefined) m.symbol = j.symbol\n if (j?.decimals !== undefined) m.decimals = j.decimals\n return m\n}\n\nconst addr = (a: unknown): string | undefined => (typeof a === 'object' && a !== null && typeof (a as TonapiAccount).address === 'string' ? (a as TonapiAccount).address.toLowerCase() : typeof a === 'string' ? a.toLowerCase() : undefined)\nconst isWallet = (a: unknown): boolean => typeof a === 'object' && a !== null && (a as TonapiAccount).is_wallet === true\n\n/** tonapi actions → transfers + the contract call. Only `ok` actions move value. */\nexport function mapActions(actions: TonapiAction[]): MappedActions {\n const out: MappedActions = { transfers: [] }\n const native = (from: string | undefined, to: string | undefined, amount: bigint) => {\n if (from === undefined || to === undefined || amount <= 0n) return\n out.transfers.push({ token: null, from, to, amount })\n }\n const jetton = (j: TonapiJetton | undefined, from: string | undefined, to: string | undefined, amount: bigint) => {\n if (!j || from === undefined || to === undefined || amount <= 0n) return\n out.transfers.push({ token: j.address.toLowerCase(), from, to, amount, standard: 'jetton', ...jettonMeta(j) })\n }\n const setCall = (c: ChainCall | undefined) => {\n if (c && !out.call) out.call = c\n }\n const init = (a: string | undefined) => {\n if (out.initiator === undefined && a !== undefined) out.initiator = a\n }\n for (const a of actions) {\n const b = (a[a.type] ?? {}) as Record<string, unknown>\n const ok = a.status === 'ok'\n switch (a.type) {\n case 'TonTransfer': {\n const from = addr(b.sender), to = addr(b.recipient)\n init(from)\n if (ok) native(from, to, big(b.amount))\n break\n }\n case 'JettonTransfer': {\n const from = addr(b.sender) ?? addr(b.senders_wallet), to = addr(b.recipient) ?? addr(b.recipients_wallet)\n init(from)\n if (ok) jetton(b.jetton as TonapiJetton, from, to, big(b.amount))\n // A jetton sent to a contract with a forward payload is a call; tonapi surfaces the op as \"Call: 0x…\".\n if (to !== undefined && b.recipient !== undefined && !isWallet(b.recipient)) {\n const c: ChainCall = { to, method: 'jetton_transfer' }\n const m = typeof b.comment === 'string' ? /^Call:\\s*(0x[0-9a-f]+)/i.exec(b.comment) : null\n if (m) c.data = m[1]!.toLowerCase()\n setCall(c)\n }\n break\n }\n case 'JettonMint': {\n const j = b.jetton as TonapiJetton | undefined\n if (ok) jetton(j, j?.address.toLowerCase(), addr(b.recipient) ?? addr(b.recipients_wallet), big(b.amount))\n break\n }\n case 'JettonBurn': {\n const j = b.jetton as TonapiJetton | undefined\n const from = addr(b.sender) ?? addr(b.senders_wallet)\n init(from)\n if (ok) jetton(j, from, j?.address.toLowerCase(), big(b.amount))\n setCall(j ? { to: j.address.toLowerCase(), method: 'jetton_burn' } : undefined)\n break\n }\n case 'JettonSwap': {\n const user = addr(b.user_wallet), router = addr(b.router)\n init(user)\n if (ok) {\n native(user, router, big(b.ton_in))\n jetton(b.jetton_master_in as TonapiJetton | undefined, user, router, big(b.amount_in))\n native(router, user, big(b.ton_out))\n jetton(b.jetton_master_out as TonapiJetton | undefined, router, user, big(b.amount_out))\n }\n if (router !== undefined) setCall({ to: router, method: 'swap' })\n break\n }\n case 'SmartContractExec': {\n const executor = addr(b.executor), contract = addr(b.contract)\n init(executor)\n if (ok) native(executor, contract, big(b.ton_attached))\n if (contract !== undefined) {\n const c: ChainCall = { to: contract }\n if (isHexOp(b.operation)) c.data = b.operation.toLowerCase()\n else if (typeof b.operation === 'string' && b.operation) c.method = b.operation\n setCall(c)\n }\n break\n }\n case 'DepositStake': {\n const staker = addr(b.staker), pool = addr(b.pool)\n init(staker)\n if (ok) native(staker, pool, big(b.amount))\n if (pool !== undefined) setCall({ to: pool, method: 'stake' })\n break\n }\n case 'WithdrawStakeRequest': {\n const staker = addr(b.staker), pool = addr(b.pool)\n init(staker)\n if (ok && b.amount !== undefined) native(staker, pool, big(b.amount))\n if (pool !== undefined) {\n setCall({ to: pool, method: 'unstake' })\n // tonapi does not spell out the pool-token burn; `value_flow` has it.\n if (ok) out.needsValueFlow ??= { counterparty: pool }\n }\n break\n }\n case 'WithdrawStake': {\n const staker = addr(b.staker), pool = addr(b.pool)\n init(pool)\n if (ok) native(pool, staker, big(b.amount))\n if (pool !== undefined) setCall({ to: pool, method: 'withdraw_stake' })\n break\n }\n case 'ElectionsDepositStake':\n case 'ElectionsRecoverStake': {\n const staker = addr(b.staker)\n init(staker)\n // The elector has no address in the action; keep the movement against the elector pseudo-account.\n if (ok) a.type === 'ElectionsDepositStake' ? native(staker, '-1:3333333333333333333333333333333333333333333333333333333333333333', big(b.amount)) : native('-1:3333333333333333333333333333333333333333333333333333333333333333', staker, big(b.amount))\n break\n }\n case 'Subscribe':\n case 'UnSubscribe': {\n const subscriber = addr(b.subscriber), beneficiary = addr(b.beneficiary), subscription = addr(b.subscription)\n init(subscriber)\n if (ok && a.type === 'Subscribe') native(subscriber, beneficiary, big(b.amount))\n if (subscription !== undefined) setCall({ to: subscription, method: a.type === 'Subscribe' ? 'subscribe' : 'unsubscribe' })\n break\n }\n case 'NftPurchase': {\n const buyer = addr(b.buyer), seller = addr(b.seller), nft = addr(b.nft)\n init(buyer)\n if (ok) native(buyer, seller, big((b.amount as { value?: unknown } | undefined)?.value ?? b.amount))\n if (nft !== undefined) setCall({ to: nft, method: 'nft_purchase' })\n break\n }\n case 'ContractDeploy': {\n const deployed = addr(b.address)\n if (deployed !== undefined) setCall({ to: deployed, method: 'deploy' })\n break\n }\n default:\n // NftItemTransfer, AuctionBid, DomainRenew, Unknown…: nothing to account for.\n break\n }\n }\n return out\n}\n\n/** The account's jetton deltas from `value_flow` as transfers against `counterparty`. */\nexport function valueFlowTransfers(event: TonapiEvent, own: string, counterparty: string): ChainTransfer[] {\n const flow = event.value_flow?.find((v) => addr(v.account) === own)\n const out: ChainTransfer[] = []\n for (const j of flow?.jettons ?? []) {\n const q = big(j.quantity)\n if (q === 0n) continue\n const t: ChainTransfer = { token: j.jetton.address.toLowerCase(), from: q < 0n ? own : counterparty, to: q < 0n ? counterparty : own, amount: q < 0n ? -q : q, standard: 'jetton', ...jettonMeta(j.jetton) }\n out.push(t)\n }\n return out\n}\n\nexport function mapTonapiEvent(chain: string, address: string, own: string, event: TonapiEvent, valueFlow?: TonapiEvent): TonChainTx {\n const mapped = mapActions(event.actions ?? [])\n const transfers = mapped.transfers\n const raw: TonHistoryRaw = { backend: 'tonapi', event }\n if (mapped.needsValueFlow && valueFlow) {\n raw.valueFlow = valueFlow.value_flow\n const extra = valueFlowTransfers(valueFlow, own, mapped.needsValueFlow.counterparty)\n for (const t of extra) if (!transfers.some((x) => x.token === t.token && x.from === t.from && x.to === t.to && x.amount === t.amount)) transfers.push(t)\n }\n const from = mapped.initiator ?? own\n const involves = (t: ChainTransfer) => t.from === own || t.to === own\n const primary = transfers.find((t) => t.token !== null && involves(t)) ?? transfers.find(involves) ?? transfers[0]\n const to = mapped.call?.to ?? primary?.to ?? null\n let nativeValue = 0n\n for (const t of transfers) if (t.token === null && t.from === from) nativeValue += t.amount\n const actions = event.actions ?? []\n const status: ChainTx['status'] = event.in_progress ? 'pending' : actions.length > 0 && actions.every((a) => a.status !== 'ok') ? 'failed' : 'confirmed'\n const out: TonChainTx = {\n chain, hash: event.event_id, time: event.timestamp, status, address, from, to, nativeValue, transfers, block: big(event.lt), raw,\n }\n if (typeof event.extra === 'number' && event.extra < 0) out.fee = BigInt(-event.extra)\n if (mapped.call) out.call = mapped.call\n if (event.is_scam) {\n out.scam = true\n raw.scam = true\n }\n return out\n}\n\n// ── toncenter v3 shapes ──────────────────────────────────────────────────────\n\ninterface V3Message {\n source?: string | null\n destination?: string | null\n value?: string | null\n opcode?: string | null\n decoded_opcode?: string | null\n}\nexport interface V3Transaction {\n account: string\n /** base64. */\n hash: string\n lt: string\n now: number\n total_fees: string\n description?: { aborted?: boolean; compute_ph?: { success?: boolean; exit_code?: number; skipped?: boolean }; action?: { success?: boolean } }\n in_msg?: V3Message | null\n out_msgs?: V3Message[]\n}\n\nconst TEXT_COMMENT_OP = '0x00000000'\n\n/** Reduced mapping: TON in / out and op codes of the account's own transaction; jettons are not visible here. */\nexport function mapToncenterTransaction(chain: string, address: string, row: V3Transaction): TonChainTx {\n const own = row.account.toLowerCase()\n const hash = Buffer.from(row.hash, 'base64').toString('hex')\n const d = row.description\n const failed = d?.aborted === true || (d?.compute_ph?.skipped !== true && d?.compute_ph?.success === false) || d?.action?.success === false\n const transfers: ChainTransfer[] = []\n let from = own\n let to: string | null = null\n let call: ChainCall | undefined\n const source = row.in_msg?.source ? row.in_msg.source.toLowerCase() : undefined\n if (source === undefined) {\n // External message: the wallet acted. Its outgoing messages are the transfers.\n for (const m of row.out_msgs ?? []) {\n const dest = m.destination?.toLowerCase()\n if (!dest) continue\n const value = big(m.value)\n if (value > 0n) transfers.push({ token: null, from: own, to: dest, amount: value })\n if (!call && m.opcode && m.opcode !== TEXT_COMMENT_OP) {\n call = { to: dest, data: m.opcode.toLowerCase() }\n if (m.decoded_opcode) call.method = m.decoded_opcode\n }\n to ??= dest\n }\n } else {\n from = source\n to = own\n const value = big(row.in_msg?.value)\n if (value > 0n) transfers.push({ token: null, from: source, to: own, amount: value })\n const op = row.in_msg?.opcode\n if (op && op !== TEXT_COMMENT_OP) {\n call = { to: own, data: op.toLowerCase() }\n if (row.in_msg?.decoded_opcode) call.method = row.in_msg.decoded_opcode\n }\n }\n let nativeValue = 0n\n for (const t of transfers) if (t.token === null && t.from === from) nativeValue += t.amount\n const out: TonChainTx = {\n chain, hash, time: row.now, status: failed ? 'failed' : 'confirmed', address, from, to: call?.to ?? to, nativeValue, transfers, fee: big(row.total_fees), block: big(row.lt),\n raw: { backend: 'toncenter', event: row },\n }\n if (call) out.call = call\n return out\n}\n\n// ── Source ───────────────────────────────────────────────────────────────────\n\n/** Tonviewer link for a transaction. */\nexport function tonExplorerTxUrl(hash: string, network: 'mainnet' | 'testnet' = 'mainnet'): string {\n return `https://${network === 'testnet' ? 'testnet.' : ''}tonviewer.com/transaction/${hash}`\n}\n\n/**\n * A `HistorySource` for TON: tonapi account events first, toncenter v3 when\n * tonapi is down or disabled. Both page by `lt`, so a cursor from one backend\n * resumes on the other.\n */\nexport function createTonHistory(options: TonHistoryOptions = {}): TonHistorySource {\n const network = options.network ?? 'mainnet'\n const chain = CAIP2[network]\n const fetchFn: HistoryFetch = options.fetch ?? ((globalThis as { fetch?: HistoryFetch }).fetch as HistoryFetch)\n if (typeof fetchFn !== 'function') throw new Error('@anywalletkit/wallet-ton: no global fetch; pass `fetch` in the options')\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const tonapiUrl = options.tonapiUrl === null ? undefined : (options.tonapiUrl ?? (network === 'testnet' ? 'https://testnet.tonapi.io' : 'https://tonapi.io')).replace(/\\/+$/, '')\n const toncenterUrl = options.toncenterUrl === null ? undefined : (options.toncenterUrl ?? (network === 'testnet' ? 'https://testnet.toncenter.com' : 'https://toncenter.com')).replace(/\\/+$/, '')\n if (!tonapiUrl && !toncenterUrl) throw new Error('@anywalletkit/wallet-ton: createTonHistory needs tonapi or toncenter')\n const tonapiBucket = new TokenBucket(options.rateLimit ?? (options.apiKey ? 10 : 1))\n const toncenterBucket = new TokenBucket(options.toncenterApiKey ? 10 : 1)\n\n async function getJson(backend: TonHistoryBackend, url: string, headers: Record<string, string>): Promise<{ status: number; body: unknown }> {\n await (backend === 'tonapi' ? tonapiBucket : toncenterBucket).acquire()\n let res: Awaited<ReturnType<HistoryFetch>>\n try {\n const signal = timeoutSignal(timeoutMs)\n res = await fetchFn(url, { headers: { accept: 'application/json', ...headers }, ...(signal ? { signal } : {}) })\n } catch (e) {\n throw new Error(`${backend}: ${e instanceof Error ? e.message : String(e)}`)\n }\n let body: unknown\n try {\n body = await res.json()\n } catch {\n body = undefined\n }\n return { status: res.status, body }\n }\n\n const tonapiHeaders = () => (options.apiKey ? { authorization: `Bearer ${options.apiKey}` } : {})\n const toncenterHeaders = () => (options.toncenterApiKey ? { 'x-api-key': options.toncenterApiKey } : {})\n\n const fail = (backend: TonHistoryBackend, r: { status: number; body: unknown }): never => {\n const msg = typeof r.body === 'object' && r.body !== null && typeof (r.body as { error?: unknown }).error === 'string' ? (r.body as { error: string }).error : ''\n throw new Error(`${backend}: HTTP ${r.status}${msg ? ` ${msg}` : ''}`)\n }\n\n async function tonapiEventFull(eventId: string): Promise<TonapiEvent | undefined> {\n const r = await getJson('tonapi', `${tonapiUrl}/v2/events/${eventId}`, tonapiHeaders())\n if (r.status === 404) return undefined\n if (r.status !== 200) fail('tonapi', r)\n return r.body as TonapiEvent\n }\n\n async function finishTonapi(address: string, own: string, event: TonapiEvent): Promise<TonChainTx> {\n const probe = mapActions(event.actions ?? [])\n let flow: TonapiEvent | undefined\n if (probe.needsValueFlow) {\n try {\n flow = await tonapiEventFull(event.event_id)\n } catch {\n flow = undefined // best effort: the row still carries the call\n }\n }\n return mapTonapiEvent(chain, address, own, event, flow)\n }\n\n async function tonapiPage(address: string, own: string, limit: number, before?: string): Promise<TonHistoryPage> {\n if (!tonapiUrl) throw new Error('tonapi: disabled')\n const q = `limit=${limit}${before ? `&before_lt=${before}` : ''}`\n const r = await getJson('tonapi', `${tonapiUrl}/v2/accounts/${encodeURIComponent(address)}/events?${q}`, tonapiHeaders())\n if (r.status !== 200) fail('tonapi', r)\n const body = r.body as { events?: TonapiEvent[]; next_from?: number | string } | undefined\n const events = body?.events ?? []\n const items: TonChainTx[] = []\n for (const e of events) items.push(await finishTonapi(address, own, e))\n const page: TonHistoryPage = { items, backend: 'tonapi' }\n if (events.length >= limit) {\n const last = events[events.length - 1]!\n page.cursor = encodeCursor({ v: 1, b: 'tonapi', lt: String(body?.next_from ?? last.lt) })\n }\n return page\n }\n\n async function toncenterPage(address: string, limit: number, before?: string): Promise<TonHistoryPage> {\n if (!toncenterUrl) throw new Error('toncenter: disabled')\n const endLt = before ? (BigInt(before) - 1n).toString() : undefined\n const q = `account=${encodeURIComponent(address)}&limit=${limit}&sort=desc${endLt ? `&end_lt=${endLt}` : ''}`\n const r = await getJson('toncenter', `${toncenterUrl}/api/v3/transactions?${q}`, toncenterHeaders())\n if (r.status !== 200) fail('toncenter', r)\n const rows = (r.body as { transactions?: V3Transaction[] } | undefined)?.transactions ?? []\n const items = rows.map((row) => mapToncenterTransaction(chain, address, row))\n const page: TonHistoryPage = { items, backend: 'toncenter' }\n if (rows.length >= limit) page.cursor = encodeCursor({ v: 1, b: 'toncenter', lt: rows[rows.length - 1]!.lt })\n return page\n }\n\n const backends: TonHistoryBackend[] = [...(tonapiUrl ? ['tonapi' as const] : []), ...(toncenterUrl ? ['toncenter' as const] : [])]\n\n return {\n chain,\n\n async listActivity(address: string, query: HistoryQuery = {}): Promise<TonHistoryPage> {\n const limit = Math.min(MAX_LIMIT, Math.max(1, Math.floor(query.limit ?? DEFAULT_LIMIT)))\n const cursor = query.cursor ? decodeCursor(query.cursor) : undefined\n const own = rawTonAddress(address)\n const ordered = cursor ? [...backends].sort((a, b) => (a === cursor.b ? -1 : b === cursor.b ? 1 : 0)) : backends\n const attempts: string[] = []\n for (const b of ordered) {\n try {\n let page = b === 'tonapi' ? await tonapiPage(address, own, limit, cursor?.lt) : await toncenterPage(address, limit, cursor?.lt)\n if (query.since !== undefined) {\n const since = query.since\n if (page.items.some((t) => t.time < since)) delete page.cursor\n page = { ...page, items: page.items.filter((t) => t.time >= since) }\n }\n return page\n } catch (e) {\n attempts.push(e instanceof Error ? e.message : String(e))\n }\n }\n throw new HistoryUnavailableError(chain, attempts[attempts.length - 1] ?? 'no backend configured', attempts)\n },\n\n async getTransaction(hash: string, address: string): Promise<TonChainTx | undefined> {\n const own = rawTonAddress(address)\n const attempts: string[] = []\n for (const b of backends) {\n try {\n if (b === 'tonapi') {\n const r = await getJson('tonapi', `${tonapiUrl}/v2/accounts/${encodeURIComponent(address)}/events/${encodeURIComponent(hash)}`, tonapiHeaders())\n if (r.status === 404) return undefined\n if (r.status !== 200) fail('tonapi', r)\n return await finishTonapi(address, own, r.body as TonapiEvent)\n }\n const r = await getJson('toncenter', `${toncenterUrl}/api/v3/transactions?hash=${encodeURIComponent(hash)}`, toncenterHeaders())\n if (r.status !== 200) fail('toncenter', r)\n const rows = (r.body as { transactions?: V3Transaction[] } | undefined)?.transactions ?? []\n const row = rows.find((x) => x.account.toLowerCase() === own) ?? rows[0]\n return row ? mapToncenterTransaction(chain, address, row) : undefined\n } catch (e) {\n attempts.push(e instanceof Error ? e.message : String(e))\n }\n }\n throw new HistoryUnavailableError(chain, attempts[attempts.length - 1] ?? 'no backend configured', attempts)\n },\n\n explorerTxUrl(hash: string): string {\n return tonExplorerTxUrl(hash, network)\n },\n }\n}\n","import type { Cell, StateInit } from '@ton/core'\n\n/** A toncenter v2 JSON-RPC endpoint (api keys there are meant for client-side wallets). */\nexport interface TonEndpoint { url: string; secretKey?: string }\n\n/** Anything that can answer a toncenter v2 JSON-RPC call (an endpoint wrapper, a test double, a proxy). */\nexport interface TonRpc {\n call<T = unknown>(method: string, params: Record<string, unknown>): Promise<T>\n}\n\n/** A toncenter endpoint (URL and optional key) or a ready `TonRpc`. */\nexport type TonProvider = TonEndpoint | TonRpc\n\n/**\n * Options for a TON wallet manager or account: toncenter endpoints, network, fee caps and emulation\n * before signing.\n */\nexport interface TonConfig {\n /** toncenter endpoint(s) or `TonRpc`(s). A list fails over in order. Omit for an offline (sign-only) wallet. */\n tonClient?: TonProvider | TonProvider[]\n /** Alias of `tonClient`. */\n provider?: TonProvider | TonProvider[]\n /** Extra rounds across the endpoint list after the first full pass (default 3). */\n retries?: number\n /** Per-request timeout in ms (default 15 000). */\n timeoutMs?: number\n /** Injectable fetch (tests, custom agents). Defaults to globalThis.fetch. */\n fetch?: typeof fetch\n /** Max fee (nanotons) for `transfer`. */\n transferMaxFee?: bigint | number\n /** Max fee (nanotons) for `sendTransaction` / `signTransaction`. */\n transactionMaxFee?: bigint | number\n /** toncenter v3 base used for receipts (default https://toncenter.com/api/v3). */\n indexerUrl?: string\n /** tonapi base used for fee rates and (by default) emulation (default https://tonapi.io/v2). */\n tonApiUrl?: string\n /** tonapi bearer key (sent as `Authorization: Bearer …`); also sent as X-API-Key to a toncenter-v3 emulator. */\n tonApiKey?: string\n /**\n * Preflight emulation of every send (zero-signed external). Default\n * `{kind: 'tonapi'}`: `POST {tonApiUrl}/wallet/emulate` (verdict + `risk`),\n * falling back to `/traces/emulate`. `{kind: 'toncenter-v3', url}` posts to a\n * toncenter `emulateTrace` endpoint instead. `false` = `estimateFee` only.\n * A non-zero compute exit, an aborted transaction, a failed action phase or a\n * failed FIRST-HOP internal message throws `SimulationError` before signing.\n */\n emulate?: TonEmulateConfig\n /** @deprecated Use `emulate: {kind: 'toncenter-v3', url}`. Still honoured when `emulate` is unset. */\n emulateUrl?: string\n /**\n * Allow a body whose emulated `risk.transfer_all_remaining_balance` is true\n * (send mode 128 / CARRY_ALL_BALANCE). Refused by default — nothing this\n * wallet builds does that, so it only ever comes from a foreign `bodyBoc`.\n */\n allowDrainingTransactions?: boolean\n /** Run the preflight (estimateFee + emulation when configured) before signing. Default true. */\n simulate?: boolean\n /** Seconds a signed external stays valid (default 60, max 600). */\n validUntilSeconds?: number\n /** Nanotons attached to a jetton transfer on top of `forwardTonAmount` (default 0.05 TON). */\n jettonAttachedValue?: bigint | number | string\n /**\n * 'mainnet' (ton:-239, default) or 'testnet' (ton:-3). Sets the CAIP-2 id, the address flags and the\n * wallet_id network (-239 / -3), so a testnet wallet has its own address and its signed messages are\n * not valid on mainnet (as in Tonkeeper and @ton/ton).\n */\n network?: 'mainnet' | 'testnet'\n /**\n * V5R1 wallet_id parts. Defaults (network id from `network`, subwallet 0) give the\n * addresses Tonkeeper and Tonhub derive for a key; change the subwallet only to\n * reach a wallet that was created with a different one. A networkGlobalId that\n * contradicts `network` is refused.\n */\n walletId?: { networkGlobalId?: number; subwalletNumber?: number }\n}\n\n/** One internal message. `value` in nanotons. `body`: text comment or a Cell; `bodyBoc`: the same as base64 BoC. */\nexport interface TonTransaction {\n to: string\n value: bigint | number | string\n /** Defaults to the flag in a friendly address (EQ… bounceable, UQ… not); raw addresses default to bounceable. */\n bounceable?: boolean\n body?: string | Cell\n /** Prebuilt message body as base64 BoC (e.g. an Omniston escrow payload). Ignored when `body` is set. */\n bodyBoc?: string\n /** StateInit to attach (deploys the destination): `{code, data}`, a StateInit cell, or its base64 BoC. */\n stateInit?: StateInit | Cell | string\n /** Send mode for this message (default PAY_GAS_SEPARATELY; IGNORE_ERRORS is always OR-ed in for externals). */\n sendMode?: number\n}\n\n/**\n * What `sendTransaction` / `signTransaction` accept: one message, several\n * messages in ONE external (up to 255 — swaps need it), or an already signed\n * V5R1 external-message body Cell.\n */\nexport type TonSendable = TonTransaction | TonTransaction[] | Cell\n\n/** A native TON or jetton transfer. Amount in nanotons or the jetton's base units. */\nexport interface TonTransferOptions {\n /** Jetton master address. Omit for native TON. */\n token?: string\n /** Wallet address that receives (for a jetton, its owner, not its jetton wallet). */\n recipient: string\n amount: bigint | number | string\n /** Jetton only: nanotons forwarded to the recipient with the transfer notification (default 1). */\n forwardTonAmount?: bigint | number | string\n /** Jetton only: forward payload — a text comment or a Cell (DEX / escrow payloads). */\n forwardPayload?: Cell | string\n /**\n * Text memo (a deposit memo, an exchange tag). Jetton: sent as the forward-payload comment (TEP-74);\n * native TON: the message comment. Cannot be combined with `forwardPayload`.\n */\n memo?: string\n /** Jetton only: custom payload cell (rarely needed; e.g. mintless jettons). */\n customPayload?: Cell\n /** Jetton only: where excess TON returns (default: this wallet). */\n responseDestination?: string\n /** Jetton only: query id (default random). */\n queryId?: bigint | number\n /** Jetton only: nanotons attached to the jetton-wallet call (default config.jettonAttachedValue + forwardTonAmount). */\n attachedValue?: bigint | number | string\n}\n\n/** toncenter `estimateFee` source fees, nanotons. */\nexport interface TonFees {\n inFwdFee: bigint\n storageFee: bigint\n gasFee: bigint\n fwdFee: bigint\n /** Sum of the four. */\n total: bigint\n}\n\n/**\n * Where to emulate a transaction before signing: tonapi, a toncenter v3 endpoint, or `false` for a\n * fee estimate only.\n */\nexport type TonEmulateConfig =\n | { kind: 'tonapi'; url?: string }\n | { kind: 'toncenter-v3'; url: string }\n | false\n\n/** What a message would move out of the wallet, per tonapi's `risk`. */\nexport interface TonRisk {\n /** Nanotons leaving the wallet (value + fees the emulator attributes). */\n ton: bigint\n jettons: Array<{ address: string; walletAddress: string; amount: bigint; symbol?: string; decimals?: number }>\n /** Send mode 128: the whole remaining balance goes with the message. */\n transferAllRemainingBalance: boolean\n}\n\n/**\n * Which service produced a simulation; `estimate-only` means fees were estimated without emulation.\n */\nexport type TonSimulationSource = 'tonapi' | 'toncenter-v3' | 'estimate-only'\n\n/**\n * Outcome of a simulation: the fees and, when emulated, whether the wallet transaction and its\n * actions succeeded.\n */\nexport type TonSimulation =\n | { ok: true; fees: TonFees; emulated: boolean; source: TonSimulationSource; exitCode?: number; actionSuccess?: boolean; risk?: TonRisk; warnings: string[] }\n | { ok: false; fees?: TonFees; emulated: true; source: Exclude<TonSimulationSource, 'estimate-only'>; reason: string; exitCode?: number; aborted?: boolean; risk?: TonRisk; warnings: string[] }\n\n/** Outcome of a sent wallet transaction, found by the body hash `sendTransaction` returned. */\nexport interface TonReceipt {\n /** The body hash that was returned by sendTransaction. */\n hash: string\n /** 1 when the wallet transaction completed without abort, 0 otherwise. */\n status: 0 | 1\n /** Logical time of the account transaction. */\n blockNumber: bigint\n /** Account transaction hash (base64). */\n transactionHash: string\n /** Fees of the account transaction, in nanotons. */\n totalFees: bigint\n /** The raw @ton/core Transaction. */\n raw: unknown\n}\n\n/** CAIP-2 ids of TON mainnet and testnet. */\nexport const CAIP2: Record<'mainnet' | 'testnet', string> = { mainnet: 'ton:-239', testnet: 'ton:-3' }\n"],"mappings":"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","names":["r"]}