@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.
- package/lib/cjs/burn/burnCalculations.js +140 -0
- package/lib/cjs/burn/burnCalculations.js.map +1 -0
- package/lib/cjs/client/dispersed.js.map +1 -1
- package/lib/cjs/client/pg/base.js.map +1 -1
- package/lib/cjs/client/pg/v2Client.js +245 -206
- package/lib/cjs/client/pg/v2Client.js.map +1 -1
- package/lib/cjs/index.js +4 -2
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/src/burn/burnCalculations.js +124 -0
- package/lib/esm/src/burn/burnCalculations.js.map +1 -0
- package/lib/esm/src/client/dispersed.js.map +1 -1
- package/lib/esm/src/client/pg/base.js.map +1 -1
- package/lib/esm/src/client/pg/v2Client.js +227 -191
- package/lib/esm/src/client/pg/v2Client.js.map +1 -1
- package/lib/esm/src/index.js +1 -1
- package/lib/esm/src/index.js.map +1 -1
- package/lib/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/lib/types/src/burn/burnCalculations.d.ts +52 -0
- package/lib/types/src/burn/burnCalculations.d.ts.map +1 -0
- package/lib/types/src/client/dispersed.d.ts +3 -0
- package/lib/types/src/client/dispersed.d.ts.map +1 -1
- package/lib/types/src/client/pg/base.d.ts +1 -5
- package/lib/types/src/client/pg/base.d.ts.map +1 -1
- package/lib/types/src/client/pg/v2Client.d.ts +70 -12
- package/lib/types/src/client/pg/v2Client.d.ts.map +1 -1
- package/lib/types/src/dbTypesV2.d.ts +12 -0
- package/lib/types/src/dbTypesV2.d.ts.map +1 -1
- package/lib/types/src/index.d.ts +2 -2
- package/lib/types/src/index.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispersed.js","sourceRoot":"","sources":["../../../../src/client/dispersed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAA;AACvD,OAAO,KAAK,MAAM,YAAY,CAAA;AAE9B;;;;;;;;;;GAUG;AAEH,+DAA+D;AAC/D,MAAM,MAAM,GACV,kEAAkE,CAAA;AAEpE,sDAAsD;AACtD,MAAM,uBAAuB,GAAG,MAAM,CAAA;
|
|
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":"AACA,OAAO,EAAQ,KAAK,EAAe,MAAM,IAAI,CAAA;AAE7C,OAAO,EAAE,aAAa,EAAgB,MAAM,cAAc,CACzD;AAAC,MAAM,CAAC,SAAiB,CAAC,MAAM,GAAG;IAClC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAA;AACxB,CAAC,CAAA;
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
.
|
|
216
|
-
.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
|
1104
|
-
//
|
|
1105
|
-
// would leave the grant looking unspent
|
|
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
|
-
|
|
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
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
if (f.
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
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
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
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
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
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,
|
|
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(
|
|
1592
|
+
.where('burn_id', '=', String(burnId))
|
|
1590
1593
|
.execute();
|
|
1591
|
-
log.debug(`fetchBurnJobs
|
|
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
|
-
|
|
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
|
-
|
|
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.
|