@@ -293,6 +293,7 @@ export class DistributorV2Worker {
293
293
const { data : sendSlash , error : sendSlashError } = await fetchSendSlash ( distribution )
294
294
295
295
if ( sendSlashError ) {
296
+ log . error ( sendSlashError , 'Error fetching send slash data' )
296
297
throw sendSlashError
297
298
}
298
299
@@ -344,8 +345,102 @@ export class DistributorV2Worker {
344
345
} )
345
346
}
346
347
347
- // Calculate fixed pool share weights
348
+ // Calculate initial hodler rewards using full distribution amount
348
349
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
349
444
const fixedPoolAvailableAmount = distAmt
350
445
351
446
const minBalanceByAddress : Record < string , bigint > = minBalanceAddresses . reduce (
@@ -371,6 +466,9 @@ export class DistributorV2Worker {
371
466
372
467
if ( ! hasPurchasedTag ) continue
373
468
469
+ // Get initial hodler amount - default to 0 if not found
470
+ const initialHodlerAmount = initialHodlerAmountByAddress [ address ] || 0n
471
+
374
472
let userFixedAmount = 0n
375
473
const multipliers : Record < string , Multiplier > = { }
376
474
@@ -451,6 +549,16 @@ export class DistributorV2Worker {
451
549
amount = 0n
452
550
}
453
551
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
+
454
562
if ( fixedPoolAllocatedAmount + amount <= fixedPoolAvailableAmount ) {
455
563
fixedPoolAmountsByAddress [ address ] = amount
456
564
fixedPoolAllocatedAmount += amount
0 commit comments