@render-foundation/utils 0.0.255 → 0.0.257
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/dispersed.js.map +1 -1
- package/lib/cjs/client/pg/base.js.map +1 -1
- package/lib/cjs/client/pg/v2Client.js +89 -121
- package/lib/cjs/client/pg/v2Client.js.map +1 -1
- 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 +74 -107
- package/lib/esm/src/client/pg/v2Client.js.map +1 -1
- package/lib/esm/tsconfig.esm.tsbuildinfo +1 -1
- 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 +8 -1
- package/lib/types/src/client/pg/v2Client.d.ts.map +1 -1
- package/lib/types/src/dbTypesV2.d.ts +9 -0
- package/lib/types/src/dbTypesV2.d.ts.map +1 -1
- package/lib/types/src/index.d.ts +1 -1
- package/lib/types/src/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1506,7 +1506,6 @@ export const pgClient = (config) => {
|
|
|
1506
1506
|
eurToUsdc: r.eur_to_usdc,
|
|
1507
1507
|
markedBurnedAt: r.marked_burned_at,
|
|
1508
1508
|
tags: r.tags ? r.tags.split(',') : [],
|
|
1509
|
-
fromEscrowUsdc: BigInt(r.from_escrow_usdc ?? 0),
|
|
1510
1509
|
});
|
|
1511
1510
|
burnIdToIdx[r.id] = burns.length - 1;
|
|
1512
1511
|
}
|
|
@@ -1529,133 +1528,70 @@ export const pgClient = (config) => {
|
|
|
1529
1528
|
return burns;
|
|
1530
1529
|
},
|
|
1531
1530
|
async fetchBurnsPage(db, f, log = consoleLogger) {
|
|
1532
|
-
const
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
if (f.
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
// Legacy cursor: bare burn.id — treat as buy-burn cursor.
|
|
1551
|
-
cursorId = Number(raw);
|
|
1552
|
-
cursorType = 'buy';
|
|
1553
|
-
}
|
|
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);
|
|
1554
1549
|
}
|
|
1555
|
-
// Shared WHERE fragments pushed into each union leg for index use.
|
|
1556
|
-
const dateFilters = [];
|
|
1557
|
-
if (f.executedAfter)
|
|
1558
|
-
dateFilters.push(`st.executed_at >= ${p(f.executedAfter)}`);
|
|
1559
|
-
if (f.executedBefore)
|
|
1560
|
-
dateFilters.push(`st.executed_at <= ${p(f.executedBefore)}`);
|
|
1561
|
-
const sigFilter = f.sig ? `st.sig = ${p(f.sig)}` : '';
|
|
1562
|
-
// Buy-burn leg
|
|
1563
|
-
const buyWhere = [...dateFilters];
|
|
1564
|
-
if (!f.inclManual)
|
|
1565
|
-
buyWhere.push('b.usdc_spent > 0');
|
|
1566
|
-
if (sigFilter)
|
|
1567
|
-
buyWhere.push(sigFilter);
|
|
1568
|
-
if (f.jobId !== undefined) {
|
|
1569
|
-
buyWhere.push(`b.id IN (SELECT burn_id FROM job WHERE id = ${p(f.jobId)})`);
|
|
1570
|
-
}
|
|
1571
|
-
const buyWhereClause = buyWhere.length ? `WHERE ${buyWhere.join(' AND ')}` : '';
|
|
1572
|
-
const buySql = `
|
|
1573
|
-
SELECT 'buy'::text AS type, b.id::bigint AS sortid, b.id AS id,
|
|
1574
|
-
st.executed_at, b.priced_at, b.burned::text AS burned,
|
|
1575
|
-
b.usdc_spent::text AS usdc_spent, b.quote_amt::text AS quote_amt,
|
|
1576
|
-
b.tags, st.sig, b.render_to_usdc, b.eur_to_usdc,
|
|
1577
|
-
coalesce(b.from_escrow_usdc, 0)::text AS from_escrow_usdc,
|
|
1578
|
-
b.down_correction_id, b.escrow_correction_id,
|
|
1579
|
-
b.marked_burned_at
|
|
1580
|
-
FROM burn b
|
|
1581
|
-
INNER JOIN sol_tx st ON st.id = b.sol_tx_id
|
|
1582
|
-
${buyWhereClause}`;
|
|
1583
|
-
// Grant-burn leg
|
|
1584
|
-
const grantWhere = [...dateFilters];
|
|
1585
|
-
if (sigFilter)
|
|
1586
|
-
grantWhere.push(sigFilter);
|
|
1587
1550
|
if (f.jobId !== undefined) {
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
gb.marked_burned_at
|
|
1599
|
-
FROM grant_burn gb
|
|
1600
|
-
INNER JOIN sol_tx st ON st.id = gb.sol_tx_id
|
|
1601
|
-
${grantWhereClause}`;
|
|
1602
|
-
// Cursor filter on the outer query — row comparison for deterministic paging.
|
|
1603
|
-
let cursorFilter = '';
|
|
1604
|
-
if (cursorEa && cursorType && cursorId !== undefined) {
|
|
1605
|
-
cursorFilter = `WHERE (u.executed_at, u.type, u.sortid) > (${p(cursorEa)}, ${p(cursorType)}, ${p(cursorId)})`;
|
|
1606
|
-
}
|
|
1607
|
-
else if (cursorId !== undefined) {
|
|
1608
|
-
// Legacy cursor fallback: only buy burns, ordered by id.
|
|
1609
|
-
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);
|
|
1610
1561
|
}
|
|
1611
1562
|
const limit = f.limit ?? 1000;
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
UNION ALL
|
|
1616
|
-
${grantSql}
|
|
1617
|
-
) u
|
|
1618
|
-
${cursorFilter}
|
|
1619
|
-
ORDER BY u.executed_at ASC, u.type, u.sortid
|
|
1620
|
-
LIMIT ${p(limit)}`;
|
|
1621
|
-
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);
|
|
1622
1566
|
const burns = rows.map((r) => ({
|
|
1623
1567
|
jobs: [],
|
|
1624
1568
|
id: Number(r.id),
|
|
1625
|
-
|
|
1626
|
-
renderToUsdc: r.render_to_usdc ?? undefined,
|
|
1569
|
+
renderToUsdc: r.render_to_usdc,
|
|
1627
1570
|
solTx: r.sig,
|
|
1628
1571
|
executedAt: r.executed_at,
|
|
1629
|
-
pricedAt: r.priced_at
|
|
1572
|
+
pricedAt: r.priced_at,
|
|
1630
1573
|
usdcSpent: BigInt(r.usdc_spent ?? 0),
|
|
1631
1574
|
quoteAmt: BigInt(r.quote_amt ?? 0),
|
|
1632
1575
|
burned: BigInt(r.burned),
|
|
1633
|
-
eurToUsdc: r.eur_to_usdc
|
|
1576
|
+
eurToUsdc: r.eur_to_usdc,
|
|
1634
1577
|
markedBurnedAt: r.marked_burned_at,
|
|
1635
1578
|
tags: r.tags ? r.tags.split(',') : [],
|
|
1636
|
-
fromEscrowUsdc: BigInt(r.from_escrow_usdc ?? 0),
|
|
1637
|
-
downCorrectionId: r.down_correction_id ? Number(r.down_correction_id) : undefined,
|
|
1638
|
-
escrowCorrectionId: r.escrow_correction_id ? Number(r.escrow_correction_id) : undefined,
|
|
1639
1579
|
}));
|
|
1640
1580
|
return {
|
|
1641
1581
|
burns,
|
|
1582
|
+
// Only hand back a cursor on a full page; a short page means we're done.
|
|
1642
1583
|
cursor: burns.length === limit
|
|
1643
|
-
? btoa(
|
|
1644
|
-
ea: rows[burns.length - 1].executed_at,
|
|
1645
|
-
t: rows[burns.length - 1].type,
|
|
1646
|
-
id: rows[burns.length - 1].sortid,
|
|
1647
|
-
}))
|
|
1584
|
+
? btoa(String(burns[burns.length - 1].id))
|
|
1648
1585
|
: undefined,
|
|
1649
1586
|
};
|
|
1650
1587
|
},
|
|
1651
|
-
async fetchBurnJobs(db, burnId,
|
|
1652
|
-
const fk = burnType === 'grant' ? 'grant_burn_id' : 'burn_id';
|
|
1588
|
+
async fetchBurnJobs(db, burnId, log = consoleLogger) {
|
|
1653
1589
|
const rows = await db.trx
|
|
1654
1590
|
.selectFrom('job')
|
|
1655
1591
|
.selectAll('job')
|
|
1656
|
-
.where(
|
|
1592
|
+
.where('burn_id', '=', String(burnId))
|
|
1657
1593
|
.execute();
|
|
1658
|
-
log.debug(`fetchBurnJobs
|
|
1594
|
+
log.debug(`fetchBurnJobs burn ${burnId} -> ${rows.length} jobs`);
|
|
1659
1595
|
return rows.map((r) => ({
|
|
1660
1596
|
id: Number(r.id),
|
|
1661
1597
|
completedAt: r.completed_at,
|
|
@@ -1676,8 +1612,8 @@ export const pgClient = (config) => {
|
|
|
1676
1612
|
.innerJoin('sol_tx', 'sol_tx.id', 'burn.sol_tx_id')
|
|
1677
1613
|
.select(({ fn }) => [
|
|
1678
1614
|
dayExpr.as('day'),
|
|
1679
|
-
|
|
1680
|
-
|
|
1615
|
+
fn.sum('burn.burned').as('render_burned'),
|
|
1616
|
+
fn.sum('burn.usdc_spent').as('usdc_spent'),
|
|
1681
1617
|
fn.count('burn.id').as('burn_count'),
|
|
1682
1618
|
])
|
|
1683
1619
|
.groupBy(sql `date_trunc('day', sol_tx.executed_at)`)
|
|
@@ -1957,6 +1893,21 @@ export const pgClient = (config) => {
|
|
|
1957
1893
|
});
|
|
1958
1894
|
},
|
|
1959
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
|
+
}
|
|
1960
1911
|
// The outbox row is the durable, crash-safe anchor persisted BEFORE broadcast. When it carries a
|
|
1961
1912
|
// burn-correction draw, we increment consumed_render in the SAME transaction as the insert, bounded
|
|
1962
1913
|
// so it can never exceed amount_render. Row + counter are therefore atomic and inseparable: no
|
|
@@ -1964,7 +1915,7 @@ export const pgClient = (config) => {
|
|
|
1964
1915
|
// (decremented again by voidDispersedOutbox). If the bounded increment can't fit (a concurrent draw
|
|
1965
1916
|
// took the room), the whole txn rolls back and we return {inserted:false} — the caller must NOT
|
|
1966
1917
|
// broadcast (no row, no counter change, no burn).
|
|
1967
|
-
|
|
1918
|
+
const result = await db.transaction().execute(async (trx) => {
|
|
1968
1919
|
const res = await trx
|
|
1969
1920
|
.insertInto(DISPERSED_SETTLEMENT_TABLE)
|
|
1970
1921
|
.values({
|
|
@@ -2005,13 +1956,29 @@ export const pgClient = (config) => {
|
|
|
2005
1956
|
throw new DispersedCorrectionRejected();
|
|
2006
1957
|
}
|
|
2007
1958
|
}
|
|
2008
|
-
|
|
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`);
|
|
2009
1975
|
return { inserted };
|
|
2010
1976
|
}).catch((e) => {
|
|
2011
1977
|
if (e instanceof DispersedCorrectionRejected)
|
|
2012
1978
|
return { inserted: false };
|
|
2013
1979
|
throw e;
|
|
2014
1980
|
});
|
|
1981
|
+
return result;
|
|
2015
1982
|
},
|
|
2016
1983
|
async getOutstandingDispersedCorrection(log = consoleLogger) {
|
|
2017
1984
|
// consumed_render is the atomic source of truth; outstanding = amount_render - consumed_render.
|