@render-foundation/utils 0.0.254 → 0.0.256

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.
@@ -1 +1 @@
1
- {"version":3,"file":"dispersed.js","sourceRoot":"","sources":["../../../../src/client/dispersed.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispersed.js","sourceRoot":"","sources":["../../../../src/client/dispersed.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../src/client/pg/base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../src/client/pg/base.ts"],"names":[],"mappings":"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"}
@@ -33,34 +33,114 @@ BigInt.prototype.toJSON = function () {
33
33
  // confirmed_amount = EUR, despite the column name); 1 render credit = EUR 0.25, so credits = EUR x 4.
34
34
  // job.render_amt / user_grant_spend.render_spent_delta are credits x 1e8.
35
35
  export const EUR_TO_CREDITS = BigInt(4);
36
+ // Grant accounting window: otoy_grant mirrors OTOY RFG issuances from this date. Consumption against the
37
+ // window counts EVERY job the user ran in it — buy-and-burn jobs consumed OTOY credits exactly like
38
+ // emissions-funded ones (counting only emissions-attributed spend over-issued ~2.58M credits, 2026-08-04).
39
+ export const GRANT_WINDOW_START = '2025-05-01';
36
40
  export const CREDIT_DECIMALS = BigInt(100000000); // 1e8
37
- /**
38
- * Pure core of the grant allotment: fold a user's OTOY grants against what's already been spent.
39
- *
40
- * consumed = attributedSpend (spend already stamped with an otoy_grant_id)
41
- * + correctionSettled (jobs whose grant is already being settled by a burn_correction)
42
- *
43
- * The correctionSettled term is the DOUBLE-SPEND GUARD: an escrow_credit correction means we're
44
- * recovering that job's dollars from escrow, so its grant is already committed. Counting it here stops
45
- * the same grant from also funding a future emissions burn.
46
- *
47
- * fifoGrantId = the oldest grant still holding room, i.e. the one the next spend draws from.
48
- */
49
- export const foldGrantAllotment = (grants, attributedSpend, correctionSettled) => {
50
- const granted = grants.reduce((s, g) => s + g.amountCredits, BigInt(0));
51
- const consumed = (attributedSpend > BigInt(0) ? attributedSpend : BigInt(0)) +
52
- (correctionSettled > BigInt(0) ? correctionSettled : BigInt(0));
53
- const avail = granted > consumed ? granted - consumed : BigInt(0);
54
- let drawn = consumed;
41
+ // A grant is consumable for this long after issuance; whatever is left after that EXPIRES (2026-08-05
42
+ // model change). A job can only draw grants issued within the lookback window before it ran.
43
+ export const GRANT_LOOKBACK_DAYS = 60;
44
+ export const GRANT_LOOKBACK_MS = GRANT_LOOKBACK_DAYS * 24 * 3600 * 1000;
45
+ export const foldGrantWindow = (events, opts = {}) => {
46
+ const lookback = opts.lookbackMs ?? GRANT_LOOKBACK_MS;
47
+ const now = opts.now ?? Date.now();
48
+ const sorted = [...events].sort((a, b) => a.t - b.t || (a.amt > b.amt ? -1 : 1)); // credits first on ties
49
+ const buckets = [];
50
+ const jobs = [];
51
+ const remaining = (b) => b.amount - b.reversed - b.drawnEmissions - b.drawnMisrouted;
52
+ let beyond = BigInt(0);
53
+ for (const e of sorted) {
54
+ if (e.src === 'grant') {
55
+ if (e.amt > BigInt(0)) {
56
+ buckets.push({
57
+ grantId: e.grantId,
58
+ t: e.t,
59
+ amount: e.amt,
60
+ reversed: BigInt(0),
61
+ drawnEmissions: BigInt(0),
62
+ drawnMisrouted: BigInt(0),
63
+ expired: BigInt(0),
64
+ left: BigInt(0),
65
+ });
66
+ }
67
+ else {
68
+ let claw = -e.amt; // clawback hits remaining capacity oldest-first; excess is dropped
69
+ for (const b of buckets) {
70
+ if (claw <= BigInt(0))
71
+ break;
72
+ const take = remaining(b) < claw ? remaining(b) : claw;
73
+ if (take > BigInt(0)) {
74
+ b.reversed += take;
75
+ claw -= take;
76
+ }
77
+ }
78
+ }
79
+ }
80
+ else {
81
+ let need = -e.amt;
82
+ const total = need;
83
+ let emissionsLeft = e.emissions ?? need; // no split provided -> count it all as emissions
84
+ let jobEm = BigInt(0);
85
+ let jobMis = BigInt(0);
86
+ for (const b of buckets) {
87
+ if (need <= BigInt(0))
88
+ break;
89
+ if (b.t + lookback < e.t)
90
+ continue; // grant expired before this job ran
91
+ const take = remaining(b) < need ? remaining(b) : need;
92
+ if (take <= BigInt(0))
93
+ continue;
94
+ const em = emissionsLeft < take ? emissionsLeft : take;
95
+ b.drawnEmissions += em;
96
+ b.drawnMisrouted += take - em;
97
+ jobEm += em;
98
+ jobMis += take - em;
99
+ emissionsLeft -= em;
100
+ need -= take;
101
+ }
102
+ beyond += need;
103
+ jobs.push({
104
+ id: e.id,
105
+ t: e.t,
106
+ need: total,
107
+ drawnEmissions: jobEm,
108
+ drawnMisrouted: jobMis,
109
+ beyond: need,
110
+ });
111
+ }
112
+ }
113
+ let avail = BigInt(0);
114
+ let expired = BigInt(0);
115
+ let usedEmissions = BigInt(0);
116
+ let usedMisrouted = BigInt(0);
55
117
  let fifoGrantId;
56
- for (const g of grants) {
57
- if (drawn < g.amountCredits) {
58
- fifoGrantId = g.id;
59
- break;
118
+ for (const b of buckets) {
119
+ usedEmissions += b.drawnEmissions;
120
+ usedMisrouted += b.drawnMisrouted;
121
+ const rem = remaining(b);
122
+ if (b.t + lookback < now) {
123
+ b.expired = rem;
60
124
  }
61
- drawn -= g.amountCredits;
125
+ else {
126
+ b.left = rem;
127
+ avail += rem;
128
+ if (fifoGrantId === undefined && rem > BigInt(0) && b.grantId !== undefined)
129
+ fifoGrantId = b.grantId;
130
+ }
131
+ expired += b.expired;
62
132
  }
63
- return { granted, consumed, avail, fifoGrantId };
133
+ return {
134
+ avail,
135
+ beyondGrants: beyond,
136
+ jobCharged: usedEmissions + usedMisrouted,
137
+ usedEmissions,
138
+ usedMisrouted,
139
+ expired,
140
+ buckets,
141
+ jobs,
142
+ fifoGrantId,
143
+ };
64
144
  };
65
145
  import { begin } from './base';
66
146
  import moment from 'moment';
@@ -190,63 +270,50 @@ export const pgClient = (config) => {
190
270
  const out = {};
191
271
  if (!p.userIds.length)
192
272
  return out;
193
- const grants = await db
194
- .selectFrom(OTOY_GRANT_TABLE)
195
- .select(['id', 'user_id', 'amount_credits', 'otoy_created_at'])
196
- .where('user_id', 'in', p.userIds)
197
- .orderBy('otoy_created_at', 'asc')
198
- .orderBy('id', 'asc')
199
- .execute();
200
- if (!grants.length)
201
- return out;
202
- // Anything already booked against a pool grant, in EITHER direction:
203
- // - negative delta = spend drawn from the grant (this mechanism)
204
- // - positive delta = the grant was CREDITED into current_user_grant_spend (the one-off canary
205
- // route). That balance is already handed to the caller separately, so leaving it in the pool too
206
- // would hand out the same grant twice.
207
- // Hence abs(): both directions retire pool capacity.
208
- const spent = await db
209
- .selectFrom(USER_GRANT_SPEND_TABLE)
210
- .select((eb) => [
211
- 'user_id',
212
- eb.fn.sum(sql `abs(render_spent_delta)`).as('net'),
213
- ])
214
- .where('user_id', 'in', p.userIds)
215
- .where('otoy_grant_id', 'is not', null)
216
- .groupBy('user_id')
217
- .execute();
218
- // jobs already settled by a burn correction — their grant is spoken for (double-spend guard)
219
- const corrected = await db
220
- .selectFrom(`${JOB_TABLE} as j`)
221
- .innerJoin(`${BURN_CORRECTION_TABLE} as bc`, 'bc.job_id', 'j.id')
222
- .select((eb) => ['j.user_id as user_id', eb.fn.sum('j.render_amt').as('amt')])
223
- .where('j.user_id', 'in', p.userIds)
224
- .groupBy('j.user_id')
225
- .execute();
226
- const spentBy = new Map(spent.map((r) => [r.user_id, BigInt(r.net ?? 0)]));
227
- const corrBy = new Map(corrected.map((r) => [r.user_id, BigInt(r.amt ?? 0)]));
228
- for (const g of grants) {
229
- const u = g.user_id;
230
- const cur = out[u] ??
231
- (out[u] = { userId: u, granted: BigInt(0), consumed: BigInt(0), avail: BigInt(0), grants: [] });
232
- // amount_credits is numeric EUR — truncate to whole base units after the x4 conversion
233
- const credits = (BigInt(Math.round(Number(g.amount_credits) * 1e8)) * EUR_TO_CREDITS);
234
- cur.granted += credits;
235
- cur.grants.push({
236
- id: Number(g.id),
237
- amountCredits: credits,
238
- createdAt: g.otoy_created_at ? new Date(g.otoy_created_at) : null,
273
+ // Raw event stream, folded in code (foldGrantWindow — per-grant buckets, 60-day consumable window,
274
+ // reversals clamp capacity, only jobs create beyond-grants). SQL can't express the bucketed clamp.
275
+ const evRes = await sql `
276
+ select user_id::text as u, coalesce(otoy_created_at, ${GRANT_WINDOW_START}::timestamp) as t,
277
+ (amount_credits * 4 * 1e8)::numeric::text as amt, 'grant' as src, id as gid
278
+ from otoy_grant where user_id = any(${p.userIds}::uuid[])
279
+ union all
280
+ select user_id::text, ${GRANT_WINDOW_START}::timestamp, sum(render_spent_delta)::text, 'grant', null
281
+ from user_grant_spend
282
+ where user_id = any(${p.userIds}::uuid[]) and render_spent_delta > 0 and otoy_grant_id is null
283
+ group by user_id
284
+ union all
285
+ select user_id::text, created_at, (-render_spent_delta)::text, 'grant', null
286
+ from user_grant_spend
287
+ where user_id = any(${p.userIds}::uuid[]) and render_spent_delta > 0 and otoy_grant_id is not null
288
+ union all
289
+ select user_id, completed_at, (-render_amt)::text, 'job', null
290
+ from job
291
+ where user_id = any(${p.userIds}::text[]) and completed_at >= ${GRANT_WINDOW_START}::timestamp
292
+ `.execute(db); // db is always a Kysely trx at runtime
293
+ const byUser = new Map();
294
+ for (const r of evRes.rows) {
295
+ const arr = byUser.get(r.u) ?? [];
296
+ arr.push({
297
+ t: new Date(r.t).getTime(),
298
+ amt: BigInt(Math.round(Number(r.amt))),
299
+ src: r.src,
300
+ grantId: r.gid ?? undefined,
239
301
  });
302
+ byUser.set(r.u, arr);
240
303
  }
241
- for (const u of Object.keys(out)) {
242
- const attributed = spentBy.get(u) ?? BigInt(0); // abs() — spend drawn or grant already credited
243
- const viaCorrection = corrBy.get(u) ?? BigInt(0);
244
- const f = foldGrantAllotment(out[u].grants, attributed, viaCorrection);
245
- out[u].granted = f.granted;
246
- out[u].consumed = f.consumed;
247
- out[u].avail = f.avail;
248
- if (viaCorrection > BigInt(0)) {
249
- log.info(`grant allotment ${u}: granted ${f.granted} - attributed ${attributed} - correction-settled ${viaCorrection} = ${f.avail}`);
304
+ for (const [u, events] of byUser) {
305
+ const f = foldGrantWindow(events);
306
+ out[u] = {
307
+ userId: u,
308
+ granted: events.reduce((a, e) => (e.src === 'grant' && e.amt > BigInt(0) ? a + e.amt : a), BigInt(0)),
309
+ consumed: f.jobCharged,
310
+ avail: f.avail,
311
+ expired: f.expired,
312
+ fifoGrantId: f.fifoGrantId,
313
+ };
314
+ if (f.beyondGrants > BigInt(0)) {
315
+ log.info(`grant allotment ${u}: ${f.beyondGrants} beyond grants (purchase-paid at the time), ` +
316
+ `${f.expired} expired past the ${GRANT_LOOKBACK_DAYS}d window — avail ${f.avail}`);
250
317
  }
251
318
  }
252
319
  return out;
@@ -328,7 +395,7 @@ export const pgClient = (config) => {
328
395
  const sequenceNumbers = [];
329
396
  const dbEpochIds = [];
330
397
  for (const bt of bts) {
331
- let { solKey: toSolKey, seq, createdAt, amount, upgradeBracket, priorSupply, points, epochId, } = bt;
398
+ let { solKey: toSolKey, seq, createdAt, amount, upgradeBracket, priorSupply, points, epochId, sender, } = bt;
332
399
  let entityId;
333
400
  if (toSolKey && toSolKey != '') {
334
401
  entityId = await getOrInsertEntity(db, { solKey: toSolKey });
@@ -349,6 +416,7 @@ export const pgClient = (config) => {
349
416
  prior_supply: priorSupply,
350
417
  points: points,
351
418
  epoch_id: dbEpochId,
419
+ sender: sender,
352
420
  })
353
421
  .onConflict((oc) => oc.column('sequence').doUpdateSet({
354
422
  created_at: createdAt,
@@ -358,6 +426,7 @@ export const pgClient = (config) => {
358
426
  points: points,
359
427
  epoch_id: dbEpochId,
360
428
  entity_id: entityId,
429
+ sender: sender,
361
430
  }))
362
431
  .returning('sequence');
363
432
  const c = q.compile();
@@ -1100,16 +1169,13 @@ export const pgClient = (config) => {
1100
1169
  return;
1101
1170
  }
1102
1171
  }
1103
- // FIFO-attribute this spend to the user's oldest OTOY grant that still has room. Stamping
1104
- // otoy_grant_id is what makes getGrantAllotments count it as consumed an unattributed row
1105
- // would leave the grant looking unspent and let it fund a second burn.
1172
+ // FIFO-attribute this spend to the user's oldest LIVE OTOY grant that still has room (the fold
1173
+ // already applies the lookback window). Stamping otoy_grant_id is what shows the draw in the
1174
+ // admin drill-down — an unattributed row would leave the grant looking unspent there.
1106
1175
  let otoyGrantId = p.otoyGrantId;
1107
1176
  if (otoyGrantId === undefined && p.renderSpentDelta < BigInt(0)) {
1108
1177
  const allots = await getGrantAllotments(db.trx, { userIds: [p.userId] }, log);
1109
- const a = allots[p.userId];
1110
- if (a) {
1111
- otoyGrantId = foldGrantAllotment(a.grants, a.consumed, BigInt(0)).fifoGrantId;
1112
- }
1178
+ otoyGrantId = allots[p.userId]?.fifoGrantId;
1113
1179
  }
1114
1180
  const v = {
1115
1181
  user_id: p.userId,
@@ -1462,133 +1528,70 @@ export const pgClient = (config) => {
1462
1528
  return burns;
1463
1529
  },
1464
1530
  async fetchBurnsPage(db, f, log = consoleLogger) {
1465
- const params = [];
1466
- const p = (v) => {
1467
- params.push(v);
1468
- return `$${params.length}`;
1469
- };
1470
- // Decode cursor — supports new {t,id,ea} format and legacy bare-id format.
1471
- let cursorEa;
1472
- let cursorType;
1473
- let cursorId;
1474
- if (f.cursor) {
1475
- const raw = atob(f.cursor);
1476
- try {
1477
- const c = JSON.parse(raw);
1478
- cursorEa = new Date(c.ea);
1479
- cursorType = c.t;
1480
- cursorId = c.id;
1481
- }
1482
- catch {
1483
- // Legacy cursor: bare burn.id — treat as buy-burn cursor.
1484
- cursorId = Number(raw);
1485
- cursorType = 'buy';
1486
- }
1531
+ const lastId = f.cursor ? atob(f.cursor) : undefined;
1532
+ let q = db.trx
1533
+ .selectFrom('burn')
1534
+ .selectAll('burn')
1535
+ .innerJoin('sol_tx', 'sol_tx.id', 'burn.sol_tx_id')
1536
+ .select(['sol_tx.executed_at', 'sol_tx.sig']);
1537
+ if (!f.inclManual) {
1538
+ q = q.where('burn.usdc_spent', '>', String(0));
1539
+ }
1540
+ if (f.executedAfter) {
1541
+ q = q.where('sol_tx.executed_at', '>=', f.executedAfter);
1542
+ }
1543
+ if (f.executedBefore) {
1544
+ q = q.where('sol_tx.executed_at', '<=', f.executedBefore);
1545
+ }
1546
+ if (f.sig) {
1547
+ // Exact match, not a prefix: sol_tx.sig is unique, so this is an index hit returning at most one row.
1548
+ q = q.where('sol_tx.sig', '=', f.sig);
1487
1549
  }
1488
- // Shared WHERE fragments pushed into each union leg for index use.
1489
- const dateFilters = [];
1490
- if (f.executedAfter)
1491
- dateFilters.push(`st.executed_at >= ${p(f.executedAfter)}`);
1492
- if (f.executedBefore)
1493
- dateFilters.push(`st.executed_at <= ${p(f.executedBefore)}`);
1494
- const sigFilter = f.sig ? `st.sig = ${p(f.sig)}` : '';
1495
- // Buy-burn leg
1496
- const buyWhere = [...dateFilters];
1497
- if (!f.inclManual)
1498
- buyWhere.push('b.usdc_spent > 0');
1499
- if (sigFilter)
1500
- buyWhere.push(sigFilter);
1501
- if (f.jobId !== undefined) {
1502
- buyWhere.push(`b.id IN (SELECT burn_id FROM job WHERE id = ${p(f.jobId)})`);
1503
- }
1504
- const buyWhereClause = buyWhere.length ? `WHERE ${buyWhere.join(' AND ')}` : '';
1505
- const buySql = `
1506
- SELECT 'buy'::text AS type, b.id::bigint AS sortid, b.id AS id,
1507
- st.executed_at, b.priced_at, b.burned::text AS burned,
1508
- b.usdc_spent::text AS usdc_spent, b.quote_amt::text AS quote_amt,
1509
- b.tags, st.sig, b.render_to_usdc, b.eur_to_usdc,
1510
- coalesce(b.from_escrow_usdc, 0)::text AS from_escrow_usdc,
1511
- b.down_correction_id, b.escrow_correction_id,
1512
- b.marked_burned_at
1513
- FROM burn b
1514
- INNER JOIN sol_tx st ON st.id = b.sol_tx_id
1515
- ${buyWhereClause}`;
1516
- // Grant-burn leg
1517
- const grantWhere = [...dateFilters];
1518
- if (sigFilter)
1519
- grantWhere.push(sigFilter);
1520
1550
  if (f.jobId !== undefined) {
1521
- grantWhere.push(`gb.id IN (SELECT grant_burn_id FROM job WHERE id = ${p(f.jobId)})`);
1522
- }
1523
- const grantWhereClause = grantWhere.length ? `WHERE ${grantWhere.join(' AND ')}` : '';
1524
- const grantSql = `
1525
- SELECT 'grant'::text AS type, gb.id::bigint AS sortid, gb.id AS id,
1526
- st.executed_at, null::timestamp AS priced_at, gb.burned::text AS burned,
1527
- '0' AS usdc_spent, '0' AS quote_amt,
1528
- gb.tags, st.sig, null::float8 AS render_to_usdc, null::float8 AS eur_to_usdc,
1529
- '0' AS from_escrow_usdc,
1530
- null::bigint AS down_correction_id, null::bigint AS escrow_correction_id,
1531
- gb.marked_burned_at
1532
- FROM grant_burn gb
1533
- INNER JOIN sol_tx st ON st.id = gb.sol_tx_id
1534
- ${grantWhereClause}`;
1535
- // Cursor filter on the outer query — row comparison for deterministic paging.
1536
- let cursorFilter = '';
1537
- if (cursorEa && cursorType && cursorId !== undefined) {
1538
- cursorFilter = `WHERE (u.executed_at, u.type, u.sortid) > (${p(cursorEa)}, ${p(cursorType)}, ${p(cursorId)})`;
1539
- }
1540
- else if (cursorId !== undefined) {
1541
- // Legacy cursor fallback: only buy burns, ordered by id.
1542
- cursorFilter = `WHERE u.type = 'buy' AND u.sortid > ${p(cursorId)}`;
1551
+ // "Which burn consumed this job?" job.burn_id is the FK, so resolve it as a subquery rather than
1552
+ // joining `job` into the page query, which would multiply rows by job count and break both the limit
1553
+ // and the cursor.
1554
+ q = q.where('burn.id', 'in', (eb) => eb
1555
+ .selectFrom('job')
1556
+ .select('job.burn_id')
1557
+ .where('job.id', '=', String(f.jobId)));
1558
+ }
1559
+ if (lastId) {
1560
+ q = q.where('burn.id', '>', lastId);
1543
1561
  }
1544
1562
  const limit = f.limit ?? 1000;
1545
- const sql = `
1546
- SELECT u.* FROM (
1547
- ${buySql}
1548
- UNION ALL
1549
- ${grantSql}
1550
- ) u
1551
- ${cursorFilter}
1552
- ORDER BY u.executed_at ASC, u.type, u.sortid
1553
- LIMIT ${p(limit)}`;
1554
- const { rows } = await timedQuery(pgPool, sql, params, 'fetchBurnsPage', log);
1563
+ q = q.limit(limit).orderBy('burn.id');
1564
+ const comp = q.compile();
1565
+ const { rows } = await timedQuery(pgPool, comp.sql, comp.parameters, 'fetchBurnsPage', log);
1555
1566
  const burns = rows.map((r) => ({
1556
1567
  jobs: [],
1557
1568
  id: Number(r.id),
1558
- type: r.type,
1559
- renderToUsdc: r.render_to_usdc ?? undefined,
1569
+ renderToUsdc: r.render_to_usdc,
1560
1570
  solTx: r.sig,
1561
1571
  executedAt: r.executed_at,
1562
- pricedAt: r.priced_at ?? undefined,
1572
+ pricedAt: r.priced_at,
1563
1573
  usdcSpent: BigInt(r.usdc_spent ?? 0),
1564
1574
  quoteAmt: BigInt(r.quote_amt ?? 0),
1565
1575
  burned: BigInt(r.burned),
1566
- eurToUsdc: r.eur_to_usdc ?? undefined,
1576
+ eurToUsdc: r.eur_to_usdc,
1567
1577
  markedBurnedAt: r.marked_burned_at,
1568
1578
  tags: r.tags ? r.tags.split(',') : [],
1569
- fromEscrowUsdc: BigInt(r.from_escrow_usdc ?? 0),
1570
- downCorrectionId: r.down_correction_id ? Number(r.down_correction_id) : undefined,
1571
- escrowCorrectionId: r.escrow_correction_id ? Number(r.escrow_correction_id) : undefined,
1572
1579
  }));
1573
1580
  return {
1574
1581
  burns,
1582
+ // Only hand back a cursor on a full page; a short page means we're done.
1575
1583
  cursor: burns.length === limit
1576
- ? btoa(JSON.stringify({
1577
- ea: rows[burns.length - 1].executed_at,
1578
- t: rows[burns.length - 1].type,
1579
- id: rows[burns.length - 1].sortid,
1580
- }))
1584
+ ? btoa(String(burns[burns.length - 1].id))
1581
1585
  : undefined,
1582
1586
  };
1583
1587
  },
1584
- async fetchBurnJobs(db, burnId, burnType = 'buy', log = consoleLogger) {
1585
- const fk = burnType === 'grant' ? 'grant_burn_id' : 'burn_id';
1588
+ async fetchBurnJobs(db, burnId, log = consoleLogger) {
1586
1589
  const rows = await db.trx
1587
1590
  .selectFrom('job')
1588
1591
  .selectAll('job')
1589
- .where(fk, '=', String(burnId))
1592
+ .where('burn_id', '=', String(burnId))
1590
1593
  .execute();
1591
- log.debug(`fetchBurnJobs ${burnType} ${burnId} -> ${rows.length} jobs`);
1594
+ log.debug(`fetchBurnJobs burn ${burnId} -> ${rows.length} jobs`);
1592
1595
  return rows.map((r) => ({
1593
1596
  id: Number(r.id),
1594
1597
  completedAt: r.completed_at,
@@ -1890,6 +1893,21 @@ export const pgClient = (config) => {
1890
1893
  });
1891
1894
  },
1892
1895
  async insertDispersedOutbox(p, log = consoleLogger) {
1896
+ // Check if dispersed_obligation table exists BEFORE the transaction so a missing table never
1897
+ // poisons the txn (PG aborts the entire transaction on any error, even a caught one).
1898
+ let hasObligationTable = false;
1899
+ if (p.obligations?.length) {
1900
+ try {
1901
+ const { rows } = await timedQuery(pgPool, `SELECT 1 FROM information_schema.tables WHERE table_name = 'dispersed_obligation' LIMIT 1`, [], 'checkObligationTable', log);
1902
+ hasObligationTable = rows.length > 0;
1903
+ }
1904
+ catch {
1905
+ hasObligationTable = false;
1906
+ }
1907
+ if (!hasObligationTable) {
1908
+ log.warn(`dispersed obligations: table not found (migration 44 pending); skipping for tx ${p.txSignature}`);
1909
+ }
1910
+ }
1893
1911
  // The outbox row is the durable, crash-safe anchor persisted BEFORE broadcast. When it carries a
1894
1912
  // burn-correction draw, we increment consumed_render in the SAME transaction as the insert, bounded
1895
1913
  // so it can never exceed amount_render. Row + counter are therefore atomic and inseparable: no
@@ -1897,7 +1915,7 @@ export const pgClient = (config) => {
1897
1915
  // (decremented again by voidDispersedOutbox). If the bounded increment can't fit (a concurrent draw
1898
1916
  // took the room), the whole txn rolls back and we return {inserted:false} — the caller must NOT
1899
1917
  // broadcast (no row, no counter change, no burn).
1900
- return await db.transaction().execute(async (trx) => {
1918
+ const result = await db.transaction().execute(async (trx) => {
1901
1919
  const res = await trx
1902
1920
  .insertInto(DISPERSED_SETTLEMENT_TABLE)
1903
1921
  .values({
@@ -1912,6 +1930,8 @@ export const pgClient = (config) => {
1912
1930
  usdc_spent: p.usdcSpent ?? null,
1913
1931
  correction_id: p.correctionId ?? null,
1914
1932
  correction_render: p.correctionRender ?? null,
1933
+ usage_from: p.usageFrom ?? null,
1934
+ usage_to: p.usageTo ?? null,
1915
1935
  })
1916
1936
  .onConflict((oc) => oc.column('tx_signature').doNothing())
1917
1937
  .executeTakeFirst();
@@ -1936,13 +1956,29 @@ export const pgClient = (config) => {
1936
1956
  throw new DispersedCorrectionRejected();
1937
1957
  }
1938
1958
  }
1939
- log.debug(`dispersed outbox tx ${p.txSignature}: ${res.numInsertedOrUpdatedRows} row(s)`);
1959
+ if (inserted && hasObligationTable && p.obligations?.length) {
1960
+ for (const o of p.obligations) {
1961
+ await trx
1962
+ .insertInto('dispersed_obligation')
1963
+ .values({
1964
+ settlement_tx_sig: p.txSignature,
1965
+ uuid: o.uuid,
1966
+ amount_eur: o.amountEur,
1967
+ opened_at: o.openedAt,
1968
+ authorization_uuid: o.authorizationUuid ?? null,
1969
+ })
1970
+ .onConflict((oc) => oc.column('uuid').doNothing())
1971
+ .execute();
1972
+ }
1973
+ }
1974
+ log.debug(`dispersed outbox tx ${p.txSignature}: ${res.numInsertedOrUpdatedRows} row(s), ${hasObligationTable ? (p.obligations?.length ?? 0) : 0} obligations`);
1940
1975
  return { inserted };
1941
1976
  }).catch((e) => {
1942
1977
  if (e instanceof DispersedCorrectionRejected)
1943
1978
  return { inserted: false };
1944
1979
  throw e;
1945
1980
  });
1981
+ return result;
1946
1982
  },
1947
1983
  async getOutstandingDispersedCorrection(log = consoleLogger) {
1948
1984
  // consumed_render is the atomic source of truth; outstanding = amount_render - consumed_render.