Finalization with payouts compiles.
This commit is contained in:
parent
55238b9669
commit
8e41cc7651
@ -249,6 +249,7 @@ contract Staking is
|
||||
external
|
||||
{
|
||||
_goToNextEpoch();
|
||||
_payRebates();
|
||||
}
|
||||
|
||||
function getEpochPeriodInSeconds()
|
||||
|
@ -27,11 +27,14 @@ import "../interfaces/IStakingEvents.sol";
|
||||
import "./MixinStakeBalances.sol";
|
||||
import "./MixinEpoch.sol";
|
||||
import "./MixinPools.sol";
|
||||
import "../interfaces/IStructs.sol";
|
||||
import "../libs/LibMath.sol";
|
||||
|
||||
|
||||
contract MixinFees is
|
||||
SafeMath,
|
||||
IStakingEvents,
|
||||
IStructs,
|
||||
MixinConstants,
|
||||
MixinStorage,
|
||||
MixinEpoch,
|
||||
@ -70,6 +73,59 @@ contract MixinFees is
|
||||
function _payRebates()
|
||||
internal
|
||||
{
|
||||
// Step 1 - compute total fees this epoch
|
||||
uint256 numberOfActivePoolIds = activePoolIdsThisEpoch.length;
|
||||
ActivePool[] memory activePoolIds = new ActivePool[](activePoolIdsThisEpoch.length);
|
||||
uint256 totalFees = 0;
|
||||
for (uint i = 0; i != numberOfActivePoolIds; i++) {
|
||||
activePoolIds[i].poolId = activePoolIdsThisEpoch[i];
|
||||
activePoolIds[i].feesCollected = protocolFeesThisEpochByPool[activePoolIds[i].poolId];
|
||||
totalFees = _safeAdd(totalFees, activePoolIds[i].feesCollected);
|
||||
}
|
||||
|
||||
// Step 2 - payout
|
||||
uint256 totalRewards = address(this).balance;
|
||||
uint256 totalStake = _getActivatedStakeAcrossAllOwners();
|
||||
uint256 totalRewardsRecordedInVault = 0;
|
||||
for (uint i = 0; i != numberOfActivePoolIds; i++) {
|
||||
uint256 stakeDelegatedToPool = _getStakeDelegatedToPool(activePoolIds[i].poolId);
|
||||
uint256 stakeHeldByPoolOperator = _getActivatedAndUndelegatedStake(_getPoolOperator(activePoolIds[i].poolId));
|
||||
uint256 scaledStake = _safeAdd(
|
||||
stakeHeldByPoolOperator,
|
||||
_safeDiv(
|
||||
_safeMul(
|
||||
stakeDelegatedToPool,
|
||||
REWARD_PAYOUT_DELEGATED_STAKE_PERCENT_VALUE
|
||||
),
|
||||
100
|
||||
)
|
||||
);
|
||||
uint256 reward = LibMath._cobbDouglasSuperSimplified(
|
||||
totalRewards,
|
||||
activePoolIds[i].feesCollected,
|
||||
totalFees,
|
||||
scaledStake,
|
||||
totalStake
|
||||
);
|
||||
|
||||
// record reward in vault
|
||||
rewardVault.recordDepositFor(activePoolIds[i].poolId, reward);
|
||||
totalRewardsRecordedInVault = _safeAdd(totalRewardsRecordedInVault, reward);
|
||||
|
||||
// clear state
|
||||
protocolFeesThisEpochByPool[activePoolIds[i].poolId] = 0;
|
||||
activePoolIdsThisEpoch[i] = 0;
|
||||
}
|
||||
activePoolIdsThisEpoch.length = 0;
|
||||
|
||||
// Step 3 send total payout to vault
|
||||
require(
|
||||
totalRewardsRecordedInVault <= totalRewards,
|
||||
"MISCALCULATED_REWARDS"
|
||||
);
|
||||
if (totalRewardsRecordedInVault > 0) {
|
||||
address payable rewardVaultAddress = address(uint160(address(rewardVault)));
|
||||
rewardVaultAddress.transfer(totalRewardsRecordedInVault);
|
||||
}
|
||||
}
|
||||
}
|
@ -32,6 +32,8 @@ contract MixinRewards is
|
||||
// Pinciple - design any Mixin such that internal members are callable without messing up internal state
|
||||
// any function that could mess up internal state should be private.
|
||||
|
||||
// @TODO -- add a MixinZrxVault and a MixinRewardVault that interact with the vaults.
|
||||
|
||||
|
||||
|
||||
function _computeOperatorReward(address operator, bytes32 poolId)
|
||||
|
@ -69,6 +69,7 @@ contract MixinStake is
|
||||
"INSUFFICIENT_BALANCE"
|
||||
);
|
||||
activeStakeByOwner[owner] = _safeAdd(activeStakeByOwner[owner], amount);
|
||||
totalActivatedStake = _safeAdd(totalActivatedStake, amount);
|
||||
}
|
||||
|
||||
function _activateAndDelegateStake(
|
||||
@ -91,6 +92,7 @@ contract MixinStake is
|
||||
"INSUFFICIENT_BALANCE"
|
||||
);
|
||||
activeStakeByOwner[owner] = _safeSub(activeStakeByOwner[owner], amount);
|
||||
totalActivatedStake = _safeSub(totalActivatedStake, amount);
|
||||
_timelockStake(owner, amount);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,14 @@ contract MixinStakeBalances is
|
||||
MixinEpoch
|
||||
{
|
||||
|
||||
function _getActivatedStakeAcrossAllOwners()
|
||||
internal
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return totalActivatedStake;
|
||||
}
|
||||
|
||||
function _getTotalStake(address owner)
|
||||
internal
|
||||
view
|
||||
@ -57,6 +65,15 @@ contract MixinStakeBalances is
|
||||
return _safeSub(_getTotalStake(owner), _getActivatedStake(owner));
|
||||
}
|
||||
|
||||
|
||||
function _getActivatedAndUndelegatedStake(address owner)
|
||||
internal
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return _safeSub(activeStakeByOwner[owner], _getStakeDelegatedByOwner(owner));
|
||||
}
|
||||
|
||||
function _getActivatableStake(address owner)
|
||||
internal
|
||||
view
|
||||
|
@ -23,7 +23,7 @@ contract MixinConstants {
|
||||
|
||||
uint64 constant MAX_UINT_64 = 2**64 - 1;
|
||||
|
||||
uint256 constant TOKEN_MULTIPLIER = 10**18;
|
||||
uint256 constant TOKEN_MULTIPLIER = 1000000000000000000; // 10**18
|
||||
|
||||
bytes32 constant INITIAL_POOL_ID = 0x0000000000000000000000000000000100000000000000000000000000000000;
|
||||
|
||||
@ -38,4 +38,8 @@ contract MixinConstants {
|
||||
uint64 constant public EPOCH_PERIOD_IN_SECONDS = 1000; // @TODO SET FOR DEPLOYMENT
|
||||
|
||||
uint64 constant public TIMELOCK_PERIOD_IN_EPOCHS = 3; // @TODO SET FOR DEPLOYMENT
|
||||
|
||||
uint256 constant public COBB_DOUGLAS_ALPHA_DENOMINATOR = 6; // @TODO SET FOR DEPLOYMENT
|
||||
|
||||
uint256 constant public REWARD_PAYOUT_DELEGATED_STAKE_PERCENT_VALUE = 90; // @TODO SET FOR DEPLOYMENT
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ contract MixinStorage is
|
||||
// mapping from Pool Id to Amount Delegated
|
||||
mapping (bytes32 => uint256) delegatedStakeByPoolId;
|
||||
|
||||
// total activated stake in the system
|
||||
uint256 totalActivatedStake;
|
||||
|
||||
// tracking Pool Id
|
||||
bytes32 nextPoolId = INITIAL_POOL_ID;
|
||||
|
||||
|
@ -29,6 +29,9 @@ interface IRewardVault {
|
||||
external
|
||||
payable;
|
||||
|
||||
function recordDepositFor(bytes32 poolId, uint256 amount)
|
||||
external;
|
||||
|
||||
function withdrawFor(bytes32 poolId, uint256 amount)
|
||||
external;
|
||||
|
||||
|
@ -31,4 +31,9 @@ interface IStructs {
|
||||
address operatorAddress;
|
||||
uint8 operatorShare;
|
||||
}
|
||||
|
||||
struct ActivePool {
|
||||
bytes32 poolId;
|
||||
uint256 feesCollected;
|
||||
}
|
||||
}
|
@ -129,6 +129,25 @@ library LibMath {
|
||||
root = (scalar * numerator) / denominator;
|
||||
}
|
||||
|
||||
// N is defined in `MixinConstants.COBB_DOUGLAS_ALPHA_DENOMINATOR`
|
||||
// Currently set to 6.
|
||||
// @TODO Once better nth root - choose a value that is not a divisor of 18, like 7.
|
||||
// @TODO Update this value for deployment
|
||||
uint256 constant COBB_DOUGLAS_ALPHA_DENOMINATOR = 6;
|
||||
uint256 constant TOKEN_MULTIPLIER = 1000000000000000000;
|
||||
uint256 constant NTH_ROOT_OF_TOKEN_MULTIPLIER = 1000;
|
||||
function _nthRootFixedPointFixedN(
|
||||
uint256 base
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 root)
|
||||
{
|
||||
root = (TOKEN_MULTIPLIER * _nthRoot(base, COBB_DOUGLAS_ALPHA_DENOMINATOR)) / NTH_ROOT_OF_TOKEN_MULTIPLIER;
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
// scalar gets multiplied by once at the beginning
|
||||
function _exp(uint256 numerator, uint256 scalar, uint256 denominator, uint256 power)
|
||||
internal
|
||||
@ -202,4 +221,42 @@ library LibMath {
|
||||
return (_nthRootFixedPoint(ownerStake * totalFees, alphaDenominator) * totalRewards * ownerFees) /
|
||||
(_nthRootFixedPoint(totalStake * ownerFees, alphaDenominator) * totalFees);
|
||||
}
|
||||
|
||||
// alpha = 1/x, where x is known
|
||||
// x is defined in `MixinConstants.COBB_DOUGLAS_ALPHA_DENOMINATOR`
|
||||
// Currently set to 6.
|
||||
function _cobbDouglasSuperSimplified(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return (_nthRootFixedPointFixedN(ownerFees * totalStake) * totalRewards * ownerStake) /
|
||||
(_nthRootFixedPointFixedN(totalFees * ownerStake) * totalStake);
|
||||
}
|
||||
|
||||
// (1 - alpha) = 1/x, where x is known
|
||||
// x is defined in `MixinConstants.COBB_DOUGLAS_ALPHA_DENOMINATOR`
|
||||
// Currently set to 6.
|
||||
function _cobbDouglasSuperSimplifiedInverse(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return (_nthRootFixedPointFixedN(ownerStake * totalFees) * totalRewards * ownerFees) /
|
||||
(_nthRootFixedPointFixedN(totalStake * ownerFees) * totalFees);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -56,6 +56,25 @@ contract RewardVault is
|
||||
balanceByPoolId[poolId] = _safeAdd(balanceByPoolId[poolId], msg.value);
|
||||
}
|
||||
|
||||
function recordDepositFor(bytes32 poolId, uint256 amount)
|
||||
external
|
||||
onlyStakingContract
|
||||
{
|
||||
balanceByPoolId[poolId] = _safeAdd(balanceByPoolId[poolId], amount);
|
||||
}
|
||||
|
||||
function deposit()
|
||||
external
|
||||
payable
|
||||
onlyStakingContract
|
||||
{}
|
||||
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
onlyStakingContract
|
||||
{}
|
||||
|
||||
function withdrawFor(bytes32 poolId, uint256 amount)
|
||||
external
|
||||
onlyStakingContract
|
||||
|
@ -692,6 +692,17 @@ describe('Staking Core', () => {
|
||||
expect(rootAsFloatingPoint).to.be.bignumber.equal(expectedResult);
|
||||
});
|
||||
|
||||
it('nth root #3 with fixed point (integer nth root would fail here)', async () => {
|
||||
const decimals = 18;
|
||||
const base = stakingWrapper.toFixedPoint(10, decimals);
|
||||
console.log(base);
|
||||
const n = new BigNumber(9);
|
||||
const root = await stakingWrapper.nthRootFixedPoint(base, n);
|
||||
const rootAsFloatingPoint = stakingWrapper.toFloatingPoint(root, decimals);
|
||||
const expectedResult = new BigNumber(26);
|
||||
expect(rootAsFloatingPoint).to.be.bignumber.equal(expectedResult);
|
||||
});
|
||||
|
||||
it.skip('nth root #4 with fixed point (integer nth root would fail here) (max number of decimals - currently does not retain)', async () => {
|
||||
const decimals = 18;
|
||||
const base = stakingWrapper.toFixedPoint(new BigNumber('5429503678976.295036789761543678', 10), decimals);
|
||||
|
Loading…
x
Reference in New Issue
Block a user