Skip to content

Commit 25c21fe

Browse files
committed
Use preciseDivCeil (int256) when issuing in #_executePositionTrades
1 parent ae35b81 commit 25c21fe

File tree

4 files changed

+113
-5
lines changed

4 files changed

+113
-5
lines changed

contracts/lib/PreciseUnitMath.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol"
3434
* CHANGELOG:
3535
* - 9/21/20: Added safePower function
3636
* - 4/21/21: Added approximatelyEquals function
37+
* - 12/13/21: Added preciseDivCeil (int overloads) function
38+
* - 12/13/21: Added abs function
3739
*/
3840
library PreciseUnitMath {
3941
using SafeMath for uint256;
@@ -136,6 +138,22 @@ library PreciseUnitMath {
136138
return a > 0 ? a.mul(PRECISE_UNIT).sub(1).div(b).add(1) : 0;
137139
}
138140

141+
/**
142+
* @dev Divides value a by value b (result is rounded up or away from 0). When `a` is 0, 0 is
143+
* returned. When `b` is 0, method reverts with divide-by-zero error.
144+
*/
145+
function preciseDivCeil(int256 a, int256 b) internal pure returns (int256) {
146+
require(b != 0, "Cant divide by 0");
147+
148+
if (a == 0 ) {
149+
return 0;
150+
} else if ((a > 0 && b > 0) || (a < 0 && b < 0)) {
151+
return a.mul(PRECISE_UNIT_INT).sub(1).div(b).add(1);
152+
} else {
153+
return a.mul(PRECISE_UNIT_INT).add(1).div(b).sub(1);
154+
}
155+
}
156+
139157
/**
140158
* @dev Divides value a by value b (result is rounded down - positive numbers toward 0 and negative away from 0).
141159
*/

contracts/mocks/PreciseUnitMathMock.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ contract PreciseUnitMathMock {
6666
return a.preciseDivCeil(b);
6767
}
6868

69+
function preciseDivCeilInt(int256 a, int256 b) external pure returns(int256) {
70+
return a.preciseDivCeil(b);
71+
}
72+
6973
function divDown(int256 a, int256 b) external pure returns(int256) {
7074
return a.divDown(b);
7175
}

contracts/protocol/modules/PerpV2LeverageModule.sol

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -751,12 +751,10 @@ contract PerpV2LeverageModule is ModuleBase, ReentrancyGuard, Ownable, AllowSetT
751751
}
752752

753753
// Return value in collateral decimals (e.g USDC = 6)
754-
//
755-
// TODO - we need to add a method to preciseMath to handle the int case for this....
756-
//
757754
// Use preciseDivCeil when issuing to ensure we don't under-collateralize due to rounding error
758-
// _isIssue ? accountValueIssued.preciseDivCeil(setTokenQuantityInt) : accountValueIssued.preciseDiv(setTokenQuantityInt),
759-
return accountValueIssued.preciseDiv(setTokenQuantityInt).fromPreciseUnitToDecimals(collateralDecimals);
755+
return (_isIssue)
756+
? accountValueIssued.preciseDivCeil(setTokenQuantityInt).fromPreciseUnitToDecimals(collateralDecimals)
757+
: accountValueIssued.preciseDiv(setTokenQuantityInt).fromPreciseUnitToDecimals(collateralDecimals);
760758
}
761759

762760
/**

test/lib/preciseUnitMath.spec.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ describe("PreciseUnitMath", () => {
3030

3131
// Used to make sure rounding is done correctly, 1020408168544454473
3232
const preciseNumber = BigNumber.from("0x0e2937d2abffc749");
33+
const negativePreciseNumber = preciseNumber.mul(-1);
3334

3435
before(async () => {
3536
[
@@ -236,6 +237,93 @@ describe("PreciseUnitMath", () => {
236237
});
237238
});
238239

240+
describe("#preciseDivCeil: int256", async () => {
241+
let subjectA: BigNumber;
242+
let subjectB: BigNumber;
243+
244+
async function subject(): Promise<BigNumber> {
245+
return mathMock.preciseDivCeilInt(subjectA, subjectB);
246+
}
247+
248+
describe("when a and b are positive", () => {
249+
beforeEach(async () => {
250+
subjectA = preciseNumber;
251+
subjectB = ether(.3);
252+
});
253+
254+
it("returns the correct number", async () => {
255+
const division = await subject();
256+
257+
const expectedDivision = preciseDivCeilInt(subjectA, subjectB);
258+
expect(division).to.eq(expectedDivision);
259+
});
260+
});
261+
262+
describe("when a and b are negative", () => {
263+
beforeEach(async () => {
264+
subjectA = negativePreciseNumber;
265+
subjectB = ether(-.3);
266+
});
267+
268+
it("returns the correct number", async () => {
269+
const division = await subject();
270+
271+
const expectedDivision = preciseDivCeilInt(subjectA, subjectB);
272+
expect(division).to.eq(expectedDivision);
273+
});
274+
});
275+
276+
describe("when a is positive and b is negative", () => {
277+
beforeEach(async () => {
278+
subjectA = preciseNumber;
279+
subjectB = ether(-.3);
280+
});
281+
282+
it("returns the correct number", async () => {
283+
const division = await subject();
284+
285+
const expectedDivision = preciseDivCeilInt(subjectA, subjectB);
286+
expect(division).to.eq(expectedDivision);
287+
});
288+
});
289+
290+
describe("when a is negative and b is positive", () => {
291+
beforeEach(async () => {
292+
subjectA = negativePreciseNumber;
293+
subjectB = ether(.3);
294+
});
295+
296+
it("returns the correct number", async () => {
297+
const division = await subject();
298+
299+
const expectedDivision = preciseDivCeilInt(subjectA, subjectB);
300+
expect(division).to.eq(expectedDivision);
301+
});
302+
});
303+
304+
describe("when a is 0", async () => {
305+
beforeEach(async () => {
306+
subjectA = ZERO;
307+
});
308+
309+
it("should return 0", async () => {
310+
const division = await subject();
311+
expect(division).to.eq(ZERO);
312+
});
313+
});
314+
315+
describe("when b is 0", async () => {
316+
beforeEach(async () => {
317+
subjectA = ZERO;
318+
subjectB = ZERO;
319+
});
320+
321+
it("should revert", async () => {
322+
await expect(subject()).to.be.revertedWith("Cant divide by 0");
323+
});
324+
});
325+
});
326+
239327
describe("#divDown: int256", async () => {
240328
let subjectA: BigNumber;
241329
let subjectB: BigNumber;

0 commit comments

Comments
 (0)