浏览代码

A function which returns the absolute value of a signed value (#2984)

* Add a function which returns the absolute (and obviously unsigned) value of a signed value.

* add changelog entry and fix lint

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
barakman 3 年之前
父节点
当前提交
f6db5c1f30
共有 4 个文件被更改,包括 32 次插入1 次删除
  1. 1 0
      CHANGELOG.md
  2. 4 0
      contracts/mocks/MathMock.sol
  3. 10 0
      contracts/utils/math/Math.sol
  4. 17 1
      test/utils/math/Math.test.js

+ 1 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@
 ## Unreleased
 
 * `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977))
+* `Math`: add a `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984))
 
 ## Unreleased
 

+ 4 - 0
contracts/mocks/MathMock.sol

@@ -20,4 +20,8 @@ contract MathMock {
     function ceilDiv(uint256 a, uint256 b) public pure returns (uint256) {
         return Math.ceilDiv(a, b);
     }
+
+    function abs(int256 n) public pure returns (uint256) {
+        return Math.abs(n);
+    }
 }

+ 10 - 0
contracts/utils/math/Math.sol

@@ -40,4 +40,14 @@ library Math {
         // (a + b - 1) / b can overflow on addition, so we distribute.
         return a / b + (a % b == 0 ? 0 : 1);
     }
+
+    /**
+     * @dev Returns the absolute unsigned value of a signed value.
+     */
+    function abs(int256 n) internal pure returns (uint256) {
+        unchecked {
+            // must be unchecked in order to support `n = type(int256).min`
+            return uint256(n >= 0 ? n : -n);
+        }
+    }
 }

+ 17 - 1
test/utils/math/Math.test.js

@@ -1,6 +1,6 @@
 const { BN, constants } = require('@openzeppelin/test-helpers');
 const { expect } = require('chai');
-const { MAX_UINT256 } = constants;
+const { MAX_UINT256, MAX_INT256, MIN_INT256 } = constants;
 
 const MathMock = artifacts.require('MathMock');
 
@@ -85,4 +85,20 @@ contract('Math', function (accounts) {
       expect(await this.math.ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(MAX_UINT256);
     });
   });
+
+  describe('abs', function () {
+    for (const n of [
+      MIN_INT256,
+      MIN_INT256.addn(1),
+      new BN('-1'),
+      new BN('0'),
+      new BN('1'),
+      MAX_INT256.subn(1),
+      MAX_INT256,
+    ]) {
+      it(`correctly computes the absolute value of ${n}`, async function () {
+        expect(await this.math.abs(n)).to.be.bignumber.equal(n.abs());
+      });
+    }
+  });
 });