Skip to content

Commit

Permalink
fix: off-by-one: minimum positive result of getOutputPrice() is 1 (#2198
Browse files Browse the repository at this point in the history
)

* fix: off-by-one: minimum positive result of getOutputPrice() is 1

* fix: add one as BigInt before converting to Nat.
  • Loading branch information
Chris-Hibbert authored Jan 16, 2021
1 parent 3cb4606 commit 82d68d9
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 9 deletions.
3 changes: 2 additions & 1 deletion packages/zoe/src/contractSupport/bondingCurves.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { multiply, floorDivide } = natSafeMath;
// We use this workaround due to some parser in our toolchain that can't parse
// bigint literals.
const BIG_10000 = BigInt(10000);
const BIG_ONE = BigInt(1);

/**
* Calculations for constant product markets like Uniswap.
Expand Down Expand Up @@ -98,7 +99,7 @@ export const getOutputPrice = (
const numerator = BigInt(outputValue) * BigInt(inputReserve) * BIG_10000;
const denominator =
(BigInt(outputReserve) - BigInt(outputValue)) * oneMinusFeeScaled;
return Nat(Number(numerator / denominator));
return Nat(Number(numerator / denominator + BIG_ONE));
};

function assertDefined(label, value) {
Expand Down
12 changes: 7 additions & 5 deletions packages/zoe/test/autoswapJig.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@ export const outputFromInputPrice = (xPre, yPre, deltaX, fee) => {
);
};

// deltaX = beta * xPre / ( (1 - beta) * gamma )
// deltaX = (beta * xPre / ( (1 - beta) * gamma )) + 1
// gamma is (10000 - fee) / 10000
// beta is deltaY / yPre
// reducing to a single division:
// deltaX = deltaY * xPre * 10000 / (yPre - deltaY ) * gammaNum)
// deltaX = (deltaY * xPre * 10000 / (yPre - deltaY ) * gammaNum)) + 1
export const priceFromTargetOutput = (deltaY, yPre, xPre, fee) => {
const gammaNumerator = 10000 - fee;
return floorDivide(
multiply(multiply(deltaY, xPre), 10000),
multiply(subtract(yPre, deltaY), gammaNumerator),
return (
floorDivide(
multiply(multiply(deltaY, xPre), 10000),
multiply(subtract(yPre, deltaY), gammaNumerator),
) + 1
);
};

Expand Down
2 changes: 1 addition & 1 deletion packages/zoe/test/swingsetTests/zoe/test-zoe.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ const expectedAutoswapOkLog = [
'Swap successfully completed.',
'bobMoolaPurse: balance {"brand":{},"value":5}',
'bobSimoleanPurse: balance {"brand":{},"value":5}',
'simoleans required {"brand":{},"value":4}',
'simoleans required {"brand":{},"value":5}',
'Liquidity successfully removed.',
'poolAmounts{"Liquidity":{"brand":{},"value":10},"Central":{"brand":{},"value":0},"Secondary":{"brand":{},"value":0}}',
'aliceMoolaPurse: balance {"brand":{},"value":8}',
Expand Down
14 changes: 12 additions & 2 deletions packages/zoe/test/unitTests/contractSupport/test-bondingCurves.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ test('getOutputPrice ok', t => {
inputReserve: 43,
outputValue: 37,
};
const expectedOutput = 19;
const expectedOutput = 20;
testGetOutputPrice(t, input, expectedOutput);
});

Expand Down Expand Up @@ -231,6 +231,16 @@ test('getOutputPrice big product', t => {
inputReserve: 100000000,
outputValue: 1000,
};
const expectedOutput = 1003;
const expectedOutput = 1004;
testGetOutputPrice(t, input, expectedOutput);
});

test('getOutputPrice minimum price', t => {
const input = {
outputReserve: 10,
inputReserve: 1,
outputValue: 1,
};
const expectedOutput = 1;
testGetOutputPrice(t, input, expectedOutput);
});

0 comments on commit 82d68d9

Please sign in to comment.