Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion contracts/utils/Math.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,37 @@
pragma solidity ^0.8.8;

library Math {
/**
* @notice select the greater of two numbers
* @param a first number
* @param b second number
* @return greater number
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}

/**
* @notice select the lesser of two numbers
* @param a first number
* @param b second number
* @return lesser number
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? b : a;
}

/**
* @notice calculate the average of two numbers, rounded down
* @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
* @param a first number
* @param b second number
* @return mean value
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a >> 1) + (b >> 1) + (((a & 1) + (b & 1)) >> 1);
unchecked {
return (a & b) + ((a ^ b) >> 1);
}
}

/**
Expand Down
10 changes: 9 additions & 1 deletion contracts/utils/MathMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ import { Math } from './Math.sol';
contract MathMock {
using Math for uint256;

function max(uint256 a, uint256 b) external pure returns (uint256) {
return Math.max(a, b);
}

function min(uint256 a, uint256 b) external pure returns (uint256) {
return Math.min(a, b);
}

function average(uint256 a, uint256 b) external pure returns (uint256) {
return a.average(b);
return Math.average(a, b);
}

function sqrt(uint256 x) external pure returns (uint256) {
Expand Down
95 changes: 83 additions & 12 deletions test/utils/Math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,56 +11,127 @@ describe('Math', function () {
});

describe('__internal', function () {
describe('#max(uint256,uint256)', function () {
it('returns the greater of two numbers', async () => {
expect(
await instance.callStatic.max(
ethers.constants.One,
ethers.constants.Two,
),
).to.equal(ethers.constants.Two);

expect(
await instance.callStatic.max(
ethers.constants.Two,
ethers.constants.One,
),
).to.equal(ethers.constants.Two);

expect(
await instance.callStatic.max(
ethers.constants.One,
ethers.constants.One,
),
).to.equal(ethers.constants.One);

expect(
await instance.callStatic.max(
ethers.constants.Zero,
ethers.constants.MaxUint256,
),
).to.equal(ethers.constants.MaxUint256);
});
});

describe('#min(uint256,uint256)', function () {
it('returns the lesser of two numbers', async () => {
expect(
await instance.callStatic.min(
ethers.constants.One,
ethers.constants.Two,
),
).to.equal(ethers.constants.One);

expect(
await instance.callStatic.min(
ethers.constants.Two,
ethers.constants.One,
),
).to.equal(ethers.constants.One);

expect(
await instance.callStatic.min(
ethers.constants.One,
ethers.constants.One,
),
).to.equal(ethers.constants.One);

expect(
await instance.callStatic.min(
ethers.constants.Zero,
ethers.constants.MaxUint256,
),
).to.equal(ethers.constants.Zero);
});
});

describe('#average(uint256,uint256)', function () {
it('returns the average of two positive numbers from 0 to maxUint256', async function () {
expect(
await instance.average(
await instance.callStatic.average(
ethers.BigNumber.from('11'),
ethers.BigNumber.from('5'),
),
).to.equal(ethers.BigNumber.from('8'));

expect(
await instance.average(
await instance.callStatic.average(
ethers.BigNumber.from('6'),
ethers.BigNumber.from('5'),
),
).to.equal(ethers.BigNumber.from('5'));

expect(
await instance.average(
await instance.callStatic.average(
ethers.BigNumber.from('0'),
ethers.BigNumber.from('0'),
),
).to.equal(ethers.BigNumber.from('0'));

expect(
await instance.average(
await instance.callStatic.average(
ethers.constants.MaxUint256,
ethers.constants.MaxUint256,
),
).to.equal(ethers.constants.MaxUint256);

expect(
await instance.callStatic.average(
ethers.constants.MaxUint256,
ethers.constants.MaxUint256.sub(ethers.constants.One),
),
).to.equal(ethers.constants.MaxUint256.sub(ethers.constants.One));
});
});

describe('#sqrt(uint256)', function () {
it('returns the sqrt of a positive integer from 0 to maxUint256', async function () {
expect(await instance.sqrt(ethers.BigNumber.from('16'))).to.eq(
ethers.BigNumber.from('4'),
);
expect(
await instance.callStatic.sqrt(ethers.BigNumber.from('16')),
).to.eq(ethers.BigNumber.from('4'));

for (let i = 10; i < 16; i++) {
expect(
await instance.sqrt(ethers.BigNumber.from(i.toString())),
await instance.callStatic.sqrt(ethers.BigNumber.from(i.toString())),
).to.eq(ethers.BigNumber.from('3'));
}

expect(await instance.sqrt(ethers.BigNumber.from('0'))).to.eq(
ethers.BigNumber.from('0'),
);
expect(
await instance.callStatic.sqrt(ethers.BigNumber.from('0')),
).to.eq(ethers.BigNumber.from('0'));

expect(
await instance.sqrt(
await instance.callStatic.sqrt(
ethers.constants.MaxUint256.sub(ethers.BigNumber.from('1')),
),
).to.eq(
Expand Down