The vePWN Power contract provides computation functions for voting power in PWN DAO. This contract is inherited by vePWN.
{% embed url="https://github.com/PWNDAO/pwn_dao/blob/main/src/token/vePWN/VoteEscrowedPWNPower.sol" %}
- VoteEscrowedPWNPower.sol is written in Solidity version 0.8.25
- Calculate voting power for stakers
- Calculate total voting power for an epoch(s)
- Get all stake IDs of a staker in given epoch
stakePowers(uint256 initialEpoch, uint256 amount, uint256 lockUpEpochs)
Function to compute powers in epochs for given stake parameters.
This function takes three arguments:
uint256
initialEpoch
- initial epoch of the stake poweruint256
amount
- amount of PWN tokens stakeduint256
lockUpEpochs
- number of epochs the stake is locked up for
function stakePowers(uint256 initialEpoch, uint256 amount, uint256 lockUpEpochs)
external
pure
returns (EpochPower[] memory powers)
{
if (amount < 100 || amount % 100 > 0 || amount > type(uint88).max) {
revert Error.InvalidAmount();
}
if (lockUpEpochs < 1 || lockUpEpochs > EPOCHS_IN_YEAR * 10) {
revert Error.InvalidLockUpPeriod();
}
// calculate how many epochs are needed
uint256 epochs;
if (lockUpEpochs > EPOCHS_IN_YEAR * 5) {
epochs = 7;
} else {
epochs = lockUpEpochs / EPOCHS_IN_YEAR + (lockUpEpochs % EPOCHS_IN_YEAR > 0 ? 2 : 1);
}
powers = new EpochPower[](epochs);
uint16 epoch = SafeCast.toUint16(initialEpoch);
uint8 remainingLockup = uint8(lockUpEpochs);
int104 _amount = SafeCast.toInt104(int256(uint256(amount)));
int104 power = _power(_amount, remainingLockup);
// calculate epoch powers
powers[0] = EpochPower({ epoch: epoch, power: power });
for (uint256 i = 1; i < epochs; ++i) {
uint8 epochsToNextPowerChange = _epochsToNextPowerChange(remainingLockup);
remainingLockup -= epochsToNextPowerChange;
epoch += epochsToNextPowerChange;
power += _powerDecrease(_amount, remainingLockup);
powers[i] = EpochPower({ epoch: epoch, power: power });
}
}
stakerPowers(address staker, uint256[] calldata epochs)
Function to compute power of a staker at given epochs.
This function takes two arguments:
address
staker
uint256[] calldata
epochs
function stakerPowers(address staker, uint256[] calldata epochs) external view returns (uint256[] memory) {
uint256[] memory powers = new uint256[](epochs.length);
for (uint256 i; i < epochs.length;) {
powers[i] = stakerPowerAt({
staker: staker,
epoch: epochs[i]
});
unchecked { ++i; }
}
return powers;
}
stakerPowerAt
Function to compute staker power at the given epoch.
This function takes two arguments:
address
staker
uint256
epoch
function stakerPowerAt(address staker, uint256 epoch) override virtual public view returns (uint256) {
uint16 _epoch = SafeCast.toUint16(epoch);
uint256[] memory stakeIds = beneficiaryOfStakesAt(staker, _epoch);
uint256 stakesLength = stakeIds.length;
int104 power;
for (uint256 i; i < stakesLength;) {
// sum up all stake powers
power += _stakePowerAt({
stake: _stakes[stakeIds[i]],
epoch: _epoch
});
unchecked { ++i; }
}
return SafeCast.toUint256(int256(power));
}
beneficiaryOfStakesAt
Function to get the list of stake IDs the staker is a beneficiary of in an given epoch.
This function takes two arguments:
address
staker
uint16
epoch
function beneficiaryOfStakesAt(address staker, uint16 epoch) public view returns (uint256[] memory) {
StakesInEpoch[] storage stakesInEpoch = beneficiaryOfStakes[staker];
// no owned stakes
if (stakesInEpoch.length == 0) {
return new uint256[](0);
}
// first owned stake is in the future
if (epoch < stakesInEpoch[0].epoch) {
return new uint256[](0);
}
// find change epoch
uint256 changeIndex = stakesInEpoch.length - 1;
while (stakesInEpoch[changeIndex].epoch > epoch) {
changeIndex--;
}
// collect ids as uint256
uint256 length = stakesInEpoch[changeIndex].ids.length;
uint256[] memory ids = new uint256[](length);
for (uint256 i; i < length;) {
ids[i] = stakesInEpoch[changeIndex].ids[i];
unchecked { ++i; }
}
return ids;
}
totalPowers
Function to get total power at given epochs.
This function takes one argument:
uint256[] calldata
epochs
function totalPowers(uint256[] calldata epochs) external view returns (uint256[] memory) {
uint256[] memory powers = new uint256[](epochs.length);
for (uint256 i; i < epochs.length;) {
powers[i] = totalPowerAt(epochs[i]);
unchecked { ++i; }
}
return powers;
}
totalPowerAt
Function to get total power at a given epoch.
This function takes one argument:
uint256
epoch
function totalPowerAt(uint256 epoch) override virtual public view returns (uint256) {
if (lastCalculatedTotalPowerEpoch >= epoch) {
return SafeCast.toUint256(int256(TOTAL_POWER_NAMESPACE.getEpochPower(epoch)));
}
// sum the rest of epochs
int104 totalPower;
for (uint256 i = lastCalculatedTotalPowerEpoch; i <= epoch;) {
totalPower += TOTAL_POWER_NAMESPACE.getEpochPower(i);
unchecked { ++i; }
}
return SafeCast.toUint256(int256(totalPower));
}
calculateTotalPower
Function to calculate total power in current epoch.
This function doesn't take any arguments.
function calculateTotalPower() external {
calculateTotalPowerUpTo(epochClock.currentEpoch());
}
calculateTotalPowerUpTo
Function to calculate total power for all epochs up to the given epoch.
This function takes one argument:
uint256
epoch
function calculateTotalPowerUpTo(uint256 epoch) public {
if (epoch > epochClock.currentEpoch()) {
revert Error.EpochStillRunning();
}
if (lastCalculatedTotalPowerEpoch >= epoch) {
revert Error.PowerAlreadyCalculated(lastCalculatedTotalPowerEpoch);
}
for (uint256 i = lastCalculatedTotalPowerEpoch; i < epoch;) {
TOTAL_POWER_NAMESPACE.updateEpochPower({
epoch: i + 1,
power: TOTAL_POWER_NAMESPACE.getEpochPower(i)
});
unchecked { ++i; }
}
lastCalculatedTotalPowerEpoch = epoch;
emit TotalPowerCalculated(epoch);
}
event TotalPowerCalculated(uint256 indexed epoch);
TotalPowerCalculated
TotalPowerCalculated event is emitted when the total power for an epoch is calculated.
This event has one parameter:
uint256 indexed
epoch
struct EpochPower {
uint16 epoch;
int104 power;
}