cobb douglas / simplified / inverse simplified (better results across the board - esp w simplified impls)
This commit is contained in:
parent
f15693af1d
commit
bcfabf18bc
@ -123,39 +123,13 @@ library LibMath {
|
||||
root = (scalar * numerator) / denominator;
|
||||
}
|
||||
|
||||
// workaround for bug in ganache
|
||||
function _exp(uint256 base, uint256 power)
|
||||
// scalar gets multiplied by once at the beginning
|
||||
function _exp(uint256 numerator, uint256 scalar, uint256 denominator, uint256 power)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 result)
|
||||
{
|
||||
result = base;
|
||||
for(power = power - 1; power > 0; power -= 1) {
|
||||
result *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function _exp2(uint256 numerator_1, uint256 numerator_2, uint256 denominator, uint256 power)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 result)
|
||||
{
|
||||
result = (numerator_1 * numerator_2) / denominator;
|
||||
for(power = power - 1; power > 0; power -= 1) {
|
||||
result *= numerator_1;
|
||||
result /= denominator;
|
||||
result *= numerator_2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function _exp3(uint256 numerator, uint256 denominator, uint256 power)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 result)
|
||||
{
|
||||
result = numerator / denominator;
|
||||
result = (numerator * scalar) / denominator;
|
||||
for(power = power - 1; power > 0; power -= 1) {
|
||||
result = (result * numerator) / denominator;
|
||||
}
|
||||
@ -166,7 +140,9 @@ library LibMath {
|
||||
uint256 constant scalar = 10**fixedPointDecimals;
|
||||
uint256 constant halfScalar = 10**(fixedPointDecimals/2);
|
||||
|
||||
// rough implementation of cobb-douglas using the nth root fixed point algorithm above
|
||||
// cobb-douglas using the nth root fixed point algorithm above
|
||||
// no limitation on alpha. We tend to get better rounding
|
||||
// on the simplified versions below.
|
||||
function _cobbDouglas(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
@ -180,10 +156,44 @@ library LibMath {
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
uint256 lhs = _exp3(_nthRootFixedPoint(ownerFees * totalStake, alphaDenominator, 18),
|
||||
_nthRootFixedPoint(totalFees * ownerStake, alphaDenominator, 18),
|
||||
alphaNumerator
|
||||
);
|
||||
return lhs * ((totalRewards * ownerStake) / totalStake);
|
||||
return _exp(_nthRootFixedPoint(ownerFees * totalStake, alphaDenominator, 18),
|
||||
((totalRewards * ownerStake) / totalStake),
|
||||
_nthRootFixedPoint(totalFees * ownerStake, alphaDenominator, 18),
|
||||
alphaNumerator
|
||||
);
|
||||
}
|
||||
|
||||
// alpha = 1/x
|
||||
function _cobbDouglasSimplified(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake,
|
||||
uint8 alphaDenominator
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return (_nthRootFixedPoint(ownerFees * totalStake, alphaDenominator, 18) * totalRewards * ownerStake) /
|
||||
(_nthRootFixedPoint(totalFees * ownerStake, alphaDenominator, 18) * totalStake);
|
||||
}
|
||||
|
||||
// (1 - alpha) = 1/x
|
||||
function _cobbDouglasSimplifiedInverse(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake,
|
||||
uint8 alphaDenominator
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return (_nthRootFixedPoint(ownerStake * totalFees, alphaDenominator, 18) * totalRewards * ownerFees) /
|
||||
(_nthRootFixedPoint(totalStake * ownerFees, alphaDenominator, 18) * totalFees);
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,50 @@ contract LibMathTest {
|
||||
alphaDenominator
|
||||
);
|
||||
}
|
||||
|
||||
function cobbDouglasSimplified(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake,
|
||||
uint8 alphaDenominator
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return LibMath._cobbDouglasSimplified(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaDenominator
|
||||
);
|
||||
}
|
||||
|
||||
function cobbDouglasSimplifiedInverse(
|
||||
uint256 totalRewards,
|
||||
uint256 ownerFees,
|
||||
uint256 totalFees,
|
||||
uint256 ownerStake,
|
||||
uint256 totalStake,
|
||||
uint8 alphaDenominator
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return LibMath._cobbDouglasSimplifiedInverse(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaDenominator
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,79 +145,18 @@ describe('Staking Core', () => {
|
||||
expect(rootAsFloatingPoint).to.be.bignumber.equal(expectedResult);
|
||||
});
|
||||
|
||||
it.skip('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.skip('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);
|
||||
});
|
||||
|
||||
it.only('cobb douglas - complex token computation', async() => {
|
||||
it('cobb douglas - approximate', async() => {
|
||||
const totalRewards = stakingWrapper.toBaseUnitAmount(57.154398);
|
||||
const ownerFees = stakingWrapper.toBaseUnitAmount(5.64375);
|
||||
const totalFees = stakingWrapper.toBaseUnitAmount(29.00679);
|
||||
const ownerStake = stakingWrapper.toBaseUnitAmount(56);
|
||||
const totalStake = stakingWrapper.toBaseUnitAmount(10906);
|
||||
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*/
|
||||
console.log(`EXPECTED - `, stakingWrapper.toFloatingPoint(expectedOwnerReward, 18));
|
||||
|
||||
const alphaNumerator = new BigNumber(3);
|
||||
const alphaDenominator = new BigNumber(7);
|
||||
// create expected output
|
||||
// https://www.wolframalpha.com/input/?i=57.154398+*+(5.64375%2F29.00679)+%5E+(3%2F7)+*+(56+%2F+10906)+%5E+(1+-+3%2F7)
|
||||
const expectedOwnerReward = new BigNumber(1.3934);
|
||||
// run computation
|
||||
const ownerReward = await stakingWrapper.cobbDouglas(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
@ -227,34 +166,58 @@ describe('Staking Core', () => {
|
||||
alphaNumerator,
|
||||
alphaDenominator
|
||||
);
|
||||
console.log(`ACTUAL - `, stakingWrapper.toFloatingPoint(ownerReward, 18));
|
||||
//expect(ownerReward).to.be.bignumber.equal(expectedOwnerReward);
|
||||
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(stakingWrapper.toFloatingPoint(ownerReward, 18), 4);
|
||||
// validation
|
||||
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
|
||||
});
|
||||
|
||||
it.only('cobb douglas - complex token computation #2', async() => {
|
||||
it('cobb douglas - simplified (alpha = 1/x)', async() => {
|
||||
// setup test parameters
|
||||
const totalRewards = stakingWrapper.toBaseUnitAmount(57.154398);
|
||||
const ownerFees = stakingWrapper.toBaseUnitAmount(5.64375);
|
||||
const totalFees = stakingWrapper.toBaseUnitAmount(29.00679);
|
||||
const ownerStake = stakingWrapper.toBaseUnitAmount(56);
|
||||
const totalStake = stakingWrapper.toBaseUnitAmount(10906);
|
||||
const alphaNumerator = new BigNumber(1);
|
||||
const alphaDenominator = new BigNumber(3);
|
||||
|
||||
// create expected output
|
||||
// https://www.wolframalpha.com/input/?i=57.154398+*+(5.64375%2F29.00679)+%5E+(1%2F3)+*+(56+%2F+10906)+%5E+(1+-+1%2F3)
|
||||
console.log(`EXPECTED - 0.9857...`);
|
||||
|
||||
const ownerReward = await stakingWrapper.cobbDouglas(
|
||||
const expectedOwnerReward = new BigNumber(0.98572107681878);
|
||||
// run computation
|
||||
const ownerReward = await stakingWrapper.cobbDouglasSimplified(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaNumerator,
|
||||
alphaDenominator
|
||||
);
|
||||
//console.log(ownerReward);
|
||||
console.log(`ACTUAL - `, stakingWrapper.toFloatingPoint(ownerReward, 18));
|
||||
//expect(ownerReward).to.be.bignumber.equal(expectedOwnerReward);
|
||||
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(stakingWrapper.toFloatingPoint(ownerReward, 18), 14);
|
||||
// validation
|
||||
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
|
||||
});
|
||||
|
||||
it('cobb douglas - simplified inverse (1 - alpha = 1/x)', async() => {
|
||||
const totalRewards = stakingWrapper.toBaseUnitAmount(57.154398);
|
||||
const ownerFees = stakingWrapper.toBaseUnitAmount(5.64375);
|
||||
const totalFees = stakingWrapper.toBaseUnitAmount(29.00679);
|
||||
const ownerStake = stakingWrapper.toBaseUnitAmount(56);
|
||||
const totalStake = stakingWrapper.toBaseUnitAmount(10906);
|
||||
const inverseAlphaDenominator = new BigNumber(3);
|
||||
// create expected output
|
||||
// https://www.wolframalpha.com/input/?i=57.154398+*+(5.64375%2F29.00679)+%5E+(2%2F3)+*+(56+%2F+10906)+%5E+(1+-+2%2F3)
|
||||
const expectedOwnerReward = new BigNumber(3.310822494188);
|
||||
// run computation
|
||||
const ownerReward = await stakingWrapper.cobbDouglasSimplifiedInverse(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
inverseAlphaDenominator
|
||||
);
|
||||
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(stakingWrapper.toFloatingPoint(ownerReward, 18), 12);
|
||||
// validation
|
||||
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -126,6 +126,42 @@ export class StakingWrapper {
|
||||
);
|
||||
return output;
|
||||
}
|
||||
public async cobbDouglasSimplified(
|
||||
totalRewards: BigNumber,
|
||||
ownerFees: BigNumber,
|
||||
totalFees: BigNumber,
|
||||
ownerStake: BigNumber,
|
||||
totalStake: BigNumber,
|
||||
alphaDenominator: BigNumber
|
||||
) {
|
||||
const output = await this.getLibMathTestContract().cobbDouglasSimplified.callAsync(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaDenominator
|
||||
);
|
||||
return output;
|
||||
}
|
||||
public async cobbDouglasSimplifiedInverse(
|
||||
totalRewards: BigNumber,
|
||||
ownerFees: BigNumber,
|
||||
totalFees: BigNumber,
|
||||
ownerStake: BigNumber,
|
||||
totalStake: BigNumber,
|
||||
alphaDenominator: BigNumber
|
||||
) {
|
||||
const output = await this.getLibMathTestContract().cobbDouglasSimplifiedInverse.callAsync(
|
||||
totalRewards,
|
||||
ownerFees,
|
||||
totalFees,
|
||||
ownerStake,
|
||||
totalStake,
|
||||
alphaDenominator
|
||||
);
|
||||
return output;
|
||||
}
|
||||
public toBaseUnitAmount(amount: BigNumber | number): BigNumber {
|
||||
const decimals = 18;
|
||||
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
|
||||
@ -144,6 +180,12 @@ export class StakingWrapper {
|
||||
const amountAsFloatingPoint = amountAsBigNumber.dividedBy(scalar);
|
||||
return amountAsFloatingPoint;
|
||||
}
|
||||
public trimFloat(amount: BigNumber | number, decimals: number): BigNumber {
|
||||
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
|
||||
const scalar = Math.pow(10, decimals);
|
||||
const amountAsFloatingPoint = ((amountAsBigNumber.multipliedBy(scalar)).dividedToIntegerBy(1)).dividedBy(scalar);
|
||||
return amountAsFloatingPoint;
|
||||
}
|
||||
private _validateDeployedOrThrow() {
|
||||
if (this._stakingContractIfExists === undefined) {
|
||||
throw new Error('Staking contract not deployed. Call `deployStakingContracts`');
|
||||
|
Loading…
x
Reference in New Issue
Block a user