@render-foundation/utils 0.0.253 → 0.0.254
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/client/pg/base.js.map +1 -1
- package/lib/cjs/client/pg/v2Client.js +199 -206
- package/lib/cjs/client/pg/v2Client.js.map +1 -1
- package/lib/cjs/index.js +2 -4
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/lib/esm/src/client/pg/base.js.map +1 -1
- package/lib/esm/src/client/pg/v2Client.js +189 -194
- 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/client/pg/base.d.ts +5 -1
- package/lib/types/src/client/pg/base.d.ts.map +1 -1
- package/lib/types/src/client/pg/v2Client.d.ts +12 -63
- package/lib/types/src/client/pg/v2Client.d.ts.map +1 -1
- package/lib/types/src/dbTypesV2.d.ts +0 -3
- 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
- package/lib/cjs/burn/burnCalculations.js +0 -140
- package/lib/cjs/burn/burnCalculations.js.map +0 -1
- package/lib/esm/src/burn/burnCalculations.js +0 -124
- package/lib/esm/src/burn/burnCalculations.js.map +0 -1
- package/lib/types/src/burn/burnCalculations.d.ts +0 -52
- package/lib/types/src/burn/burnCalculations.d.ts.map +0 -1
|
@@ -33,114 +33,34 @@ 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';
|
|
40
36
|
export const CREDIT_DECIMALS = BigInt(100000000); // 1e8
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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);
|
|
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;
|
|
117
55
|
let fifoGrantId;
|
|
118
|
-
for (const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (b.t + lookback < now) {
|
|
123
|
-
b.expired = rem;
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
b.left = rem;
|
|
127
|
-
avail += rem;
|
|
128
|
-
if (fifoGrantId === undefined && rem > BigInt(0) && b.grantId !== undefined)
|
|
129
|
-
fifoGrantId = b.grantId;
|
|
56
|
+
for (const g of grants) {
|
|
57
|
+
if (drawn < g.amountCredits) {
|
|
58
|
+
fifoGrantId = g.id;
|
|
59
|
+
break;
|
|
130
60
|
}
|
|
131
|
-
|
|
61
|
+
drawn -= g.amountCredits;
|
|
132
62
|
}
|
|
133
|
-
return {
|
|
134
|
-
avail,
|
|
135
|
-
beyondGrants: beyond,
|
|
136
|
-
jobCharged: usedEmissions + usedMisrouted,
|
|
137
|
-
usedEmissions,
|
|
138
|
-
usedMisrouted,
|
|
139
|
-
expired,
|
|
140
|
-
buckets,
|
|
141
|
-
jobs,
|
|
142
|
-
fifoGrantId,
|
|
143
|
-
};
|
|
63
|
+
return { granted, consumed, avail, fifoGrantId };
|
|
144
64
|
};
|
|
145
65
|
import { begin } from './base';
|
|
146
66
|
import moment from 'moment';
|
|
@@ -270,50 +190,63 @@ export const pgClient = (config) => {
|
|
|
270
190
|
const out = {};
|
|
271
191
|
if (!p.userIds.length)
|
|
272
192
|
return out;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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,
|
|
301
239
|
});
|
|
302
|
-
byUser.set(r.u, arr);
|
|
303
240
|
}
|
|
304
|
-
for (const
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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}`);
|
|
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}`);
|
|
317
250
|
}
|
|
318
251
|
}
|
|
319
252
|
return out;
|
|
@@ -395,7 +328,7 @@ export const pgClient = (config) => {
|
|
|
395
328
|
const sequenceNumbers = [];
|
|
396
329
|
const dbEpochIds = [];
|
|
397
330
|
for (const bt of bts) {
|
|
398
|
-
let { solKey: toSolKey, seq, createdAt, amount, upgradeBracket, priorSupply, points, epochId,
|
|
331
|
+
let { solKey: toSolKey, seq, createdAt, amount, upgradeBracket, priorSupply, points, epochId, } = bt;
|
|
399
332
|
let entityId;
|
|
400
333
|
if (toSolKey && toSolKey != '') {
|
|
401
334
|
entityId = await getOrInsertEntity(db, { solKey: toSolKey });
|
|
@@ -416,7 +349,6 @@ export const pgClient = (config) => {
|
|
|
416
349
|
prior_supply: priorSupply,
|
|
417
350
|
points: points,
|
|
418
351
|
epoch_id: dbEpochId,
|
|
419
|
-
sender: sender,
|
|
420
352
|
})
|
|
421
353
|
.onConflict((oc) => oc.column('sequence').doUpdateSet({
|
|
422
354
|
created_at: createdAt,
|
|
@@ -426,7 +358,6 @@ export const pgClient = (config) => {
|
|
|
426
358
|
points: points,
|
|
427
359
|
epoch_id: dbEpochId,
|
|
428
360
|
entity_id: entityId,
|
|
429
|
-
sender: sender,
|
|
430
361
|
}))
|
|
431
362
|
.returning('sequence');
|
|
432
363
|
const c = q.compile();
|
|
@@ -1169,13 +1100,16 @@ export const pgClient = (config) => {
|
|
|
1169
1100
|
return;
|
|
1170
1101
|
}
|
|
1171
1102
|
}
|
|
1172
|
-
// FIFO-attribute this spend to the user's oldest
|
|
1173
|
-
//
|
|
1174
|
-
//
|
|
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.
|
|
1175
1106
|
let otoyGrantId = p.otoyGrantId;
|
|
1176
1107
|
if (otoyGrantId === undefined && p.renderSpentDelta < BigInt(0)) {
|
|
1177
1108
|
const allots = await getGrantAllotments(db.trx, { userIds: [p.userId] }, log);
|
|
1178
|
-
|
|
1109
|
+
const a = allots[p.userId];
|
|
1110
|
+
if (a) {
|
|
1111
|
+
otoyGrantId = foldGrantAllotment(a.grants, a.consumed, BigInt(0)).fifoGrantId;
|
|
1112
|
+
}
|
|
1179
1113
|
}
|
|
1180
1114
|
const v = {
|
|
1181
1115
|
user_id: p.userId,
|
|
@@ -1528,70 +1462,133 @@ export const pgClient = (config) => {
|
|
|
1528
1462
|
return burns;
|
|
1529
1463
|
},
|
|
1530
1464
|
async fetchBurnsPage(db, f, log = consoleLogger) {
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1533
|
-
.
|
|
1534
|
-
.
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
if (f.
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
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
|
+
}
|
|
1549
1487
|
}
|
|
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);
|
|
1550
1501
|
if (f.jobId !== undefined) {
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
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
|
+
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)}`;
|
|
1561
1543
|
}
|
|
1562
1544
|
const limit = f.limit ?? 1000;
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
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);
|
|
1566
1555
|
const burns = rows.map((r) => ({
|
|
1567
1556
|
jobs: [],
|
|
1568
1557
|
id: Number(r.id),
|
|
1569
|
-
|
|
1558
|
+
type: r.type,
|
|
1559
|
+
renderToUsdc: r.render_to_usdc ?? undefined,
|
|
1570
1560
|
solTx: r.sig,
|
|
1571
1561
|
executedAt: r.executed_at,
|
|
1572
|
-
pricedAt: r.priced_at,
|
|
1562
|
+
pricedAt: r.priced_at ?? undefined,
|
|
1573
1563
|
usdcSpent: BigInt(r.usdc_spent ?? 0),
|
|
1574
1564
|
quoteAmt: BigInt(r.quote_amt ?? 0),
|
|
1575
1565
|
burned: BigInt(r.burned),
|
|
1576
|
-
eurToUsdc: r.eur_to_usdc,
|
|
1566
|
+
eurToUsdc: r.eur_to_usdc ?? undefined,
|
|
1577
1567
|
markedBurnedAt: r.marked_burned_at,
|
|
1578
1568
|
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,
|
|
1579
1572
|
}));
|
|
1580
1573
|
return {
|
|
1581
1574
|
burns,
|
|
1582
|
-
// Only hand back a cursor on a full page; a short page means we're done.
|
|
1583
1575
|
cursor: burns.length === limit
|
|
1584
|
-
? btoa(
|
|
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
|
+
}))
|
|
1585
1581
|
: undefined,
|
|
1586
1582
|
};
|
|
1587
1583
|
},
|
|
1588
|
-
async fetchBurnJobs(db, burnId, log = consoleLogger) {
|
|
1584
|
+
async fetchBurnJobs(db, burnId, burnType = 'buy', log = consoleLogger) {
|
|
1585
|
+
const fk = burnType === 'grant' ? 'grant_burn_id' : 'burn_id';
|
|
1589
1586
|
const rows = await db.trx
|
|
1590
1587
|
.selectFrom('job')
|
|
1591
1588
|
.selectAll('job')
|
|
1592
|
-
.where(
|
|
1589
|
+
.where(fk, '=', String(burnId))
|
|
1593
1590
|
.execute();
|
|
1594
|
-
log.debug(`fetchBurnJobs
|
|
1591
|
+
log.debug(`fetchBurnJobs ${burnType} ${burnId} -> ${rows.length} jobs`);
|
|
1595
1592
|
return rows.map((r) => ({
|
|
1596
1593
|
id: Number(r.id),
|
|
1597
1594
|
completedAt: r.completed_at,
|
|
@@ -1915,8 +1912,6 @@ export const pgClient = (config) => {
|
|
|
1915
1912
|
usdc_spent: p.usdcSpent ?? null,
|
|
1916
1913
|
correction_id: p.correctionId ?? null,
|
|
1917
1914
|
correction_render: p.correctionRender ?? null,
|
|
1918
|
-
usage_from: p.usageFrom ?? null,
|
|
1919
|
-
usage_to: p.usageTo ?? null,
|
|
1920
1915
|
})
|
|
1921
1916
|
.onConflict((oc) => oc.column('tx_signature').doNothing())
|
|
1922
1917
|
.executeTakeFirst();
|