@render-foundation/utils 0.0.232-beta.0 → 0.0.233-beta.0
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 +1 -1
- package/lib/cjs/client/dispersed.js.map +1 -1
- package/lib/cjs/client/pg/v2Client.js +222 -54
- package/lib/cjs/client/pg/v2Client.js.map +1 -1
- package/lib/cjs/client/trade.js +2 -0
- package/lib/cjs/client/trade.js.map +1 -1
- package/lib/esm/src/client/dispersed.js +1 -1
- package/lib/esm/src/client/dispersed.js.map +1 -1
- package/lib/esm/src/client/pg/v2Client.js +214 -53
- package/lib/esm/src/client/pg/v2Client.js.map +1 -1
- package/lib/esm/src/client/trade.js +2 -0
- package/lib/esm/src/client/trade.js.map +1 -1
- package/lib/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/lib/types/src/client/pg/v2Client.d.ts +41 -5
- package/lib/types/src/client/pg/v2Client.d.ts.map +1 -1
- package/lib/types/src/client/trade.d.ts +2 -0
- package/lib/types/src/client/trade.d.ts.map +1 -1
- package/lib/types/src/dbTypesV2.d.ts +41 -3
- package/lib/types/src/dbTypesV2.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -9,12 +9,15 @@ export const MANUAL_BURN_TABLE = 'manual_burn';
|
|
|
9
9
|
export const ENTITY_TABLE = 'entity';
|
|
10
10
|
export const SOL_TRANSFER_TABLE = 'sol_transfer1';
|
|
11
11
|
export const LIABILITY_TABLE = 'liability';
|
|
12
|
+
export const LIABILITY_ADJUSTMENT_TABLE = 'liability_adjustment';
|
|
13
|
+
export const LIABILITY_ADJUSTMENT_BATCH_TABLE = 'liability_adjustment_batch';
|
|
12
14
|
export const JOB_ID_TABLE = 'job_id';
|
|
13
15
|
export const JOB_TABLE = 'job';
|
|
14
16
|
export const BURN_TABLE = 'burn';
|
|
15
17
|
export const BRIDGE_TRANSFER_TABLE = 'bridge_transfer';
|
|
16
18
|
export const NETWORK_REVENUE_TABLE = 'network_revenue';
|
|
17
|
-
export const
|
|
19
|
+
export const JOB_BURN_ADJUSTMENT_TABLE = 'job_burn_adjustment';
|
|
20
|
+
export const TX_BURN_ADJUSTMENT_TABLE = 'tx_burn_adjustment';
|
|
18
21
|
export const ENTITY_EPOCH_INFO_TABLE = 'entity_epoch_info';
|
|
19
22
|
export const POLYGON_UPGRADE_TABLE = 'polygon_upgrade';
|
|
20
23
|
export const CURRENT_USER_GRANT_SPEND_TABLE = 'current_user_grant_spend';
|
|
@@ -313,7 +316,11 @@ export const pgClient = (config) => {
|
|
|
313
316
|
sig: solTx,
|
|
314
317
|
executedAt,
|
|
315
318
|
}, log);
|
|
316
|
-
|
|
319
|
+
// sol_transfer1 already has UNIQUE(sol_tx_id, from_entity_id,
|
|
320
|
+
// to_entity_id, symbol). Without ON CONFLICT a retry of the record step
|
|
321
|
+
// throws a unique violation and wedges the BullMQ job; make it an
|
|
322
|
+
// idempotent no-op and re-fetch the existing id instead.
|
|
323
|
+
let transferRow = await db
|
|
317
324
|
.insertInto(SOL_TRANSFER_TABLE)
|
|
318
325
|
.values({
|
|
319
326
|
id: dbId,
|
|
@@ -324,9 +331,23 @@ export const pgClient = (config) => {
|
|
|
324
331
|
symbol,
|
|
325
332
|
amount_payed: amountPayed,
|
|
326
333
|
})
|
|
334
|
+
.onConflict((oc) => oc
|
|
335
|
+
.columns(['sol_tx_id', 'from_entity_id', 'to_entity_id', 'symbol'])
|
|
336
|
+
.doNothing())
|
|
327
337
|
.returning((eb) => ['id as id'])
|
|
328
|
-
.
|
|
329
|
-
|
|
338
|
+
.executeTakeFirst();
|
|
339
|
+
if (!transferRow) {
|
|
340
|
+
log.warn(`sol_transfer for sol_tx_id ${solTxId} ${fromEntityId}->${toEntityId} ${symbol} already exists; reusing existing id (idempotent retry)`);
|
|
341
|
+
transferRow = await db
|
|
342
|
+
.selectFrom(SOL_TRANSFER_TABLE)
|
|
343
|
+
.select((eb) => ['id as id'])
|
|
344
|
+
.where('sol_tx_id', '=', solTxId)
|
|
345
|
+
.where('from_entity_id', '=', fromEntityId)
|
|
346
|
+
.where('to_entity_id', '=', toEntityId)
|
|
347
|
+
.where('symbol', '=', symbol)
|
|
348
|
+
.executeTakeFirstOrThrow();
|
|
349
|
+
}
|
|
350
|
+
transferId = BigInt(transferRow.id);
|
|
330
351
|
}
|
|
331
352
|
ids.push({ transferId, liabilityId });
|
|
332
353
|
}
|
|
@@ -633,9 +654,36 @@ export const pgClient = (config) => {
|
|
|
633
654
|
}
|
|
634
655
|
return b.as('x');
|
|
635
656
|
}, (join) => join.onRef('y.sol_key', '=', 'x.sol_key'))
|
|
657
|
+
// Standing per-wallet/channel corrections (migration 36). NO epoch filter — an adjustment is
|
|
658
|
+
// a permanent delta on outstanding, not tied to a payout window; payments net it via `payed`.
|
|
659
|
+
.fullJoin((eb) => {
|
|
660
|
+
let b = eb
|
|
661
|
+
.selectFrom(LIABILITY_ADJUSTMENT_TABLE)
|
|
662
|
+
.select(({ fn }) => fn.sum(`amount_adjustment`).as('adj'))
|
|
663
|
+
.innerJoin(ENTITY_TABLE, `${LIABILITY_ADJUSTMENT_TABLE}.entity_id`, 'entity.id')
|
|
664
|
+
.select(['entity.sol_key'])
|
|
665
|
+
.groupBy('entity.sol_key');
|
|
666
|
+
if (f.banned) {
|
|
667
|
+
b = b.where('entity.banned', '=', true);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
b = b.where('entity.banned', '=', false);
|
|
671
|
+
}
|
|
672
|
+
if (f.channels && f.channels.length > 0) {
|
|
673
|
+
b = b.where((eb) => eb.or(f.channels.map((c) => eb('liability_adjustment.channel', '=', c))));
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
b = b.where((eb) => eb.or([
|
|
677
|
+
eb('liability_adjustment.channel', '=', 'node_operator'),
|
|
678
|
+
eb('liability_adjustment.channel', '=', 'availability'),
|
|
679
|
+
]));
|
|
680
|
+
}
|
|
681
|
+
return b.as('a');
|
|
682
|
+
}, (join) => join.on(sql `"a"."sol_key" = coalesce("y"."sol_key", "x"."sol_key")`))
|
|
636
683
|
.select(({ fn }) => [
|
|
637
|
-
fn.coalesce('y.sol_key', 'x.sol_key').as('sol_key'),
|
|
638
|
-
sql `${fn.coalesce(`x.due`, sql `0`)}
|
|
684
|
+
fn.coalesce('y.sol_key', 'x.sol_key', 'a.sol_key').as('sol_key'),
|
|
685
|
+
sql `${fn.coalesce(`x.due`, sql `0`)} +
|
|
686
|
+
${fn.coalesce(`a.adj`, sql `0`)} -
|
|
639
687
|
${fn.coalesce(`y.payed`, sql `0`)}`.as('out'),
|
|
640
688
|
])
|
|
641
689
|
.as('z'))
|
|
@@ -658,6 +706,56 @@ export const pgClient = (config) => {
|
|
|
658
706
|
}
|
|
659
707
|
return out;
|
|
660
708
|
},
|
|
709
|
+
async addLiabilityAdjustments(batch, rows, log = consoleLogger) {
|
|
710
|
+
return await db.transaction().execute(async (trx) => {
|
|
711
|
+
// Upsert the batch by its label (idempotent re-runs; label is the run identity).
|
|
712
|
+
const b = await trx
|
|
713
|
+
.insertInto(LIABILITY_ADJUSTMENT_BATCH_TABLE)
|
|
714
|
+
.values({
|
|
715
|
+
label: batch.label,
|
|
716
|
+
description: batch.description,
|
|
717
|
+
created_by: batch.createdBy,
|
|
718
|
+
})
|
|
719
|
+
.onConflict((oc) => oc.column('label').doUpdateSet({
|
|
720
|
+
description: batch.description,
|
|
721
|
+
created_by: batch.createdBy,
|
|
722
|
+
}))
|
|
723
|
+
.returning('id')
|
|
724
|
+
.executeTakeFirstOrThrow();
|
|
725
|
+
const batchId = BigInt(b.id);
|
|
726
|
+
let inserted = 0;
|
|
727
|
+
let skipped = 0;
|
|
728
|
+
let net = BigInt(0);
|
|
729
|
+
let positive = BigInt(0);
|
|
730
|
+
let negative = BigInt(0);
|
|
731
|
+
for (const r of rows) {
|
|
732
|
+
const entityId = await getOrInsertEntity(trx, { solKey: r.solKey }, log);
|
|
733
|
+
const res = await trx
|
|
734
|
+
.insertInto(LIABILITY_ADJUSTMENT_TABLE)
|
|
735
|
+
.values({
|
|
736
|
+
entity_id: entityId,
|
|
737
|
+
channel: r.channel,
|
|
738
|
+
amount_adjustment: r.amountAdjustment,
|
|
739
|
+
batch_id: batchId,
|
|
740
|
+
})
|
|
741
|
+
// unique (entity_id, channel, batch_id) → a re-run of the same batch is a no-op
|
|
742
|
+
.onConflict((oc) => oc.columns(['entity_id', 'channel', 'batch_id']).doNothing())
|
|
743
|
+
.executeTakeFirst();
|
|
744
|
+
if ((res.numInsertedOrUpdatedRows ?? BigInt(0)) > BigInt(0))
|
|
745
|
+
inserted++;
|
|
746
|
+
else
|
|
747
|
+
skipped++;
|
|
748
|
+
net += r.amountAdjustment;
|
|
749
|
+
if (r.amountAdjustment > BigInt(0))
|
|
750
|
+
positive += r.amountAdjustment;
|
|
751
|
+
else
|
|
752
|
+
negative += r.amountAdjustment;
|
|
753
|
+
}
|
|
754
|
+
log.info(`liability_adjustment batch '${batch.label}' (id ${batchId}): ` +
|
|
755
|
+
`inserted ${inserted}, skipped ${skipped}, net ${net} (+${positive} / ${negative})`);
|
|
756
|
+
return { batchId, inserted, skipped, net, positive, negative };
|
|
757
|
+
});
|
|
758
|
+
},
|
|
661
759
|
async fetchNodeOperatorEpoch(epochId, log = consoleLogger) {
|
|
662
760
|
const q = db
|
|
663
761
|
.selectFrom(JOB_ID_TABLE)
|
|
@@ -942,7 +1040,7 @@ export const pgClient = (config) => {
|
|
|
942
1040
|
let buyBurnId;
|
|
943
1041
|
let grantBurnId;
|
|
944
1042
|
if (p.buyBurn) {
|
|
945
|
-
const { burned, usdcSpent, eurToUsdc, renderToUsdc, quoteAmt, tags,
|
|
1043
|
+
const { burned, usdcSpent, eurToUsdc, renderToUsdc, quoteAmt, tags, jobBurnAdjustmentId, txBurnAdjustmentId, toBurn, fromEscrowUsdc, } = p.buyBurn;
|
|
946
1044
|
let pricedAt = p.buyBurn.pricedAt;
|
|
947
1045
|
if (!pricedAt) {
|
|
948
1046
|
const jobs = await fetchJobs1(trx.trx, { ids: p.jobs.map((j) => String(j.id)) }, log);
|
|
@@ -961,17 +1059,30 @@ export const pgClient = (config) => {
|
|
|
961
1059
|
quote_amt: quoteAmt,
|
|
962
1060
|
burned: burned,
|
|
963
1061
|
tags: tags.join(','),
|
|
964
|
-
|
|
1062
|
+
job_burn_adjustment_id: jobBurnAdjustmentId,
|
|
1063
|
+
tx_burn_adjustment_id: txBurnAdjustmentId,
|
|
965
1064
|
to_burn: toBurn,
|
|
1065
|
+
from_escrow_usdc: fromEscrowUsdc ?? 0,
|
|
966
1066
|
};
|
|
967
1067
|
log.debug(`inserting burn ${JSON.stringify(v)}`);
|
|
968
|
-
|
|
1068
|
+
// Idempotent on sol_tx_id (uniq_burn_sol_tx_id, migration 27): a retry of
|
|
1069
|
+
// the record step for the same on-chain burn is a safe no-op. On conflict
|
|
1070
|
+
// executeTakeFirst() returns undefined, so re-fetch the existing id.
|
|
1071
|
+
let burnRow = await trx.trx
|
|
969
1072
|
.insertInto(BURN_TABLE)
|
|
970
1073
|
.values(v)
|
|
971
|
-
|
|
1074
|
+
.onConflict((oc) => oc.column('sol_tx_id').doNothing())
|
|
972
1075
|
.returning((eb) => ['id as id'])
|
|
973
|
-
.
|
|
974
|
-
|
|
1076
|
+
.executeTakeFirst();
|
|
1077
|
+
if (!burnRow) {
|
|
1078
|
+
log.warn(`burn for sol_tx_id ${solTxId} already exists; reusing existing id (idempotent retry)`);
|
|
1079
|
+
burnRow = await trx.trx
|
|
1080
|
+
.selectFrom(BURN_TABLE)
|
|
1081
|
+
.select((eb) => ['id as id'])
|
|
1082
|
+
.where('sol_tx_id', '=', solTxId)
|
|
1083
|
+
.executeTakeFirstOrThrow();
|
|
1084
|
+
}
|
|
1085
|
+
buyBurnId = Number(burnRow.id);
|
|
975
1086
|
}
|
|
976
1087
|
if (p.grantBurn) {
|
|
977
1088
|
const { burned, tags } = p.grantBurn;
|
|
@@ -981,12 +1092,22 @@ export const pgClient = (config) => {
|
|
|
981
1092
|
tags: tags?.join(','),
|
|
982
1093
|
};
|
|
983
1094
|
log.debug(`inserting grant burn ${JSON.stringify(v)}`);
|
|
984
|
-
|
|
1095
|
+
// Idempotent on sol_tx_id (uniq_grant_burn_sol_tx_id, migration 27).
|
|
1096
|
+
let grantBurnRow = await trx.trx
|
|
985
1097
|
.insertInto(GRANT_BURN_TABLE)
|
|
986
1098
|
.values(v)
|
|
1099
|
+
.onConflict((oc) => oc.column('sol_tx_id').doNothing())
|
|
987
1100
|
.returning((eb) => ['id as id'])
|
|
988
|
-
.
|
|
989
|
-
|
|
1101
|
+
.executeTakeFirst();
|
|
1102
|
+
if (!grantBurnRow) {
|
|
1103
|
+
log.warn(`grant_burn for sol_tx_id ${solTxId} already exists; reusing existing id (idempotent retry)`);
|
|
1104
|
+
grantBurnRow = await trx.trx
|
|
1105
|
+
.selectFrom(GRANT_BURN_TABLE)
|
|
1106
|
+
.select((eb) => ['id as id'])
|
|
1107
|
+
.where('sol_tx_id', '=', solTxId)
|
|
1108
|
+
.executeTakeFirstOrThrow();
|
|
1109
|
+
}
|
|
1110
|
+
grantBurnId = Number(grantBurnRow.id);
|
|
990
1111
|
}
|
|
991
1112
|
const burnId = buyBurnId;
|
|
992
1113
|
const grantId = grantBurnId ?? buyBurnId;
|
|
@@ -1595,45 +1716,85 @@ export const pgClient = (config) => {
|
|
|
1595
1716
|
: {},
|
|
1596
1717
|
}));
|
|
1597
1718
|
},
|
|
1598
|
-
async
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
])
|
|
1614
|
-
.groupBy([
|
|
1615
|
-
`${BURN_ADJUSTMENT_TABLE}.id`,
|
|
1616
|
-
`${JOB_TABLE}.completed_at`,
|
|
1617
|
-
`${JOB_TABLE}.render_amt`,
|
|
1618
|
-
])
|
|
1619
|
-
.havingRef(sql `SUM(COALESCE("burn"."to_burn", 0)) - SUM(COALESCE("burn"."burned", 0))`, '<', `${BURN_ADJUSTMENT_TABLE}.down_adj_to_burn`);
|
|
1620
|
-
log.info(`getBurnAdjustments ${q.compile().sql}`);
|
|
1621
|
-
const res = await q.execute();
|
|
1622
|
-
return res.map((r) => ({
|
|
1623
|
-
id: Number(r.id),
|
|
1624
|
-
createdAt: r.created_at,
|
|
1625
|
-
jobId: Number(r.job_id),
|
|
1626
|
-
downAdjRndrUsed: Number(r.down_adj_rndr_used),
|
|
1627
|
-
downAdjToBurn: Number(r.down_adj_to_burn),
|
|
1628
|
-
adjusted: Number(r.tot_to_burn) - Number(r.tot_burned),
|
|
1629
|
-
job: {
|
|
1630
|
-
id: Number(r.job_id),
|
|
1631
|
-
completedAt: r.completed_at,
|
|
1632
|
-
rndrUsed: BigInt(r.render_amt),
|
|
1633
|
-
},
|
|
1634
|
-
}));
|
|
1719
|
+
async createTxBurnAdjustment(trx, p, log = consoleLogger) {
|
|
1720
|
+
// Idempotent per sol_tx_id (unique) — a re-run for the same bad tx is a no-op.
|
|
1721
|
+
const row = await trx.trx
|
|
1722
|
+
.insertInto(TX_BURN_ADJUSTMENT_TABLE)
|
|
1723
|
+
.values({
|
|
1724
|
+
sol_tx_id: p.solTxId,
|
|
1725
|
+
surplus_usdc: p.surplusUsdc,
|
|
1726
|
+
description: p.description,
|
|
1727
|
+
})
|
|
1728
|
+
.onConflict((oc) => oc.column('sol_tx_id').doNothing())
|
|
1729
|
+
.returning('id')
|
|
1730
|
+
.executeTakeFirst();
|
|
1731
|
+
if (!row) {
|
|
1732
|
+
log.info(`tx_burn_adjustment for sol_tx ${p.solTxId} already exists — skipped`);
|
|
1733
|
+
return undefined;
|
|
1635
1734
|
}
|
|
1636
|
-
|
|
1735
|
+
log.info(`created tx_burn_adjustment ${row.id}: ${p.surplusUsdc} USDC over-spent (sol_tx ${p.solTxId})`);
|
|
1736
|
+
return Number(row.id);
|
|
1737
|
+
},
|
|
1738
|
+
async getJobBurnAdjustments(trx, ps, log = consoleLogger) {
|
|
1739
|
+
if (!ps.toFill)
|
|
1740
|
+
return [];
|
|
1741
|
+
const q = trx.trx
|
|
1742
|
+
.selectFrom(JOB_BURN_ADJUSTMENT_TABLE)
|
|
1743
|
+
.selectAll(JOB_BURN_ADJUSTMENT_TABLE)
|
|
1744
|
+
.innerJoin(JOB_TABLE, `${JOB_TABLE}.id`, `${JOB_BURN_ADJUSTMENT_TABLE}.job_id`)
|
|
1745
|
+
.select([`${JOB_TABLE}.completed_at`, `${JOB_TABLE}.render_amt`])
|
|
1746
|
+
.leftJoin(BURN_TABLE, `${BURN_TABLE}.job_burn_adjustment_id`, `${JOB_BURN_ADJUSTMENT_TABLE}.id`)
|
|
1747
|
+
.select(({ fn, lit }) => [
|
|
1748
|
+
fn.sum(fn.coalesce(`${BURN_TABLE}.to_burn`, lit(0))).as('tot_to_burn'),
|
|
1749
|
+
fn.sum(fn.coalesce(`${BURN_TABLE}.burned`, lit(0))).as('tot_burned'),
|
|
1750
|
+
])
|
|
1751
|
+
.groupBy([
|
|
1752
|
+
`${JOB_BURN_ADJUSTMENT_TABLE}.id`,
|
|
1753
|
+
`${JOB_TABLE}.completed_at`,
|
|
1754
|
+
`${JOB_TABLE}.render_amt`,
|
|
1755
|
+
]);
|
|
1756
|
+
log.info(`getJobBurnAdjustments ${q.compile().sql}`);
|
|
1757
|
+
const res = await q.execute();
|
|
1758
|
+
return res
|
|
1759
|
+
.map((r) => ({
|
|
1760
|
+
id: Number(r.id),
|
|
1761
|
+
createdAt: r.created_at,
|
|
1762
|
+
jobId: Number(r.job_id),
|
|
1763
|
+
downAdjRndrUsed: Number(r.down_adj_rndr_used),
|
|
1764
|
+
downAdjToBurn: Number(r.down_adj_to_burn),
|
|
1765
|
+
adjusted: Number(r.tot_to_burn) - Number(r.tot_burned),
|
|
1766
|
+
job: {
|
|
1767
|
+
id: Number(r.job_id),
|
|
1768
|
+
completedAt: r.completed_at,
|
|
1769
|
+
rndrUsed: BigInt(r.render_amt),
|
|
1770
|
+
},
|
|
1771
|
+
}))
|
|
1772
|
+
.filter((a) => a.adjusted < a.downAdjToBurn);
|
|
1773
|
+
},
|
|
1774
|
+
async getTxBurnAdjustments(trx, ps, log = consoleLogger) {
|
|
1775
|
+
if (!ps.toFill)
|
|
1776
|
+
return [];
|
|
1777
|
+
const q = trx.trx
|
|
1778
|
+
.selectFrom(TX_BURN_ADJUSTMENT_TABLE)
|
|
1779
|
+
.selectAll(TX_BURN_ADJUSTMENT_TABLE)
|
|
1780
|
+
.leftJoin(BURN_TABLE, `${BURN_TABLE}.tx_burn_adjustment_id`, `${TX_BURN_ADJUSTMENT_TABLE}.id`)
|
|
1781
|
+
.select(({ fn, lit }) => [
|
|
1782
|
+
fn
|
|
1783
|
+
.sum(fn.coalesce(`${BURN_TABLE}.from_escrow_usdc`, lit(0)))
|
|
1784
|
+
.as('tot_from_escrow'),
|
|
1785
|
+
])
|
|
1786
|
+
.groupBy(`${TX_BURN_ADJUSTMENT_TABLE}.id`);
|
|
1787
|
+
log.info(`getTxBurnAdjustments ${q.compile().sql}`);
|
|
1788
|
+
const res = await q.execute();
|
|
1789
|
+
return res
|
|
1790
|
+
.map((r) => ({
|
|
1791
|
+
id: Number(r.id),
|
|
1792
|
+
createdAt: r.created_at,
|
|
1793
|
+
solTxId: Number(r.sol_tx_id),
|
|
1794
|
+
surplusUsdc: Number(r.surplus_usdc),
|
|
1795
|
+
consumed: Number(r.tot_from_escrow),
|
|
1796
|
+
}))
|
|
1797
|
+
.filter((a) => a.consumed < a.surplusUsdc);
|
|
1637
1798
|
},
|
|
1638
1799
|
async insertPolygonUpgrade(db, p, log = consoleLogger) {
|
|
1639
1800
|
const solTxId = await getOrInsertTx(db.trx, {
|