decent cobb douglas implementation

This commit is contained in:
Greg Hysen
2019-05-23 14:48:52 -07:00
parent 3c4cfe8aee
commit 19f6a8dcfe
4 changed files with 145 additions and 1 deletions

View File

@@ -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;
}
}

View File

@@ -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
);
}
}

View File

@@ -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

View File

@@ -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;