Skip to content

Commit fdf5fcb

Browse files
Cap fixed rewards by hodler rewards
1 parent 7302bad commit fdf5fcb

File tree

1 file changed

+109
-1
lines changed

1 file changed

+109
-1
lines changed

apps/distributor/src/distributorv2.ts

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ export class DistributorV2Worker {
293293
const { data: sendSlash, error: sendSlashError } = await fetchSendSlash(distribution)
294294

295295
if (sendSlashError) {
296+
log.error(sendSlashError, 'Error fetching send slash data')
296297
throw sendSlashError
297298
}
298299

@@ -344,8 +345,102 @@ export class DistributorV2Worker {
344345
})
345346
}
346347

347-
// Calculate fixed pool share weights
348+
// Calculate initial hodler rewards using full distribution amount
348349
const distAmt = BigInt(distribution.amount)
350+
let initialHodlerShares: { address: string; amount: bigint }[] = []
351+
352+
// Initial hodler reward calculation
353+
const endDate = new Date(distribution.qualification_end)
354+
const currentDate = new Date() > endDate ? endDate : new Date()
355+
const hoursInMonth = getHoursInMonth(currentDate)
356+
const currentHour = getCurrentHourInMonth(currentDate)
357+
358+
// Calculate time adjustment for initial amounts using full distribution amount
359+
const hourlyHodlerAmount = (distAmt * PERC_DENOM) / BigInt(hoursInMonth)
360+
const timeAdjustedAmount =
361+
(hourlyHodlerAmount * BigInt(currentHour + 1)) / PERC_DENOM > distAmt
362+
? distAmt
363+
: (hourlyHodlerAmount * BigInt(currentHour + 1)) / PERC_DENOM
364+
365+
// Calculate initial slashed balances
366+
const initialSlashedBalances = minBalanceAddresses
367+
.map((balance) => {
368+
const userId = hodlerUserIdByAddress[balance.address] ?? ''
369+
const address = balance.address
370+
371+
// Check for tag registration verification
372+
const verifications = verificationsByUserId[userId] || []
373+
const hasPurchasedTag = verifications.some(
374+
(v) => v.type === 'tag_registration' && v.weight > 0
375+
)
376+
377+
const sendCeilingData = sendCeilingByUserId[userId]
378+
let slashPercentage = 0n
379+
380+
if (sendCeilingData && sendCeilingData.weight > 0n && hasPurchasedTag) {
381+
const previousReward =
382+
previousSharesByUserId[userId] || BigInt(distribution.hodler_min_balance)
383+
const scaledPreviousReward =
384+
(previousReward * PERC_DENOM) / (BigInt(sendSlash.scaling_divisor) * PERC_DENOM)
385+
386+
const scaledWeight = sendCeilingData.weight * PERC_DENOM
387+
const cappedWeight =
388+
scaledWeight > scaledPreviousReward ? scaledPreviousReward : scaledWeight
389+
390+
slashPercentage = (cappedWeight * PERC_DENOM) / scaledPreviousReward
391+
}
392+
393+
const slashedBalance = ((BigInt(balance.balance) * slashPercentage) / PERC_DENOM).toString()
394+
395+
return {
396+
address,
397+
balance: slashedBalance,
398+
}
399+
})
400+
.filter((balance) => BigInt(balance.balance) >= BigInt('0'))
401+
402+
if (log.isLevelEnabled('debug')) {
403+
await Bun.write(
404+
'dist/initialSlashedBalances.json',
405+
JSON.stringify(initialSlashedBalances, jsonBigint, 2)
406+
).catch((e) => {
407+
log.error(e, 'Error writing initialSlashedBalances.json')
408+
})
409+
}
410+
411+
// Calculate initial weighted shares
412+
const initialWeightedShares = calculateWeights(
413+
initialSlashedBalances,
414+
timeAdjustedAmount,
415+
Mode.EaseInOut
416+
)
417+
418+
initialHodlerShares = initialSlashedBalances.map((balance) => ({
419+
address: balance.address,
420+
amount: initialWeightedShares[balance.address]?.amount || 0n,
421+
}))
422+
423+
log.info(
424+
{
425+
hoursInMonth,
426+
currentHour,
427+
hourlyHodlerAmount,
428+
timeAdjustedAmount,
429+
fullAmount: distAmt,
430+
},
431+
'Initial time-based hodler pool calculations'
432+
)
433+
434+
// Create lookup for initial hodler amounts (add this before fixed pool calculation)
435+
const initialHodlerAmountByAddress = initialHodlerShares.reduce(
436+
(acc, share) => {
437+
acc[share.address] = share.amount
438+
return acc
439+
},
440+
{} as Record<string, bigint>
441+
)
442+
443+
// Calculate fixed pool share weights
349444
const fixedPoolAvailableAmount = distAmt
350445

351446
const minBalanceByAddress: Record<string, bigint> = minBalanceAddresses.reduce(
@@ -371,6 +466,9 @@ export class DistributorV2Worker {
371466

372467
if (!hasPurchasedTag) continue
373468

469+
// Get initial hodler amount - default to 0 if not found
470+
const initialHodlerAmount = initialHodlerAmountByAddress[address] || 0n
471+
374472
let userFixedAmount = 0n
375473
const multipliers: Record<string, Multiplier> = {}
376474

@@ -451,6 +549,16 @@ export class DistributorV2Worker {
451549
amount = 0n
452550
}
453551

552+
if (amount > initialHodlerAmount) {
553+
if (log.isLevelEnabled('debug')) {
554+
log.debug(
555+
{ address, original: amount, capped: initialHodlerAmount },
556+
'Fixed reward capped by hodler amount'
557+
)
558+
}
559+
amount = initialHodlerAmount
560+
}
561+
454562
if (fixedPoolAllocatedAmount + amount <= fixedPoolAvailableAmount) {
455563
fixedPoolAmountsByAddress[address] = amount
456564
fixedPoolAllocatedAmount += amount

0 commit comments

Comments
 (0)