mirror of
https://github.com/luxfi/platformvm.git
synced 2026-10-30 15:22:12 +00:00
- Drop atomic_block.go + legacy *_block_test.go (consolidated) - Add block/v0/ subdir + lift_v0.go for old version handling - Copyright header: 'Lux Industries, Inc.' → 'Lux Industries Inc' (no comma) - block_adapter.go: new adapter layer
84 lines
3.0 KiB
Go
84 lines
3.0 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package reward
|
|
|
|
import (
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/luxfi/math"
|
|
)
|
|
|
|
var _ Calculator = (*calculator)(nil)
|
|
|
|
type Calculator interface {
|
|
Calculate(stakedDuration time.Duration, stakedAmount, currentSupply uint64) uint64
|
|
}
|
|
|
|
type calculator struct {
|
|
maxSubMinConsumptionRate *big.Int
|
|
minConsumptionRate *big.Int
|
|
mintingPeriod *big.Int
|
|
supplyCap uint64
|
|
}
|
|
|
|
func NewCalculator(c Config) Calculator {
|
|
return &calculator{
|
|
maxSubMinConsumptionRate: new(big.Int).SetUint64(c.MaxConsumptionRate - c.MinConsumptionRate),
|
|
minConsumptionRate: new(big.Int).SetUint64(c.MinConsumptionRate),
|
|
mintingPeriod: new(big.Int).SetUint64(uint64(c.MintingPeriod)),
|
|
supplyCap: c.SupplyCap,
|
|
}
|
|
}
|
|
|
|
// Reward returns the amount of tokens to reward the staker with.
|
|
//
|
|
// RemainingSupply = SupplyCap - ExistingSupply
|
|
// PortionOfExistingSupply = StakedAmount / ExistingSupply
|
|
// PortionOfStakingDuration = StakingDuration / MaximumStakingDuration
|
|
// MintingRate = MinMintingRate + MaxSubMinMintingRate * PortionOfStakingDuration
|
|
// Reward = RemainingSupply * PortionOfExistingSupply * MintingRate * PortionOfStakingDuration
|
|
func (c *calculator) Calculate(stakedDuration time.Duration, stakedAmount, currentSupply uint64) uint64 {
|
|
bigStakedDuration := new(big.Int).SetUint64(uint64(stakedDuration))
|
|
bigStakedAmount := new(big.Int).SetUint64(stakedAmount)
|
|
bigCurrentSupply := new(big.Int).SetUint64(currentSupply)
|
|
|
|
adjustedConsumptionRateNumerator := new(big.Int).Mul(c.maxSubMinConsumptionRate, bigStakedDuration)
|
|
adjustedMinConsumptionRateNumerator := new(big.Int).Mul(c.minConsumptionRate, c.mintingPeriod)
|
|
adjustedConsumptionRateNumerator.Add(adjustedConsumptionRateNumerator, adjustedMinConsumptionRateNumerator)
|
|
adjustedConsumptionRateDenominator := new(big.Int).Mul(c.mintingPeriod, consumptionRateDenominator)
|
|
|
|
remainingSupply := c.supplyCap - currentSupply
|
|
reward := new(big.Int).SetUint64(remainingSupply)
|
|
reward.Mul(reward, adjustedConsumptionRateNumerator)
|
|
reward.Mul(reward, bigStakedAmount)
|
|
reward.Mul(reward, bigStakedDuration)
|
|
reward.Div(reward, adjustedConsumptionRateDenominator)
|
|
reward.Div(reward, bigCurrentSupply)
|
|
reward.Div(reward, c.mintingPeriod)
|
|
|
|
if !reward.IsUint64() {
|
|
return remainingSupply
|
|
}
|
|
|
|
finalReward := reward.Uint64()
|
|
return min(remainingSupply, finalReward)
|
|
}
|
|
|
|
// Split [totalAmount] into [totalAmount * shares percentage] and the remainder.
|
|
//
|
|
// Invariant: [shares] <= [PercentDenominator]
|
|
func Split(totalAmount uint64, shares uint32) (uint64, uint64) {
|
|
remainderShares := PercentDenominator - uint64(shares)
|
|
remainderAmount := remainderShares * (totalAmount / PercentDenominator)
|
|
|
|
// Delay rounding as long as possible for small numbers
|
|
if optimisticReward, err := math.Mul64(remainderShares, totalAmount); err == nil {
|
|
remainderAmount = optimisticReward / PercentDenominator
|
|
}
|
|
|
|
amountFromShares := totalAmount - remainderAmount
|
|
return amountFromShares, remainderAmount
|
|
}
|