diff --git a/contracts/libs/decimals/DecimalsConverter.sol b/contracts/libs/decimals/DecimalsConverter.sol index 99e4c255..1b07f740 100644 --- a/contracts/libs/decimals/DecimalsConverter.sol +++ b/contracts/libs/decimals/DecimalsConverter.sol @@ -80,7 +80,7 @@ library DecimalsConverter { * @return the number brought to 18 decimals of precision */ function to18Safe(uint256 amount_, uint256 baseDecimals_) internal pure returns (uint256) { - return convertSafe(amount_, baseDecimals_, precisionTo18); + return _convertSafe(amount_, baseDecimals_, _to18); } /** @@ -122,7 +122,7 @@ library DecimalsConverter { * @return the number brought from 18 to desired decimals of precision */ function from18Safe(uint256 amount_, uint256 destDecimals_) internal pure returns (uint256) { - return convertSafe(amount_, destDecimals_, precisionFrom18); + return _convertSafe(amount_, destDecimals_, _from18); } /** @@ -142,7 +142,7 @@ library DecimalsConverter { * @return the rounded number. Comes with 18 precision decimals */ function round18Safe(uint256 amount_, uint256 decimals_) internal pure returns (uint256) { - return convertSafe(amount_, decimals_, round18); + return _convertSafe(amount_, decimals_, round18); } /** @@ -152,7 +152,7 @@ library DecimalsConverter { * @param destToken_ desired token * @return the converted number */ - function roundTokens( + function convert( uint256 amount_, address baseToken_, address destToken_ @@ -160,6 +160,27 @@ library DecimalsConverter { return convert(amount_, uint256(decimals(baseToken_)), uint256(decimals(destToken_))); } + /** + * @notice The function to do the precision convertion + * @param amount_ the amount to covert + * @param baseDecimals_ current number precision + * @param destDecimals_ desired number precision + * @return the converted number + */ + function convert( + uint256 amount_, + uint256 baseDecimals_, + uint256 destDecimals_ + ) internal pure returns (uint256) { + if (baseDecimals_ > destDecimals_) { + amount_ = amount_ / 10 ** (baseDecimals_ - destDecimals_); + } else if (baseDecimals_ < destDecimals_) { + amount_ = amount_ * 10 ** (destDecimals_ - baseDecimals_); + } + + return amount_; + } + /** * @notice The function to do the token precision convertion. Reverts if output is zero * @param amount_ the amount to convert @@ -167,44 +188,47 @@ library DecimalsConverter { * @param destToken_ desired token * @return the converted number */ - function roundTokensSave( + function convertTokensSafe( uint256 amount_, address baseToken_, address destToken_ ) internal view returns (uint256) { - return convertTokensSafe(amount_, baseToken_, destToken_, roundTokens); + return _convertTokensSafe(amount_, baseToken_, destToken_, _convertTokens); } - function precisionTo18(uint256 amount_, uint256 baseDecimals_) private pure returns (uint256) { + /** + * @notice The function to bring the number to 18 decimals of precision + * @param amount_ the number to convert + * @param baseDecimals_ the current precision of the number + * @return the number brought to 18 decimals of precision + */ + function _to18(uint256 amount_, uint256 baseDecimals_) private pure returns (uint256) { return convert(amount_, baseDecimals_, 18); } - function precisionFrom18( - uint256 amount_, - uint256 destDecimals_ - ) private pure returns (uint256) { + /** + * @notice The function to bring the number from 18 decimals to the desired decimals of precision + * @param amount_ the number to covert + * @param destDecimals_ the desired precision decimals + * @return the number brought from 18 to desired decimals of precision + */ + function _from18(uint256 amount_, uint256 destDecimals_) private pure returns (uint256) { return convert(amount_, 18, destDecimals_); } /** - * @notice The function to do the precision convertion - * @param amount_ the amount to covert - * @param baseDecimals_ current number precision - * @param destDecimals_ desired number precision + * @notice The function to do the token precision convertion + * @param amount_ the amount to convert + * @param baseToken_ current token + * @param destToken_ desired token * @return the converted number */ - function convert( + function _convertTokens( uint256 amount_, - uint256 baseDecimals_, - uint256 destDecimals_ - ) private pure returns (uint256) { - if (baseDecimals_ > destDecimals_) { - amount_ = amount_ / 10 ** (baseDecimals_ - destDecimals_); - } else if (baseDecimals_ < destDecimals_) { - amount_ = amount_ * 10 ** (destDecimals_ - baseDecimals_); - } - - return amount_; + address baseToken_, + address destToken_ + ) private view returns (uint256) { + return convert(amount_, uint256(decimals(baseToken_)), uint256(decimals(destToken_))); } /** @@ -214,7 +238,7 @@ library DecimalsConverter { * @param _convertFunc the internal function pointer to "from", "to", or "round" functions * @return conversionResult_ the convertion result */ - function convertSafe( + function _convertSafe( uint256 amount_, uint256 decimals_, function(uint256, uint256) internal pure returns (uint256) _convertFunc @@ -232,7 +256,7 @@ library DecimalsConverter { * @param _convertFunc the internal function pointer to "from", "to", or "round" functions * @return conversionResult_ the convertion result */ - function convertTokensSafe( + function _convertTokensSafe( uint256 amount_, address baseToken_, address destToken_, diff --git a/contracts/mock/libs/decimals/DecimalsConverterMock.sol b/contracts/mock/libs/decimals/DecimalsConverterMock.sol index 046b04fd..75811a4d 100644 --- a/contracts/mock/libs/decimals/DecimalsConverterMock.sol +++ b/contracts/mock/libs/decimals/DecimalsConverterMock.sol @@ -51,19 +51,27 @@ contract DecimalsConverterMock { return amount_.round18Safe(decimals_); } - function roundTokens( + function convert( + uint256 amount_, + uint256 baseDecimals_, + uint256 destDecimals_ + ) external pure returns (uint256) { + return amount_.convert(baseDecimals_, destDecimals_); + } + + function convert( uint256 amount_, address baseToken_, address destToken_ ) public view returns (uint256) { - return amount_.roundTokens(baseToken_, destToken_); + return amount_.convert(baseToken_, destToken_); } - function roundTokensSave( + function convertTokensSafe( uint256 amount_, address baseToken_, address destToken_ ) external view returns (uint256) { - return amount_.roundTokensSave(baseToken_, destToken_); + return amount_.convertTokensSafe(baseToken_, destToken_); } } diff --git a/test/libs/decimals/DecimalsConverter.test.js b/test/libs/decimals/DecimalsConverter.test.js index 8c2c9516..ccafa167 100644 --- a/test/libs/decimals/DecimalsConverter.test.js +++ b/test/libs/decimals/DecimalsConverter.test.js @@ -25,6 +25,62 @@ describe("DecimalsConverter", () => { }); }); + describe("convert", () => { + it("should convert", async () => { + assert.equal((await mock.methods["convert(uint256,uint256,uint256)"](wei("1"), 18, 6)).toFixed(), wei("1", 6)); + assert.equal((await mock.methods["convert(uint256,uint256,uint256)"](wei("1", 6), 6, 18)).toFixed(), wei("1")); + assert.equal( + (await mock.methods["convert(uint256,uint256,uint256)"](wei("1", 6), 18, 18)).toFixed(), + wei("1", 6) + ); + }); + + it("should convert tokens", async () => { + const token1 = await ERC20Mock.new("MK1", "MK1", 18); + const token2 = await ERC20Mock.new("MK2", "MK2", 3); + + assert.equal( + (await mock.methods["convert(uint256,address,address)"](wei("1"), token1.address, token2.address)).toFixed(), + wei("1", 3) + ); + assert.equal( + (await mock.methods["convert(uint256,address,address)"](wei("1", 3), token2.address, token1.address)).toFixed(), + wei("1") + ); + }); + }); + + describe("convert tokens safe", () => { + it("should correctly convert tokens", async () => { + const token1 = await ERC20Mock.new("MK1", "MK1", 6); + const token2 = await ERC20Mock.new("MK2", "MK2", 9); + + assert.equal( + ( + await mock.methods["convertTokensSafe(uint256,address,address)"](wei("1", 6), token1.address, token2.address) + ).toFixed(), + wei("1", 9) + ); + assert.equal( + ( + await mock.methods["convertTokensSafe(uint256,address,address)"](wei("1", 9), token2.address, token1.address) + ).toFixed(), + wei("1", 6) + ); + }); + it("should get exception if the result of conversion is zero", async () => { + const token1 = await ERC20Mock.new("MK1", "MK1", 18); + const token2 = await ERC20Mock.new("MK2", "MK2", 3); + + const reason = "DecimalsConverter: conversion failed"; + + await truffleAssert.reverts( + mock.methods["convertTokensSafe(uint256,address,address)"](wei("1", 3), token1.address, token2.address), + reason + ); + }); + }); + describe("to18", () => { it("should convert to 18", async () => { assert.equal((await mock.methods["to18(uint256,uint256)"](wei("1", 6), 6)).toFixed(), wei("1")); @@ -147,31 +203,4 @@ describe("DecimalsConverter", () => { await truffleAssert.reverts(mock.round18Safe(wei("1", 6), 6), reason); }); }); - - describe("roundTokens", () => { - it("should round tokens decimals", async () => { - const token1 = await ERC20Mock.new("MK1", "MK1", 18); - const token2 = await ERC20Mock.new("MK2", "MK2", 3); - - assert.equal((await mock.roundTokens(wei("1"), token1.address, token2.address)).toFixed(), wei("1", 3)); - assert.equal((await mock.roundTokens(wei("1", 3), token2.address, token1.address)).toFixed(), wei("1")); - }); - }); - describe("roundTokensSafe", () => { - it("should round tokens decimals", async () => { - const token1 = await ERC20Mock.new("MK1", "MK1", 6); - const token2 = await ERC20Mock.new("MK2", "MK2", 9); - - assert.equal((await mock.roundTokensSave(wei("1", 6), token1.address, token2.address)).toFixed(), wei("1", 9)); - assert.equal((await mock.roundTokensSave(wei("1", 9), token2.address, token1.address)).toFixed(), wei("1", 6)); - }); - it("should get exception if the result of conversion is zero", async () => { - const token1 = await ERC20Mock.new("MK1", "MK1", 18); - const token2 = await ERC20Mock.new("MK2", "MK2", 3); - - const reason = "DecimalsConverter: conversion failed"; - - await truffleAssert.reverts(mock.roundTokensSave(wei("1", 3), token1.address, token2.address), reason); - }); - }); });