decent cobb douglas implementation
This commit is contained in:
@@ -108,7 +108,6 @@ library LibMath {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _nthRootFixedPoint(
|
||||
uint256 base,
|
||||
uint256 n,
|
||||
@@ -123,4 +122,49 @@ library LibMath {
|
||||
uint256 denominator = _nthRoot(scalar, n);
|
||||
root = (scalar * numerator) / denominator;
|
||||
}
|
||||
|
||||
// workaround for bug in ganache
|
||||
function _exp(uint256 base, uint256 power)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 result)
|
||||
{
|
||||
result = base;
|
||||
for(power = power - 1; power > 0; power -= 1) {
|
||||
result *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint256 constant fixedPointDecimals = 18;
|
||||
uint256 constant scalar = 10**fixedPointDecimals;
|
||||
|
||||
// rough implementation of cobb-douglas using the nth root fixed point algorithm above
|
||||
function _cobbDouglas(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake,
|
||||
uint8 alphaNumerator,
|
||||
uint8 alphaDenominator
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
require(
|
||||
alphaDenominator - alphaNumerator <= 10,
|
||||
"numerator of (1 - alpha) is out of range"
|
||||
);
|
||||
|
||||
uint256 feeRatio = _exp((totalRewards * ownerFees), alphaNumerator) / totalFees;
|
||||
uint256 rootedFeeRatio = _nthRootFixedPoint(feeRatio, alphaDenominator, fixedPointDecimals);
|
||||
|
||||
uint256 inverseAlphaNumerator = alphaDenominator - alphaNumerator;
|
||||
uint256 stakeRatio = _exp((totalRewards * ownerStake), inverseAlphaNumerator) / totalStake;
|
||||
uint256 rootedStakeRatio = _nthRootFixedPoint(stakeRatio, alphaDenominator, fixedPointDecimals);
|
||||
|
||||
return (rootedFeeRatio * rootedStakeRatio) / scalar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,30 @@ contract LibMathTest {
|
||||
{
|
||||
return LibMath._nthRootFixedPoint(base, n, decimals);
|
||||
}
|
||||
|
||||
function cobbDouglas(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake,
|
||||
uint8 alphaNumerator,
|
||||
uint8 alphaDenominator
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return LibMath._cobbDouglas(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaNumerator,
|
||||
alphaDenominator
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -144,6 +144,62 @@ describe('Staking Core', () => {
|
||||
const expectedResult = new BigNumber(26);
|
||||
expect(rootAsFloatingPoint).to.be.bignumber.equal(expectedResult);
|
||||
});
|
||||
|
||||
it('cobb douglas - basic computation', async() => {
|
||||
const totalRewards = new BigNumber(50);
|
||||
const ownerFees = new BigNumber(5);
|
||||
const totalFees = new BigNumber(10);
|
||||
const ownerStake = new BigNumber(5);
|
||||
const totalStake = new BigNumber(10);
|
||||
const alphaNumerator = new BigNumber(1);
|
||||
const alphaDenominator = new BigNumber(2);
|
||||
|
||||
const expectedOwnerReward = totalRewards
|
||||
.times(
|
||||
(ownerFees.div(totalFees)).squareRoot()
|
||||
).times(
|
||||
(ownerStake.div(totalStake)).squareRoot()
|
||||
).dividedToIntegerBy(1); // 25
|
||||
|
||||
const ownerReward = await stakingWrapper.cobbDouglas(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaNumerator,
|
||||
alphaDenominator
|
||||
);
|
||||
expect(ownerReward).to.be.bignumber.equal(expectedOwnerReward);
|
||||
});
|
||||
|
||||
it('cobb douglas - token computation', async() => {
|
||||
const totalRewards = stakingWrapper.toBaseUnitAmount(50);
|
||||
const ownerFees = stakingWrapper.toBaseUnitAmount(5);
|
||||
const totalFees = stakingWrapper.toBaseUnitAmount(10);
|
||||
const ownerStake = stakingWrapper.toBaseUnitAmount(5);
|
||||
const totalStake = stakingWrapper.toBaseUnitAmount(10);
|
||||
const alphaNumerator = new BigNumber(1);
|
||||
const alphaDenominator = new BigNumber(2);
|
||||
|
||||
const expectedOwnerReward = totalRewards
|
||||
.times(
|
||||
(ownerFees.div(totalFees)).squareRoot()
|
||||
).times(
|
||||
(ownerStake.div(totalStake)).squareRoot()
|
||||
).dividedToIntegerBy(1); // 25000000000000000000
|
||||
|
||||
const ownerReward = await stakingWrapper.cobbDouglas(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaNumerator,
|
||||
alphaDenominator
|
||||
);
|
||||
expect(ownerReward).to.be.bignumber.equal(expectedOwnerReward);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
|
||||
@@ -106,6 +106,26 @@ export class StakingWrapper {
|
||||
const output = await this.getLibMathTestContract().nthRootFixedPoint.callAsync(value, n, decimals);
|
||||
return output;
|
||||
}
|
||||
public async cobbDouglas(
|
||||
totalRewards: BigNumber,
|
||||
ownerFees: BigNumber,
|
||||
totalFees: BigNumber,
|
||||
ownerStake: BigNumber,
|
||||
totalStake: BigNumber,
|
||||
alphaNumerator: BigNumber,
|
||||
alphaDenominator: BigNumber
|
||||
) {
|
||||
const output = await this.getLibMathTestContract().cobbDouglas.callAsync(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaNumerator,
|
||||
alphaDenominator
|
||||
);
|
||||
return output;
|
||||
}
|
||||
public toBaseUnitAmount(amount: BigNumber | number): BigNumber {
|
||||
const decimals = 18;
|
||||
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
|
||||
|
||||
Reference in New Issue
Block a user