├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .solcover.js ├── .soliumignore ├── .soliumrc.json ├── LICENSE ├── README.md ├── contracts ├── ExponentLib.sol ├── FixidityLib.sol ├── LogarithmLib.sol ├── Migrations.sol └── mocks │ ├── FixidityLibMock.sol │ └── LogarithmLibMock.sol ├── migrations ├── 1_initial_migration.js ├── 2_deploy_libraries.js └── 3_deploy_mocks.js ├── package.json ├── test ├── FixidityLibMock_abs.js ├── FixidityLibMock_add.js ├── FixidityLibMock_convertFixed.js ├── FixidityLibMock_divide.js ├── FixidityLibMock_fractional.js ├── FixidityLibMock_fromFixed.js ├── FixidityLibMock_integer.js ├── FixidityLibMock_multiply.js ├── FixidityLibMock_newFixed.js ├── FixidityLibMock_newFixedFraction.js ├── FixidityLibMock_reciprocal.js ├── FixidityLibMock_subtract.js ├── FixidityLibMock_variables.js ├── LogarithmLibMock.js └── utils.js ├── truffle-config.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | coverage 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "indent": [ 5 | "error", 6 | 4 7 | ], 8 | "max-len": [2, 126, 4] 9 | }, 10 | "env": { 11 | "mocha": true, 12 | "es6": true 13 | }, 14 | "globals": { 15 | "artifacts": true, 16 | "web3": true, 17 | "contract": true, 18 | "assert": true 19 | } 20 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | coverage.json 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # Bower dependency directory (https://bower.io/) 28 | bower_components 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (https://nodejs.org/api/addons.html) 34 | build 35 | 36 | # Dependency directories 37 | node_modules/ 38 | jspm_packages/ 39 | 40 | # TypeScript v1 declaration files 41 | typings/ 42 | 43 | # Optional npm cache directory 44 | .npm 45 | 46 | # Optional eslint cache 47 | .eslintcache 48 | 49 | # Optional REPL history 50 | .node_repl_history 51 | 52 | # Output of 'npm pack' 53 | *.tgz 54 | 55 | # Yarn Integrity file 56 | .yarn-integrity 57 | 58 | # dotenv environment variables file 59 | .env 60 | .env.test 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # vuepress build output 72 | .vuepress/dist 73 | 74 | # Serverless directories 75 | .serverless/ 76 | 77 | # FuseBox cache 78 | .fusebox/ 79 | 80 | # DynamoDB Local files 81 | .dynamodb/ 82 | 83 | # images 84 | *.png -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | skipFiles: [] 3 | }; 4 | -------------------------------------------------------------------------------- /.soliumignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | contracts/mocks 3 | contracts/test -------------------------------------------------------------------------------- /.soliumrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solium:all", 3 | "plugins": ["security"], 4 | "rules": { 5 | "error-reason": "off", 6 | "indentation": ["error", 4], 7 | "lbrace": "off", 8 | "linebreak-style": ["error", "unix"], 9 | "max-len": ["error", 126], 10 | "no-constant": ["error"], 11 | "no-empty-blocks": "off", 12 | "quotes": ["error", "double"], 13 | "uppercase": "off", 14 | "visibility-first": "error", 15 | "security/enforce-explicit-visibility": ["error"], 16 | "security/no-block-members": ["warning"], 17 | "security/no-inline-assembly": ["warning"], 18 | "imports-on-top": "warning", 19 | "variable-declarations": "warning", 20 | "array-declarations": "warning", 21 | "operator-whitespace": "warning", 22 | "function-whitespace": "warning", 23 | "semicolon-whitespace": "warning", 24 | "comma-whitespace": "warning", 25 | "conditionals-whitespace": "warning", 26 | "arg-overflow": ["warning", 3] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 1A1Z Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FixidityLib 2 | An overflow-protected fixed-point arithmetic library for Solidity. 3 | 4 | ## Introduction 5 | FixidityLib provide fixed point arithmetic for Solidity. This is achieved by 6 | using int256 as the type throughout the library and designating a number of 7 | digits in each int256 for holding the fractional part. This is equivalent to 8 | displacing the comma in a non-integer number a fixed number of positions to the 9 | left. All the arithmetic operations that have been implemented maintain 10 | constant the number of digits to the left of the comma that are represented. 11 | 12 | The main arithmetic operations currently supported are addition, subtraction, 13 | multiplication, division and logarithms. In a near future exponentials and 14 | square roots might be supported. 15 | 16 | In addition to fixed-point airthmetic operations, FixidityLib is fully 17 | protected against overflow. Any operation that causes an overflow to happen 18 | will revert. 19 | 20 | A number of constants have been provided that identify the safe 21 | limits for operation. When fixed-point arithmetic operations are done with 22 | values between zero and a limit there will be no overflows and therefore the 23 | functions will never revert. It would be then useful in some cases to use 24 | those limits to reject user inputs with an informative message when those 25 | inputs might cause erratic behaviour. With careful consideration it is 26 | possible to perform operations with values that are beyond the limits, but 27 | doing so must only be done with appropriate knowledge of range of each 28 | operator. 29 | 30 | FixidityLib currently assumes 24 digits as the desired size for the decimal 31 | part. To change this to a different value the constants need to be adjusted. 32 | The formulas used to calculate the constants have been provided to facilitate 33 | this. All other functions will work as long as the constants are consistent. 34 | 35 | An extensive collection of tests was created to prove the robustness of 36 | FixidityLib, and they should be run whenever a change in the digits is done. 37 | 38 | Currently FixidityLib doesn't use its own type, so it is up to the user to 39 | remember whether a given int256 is a FixidityLibe fixed point number or not, 40 | and to take care to use the newFixed() and fromFixed() functions accordingly 41 | to create fixed point numbers and convert them back to non-integers. 42 | 43 | ## FixidityLib.sol 44 | This library implements addition, subtraction, 45 | multiplication and division, along with the related constants and limits. 46 | 47 | **function digits() public pure returns(uint8)** 48 | Number of positions that the comma is shifted to the right. 49 | Default: 24 50 | 51 | **function fixed1() public pure returns(int256)** 52 | This is 1 in the fixed point units used in this library. 53 | Calculated as fixed1() = equals 10^digits() 54 | Default: 1000000000000000000000000000000000000 55 | 56 | **function mulPrecision() public pure returns(int256)** 57 | The amount of decimals lost on each multiplication operand. 58 | Calcualted as mulPrecision() = sqrt(fixed1) 59 | Default: 1000000000000000000 60 | 61 | **function maxInt256() public pure returns(int256)** 62 | Maximum value that can be represented in an int256 63 | Calculated as maxInt256() = 2^255 -1 64 | Default: 57896044618658097711785492504343953926634992332820282019728792003956564819967 65 | 66 | **function minInt256() public pure returns(int256)** 67 | Minimum value that can be represented in an int256 68 | Calculated as minInt256() = (2^255) * (-1) 69 | Default: -57896044618658097711785492504343953926634992332820282019728792003956564819968 70 | 71 | **function maxNewFixed() public pure returns(int256)** 72 | Maximum value that can be converted to fixed point. 73 | Default: 57896044618658097711785492504343953926634 74 | 75 | **function minNewFixed() public pure returns(int256)** 76 | Maximum value that can be converted to fixed point. 77 | Calculated as minNewFixed() = -(maxInt256()) / fixed1() 78 | Default: -57896044618658097711785492504343953926634 79 | 80 | **function maxFixedAdd() public pure returns(int256)** 81 | Maximum value that can be safely used as an addition operand. 82 | Additions with one operand over this value might overflow, but not necessarily 83 | so. 84 | Calculated as maxFixedAdd() equals maxInt256()-1 / 2 85 | Default: 28948022309329048855892746252171976963317496166410141009864396001978282409983 86 | 87 | **function maxFixedSub() public pure returns(int256)** 88 | Maximum negative value that can be safely subtracted. Operations where values 89 | larger than maxFixedSub() are subtracted might overflow, but not necessarily 90 | so. 91 | Calculated as maxFixedSub() = minInt256() / 2 92 | Default: -28948022309329048855892746252171976963317496166410141009864396001978282409984 93 | 94 | **function maxFixedMul() public pure returns(int256)** 95 | Maximum value that can be safely used as a multiplication operator. 96 | Divisions where a value is divided by another over this value might overflow, 97 | but not necessarily so. 98 | Calculated as maxFixedMul() = sqrt(maxNewFixed())*fixed1(). 99 | Default: 240615969168004511545000000000000000000000000000000000000 100 | 101 | **function maxFixedDiv() public pure returns(int256)** 102 | Maximum value that can be safely used as a dividend. 103 | Operations where values larger than maxFixedDiv() are divided might 104 | overflow, but not necessarily so. 105 | Calculated as divide(maxFixedDiv,newFixedFraction(1,fixed1())) = maxInt256(). 106 | Default: 57896044618658097711785492504343953926634 107 | } 108 | 109 | **function maxFixedDivisor() public pure returns(int256)** 110 | Maximum value that can be safely used as a divisor. The divide(x, y) function 111 | uses reciprocal(y), and numbers above maxFixedDivisor() will cause a division 112 | by zero. 113 | Calculated as maxFixedDivisor() = fixed1()*fixed1() 114 | Default: 1000000000000000000000000000000000000000000000000000000000000000000000000 115 | 116 | **function newFixed(int256 x)** 117 | Converts an int256 to fixed point units, equivalent to multiplying by 118 | 10^digits(). 119 | 120 | **function fromFixed(int256 x)** 121 | Converts an int256 in the fixed point representation of this library to a non 122 | decimal. All decimal digits will be truncated. 123 | 124 | **function convertFixed(int256 x, uint8 _originDigits, uint8 _destinationDigits)** 125 | Converts an int256 which is already in some fixed point representation to a 126 | different fixed precision representation. Both the origin and destination 127 | precisions must be 38 or less digits. Origin values with a precision higher 128 | than the destination precision will be truncated accordingly. 129 | 130 | **function newFixed(int256 x, uint8 _originDigits)** 131 | Converts an int256 which is already in some fixed point representation to that 132 | of this library. The _originDigits parameter is the precision of x. Values with 133 | a precision higher than FixidityLib.digits() will be truncated accordingly. 134 | 135 | **function fromFixed(int256 x, uint8 _destinationDigits)** 136 | Converts an int256 in the fixed point representation of this library to a 137 | different representation. The _destinationDigits parameter is the precision of 138 | the output x. Values with a precision below than FixidityLib.digits() will be 139 | truncated accordingly. 140 | 141 | **function newFixedFraction(int256 numerator, int256 denominator)** 142 | Converts two int256 representing a fraction to fixed point units, equivalent to 143 | multiplying dividend and divisor by 10^digits() and then dividing them. 144 | 145 | **function integer(int256 x) public pure returns (int256)** 146 | Returns the integer part of a fixed point number, still in fixed point format. 147 | 148 | **function fractional(int256 x) public pure returns (int256)** 149 | Returns the fractional part of a fixed point number. In the case of a negative 150 | number the fractional is also negative. 151 | 152 | **function abs(int256 x) public pure returns (int256)** 153 | Converts to positive if negative. 154 | Due to int256 having one more negative number than positive numbers 155 | abs(minInt256) reverts. 156 | 157 | **function add(int256 x, int256 y) public pure returns (int256)** 158 | x+y. If any operator is higher than maxFixedAdd() it might overflow. 159 | 160 | **function subtract(int256 x, int256 y) public pure returns (int256)** 161 | x-y. You can use add(x,-y) instead. 162 | 163 | **function multiply(int256 x, int256 y) public pure returns (int256)** 164 | x*y. If any of the operators is higher than maxFixedMul() it might overflow. 165 | 166 | **function reciprocal(int256 x) public pure returns (int256)** 167 | 1/x. 168 | 169 | **function divide(int256 x, int256 y) public pure returns (int256)** 170 | x/y. If the dividend is higher than maxFixedDiv() it might overflow. You can 171 | use multiply(x,reciprocal(y)) instead. 172 | There is a loss of precision on division for the lower mulPrecision() decimals. 173 | 174 | ## LogarithmLib.sol 175 | This library extends FixidityLib by implementing logarithms, along with the related constants and limits. 176 | 177 | **function fixedE() public pure returns(int256)** 178 | This is e in the fixed point units used in this library. 179 | Default: 27182818284590452353602874713526624977572470936999595749669676277240766303535/fixed1() 180 | 181 | **function fixedLn1_5() public pure returns(int256)** 182 | ln(1.5) 183 | Default: 405465108108164381978013115464349137; 184 | 185 | **function fixedLn10() public pure returns (int256)** 186 | ln(10) 187 | Default: 2302585092994045684017991454684364208; 188 | 189 | **function ln(int256 value) public pure returns (int256)** 190 | ln(x). This function has a 1/50 deviation close to ln(-1), 1/maxFixedMul() deviation at fixedE()**2, but diverges to 10x deviation at maxNewFixed(). 191 | 192 | **function log_b(int256 b, int256 x) public pure returns (int256)** 193 | log_b(x) 194 | - int256 b Base in fixed point representation. 195 | - int256 x Value to calculate the logarithm for in fixed point representation. 196 | -------------------------------------------------------------------------------- /contracts/ExponentLib.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./FixidityLib.sol"; 4 | import "./LogarithmLib.sol"; 5 | 6 | 7 | library ExponentLib { 8 | 9 | function fixedExp10() public pure returns(int256) { 10 | return 22026465794806716516957900645; 11 | } 12 | 13 | /** 14 | * @notice Not fully tested anymore. 15 | */ 16 | function powerE(int256 _x) 17 | public 18 | pure 19 | returns (int256) 20 | { 21 | assert(_x < 172 * FixidityLib.fixed1()); 22 | int256 x = _x; 23 | int256 r = FixidityLib.fixed1(); 24 | while (x >= 10 * FixidityLib.fixed1()) { 25 | x -= 10 * FixidityLib.fixed1(); 26 | r = FixidityLib.multiply(r, fixedExp10()); 27 | } 28 | if (x == FixidityLib.fixed1()) { 29 | return FixidityLib.multiply(r, LogarithmLib.fixedE()); 30 | } else if (x == 0) { 31 | return r; 32 | } 33 | int256 tr = 100 * FixidityLib.fixed1(); 34 | int256 d = tr; 35 | for (uint8 i = 1; i <= 2 * FixidityLib.digits(); i++) { 36 | d = (d * x) / (FixidityLib.fixed1() * i); 37 | tr += d; 38 | } 39 | return trunc_digits(FixidityLib.multiply(tr, r), 2); 40 | } 41 | 42 | function powerAny(int256 a, int256 b) 43 | public 44 | pure 45 | returns (int256) 46 | { 47 | return powerE(FixidityLib.multiply(LogarithmLib.ln(a), b)); 48 | } 49 | 50 | function rootAny(int256 a, int256 b) 51 | public 52 | pure 53 | returns (int256) 54 | { 55 | return powerAny(a, FixidityLib.reciprocal(b)); 56 | } 57 | 58 | function rootN(int256 a, uint8 n) 59 | public 60 | pure 61 | returns (int256) 62 | { 63 | return powerE(FixidityLib.divide(LogarithmLib.ln(a), FixidityLib.fixed1() * n)); 64 | } 65 | 66 | // solium-disable-next-line mixedcase 67 | function round_off(int256 _v, uint8 digits) 68 | public 69 | pure 70 | returns (int256) 71 | { 72 | int256 t = int256(uint256(10) ** uint256(digits)); 73 | int8 sign = 1; 74 | int256 v = _v; 75 | if (v < 0) { 76 | sign = -1; 77 | v = 0 - v; 78 | } 79 | if (v % t >= t / 2) v = v + t - v % t; 80 | return v * sign; 81 | } 82 | 83 | // solium-disable-next-line mixedcase 84 | function trunc_digits(int256 v, uint8 digits) 85 | public 86 | pure 87 | returns (int256) 88 | { 89 | if (digits <= 0) return v; 90 | return round_off(v, digits) / FixidityLib.fixed1(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /contracts/FixidityLib.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | /** 5 | * @title FixidityLib 6 | * @author Gadi Guy, Alberto Cuesta Canada 7 | * @notice This library provides fixed point arithmetic with protection against 8 | * overflow. 9 | * All operations are done with int256 and the operands must have been created 10 | * with any of the newFrom* functions, which shift the comma digits() to the 11 | * right and check for limits. 12 | * When using this library be sure of using maxNewFixed() as the upper limit for 13 | * creation of fixed point numbers. Use maxFixedMul(), maxFixedDiv() and 14 | * maxFixedAdd() if you want to be certain that those operations don't 15 | * overflow. 16 | */ 17 | library FixidityLib { 18 | 19 | /** 20 | * @notice Number of positions that the comma is shifted to the right. 21 | */ 22 | function digits() public pure returns(uint8) { 23 | return 24; 24 | } 25 | 26 | /** 27 | * @notice This is 1 in the fixed point units used in this library. 28 | * @dev Test fixed1() equals 10^digits() 29 | * Hardcoded to 24 digits. 30 | */ 31 | function fixed1() public pure returns(int256) { 32 | return 1000000000000000000000000; 33 | } 34 | 35 | /** 36 | * @notice The amount of decimals lost on each multiplication operand. 37 | * @dev Test mulPrecision() equals sqrt(fixed1) 38 | * Hardcoded to 24 digits. 39 | */ 40 | function mulPrecision() public pure returns(int256) { 41 | return 1000000000000; 42 | } 43 | 44 | /** 45 | * @notice Maximum value that can be represented in an int256 46 | * @dev Test maxInt256() equals 2^255 -1 47 | */ 48 | function maxInt256() public pure returns(int256) { 49 | return 57896044618658097711785492504343953926634992332820282019728792003956564819967; 50 | } 51 | 52 | /** 53 | * @notice Minimum value that can be represented in an int256 54 | * @dev Test minInt256 equals (2^255) * (-1) 55 | */ 56 | function minInt256() public pure returns(int256) { 57 | return -57896044618658097711785492504343953926634992332820282019728792003956564819968; 58 | } 59 | 60 | /** 61 | * @notice Maximum value that can be converted to fixed point. Optimize for 62 | * @dev deployment. 63 | * Test maxNewFixed() equals maxInt256() / fixed1() 64 | * Hardcoded to 24 digits. 65 | */ 66 | function maxNewFixed() public pure returns(int256) { 67 | return 57896044618658097711785492504343953926634992332820282; 68 | } 69 | 70 | /** 71 | * @notice Maximum value that can be converted to fixed point. Optimize for 72 | * deployment. 73 | * @dev Test minNewFixed() equals -(maxInt256()) / fixed1() 74 | * Hardcoded to 24 digits. 75 | */ 76 | function minNewFixed() public pure returns(int256) { 77 | return -57896044618658097711785492504343953926634992332820282; 78 | } 79 | 80 | /** 81 | * @notice Maximum value that can be safely used as an addition operator. 82 | * @dev Test maxFixedAdd() equals maxInt256()-1 / 2 83 | * Test add(maxFixedAdd(),maxFixedAdd()) equals maxFixedAdd() + maxFixedAdd() 84 | * Test add(maxFixedAdd()+1,maxFixedAdd()) throws 85 | * Test add(-maxFixedAdd(),-maxFixedAdd()) equals -maxFixedAdd() - maxFixedAdd() 86 | * Test add(-maxFixedAdd(),-maxFixedAdd()-1) throws 87 | */ 88 | function maxFixedAdd() public pure returns(int256) { 89 | return 28948022309329048855892746252171976963317496166410141009864396001978282409983; 90 | } 91 | 92 | /** 93 | * @notice Maximum negative value that can be safely in a subtraction. 94 | * @dev Test maxFixedSub() equals minInt256() / 2 95 | */ 96 | function maxFixedSub() public pure returns(int256) { 97 | return -28948022309329048855892746252171976963317496166410141009864396001978282409984; 98 | } 99 | 100 | /** 101 | * @notice Maximum value that can be safely used as a multiplication operator. 102 | * @dev Calculated as sqrt(maxInt256()*fixed1()). 103 | * Be careful with your sqrt() implementation. I couldn't find a calculator 104 | * that would give the exact square root of maxInt256*fixed1 so this number 105 | * is below the real number by no more than 3*10**28. It is safe to use as 106 | * a limit for your multiplications, although powers of two of numbers over 107 | * this value might still work. 108 | * Test multiply(maxFixedMul(),maxFixedMul()) equals maxFixedMul() * maxFixedMul() 109 | * Test multiply(maxFixedMul(),maxFixedMul()+1) throws 110 | * Test multiply(-maxFixedMul(),maxFixedMul()) equals -maxFixedMul() * maxFixedMul() 111 | * Test multiply(-maxFixedMul(),maxFixedMul()+1) throws 112 | * Hardcoded to 24 digits. 113 | */ 114 | function maxFixedMul() public pure returns(int256) { 115 | return 240615969168004498257251713877715648331380787511296; 116 | } 117 | 118 | /** 119 | * @notice Maximum value that can be safely used as a dividend. 120 | * @dev divide(maxFixedDiv,newFixedFraction(1,fixed1())) = maxInt256(). 121 | * Test maxFixedDiv() equals maxInt256()/fixed1() 122 | * Test divide(maxFixedDiv(),multiply(mulPrecision(),mulPrecision())) = maxFixedDiv()*(10^digits()) 123 | * Test divide(maxFixedDiv()+1,multiply(mulPrecision(),mulPrecision())) throws 124 | * Hardcoded to 24 digits. 125 | */ 126 | function maxFixedDiv() public pure returns(int256) { 127 | return 57896044618658097711785492504343953926634992332820282; 128 | } 129 | 130 | /** 131 | * @notice Maximum value that can be safely used as a divisor. 132 | * @dev Test maxFixedDivisor() equals fixed1()*fixed1() - Or 10**(digits()*2) 133 | * Test divide(10**(digits()*2 + 1),10**(digits()*2)) = returns 10*fixed1() 134 | * Test divide(10**(digits()*2 + 1),10**(digits()*2 + 1)) = throws 135 | * Hardcoded to 24 digits. 136 | */ 137 | function maxFixedDivisor() public pure returns(int256) { 138 | return 1000000000000000000000000000000000000000000000000; 139 | } 140 | 141 | /** 142 | * @notice Converts an int256 to fixed point units, equivalent to multiplying 143 | * by 10^digits(). 144 | * @dev Test newFixed(0) returns 0 145 | * Test newFixed(1) returns fixed1() 146 | * Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1() 147 | * Test newFixed(maxNewFixed()+1) fails 148 | */ 149 | function newFixed(int256 x) 150 | public 151 | pure 152 | returns (int256) 153 | { 154 | assert(x <= maxNewFixed()); 155 | assert(x >= minNewFixed()); 156 | return x * fixed1(); 157 | } 158 | 159 | /** 160 | * @notice Converts an int256 in the fixed point representation of this 161 | * library to a non decimal. All decimal digits will be truncated. 162 | */ 163 | function fromFixed(int256 x) 164 | public 165 | pure 166 | returns (int256) 167 | { 168 | return x / fixed1(); 169 | } 170 | 171 | /** 172 | * @notice Converts an int256 which is already in some fixed point 173 | * representation to a different fixed precision representation. 174 | * Both the origin and destination precisions must be 38 or less digits. 175 | * Origin values with a precision higher than the destination precision 176 | * will be truncated accordingly. 177 | * @dev 178 | * Test convertFixed(1,0,0) returns 1; 179 | * Test convertFixed(1,1,1) returns 1; 180 | * Test convertFixed(1,1,0) returns 0; 181 | * Test convertFixed(1,0,1) returns 10; 182 | * Test convertFixed(10,1,0) returns 1; 183 | * Test convertFixed(10,0,1) returns 100; 184 | * Test convertFixed(100,1,0) returns 10; 185 | * Test convertFixed(100,0,1) returns 1000; 186 | * Test convertFixed(1000,2,0) returns 10; 187 | * Test convertFixed(1000,0,2) returns 100000; 188 | * Test convertFixed(1000,2,1) returns 100; 189 | * Test convertFixed(1000,1,2) returns 10000; 190 | * Test convertFixed(maxInt256,1,0) returns maxInt256/10; 191 | * Test convertFixed(maxInt256,0,1) throws 192 | * Test convertFixed(maxInt256,38,0) returns maxInt256/(10**38); 193 | * Test convertFixed(1,0,38) returns 10**38; 194 | * Test convertFixed(maxInt256,39,0) throws 195 | * Test convertFixed(1,0,39) throws 196 | */ 197 | function convertFixed(int256 x, uint8 _originDigits, uint8 _destinationDigits) 198 | public 199 | pure 200 | returns (int256) 201 | { 202 | assert(_originDigits <= 38 && _destinationDigits <= 38); 203 | 204 | uint8 decimalDifference; 205 | if ( _originDigits > _destinationDigits ){ 206 | decimalDifference = _originDigits - _destinationDigits; 207 | return x/(uint128(10)**uint128(decimalDifference)); 208 | } 209 | else if ( _originDigits < _destinationDigits ){ 210 | decimalDifference = _destinationDigits - _originDigits; 211 | // Cast uint8 -> uint128 is safe 212 | // Exponentiation is safe: 213 | // _originDigits and _destinationDigits limited to 38 or less 214 | // decimalDifference = abs(_destinationDigits - _originDigits) 215 | // decimalDifference < 38 216 | // 10**38 < 2**128-1 217 | assert(x <= maxInt256()/uint128(10)**uint128(decimalDifference)); 218 | assert(x >= minInt256()/uint128(10)**uint128(decimalDifference)); 219 | return x*(uint128(10)**uint128(decimalDifference)); 220 | } 221 | // _originDigits == digits()) 222 | return x; 223 | } 224 | 225 | /** 226 | * @notice Converts an int256 which is already in some fixed point 227 | * representation to that of this library. The _originDigits parameter is the 228 | * precision of x. Values with a precision higher than FixidityLib.digits() 229 | * will be truncated accordingly. 230 | */ 231 | function newFixed(int256 x, uint8 _originDigits) 232 | public 233 | pure 234 | returns (int256) 235 | { 236 | return convertFixed(x, _originDigits, digits()); 237 | } 238 | 239 | /** 240 | * @notice Converts an int256 in the fixed point representation of this 241 | * library to a different representation. The _destinationDigits parameter is the 242 | * precision of the output x. Values with a precision below than 243 | * FixidityLib.digits() will be truncated accordingly. 244 | */ 245 | function fromFixed(int256 x, uint8 _destinationDigits) 246 | public 247 | pure 248 | returns (int256) 249 | { 250 | return convertFixed(x, digits(), _destinationDigits); 251 | } 252 | 253 | /** 254 | * @notice Converts two int256 representing a fraction to fixed point units, 255 | * equivalent to multiplying dividend and divisor by 10^digits(). 256 | * @dev 257 | * Test newFixedFraction(maxFixedDiv()+1,1) fails 258 | * Test newFixedFraction(1,maxFixedDiv()+1) fails 259 | * Test newFixedFraction(1,0) fails 260 | * Test newFixedFraction(0,1) returns 0 261 | * Test newFixedFraction(1,1) returns fixed1() 262 | * Test newFixedFraction(maxFixedDiv(),1) returns maxFixedDiv()*fixed1() 263 | * Test newFixedFraction(1,fixed1()) returns 1 264 | * Test newFixedFraction(1,fixed1()-1) returns 0 265 | */ 266 | function newFixedFraction( 267 | int256 numerator, 268 | int256 denominator 269 | ) 270 | public 271 | pure 272 | returns (int256) 273 | { 274 | assert(numerator <= maxNewFixed()); 275 | assert(denominator <= maxNewFixed()); 276 | assert(denominator != 0); 277 | int256 convertedNumerator = newFixed(numerator); 278 | int256 convertedDenominator = newFixed(denominator); 279 | return divide(convertedNumerator, convertedDenominator); 280 | } 281 | 282 | /** 283 | * @notice Returns the integer part of a fixed point number. 284 | * @dev 285 | * Test integer(0) returns 0 286 | * Test integer(fixed1()) returns fixed1() 287 | * Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1() 288 | * Test integer(-fixed1()) returns -fixed1() 289 | * Test integer(newFixed(-maxNewFixed())) returns -maxNewFixed()*fixed1() 290 | */ 291 | function integer(int256 x) public pure returns (int256) { 292 | return (x / fixed1()) * fixed1(); // Can't overflow 293 | } 294 | 295 | /** 296 | * @notice Returns the fractional part of a fixed point number. 297 | * In the case of a negative number the fractional is also negative. 298 | * @dev 299 | * Test fractional(0) returns 0 300 | * Test fractional(fixed1()) returns 0 301 | * Test fractional(fixed1()-1) returns 10^24-1 302 | * Test fractional(-fixed1()) returns 0 303 | * Test fractional(-fixed1()+1) returns -10^24-1 304 | */ 305 | function fractional(int256 x) public pure returns (int256) { 306 | return x - (x / fixed1()) * fixed1(); // Can't overflow 307 | } 308 | 309 | /** 310 | * @notice Converts to positive if negative. 311 | * Due to int256 having one more negative number than positive numbers 312 | * abs(minInt256) reverts. 313 | * @dev 314 | * Test abs(0) returns 0 315 | * Test abs(fixed1()) returns -fixed1() 316 | * Test abs(-fixed1()) returns fixed1() 317 | * Test abs(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1() 318 | * Test abs(newFixed(minNewFixed())) returns -minNewFixed()*fixed1() 319 | */ 320 | function abs(int256 x) public pure returns (int256) { 321 | if (x >= 0) { 322 | return x; 323 | } else { 324 | int256 result = -x; 325 | assert (result > 0); 326 | return result; 327 | } 328 | } 329 | 330 | /** 331 | * @notice x+y. If any operator is higher than maxFixedAdd() it 332 | * might overflow. 333 | * In solidity maxInt256 + 1 = minInt256 and viceversa. 334 | * @dev 335 | * Test add(maxFixedAdd(),maxFixedAdd()) returns maxInt256()-1 336 | * Test add(maxFixedAdd()+1,maxFixedAdd()+1) fails 337 | * Test add(-maxFixedSub(),-maxFixedSub()) returns minInt256() 338 | * Test add(-maxFixedSub()-1,-maxFixedSub()-1) fails 339 | * Test add(maxInt256(),maxInt256()) fails 340 | * Test add(minInt256(),minInt256()) fails 341 | */ 342 | function add(int256 x, int256 y) public pure returns (int256) { 343 | int256 z = x + y; 344 | if (x > 0 && y > 0) assert(z > x && z > y); 345 | if (x < 0 && y < 0) assert(z < x && z < y); 346 | return z; 347 | } 348 | 349 | /** 350 | * @notice x-y. You can use add(x,-y) instead. 351 | * @dev Tests covered by add(x,y) 352 | */ 353 | function subtract(int256 x, int256 y) public pure returns (int256) { 354 | return add(x,-y); 355 | } 356 | 357 | /** 358 | * @notice x*y. If any of the operators is higher than maxFixedMul() it 359 | * might overflow. 360 | * @dev 361 | * Test multiply(0,0) returns 0 362 | * Test multiply(maxFixedMul(),0) returns 0 363 | * Test multiply(0,maxFixedMul()) returns 0 364 | * Test multiply(maxFixedMul(),fixed1()) returns maxFixedMul() 365 | * Test multiply(fixed1(),maxFixedMul()) returns maxFixedMul() 366 | * Test all combinations of (2,-2), (2, 2.5), (2, -2.5) and (0.5, -0.5) 367 | * Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision()) 368 | * Test multiply(maxFixedMul()-1,maxFixedMul()) equals multiply(maxFixedMul(),maxFixedMul()-1) 369 | * Test multiply(maxFixedMul(),maxFixedMul()) returns maxInt256() // Probably not to the last digits 370 | * Test multiply(maxFixedMul()+1,maxFixedMul()) fails 371 | * Test multiply(maxFixedMul(),maxFixedMul()+1) fails 372 | */ 373 | function multiply(int256 x, int256 y) public pure returns (int256) { 374 | if (x == 0 || y == 0) return 0; 375 | if (y == fixed1()) return x; 376 | if (x == fixed1()) return y; 377 | 378 | // Separate into integer and fractional parts 379 | // x = x1 + x2, y = y1 + y2 380 | int256 x1 = integer(x) / fixed1(); 381 | int256 x2 = fractional(x); 382 | int256 y1 = integer(y) / fixed1(); 383 | int256 y2 = fractional(y); 384 | 385 | // (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2) 386 | int256 x1y1 = x1 * y1; 387 | if (x1 != 0) assert(x1y1 / x1 == y1); // Overflow x1y1 388 | 389 | // x1y1 needs to be multiplied back by fixed1 390 | // solium-disable-next-line mixedcase 391 | int256 fixed_x1y1 = x1y1 * fixed1(); 392 | if (x1y1 != 0) assert(fixed_x1y1 / x1y1 == fixed1()); // Overflow x1y1 * fixed1 393 | x1y1 = fixed_x1y1; 394 | 395 | int256 x2y1 = x2 * y1; 396 | if (x2 != 0) assert(x2y1 / x2 == y1); // Overflow x2y1 397 | 398 | int256 x1y2 = x1 * y2; 399 | if (x1 != 0) assert(x1y2 / x1 == y2); // Overflow x1y2 400 | 401 | x2 = x2 / mulPrecision(); 402 | y2 = y2 / mulPrecision(); 403 | int256 x2y2 = x2 * y2; 404 | if (x2 != 0) assert(x2y2 / x2 == y2); // Overflow x2y2 405 | 406 | // result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1(); 407 | int256 result = x1y1; 408 | result = add(result, x2y1); // Add checks for overflow 409 | result = add(result, x1y2); // Add checks for overflow 410 | result = add(result, x2y2); // Add checks for overflow 411 | return result; 412 | } 413 | 414 | /** 415 | * @notice 1/x 416 | * @dev 417 | * Test reciprocal(0) fails 418 | * Test reciprocal(fixed1()) returns fixed1() 419 | * Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated 420 | * Test reciprocal(2*fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated 421 | */ 422 | function reciprocal(int256 x) public pure returns (int256) { 423 | assert(x != 0); 424 | return (fixed1()*fixed1()) / x; // Can't overflow 425 | } 426 | 427 | /** 428 | * @notice x/y. If the dividend is higher than maxFixedDiv() it 429 | * might overflow. You can use multiply(x,reciprocal(y)) instead. 430 | * There is a loss of precision on division for the lower mulPrecision() decimals. 431 | * @dev 432 | * Test divide(fixed1(),0) fails 433 | * Test divide(maxFixedDiv(),1) = maxFixedDiv()*(10^digits()) 434 | * Test divide(maxFixedDiv()+1,1) throws 435 | * Test divide(maxFixedDiv(),maxFixedDiv()) returns fixed1() 436 | */ 437 | function divide(int256 x, int256 y) public pure returns (int256) { 438 | if (y == fixed1()) return x; 439 | assert(y != 0); 440 | assert(y <= maxFixedDivisor()); 441 | return multiply(x, reciprocal(y)); 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /contracts/LogarithmLib.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./FixidityLib.sol"; 4 | 5 | 6 | /** 7 | * @title LogarithmLib 8 | * @author Gadi Guy, Alberto Cuesta Canada 9 | * @notice This library extends FixidityLib with logarithm operations. 10 | */ 11 | library LogarithmLib { 12 | 13 | /** 14 | * @notice This is e in the fixed point units used in this library. 15 | * @dev 27182818284590452353602874713526624977572470936999595749669676277240766303535/fixed1() 16 | * Hardcoded to 24 digits. 17 | */ 18 | function fixedE() public pure returns(int256) { 19 | return 2718281828459045235360287; 20 | } 21 | 22 | /** 23 | * @notice ln(1.5), hardcoded with the comma 24 positions to the right. 24 | */ 25 | // solium-disable-next-line mixedcase 26 | function fixedLn1_5() public pure returns(int256) { 27 | return 405465108108164381978013; 28 | } 29 | 30 | /** 31 | * @notice ln(10), hardcoded with the comma 24 positions to the right. 32 | */ 33 | function fixedLn10() public pure returns(int256) { 34 | return 2302585092994045684017991; 35 | } 36 | 37 | /** 38 | * @notice ln(x) 39 | * This function has a 1/50 deviation close to ln(-1), 40 | * 1/maxFixedMul() deviation at fixedE()**2, but diverges to 10x 41 | * deviation at maxNewFixed(). 42 | * @dev 43 | * Test ln(0) fails 44 | * Test ln(-fixed1()) fails 45 | * Test ln(fixed1()) returns 0 46 | * Test ln(fixedE()) returns fixed1() 47 | * Test ln(fixedE()*fixedE()) returns ln(fixedE())+ln(fixedE()) 48 | * Test ln(maxInt256) returns 176752531042786059920093411119162458112 49 | * Test ln(1) returns -82 50 | */ 51 | function ln(int256 value) public pure returns (int256) { 52 | assert(value >= 0); 53 | int256 v = value; 54 | int256 r = 0; 55 | while (v <= FixidityLib.fixed1() / 10) { 56 | v = v * 10; 57 | r -= fixedLn10(); 58 | } 59 | while (v >= 10 * FixidityLib.fixed1()) { 60 | v = v / 10; 61 | r += fixedLn10(); 62 | } 63 | while (v < FixidityLib.fixed1()) { 64 | v = FixidityLib.multiply(v, fixedE()); 65 | r -= FixidityLib.fixed1(); 66 | } 67 | while (v > fixedE()) { 68 | v = FixidityLib.divide(v, fixedE()); 69 | r += FixidityLib.fixed1(); 70 | } 71 | if (v == FixidityLib.fixed1()) { 72 | return r; 73 | } 74 | if (v == fixedE()) { 75 | return FixidityLib.fixed1() + r; 76 | } 77 | 78 | v = v - 3 * FixidityLib.fixed1() / 2; 79 | r = r + fixedLn1_5(); 80 | int256 m = FixidityLib.fixed1() * v / (v + 3 * FixidityLib.fixed1()); 81 | r = r + 2 * m; 82 | // solium-disable-next-line mixedcase 83 | int256 m_2 = m * m / FixidityLib.fixed1(); 84 | uint8 i = 3; 85 | while (true) { 86 | m = m * m_2 / FixidityLib.fixed1(); 87 | r = r + 2 * m / int256(i); 88 | i += 2; 89 | if (i >= 3 + 2 * FixidityLib.digits()) break; 90 | } 91 | return r; 92 | } 93 | 94 | /** 95 | * @notice log_b(x). 96 | * *param int256 b Base in fixed point representation. 97 | * @dev Tests covered by ln(x) and divide(a,b) 98 | */ 99 | // solium-disable-next-line mixedcase 100 | function log_b(int256 b, int256 x) public pure returns (int256) { 101 | if (b == FixidityLib.fixed1()*10) 102 | return FixidityLib.divide(ln(x), fixedLn10()); 103 | return FixidityLib.divide(ln(x), ln(b)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | 4 | contract Migrations { 5 | address public owner; 6 | // solium-disable-next-line mixedcase 7 | uint public last_completed_migration; 8 | 9 | constructor() public { 10 | owner = msg.sender; 11 | } 12 | 13 | modifier restricted() { 14 | if (msg.sender == owner) _; 15 | } 16 | 17 | function setCompleted(uint completed) public restricted { 18 | last_completed_migration = completed; 19 | } 20 | 21 | // solium-disable-next-line mixedcase 22 | function upgrade(address new_address) public restricted { 23 | Migrations(new_address).setCompleted(last_completed_migration); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mocks/FixidityLibMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../FixidityLib.sol"; 4 | 5 | /** 6 | * @dev 7 | */ 8 | 9 | contract FixidityLibMock { 10 | 11 | /** 12 | * @dev Number of positions that the comma is shifted to the right. 13 | */ 14 | function digits() public pure returns(uint8) { 15 | return FixidityLib.digits(); 16 | } 17 | 18 | /** 19 | * @dev This is 1 in the fixed point units used in this library. 20 | * 10^digits() 21 | * Hardcoded to 24 digits. 22 | */ 23 | function fixed1() public pure returns(int256) { 24 | return FixidityLib.fixed1(); 25 | } 26 | 27 | /** 28 | * @dev The amount of decimals lost on each multiplication operand. 29 | * Test mulPrecision() equals sqrt(fixed1) 30 | * Hardcoded to 24 digits. 31 | */ 32 | function mulPrecision() public pure returns(int256) { 33 | return FixidityLib.mulPrecision(); 34 | } 35 | 36 | /** 37 | * @dev Maximum value that can be represented in an int256 38 | * 2^256 / 2 -1 39 | * Hardcoded to 24 digits. 40 | */ 41 | function maxInt256() public pure returns(int256) { 42 | return FixidityLib.maxInt256(); 43 | } 44 | 45 | /** 46 | * @dev Minimum value that can be represented in an int256 47 | * -1 * ((2^256 / 2)-2) 48 | * Hardcoded to 24 digits. 49 | */ 50 | function minInt256() public pure returns(int256) { 51 | return FixidityLib.minInt256(); 52 | } 53 | 54 | /** 55 | * @dev Maximum value that can be converted to fixed point. Optimize for 56 | * deployment. 57 | * maxInt256() / fixed1() 58 | * Hardcoded to 24 digits. 59 | */ 60 | function maxNewFixed() public pure returns(int256) { 61 | return FixidityLib.maxNewFixed(); 62 | } 63 | 64 | /** 65 | * @dev Maximum value that can be converted to fixed point. Optimize for 66 | * deployment. 67 | * -(maxInt256()-1) / fixed1() 68 | * Hardcoded to 24 digits. 69 | */ 70 | function minNewFixed() public pure returns(int256) { 71 | return FixidityLib.minNewFixed(); 72 | } 73 | 74 | /** 75 | * @dev Maximum value that can be safely used as a multiplication operator. 76 | * sqrt(maxNewFixed()) 77 | * Hardcoded to 24 digits. 78 | */ 79 | function maxFixedMul() public pure returns(int256) { 80 | return FixidityLib.maxFixedMul(); 81 | } 82 | 83 | /** 84 | * @dev Maximum value that can be safely used as a dividend. 85 | * divide(maxFixedDiv,newFixedFraction(1,fixed1())) = maxInt256(). 86 | * maxInt256()/fixed1() 87 | * Hardcoded to 24 digits. 88 | */ 89 | function maxFixedDiv() public pure returns(int256) { 90 | return FixidityLib.maxFixedDiv(); 91 | } 92 | 93 | /** 94 | * @dev Maximum value that can be safely used as a divisor. 95 | * Hardcoded to 24 digits. 96 | */ 97 | function maxFixedDivisor() public pure returns(int256) { 98 | return FixidityLib.maxFixedDivisor(); 99 | } 100 | 101 | /** 102 | * @dev Maximum value that can be safely used as an addition operator. 103 | * maxInt256() / 2 104 | * Hardcoded to 24 digits. 105 | */ 106 | function maxFixedAdd() public pure returns(int256) { 107 | return FixidityLib.maxFixedAdd(); 108 | } 109 | 110 | /** 111 | * @dev Maximum negative value that can be safely in a subtraction. 112 | * Test maxFixedSub() equals minInt256() / 2 113 | * Hardcoded to 24 digits. 114 | */ 115 | function maxFixedSub() public pure returns(int256) { 116 | return FixidityLib.maxFixedSub(); 117 | } 118 | 119 | /** 120 | * @dev Converts an int256 to fixed point units, equivalent to multiplying 121 | * by 10^digits(). 122 | */ 123 | function newFixed(int256 x) 124 | public 125 | pure 126 | returns (int256) 127 | { 128 | return FixidityLib.newFixed(x); 129 | } 130 | 131 | /** 132 | * @dev Converts an int256 in the fixed point representation of this 133 | * library to a non decimal. All decimal digits will be truncated. 134 | */ 135 | function fromFixed(int256 x) 136 | public 137 | pure 138 | returns (int256) 139 | { 140 | return FixidityLib.fromFixed(x); 141 | } 142 | 143 | /** 144 | * @dev Converts an int256 which is already in some fixed point 145 | * representation to a different fixed precision representation. 146 | * Both the origin and destination precisions must be 38 or less digits. 147 | * Origin values with a precision higher than the destination precision 148 | * will be truncated accordingly. 149 | */ 150 | function convertFixed(int256 x, uint8 _originDigits, uint8 _destinationDigits) 151 | public 152 | pure 153 | returns (int256) 154 | { 155 | return FixidityLib.convertFixed(x, _originDigits, _destinationDigits); 156 | } 157 | /** 158 | * @dev Converts two int256 representing a fraction to fixed point units, 159 | * equivalent to multiplying dividend and divisor by 10^digits(). 160 | */ 161 | function newFixedFraction( 162 | int256 numerator, 163 | int256 denominator 164 | ) 165 | public 166 | pure 167 | returns (int256) 168 | { 169 | return FixidityLib.newFixedFraction(numerator, denominator); 170 | } 171 | 172 | /** 173 | * @dev Returns the integer part of a fixed point number. 174 | */ 175 | function integer(int256 v) public pure returns (int256) { 176 | return FixidityLib.integer(v); 177 | } 178 | 179 | 180 | /** 181 | * @dev Returns the fractional part of a fixed point number. 182 | */ 183 | function fractional(int256 v) public pure returns (int256) { 184 | return FixidityLib.fractional(v); 185 | } 186 | 187 | 188 | /** 189 | * @dev Converts to positive if negative 190 | */ 191 | function abs(int256 x) public pure returns (int256) { 192 | return FixidityLib.abs(x); 193 | } 194 | 195 | /** 196 | * @dev a*b. If any of the operators is higher than maxFixedMul() it 197 | * might overflow. 198 | */ 199 | function multiply(int256 a, int256 b) public pure returns (int256) { 200 | return FixidityLib.multiply(a, b); 201 | } 202 | 203 | /** 204 | * @dev 1/a 205 | */ 206 | function reciprocal(int256 a) public pure returns (int256) { 207 | return FixidityLib.reciprocal(a); 208 | } 209 | 210 | /** 211 | * @dev a/b. If the dividend is higher than maxFixedDiv() it 212 | * might overflow. 213 | */ 214 | function divide(int256 a, int256 b) public pure returns (int256) { 215 | return FixidityLib.divide(a, b); 216 | } 217 | 218 | /** 219 | * @dev a+b. If any operator is higher than maxFixedAdd() it 220 | * might overflow. 221 | */ 222 | function add(int256 a, int256 b) public pure returns (int256) { 223 | return FixidityLib.add(a, b); 224 | } 225 | 226 | /** 227 | * @dev a-b. 228 | */ 229 | function subtract(int256 a, int256 b) public pure returns (int256) { 230 | return FixidityLib.subtract(a, b); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /contracts/mocks/LogarithmLibMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../LogarithmLib.sol"; 4 | 5 | /** 6 | * @dev 7 | */ 8 | 9 | contract LogarithmLibMock { 10 | 11 | function fixedE() public pure returns(int256) { 12 | return LogarithmLib.fixedE(); 13 | } 14 | 15 | function fixedLn1_5() public pure returns(int256) { 16 | return LogarithmLib.fixedLn1_5(); 17 | } 18 | 19 | function fixedLn10() public pure returns(int256) { 20 | return LogarithmLib.fixedLn10(); 21 | } 22 | 23 | function ln(int256 value) public pure returns (int256) { 24 | return LogarithmLib.ln(value); 25 | } 26 | 27 | function log_b(int256 b, int256 x) public pure returns (int256) { 28 | return LogarithmLib.log_b(b, x); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require('./Migrations.sol'); 2 | 3 | module.exports = (deployer) => { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_libraries.js: -------------------------------------------------------------------------------- 1 | const FixidityLib = artifacts.require('./FixidityLib.sol'); 2 | const LogarithmLib = artifacts.require('./LogarithmLib.sol'); 3 | 4 | module.exports = (deployer) => { 5 | // deploy fixidity 6 | deployer.deploy(FixidityLib); 7 | deployer.link(FixidityLib, LogarithmLib); 8 | // deploy logarithm 9 | deployer.deploy(LogarithmLib); 10 | }; 11 | -------------------------------------------------------------------------------- /migrations/3_deploy_mocks.js: -------------------------------------------------------------------------------- 1 | const FixidityLib = artifacts.require('./fixidity/FixidityLib.sol'); 2 | const LogarithmLib = artifacts.require('./fixidity/LogarithmLib.sol'); 3 | const FixidityLibMock = artifacts.require('./mocks/FixidityLibMock.sol'); 4 | const LogarithmLibMock = artifacts.require('./mocks/LogarithmLibMock.sol'); 5 | 6 | 7 | module.exports = (deployer) => { 8 | // deploy fixidity lib 9 | deployer.deploy(FixidityLib); 10 | deployer.link(FixidityLib, FixidityLibMock); 11 | deployer.link(FixidityLib, LogarithmLibMock); 12 | // deploy logarithm lib 13 | deployer.deploy(LogarithmLib); 14 | deployer.link(LogarithmLib, LogarithmLibMock); 15 | // deploy fixidity lib mock 16 | deployer.deploy(FixidityLibMock); 17 | deployer.deploy(LogarithmLibMock); 18 | }; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fixidity", 3 | "version": "0.1.0", 4 | "description": "Fixed precision decimal math library for Solidity", 5 | "main": "truffle-config.js", 6 | "files": [ 7 | "contracts" 8 | ], 9 | "scripts": { 10 | "test:local": "truffle test --network test", 11 | "test:docker": "echo TODO!", 12 | "lint:js": "eslint *.js .", 13 | "lint:sol": "solium -d contracts", 14 | "lint": "npm run lint:sol && npm run lint:js", 15 | "security": "docker run --rm --memory=3g -v $(pwd):/tmp -w \"/tmp/\" mythril/myth --truffle", 16 | "describe": "surya describe contracts/*.sol", 17 | "coverage": "solidity-coverage" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/cementdao/fixidity.git" 22 | }, 23 | "author": "gadiguy@gmail.com", 24 | "contributors": [ 25 | "alberto@techhq.io", 26 | "bernardo@techhq.io" 27 | ], 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/cementdao/fixidity/issues" 31 | }, 32 | "homepage": "https://github.com/cementdao/fixidity#readme", 33 | "dependencies": { 34 | "bignumber.js": "8.1.1" 35 | }, 36 | "devDependencies": { 37 | "chai": "4.2.0", 38 | "chai-bignumber": "3.0.0", 39 | "eslint": "^5.13.0", 40 | "eslint-config-airbnb": "^17.1.0", 41 | "eslint-plugin-import": "^2.16.0", 42 | "eslint-plugin-jsx-a11y": "^6.2.1", 43 | "eslint-plugin-react": "^7.12.4", 44 | "ganache-cli": "6.4.1", 45 | "eth-gas-reporter": "^0.1.12", 46 | "ethlint": "1.2.3", 47 | "solc": "^0.5.7", 48 | "solidity-coverage": "0.6.0-beta.4", 49 | "surya": "0.2.8", 50 | "truffle": "5.0.13", 51 | "truffle-hdwallet-provider": "^1.0.7" 52 | } 53 | } -------------------------------------------------------------------------------- /test/FixidityLibMock_abs.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - abs', () => { 11 | let fixidityLibMock; 12 | let fixed1; 13 | let maxNewFixed; 14 | let minNewFixed; 15 | let minInt256; 16 | 17 | before(async () => { 18 | fixidityLibMock = await FixidityLibMock.deployed(); 19 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 20 | maxNewFixed = new BigNumber(await fixidityLibMock.maxNewFixed()); 21 | minNewFixed = new BigNumber(await fixidityLibMock.minNewFixed()); 22 | minInt256 = new BigNumber(await fixidityLibMock.minInt256()); 23 | }); 24 | 25 | describe('abs', () => { 26 | it('abs(0)', async () => { 27 | const result = new BigNumber(await fixidityLibMock.abs(0)); 28 | result.should.be.bignumber.equal(0); 29 | }); 30 | it('abs(fixed1())', async () => { 31 | const result = new BigNumber(await fixidityLibMock.abs(fixed1.toString(10))); 32 | result.should.be.bignumber.equal(fixed1); 33 | }); 34 | it('abs(-fixed1())', async () => { 35 | const result = new BigNumber( 36 | await fixidityLibMock.abs(fixed1.multipliedBy(-1).toString(10)), 37 | ); 38 | result.should.be.bignumber.equal(fixed1); 39 | }); 40 | it('abs(newFixed(maxNewFixed()))', async () => { 41 | const newFromMaxFixedNew = new BigNumber( 42 | await fixidityLibMock.newFixed(maxNewFixed.toString(10)), 43 | ); 44 | const result = new BigNumber( 45 | await fixidityLibMock.abs(newFromMaxFixedNew.toString(10)), 46 | ); 47 | result.should.be.bignumber.equal(maxNewFixed.multipliedBy(fixed1)); 48 | }); 49 | it('abs(newFixed(minNewFixed()))', async () => { 50 | const newFromMinFixedNew = new BigNumber( 51 | await fixidityLibMock.newFixed(minNewFixed.toString(10)), 52 | ); 53 | const result = new BigNumber( 54 | await fixidityLibMock.abs(newFromMinFixedNew.toString(10)), 55 | ); 56 | result.should.be.bignumber.equal(minNewFixed.multipliedBy(fixed1).multipliedBy(-1)); 57 | }); 58 | itShouldThrow('abs(minInt256()))', async () => { 59 | await fixidityLibMock.abs(minInt256.toString(10)); 60 | }, 'revert'); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/FixidityLibMock_add.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - add', () => { 11 | let fixidityLibMock; 12 | let maxFixedAdd; 13 | let maxInt256; 14 | let maxFixedSub; 15 | let minInt256; 16 | 17 | before(async () => { 18 | fixidityLibMock = await FixidityLibMock.deployed(); 19 | maxFixedAdd = new BigNumber(await fixidityLibMock.maxFixedAdd()); 20 | maxFixedSub = new BigNumber(await fixidityLibMock.maxFixedSub()); 21 | maxInt256 = new BigNumber(await fixidityLibMock.maxInt256()); 22 | minInt256 = new BigNumber(await fixidityLibMock.minInt256()); 23 | }); 24 | 25 | describe('add', () => { 26 | it('add(maxFixedAdd(),maxFixedAdd())', async () => { 27 | const result = new BigNumber( 28 | await fixidityLibMock.add( 29 | maxFixedAdd.toString(10), 30 | maxFixedAdd.toString(10), 31 | ), 32 | ); 33 | result.should.be.bignumber.equal(maxInt256.minus(1)); 34 | }); 35 | itShouldThrow('add(maxFixedAdd()+1,maxFixedAdd()+1)', async () => { 36 | await fixidityLibMock.add( 37 | maxFixedAdd.plus(1).toString(10), 38 | maxFixedAdd.plus(1).toString(10), 39 | ); 40 | }, 'revert'); 41 | it('add(maxFixedSub(),maxFixedSub())', async () => { 42 | const result = new BigNumber( 43 | await fixidityLibMock.add( 44 | maxFixedSub.toString(10), 45 | maxFixedSub.toString(10), 46 | ), 47 | ); 48 | result.should.be.bignumber.equal(minInt256); 49 | }); 50 | itShouldThrow('add(maxFixedSub()-1,maxFixedSub()-1)', async () => { 51 | await fixidityLibMock.add( 52 | maxFixedSub.minus(1).toString(10), 53 | maxFixedSub.minus(1).toString(10), 54 | ); 55 | }, 'revert'); 56 | itShouldThrow('add(maxInt256(),maxInt256())', async () => { 57 | await fixidityLibMock.add( 58 | maxInt256.toString(10), 59 | maxInt256.toString(10), 60 | ); 61 | }, 'revert'); 62 | itShouldThrow('add(minInt256(),minInt256())', async () => { 63 | await fixidityLibMock.add( 64 | minInt256.toString(10), 65 | minInt256.toString(10), 66 | ); 67 | }, 'revert'); 68 | it('add(maxInt256(),-maxInt256())', async () => { 69 | const result = new BigNumber( 70 | await fixidityLibMock.add( 71 | maxInt256.toString(10), 72 | maxInt256.multipliedBy(-1).toString(10), 73 | ), 74 | ); 75 | result.should.be.bignumber.equal(0); 76 | }); 77 | it('add(minInt256()+1,-(minInt256()+1))', async () => { 78 | const result = new BigNumber( 79 | await fixidityLibMock.add( 80 | minInt256.plus(1).toString(10), 81 | minInt256.plus(1).multipliedBy(-1).toString(10), 82 | ), 83 | ); 84 | result.should.be.bignumber.equal(0); 85 | }); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /test/FixidityLibMock_convertFixed.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - newFixed', () => { 11 | let fixidityLibMock; 12 | let maxInt256; 13 | 14 | before(async () => { 15 | fixidityLibMock = await FixidityLibMock.deployed(); 16 | maxInt256 = new BigNumber(await fixidityLibMock.maxInt256()); 17 | }); 18 | 19 | describe('convertFixed', () => { 20 | it('convertFixed(1,0,0)', async () => { 21 | const result = new BigNumber( 22 | await fixidityLibMock.convertFixed(1, 0, 0), 23 | ); 24 | result.should.be.bignumber.equal(1); 25 | }); 26 | it('convertFixed(1,1,1)', async () => { 27 | const result = new BigNumber( 28 | await fixidityLibMock.convertFixed(1, 1, 1), 29 | ); 30 | result.should.be.bignumber.equal(1); 31 | }); 32 | it('convertFixed(1,1,0)', async () => { 33 | const result = new BigNumber( 34 | await fixidityLibMock.convertFixed(1, 1, 0), 35 | ); 36 | result.should.be.bignumber.equal(0); 37 | }); 38 | it('convertFixed(1,0,1)', async () => { 39 | const result = new BigNumber( 40 | await fixidityLibMock.convertFixed(1, 0, 1), 41 | ); 42 | result.should.be.bignumber.equal(10); 43 | }); 44 | it('convertFixed(10,1,0)', async () => { 45 | const result = new BigNumber( 46 | await fixidityLibMock.convertFixed(10, 1, 0), 47 | ); 48 | result.should.be.bignumber.equal(1); 49 | }); 50 | it('convertFixed(10,0,1)', async () => { 51 | const result = new BigNumber( 52 | await fixidityLibMock.convertFixed(10, 0, 1), 53 | ); 54 | result.should.be.bignumber.equal(100); 55 | }); 56 | it('convertFixed(100,1,0)', async () => { 57 | const result = new BigNumber( 58 | await fixidityLibMock.convertFixed(100, 1, 0), 59 | ); 60 | result.should.be.bignumber.equal(10); 61 | }); 62 | it('convertFixed(100,0,1)', async () => { 63 | const result = new BigNumber( 64 | await fixidityLibMock.convertFixed(100, 0, 1), 65 | ); 66 | result.should.be.bignumber.equal(1000); 67 | }); 68 | it('convertFixed(1000,2,0)', async () => { 69 | const result = new BigNumber( 70 | await fixidityLibMock.convertFixed(1000, 2, 0), 71 | ); 72 | result.should.be.bignumber.equal(10); 73 | }); 74 | it('convertFixed(1000,0,2)', async () => { 75 | const result = new BigNumber( 76 | await fixidityLibMock.convertFixed(1000, 0, 2), 77 | ); 78 | result.should.be.bignumber.equal(100000); 79 | }); 80 | it('convertFixed(1000,2,1)', async () => { 81 | const result = new BigNumber( 82 | await fixidityLibMock.convertFixed(1000, 2, 1), 83 | ); 84 | result.should.be.bignumber.equal(100); 85 | }); 86 | it('convertFixed(1000,1,2)', async () => { 87 | const result = new BigNumber( 88 | await fixidityLibMock.convertFixed(1000, 1, 2), 89 | ); 90 | result.should.be.bignumber.equal(10000); 91 | }); 92 | it('convertFixed(maxInt256,1,0)', async () => { 93 | const result = new BigNumber( 94 | await fixidityLibMock.convertFixed(maxInt256.toString(10), 1, 0), 95 | ); 96 | result.should.be.bignumber.equal(maxInt256.dividedBy(10).dp(0, 1)); 97 | }); 98 | it('convertFixed(maxInt256,38,0)', async () => { 99 | const result = new BigNumber( 100 | await fixidityLibMock.convertFixed(maxInt256.toString(10), 38, 0), 101 | ); 102 | result.should.be.bignumber.equal( 103 | maxInt256.dividedBy((new BigNumber(10).pow(38))).dp(0, 1), 104 | ); 105 | }); 106 | it('convertFixed(1,0,38)', async () => { 107 | const result = new BigNumber( 108 | await fixidityLibMock.convertFixed(1, 0, 38), 109 | ); 110 | result.should.be.bignumber.equal(new BigNumber(10).pow(38)); 111 | }); 112 | it('convertFixed(10**38,0,38)', async () => { 113 | const result = new BigNumber( 114 | await fixidityLibMock.convertFixed( 115 | new BigNumber(10).pow(38).toString(10), 0, 38, 116 | ), 117 | ); 118 | result.should.be.bignumber.equal(new BigNumber(10).pow(76)); 119 | }); 120 | it('convertFixed(-1*10**38,0,38)', async () => { 121 | const result = new BigNumber( 122 | await fixidityLibMock.convertFixed( 123 | new BigNumber(10).pow(38).multipliedBy(-1).toString(10), 0, 38, 124 | ), 125 | ); 126 | result.should.be.bignumber.equal(new BigNumber(10).pow(76).multipliedBy(-1)); 127 | }); 128 | itShouldThrow( 129 | 'convertFixed(maxInt256,0,1)', 130 | async () => { 131 | await fixidityLibMock 132 | .convertFixed(maxInt256.toString(10), 0, 1); 133 | }, 134 | 'revert', 135 | ); 136 | itShouldThrow( 137 | 'convertFixed(maxInt256,39,0)', 138 | async () => { 139 | await fixidityLibMock 140 | .convertFixed(maxInt256.toString(10), 39, 0); 141 | }, 142 | 'revert', 143 | ); 144 | itShouldThrow( 145 | 'convertFixed(1,0,39)', 146 | async () => { 147 | await fixidityLibMock.convertFixed(1, 0, 39); 148 | }, 149 | 'revert', 150 | ); 151 | }); 152 | }); 153 | -------------------------------------------------------------------------------- /test/FixidityLibMock_divide.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - divide', () => { 11 | let fixidityLibMock; 12 | let fixed1; 13 | let maxFixedDiv; 14 | let maxFixedDivisor; 15 | 16 | before(async () => { 17 | fixidityLibMock = await FixidityLibMock.deployed(); 18 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 19 | maxFixedDiv = new BigNumber(await fixidityLibMock.maxFixedDiv()); 20 | maxFixedDivisor = new BigNumber(await fixidityLibMock.maxFixedDivisor()); 21 | }); 22 | 23 | /* 24 | * Test divide(fixed1(),0) fails 25 | * Test divide(fixed1(),maxFixedDiv()) returns maxInt256 // Probably not to the last digits 26 | * Test divide(fixed1(),maxFixedDiv()+1) fails // Maybe it will need to be +fixed1() 27 | * Test divide(maxFixedDiv(),maxFixedDiv()) returns fixed1() 28 | */ 29 | 30 | describe('divide', () => { 31 | it('divide(fixed1(),fixed1())', async () => { 32 | const result = new BigNumber( 33 | await fixidityLibMock.divide( 34 | fixed1.toString(10), 35 | fixed1.toString(10), 36 | ), 37 | ); 38 | result.should.be.bignumber.equal( 39 | fixed1, 40 | ); 41 | }); 42 | it('divide(fixed1(),2*fixed1())', async () => { 43 | const result = new BigNumber( 44 | await fixidityLibMock.divide( 45 | fixed1.toString(10), 46 | fixed1.multipliedBy(2).toString(10), 47 | ), 48 | ); 49 | result.should.be.bignumber.equal( 50 | fixed1.div(2).dp(0, 1), 51 | ); 52 | }); 53 | itShouldThrow('divide(fixed1(),0)', async () => { 54 | await fixidityLibMock.divide( 55 | fixed1.toString(10), 56 | 0, 57 | ); 58 | }, 'revert'); 59 | it('divide(maxFixedDiv(),1)', async () => { 60 | const result = new BigNumber( 61 | await fixidityLibMock.divide( 62 | maxFixedDiv.toString(10), 63 | 1, 64 | ), 65 | ); 66 | result.should.be.bignumber.equal( 67 | maxFixedDiv.multipliedBy(fixed1), 68 | ); 69 | }); 70 | it('divide(10**38,10**38)', async () => { 71 | const result = new BigNumber( 72 | await fixidityLibMock.divide( 73 | new BigNumber(10).pow(38).toString(10), 74 | new BigNumber(10).pow(38).toString(10), 75 | ), 76 | ); 77 | result.should.be.bignumber.equal(fixed1); 78 | }); 79 | it('divide(maxFixedDivisor(),maxFixedDivisor())', async () => { 80 | const result = new BigNumber( 81 | await fixidityLibMock.divide( 82 | maxFixedDivisor.toString(10), 83 | maxFixedDivisor.toString(10), 84 | ), 85 | ); 86 | result.should.be.bignumber.equal(fixed1); 87 | }); 88 | itShouldThrow('divide(10*maxFixedDivisor(),10*maxFixedDivisor()', async () => { 89 | await fixidityLibMock.divide( 90 | maxFixedDivisor.multipliedBy(10).toString(10), 91 | maxFixedDivisor.multipliedBy(10).toString(10), 92 | ); 93 | }, 'revert'); 94 | itShouldThrow('divide(maxFixedDiv()+1,1)', async () => { 95 | await fixidityLibMock.divide( 96 | maxFixedDiv.plus(1).toString(10), 97 | 1, 98 | ); 99 | }, 'revert'); 100 | }); 101 | }); 102 | -------------------------------------------------------------------------------- /test/FixidityLibMock_fractional.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | // use default BigNumber 6 | chai.use(require('chai-bignumber')()).should(); 7 | 8 | 9 | contract('FixidityLibMock - fractional', () => { 10 | let fixidityLibMock; 11 | let fixed1; 12 | 13 | before(async () => { 14 | fixidityLibMock = await FixidityLibMock.deployed(); 15 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 16 | }); 17 | 18 | describe('fractional', () => { 19 | it('fractional(0)', async () => { 20 | const result = new BigNumber(await fixidityLibMock.fractional(0)); 21 | result.should.be.bignumber.equal(0); 22 | }); 23 | it('fractional(fixed1())', async () => { 24 | const result = new BigNumber( 25 | await fixidityLibMock.fractional(fixed1.toString(10)), 26 | ); 27 | result.should.be.bignumber.equal(0); 28 | }); 29 | it('fractional(-fixed1())', async () => { 30 | const result = new BigNumber( 31 | await fixidityLibMock.fractional(fixed1.multipliedBy(-1).toString(10)), 32 | ); 33 | result.should.be.bignumber.equal(0); 34 | }); 35 | it('fractional(fixed1()-1)', async () => { 36 | const result = new BigNumber( 37 | await fixidityLibMock.fractional(fixed1.minus(1).toString(10)), 38 | ); 39 | result.should.be.bignumber.equal(fixed1.minus(1).toString(10)); 40 | }); 41 | it('fractional(-fixed1())', async () => { 42 | const result = new BigNumber( 43 | await fixidityLibMock.fractional(fixed1.multipliedBy(-1).toString(10)), 44 | ); 45 | result.should.be.bignumber.equal(0); 46 | }); 47 | it('fractional(-fixed1()+1)', async () => { 48 | const result = new BigNumber( 49 | await fixidityLibMock.fractional(fixed1.multipliedBy(-1).plus(1).toString(10)), 50 | ); 51 | result.should.be.bignumber.equal(fixed1.multipliedBy(-1).plus(1).toString(10)); 52 | }); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /test/FixidityLibMock_fromFixed.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | // use default BigNumber 6 | chai.use(require('chai-bignumber')()).should(); 7 | 8 | 9 | contract('FixidityLibMock - newFixed', () => { 10 | let fixidityLibMock; 11 | let fixed1; 12 | let maxNewFixed; 13 | let minNewFixed; 14 | 15 | before(async () => { 16 | fixidityLibMock = await FixidityLibMock.deployed(); 17 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 18 | maxNewFixed = new BigNumber(await fixidityLibMock.maxNewFixed()); 19 | minNewFixed = new BigNumber(await fixidityLibMock.minNewFixed()); 20 | }); 21 | 22 | describe('fromFixed', () => { 23 | it('fromFixed(0)', async () => { 24 | const result = new BigNumber( 25 | await fixidityLibMock.fromFixed(0), 26 | ); 27 | result.should.be.bignumber.equal(0); 28 | }); 29 | it('fromFixed(1)', async () => { 30 | const result = new BigNumber( 31 | await fixidityLibMock.fromFixed(1), 32 | ); 33 | result.should.be.bignumber.equal(0); 34 | }); 35 | it('fromFixed(fixed1)', async () => { 36 | const result = new BigNumber( 37 | await fixidityLibMock.fromFixed(fixed1.toString(10)), 38 | ); 39 | result.should.be.bignumber.equal(1); 40 | }); 41 | it('fromFixed(maxNewFixed()*fixed1())', async () => { 42 | const result = new BigNumber( 43 | await fixidityLibMock.fromFixed(fixed1.multipliedBy(maxNewFixed).toString(10)), 44 | ); 45 | result.should.be.bignumber.equal(maxNewFixed); 46 | }); 47 | 48 | it('fromFixed(-1)', async () => { 49 | const result = new BigNumber( 50 | await fixidityLibMock.fromFixed(-1), 51 | ); 52 | result.should.be.bignumber.equal(0); 53 | }); 54 | it('fromFixed(fixed1*(-1))', async () => { 55 | const result = new BigNumber( 56 | await fixidityLibMock.fromFixed(fixed1.multipliedBy(-1).toString(10)), 57 | ); 58 | result.should.be.bignumber.equal(-1); 59 | }); 60 | it('fromFixed(minNewFixed()*fixed1())', async () => { 61 | const result = new BigNumber( 62 | await fixidityLibMock.fromFixed(fixed1.multipliedBy(minNewFixed).toString(10)), 63 | ); 64 | result.should.be.bignumber.equal(minNewFixed); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/FixidityLibMock_integer.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | // use default BigNumber 6 | chai.use(require('chai-bignumber')()).should(); 7 | 8 | 9 | contract('FixidityLibMock - integer', () => { 10 | let fixidityLibMock; 11 | let fixed1; 12 | let maxNewFixed; 13 | let minNewFixed; 14 | 15 | before(async () => { 16 | fixidityLibMock = await FixidityLibMock.deployed(); 17 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 18 | maxNewFixed = new BigNumber(await fixidityLibMock.maxNewFixed()); 19 | minNewFixed = new BigNumber(await fixidityLibMock.minNewFixed()); 20 | }); 21 | 22 | describe('integer', () => { 23 | it('integer(0)', async () => { 24 | const result = new BigNumber(await fixidityLibMock.integer(0)); 25 | assert.equal(result.comparedTo(new BigNumber(0)), 0, 'should be zero!'); 26 | }); 27 | it('integer(fixed1())', async () => { 28 | const result = new BigNumber(await fixidityLibMock.integer(fixed1.toString(10))); 29 | assert.equal(result.comparedTo(fixed1), 0, 'should be fixed1!'); 30 | }); 31 | it('integer(newFixed(maxNewFixed()))', async () => { 32 | const newFromMaxFixedNew = new BigNumber( 33 | await fixidityLibMock.newFixed(maxNewFixed.toString(10)), 34 | ); 35 | const result = new BigNumber( 36 | await fixidityLibMock.integer(newFromMaxFixedNew.toString(10)), 37 | ); 38 | assert.equal( 39 | result.comparedTo(maxNewFixed.multipliedBy(fixed1)), 40 | 0, 41 | 'should be maxNewFixed()*fixed1()!', 42 | ); 43 | }); 44 | it('integer(-fixed1())', async () => { 45 | const negativeFixed1 = fixed1.multipliedBy(-1); 46 | const result = new BigNumber( 47 | await fixidityLibMock.integer(negativeFixed1.toString(10)), 48 | ); 49 | assert.equal(result.comparedTo(negativeFixed1), 0, 'should be -fixed1()!'); 50 | }); 51 | it('integer(newFixed(minNewFixed()))', async () => { 52 | const newFromMinFixedNew = new BigNumber( 53 | await fixidityLibMock.newFixed(minNewFixed.toString(10)), 54 | ); 55 | const result = new BigNumber( 56 | await fixidityLibMock.integer(newFromMinFixedNew.toString(10)), 57 | ); 58 | assert.equal( 59 | result.comparedTo(minNewFixed.multipliedBy(fixed1)), 60 | 0, 61 | 'should be minNewFixed()*fixed1()!', 62 | ); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/FixidityLibMock_multiply.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - multiply', () => { 11 | let fixidityLibMock; 12 | let fixed1; 13 | let maxFixedMul; 14 | let mulPrecision; 15 | let maxFixedAdd; 16 | let maxInt256; 17 | 18 | before(async () => { 19 | fixidityLibMock = await FixidityLibMock.deployed(); 20 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 21 | maxFixedMul = new BigNumber(await fixidityLibMock.maxFixedMul()); 22 | mulPrecision = new BigNumber(await fixidityLibMock.mulPrecision()); 23 | maxFixedAdd = new BigNumber(await fixidityLibMock.maxFixedAdd()); 24 | maxInt256 = new BigNumber(await fixidityLibMock.maxInt256()); 25 | }); 26 | 27 | describe('multiply', () => { 28 | it('multiply(maxFixedMul(),0)', async () => { 29 | const result = new BigNumber( 30 | await fixidityLibMock.multiply( 31 | 0, 32 | 0, 33 | ), 34 | ); 35 | result.should.be.bignumber.equal(0); 36 | }); 37 | it('multiply(maxFixedMul(),0)', async () => { 38 | const result = new BigNumber( 39 | await fixidityLibMock.multiply( 40 | maxFixedMul.toString(10), 41 | 0, 42 | ), 43 | ); 44 | result.should.be.bignumber.equal(0); 45 | }); 46 | it('multiply(0, maxFixedMul())', async () => { 47 | const result = new BigNumber( 48 | await fixidityLibMock.multiply( 49 | 0, 50 | maxFixedMul.toString(10), 51 | ), 52 | ); 53 | result.should.be.bignumber.equal(0); 54 | }); 55 | it('multiply(maxFixedMul(),fixed1())', async () => { 56 | const result = new BigNumber( 57 | await fixidityLibMock.multiply( 58 | maxFixedMul.toString(10), 59 | fixed1.toString(10), 60 | ), 61 | ); 62 | result.should.be.bignumber.equal(maxFixedMul); 63 | }); 64 | it('multiply(fixed1(),maxFixedMul())', async () => { 65 | const result = new BigNumber( 66 | await fixidityLibMock.multiply( 67 | fixed1.toString(10), 68 | maxFixedMul.toString(10), 69 | ), 70 | ); 71 | result.should.be.bignumber.equal(maxFixedMul); 72 | }); 73 | it('multiply(fixed1()*2,fixed1()*2)', async () => { 74 | const result = new BigNumber( 75 | await fixidityLibMock.multiply( 76 | fixed1.multipliedBy(2).toString(10), 77 | fixed1.multipliedBy(2).toString(10), 78 | ), 79 | ); 80 | result.should.be.bignumber.equal(fixed1.multipliedBy(4)); 81 | }); 82 | it('multiply(fixed1()*2,fixed1()*2.5)', async () => { 83 | const result = new BigNumber( 84 | await fixidityLibMock.multiply( 85 | fixed1.multipliedBy(2).toString(10), 86 | fixed1.multipliedBy(2.5).toString(10), 87 | ), 88 | ); 89 | result.should.be.bignumber.equal(fixed1.multipliedBy(5)); 90 | }); 91 | it('multiply(fixed1()*2.5,fixed1()*2)', async () => { 92 | const result = new BigNumber( 93 | await fixidityLibMock.multiply( 94 | fixed1.multipliedBy(2).toString(10), 95 | fixed1.multipliedBy(2.5).toString(10), 96 | ), 97 | ); 98 | result.should.be.bignumber.equal(fixed1.multipliedBy(5)); 99 | }); 100 | it('multiply(fixed1()*0.5,fixed1()*0.5)', async () => { 101 | const result = new BigNumber( 102 | await fixidityLibMock.multiply( 103 | fixed1.multipliedBy(0.5).toString(10), 104 | fixed1.multipliedBy(0.5).toString(10), 105 | ), 106 | ); 107 | result.should.be.bignumber.equal(fixed1.multipliedBy(0.25)); 108 | }); 109 | it('multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision())', async () => { 110 | const result = new BigNumber( 111 | await fixidityLibMock.multiply( 112 | fixed1.dividedBy(mulPrecision).toString(10), 113 | fixed1.dividedBy(mulPrecision).toString(10), 114 | ), 115 | ); 116 | result.should.be.bignumber.equal(1); 117 | }); 118 | it('multiply(fixed1()*2.5,fixed1()*2.5)', async () => { 119 | const result = new BigNumber( 120 | await fixidityLibMock.multiply( 121 | fixed1.multipliedBy(2.5).toString(10), 122 | fixed1.multipliedBy(2.5).toString(10), 123 | ), 124 | ); 125 | result.should.be.bignumber.equal(fixed1.multipliedBy(6.25)); 126 | }); 127 | 128 | it('multiply(fixed1()*-2,fixed1()*-2)', async () => { 129 | const result = new BigNumber( 130 | await fixidityLibMock.multiply( 131 | fixed1.multipliedBy(-2).toString(10), 132 | fixed1.multipliedBy(-2).toString(10), 133 | ), 134 | ); 135 | result.should.be.bignumber.equal(fixed1.multipliedBy(4)); 136 | }); 137 | it('multiply(fixed1()*-2,fixed1()*2)', async () => { 138 | const result = new BigNumber( 139 | await fixidityLibMock.multiply( 140 | fixed1.multipliedBy(-2).toString(10), 141 | fixed1.multipliedBy(2).toString(10), 142 | ), 143 | ); 144 | result.should.be.bignumber.equal(fixed1.multipliedBy(-4)); 145 | }); 146 | it('multiply(fixed1()*2,fixed1()*-2)', async () => { 147 | const result = new BigNumber( 148 | await fixidityLibMock.multiply( 149 | fixed1.multipliedBy(2).toString(10), 150 | fixed1.multipliedBy(-2).toString(10), 151 | ), 152 | ); 153 | result.should.be.bignumber.equal(fixed1.multipliedBy(-4)); 154 | }); 155 | 156 | it('multiply(fixed1()*-2.5,fixed1()*-2)', async () => { 157 | const result = new BigNumber( 158 | await fixidityLibMock.multiply( 159 | fixed1.multipliedBy(-2.5).toString(10), 160 | fixed1.multipliedBy(-2).toString(10), 161 | ), 162 | ); 163 | result.should.be.bignumber.equal(fixed1.multipliedBy(5)); 164 | }); 165 | it('multiply(fixed1()*-2.5,fixed1()*2)', async () => { 166 | const result = new BigNumber( 167 | await fixidityLibMock.multiply( 168 | fixed1.multipliedBy(-2.5).toString(10), 169 | fixed1.multipliedBy(2).toString(10), 170 | ), 171 | ); 172 | result.should.be.bignumber.equal(fixed1.multipliedBy(-5)); 173 | }); 174 | it('multiply(fixed1()*2.5,fixed1()*-2)', async () => { 175 | const result = new BigNumber( 176 | await fixidityLibMock.multiply( 177 | fixed1.multipliedBy(2.5).toString(10), 178 | fixed1.multipliedBy(-2).toString(10), 179 | ), 180 | ); 181 | result.should.be.bignumber.equal(fixed1.multipliedBy(-5)); 182 | }); 183 | 184 | it('multiply(fixed1()*-2,fixed1()*-2.5)', async () => { 185 | const result = new BigNumber( 186 | await fixidityLibMock.multiply( 187 | fixed1.multipliedBy(-2).toString(10), 188 | fixed1.multipliedBy(-2.5).toString(10), 189 | ), 190 | ); 191 | result.should.be.bignumber.equal(fixed1.multipliedBy(5)); 192 | }); 193 | it('multiply(fixed1()*-2,fixed1()*2.5)', async () => { 194 | const result = new BigNumber( 195 | await fixidityLibMock.multiply( 196 | fixed1.multipliedBy(-2).toString(10), 197 | fixed1.multipliedBy(2.5).toString(10), 198 | ), 199 | ); 200 | result.should.be.bignumber.equal(fixed1.multipliedBy(-5)); 201 | }); 202 | it('multiply(fixed1()*2,fixed1()*-2.5)', async () => { 203 | const result = new BigNumber( 204 | await fixidityLibMock.multiply( 205 | fixed1.multipliedBy(2).toString(10), 206 | fixed1.multipliedBy(-2.5).toString(10), 207 | ), 208 | ); 209 | result.should.be.bignumber.equal(fixed1.multipliedBy(-5)); 210 | }); 211 | 212 | it('multiply(fixed1()*-2.5,fixed1()*-2.5)', async () => { 213 | const result = new BigNumber( 214 | await fixidityLibMock.multiply( 215 | fixed1.multipliedBy(-2.5).toString(10), 216 | fixed1.multipliedBy(-2.5).toString(10), 217 | ), 218 | ); 219 | result.should.be.bignumber.equal(fixed1.multipliedBy(6.25)); 220 | }); 221 | it('multiply(fixed1()*-2.5,fixed1()*2.5)', async () => { 222 | const result = new BigNumber( 223 | await fixidityLibMock.multiply( 224 | fixed1.multipliedBy(-2.5).toString(10), 225 | fixed1.multipliedBy(2.5).toString(10), 226 | ), 227 | ); 228 | result.should.be.bignumber.equal(fixed1.multipliedBy(-6.25)); 229 | }); 230 | it('multiply(fixed1()*2.5,fixed1()*-2.5)', async () => { 231 | const result = new BigNumber( 232 | await fixidityLibMock.multiply( 233 | fixed1.multipliedBy(2.5).toString(10), 234 | fixed1.multipliedBy(-2.5).toString(10), 235 | ), 236 | ); 237 | result.should.be.bignumber.equal(fixed1.multipliedBy(-6.25)); 238 | }); 239 | it('multiply(maxFixedAdd(),2*fixed1()', async () => { 240 | const result = new BigNumber( 241 | await fixidityLibMock.multiply( 242 | maxFixedAdd.toString(10), 243 | fixed1.multipliedBy(2).toString(10), 244 | ), 245 | ); 246 | result.should.be.bignumber.lte(maxInt256); 247 | }); 248 | itShouldThrow('multiply(maxFixedAdd()+1,2*fixed1())', async () => { 249 | await fixidityLibMock.multiply( 250 | maxFixedAdd.plus(fixed1).toString(10), 251 | fixed1.multipliedBy(2).toString(10), 252 | ); 253 | }, 'revert'); 254 | itShouldThrow('multiply(maxFixedAdd(),2.5*fixed1())', async () => { 255 | await fixidityLibMock.multiply( 256 | maxFixedAdd.plus(fixed1).toString(10), 257 | fixed1.multipliedBy(2.5).toString(10), 258 | ); 259 | }, 'revert'); 260 | itShouldThrow('multiply(maxFixedAdd(),maxFixedAdd())', async () => { 261 | await fixidityLibMock.multiply( 262 | maxFixedAdd.toString(10), 263 | maxFixedAdd.toString(10), 264 | ); 265 | }, 'revert'); 266 | it('multiply(maxFixedMul(),maxFixedMul()', async () => { 267 | const result = new BigNumber( 268 | await fixidityLibMock.multiply( 269 | maxFixedMul.toString(10), 270 | maxFixedMul.toString(10), 271 | ), 272 | ); 273 | result.should.be.bignumber.lte(maxInt256); 274 | }); 275 | itShouldThrow('multiply(maxFixedMul(),maxFixedMul()+x)', async () => { 276 | await fixidityLibMock.multiply( 277 | maxFixedMul.toString(10), 278 | maxFixedMul.plus('30000000000000000000000000000000000').toString(10), 279 | ); 280 | }, 'revert'); 281 | 282 | it('multiply(maxFixedAdd(),-2*fixed1()', async () => { 283 | const result = new BigNumber( 284 | await fixidityLibMock.multiply( 285 | maxFixedAdd.toString(10), 286 | fixed1.multipliedBy(-2).toString(10), 287 | ), 288 | ); 289 | result.should.be.bignumber.lte(maxInt256); 290 | }); 291 | itShouldThrow('multiply(maxFixedAdd()+1,-2*fixed1())', async () => { 292 | await fixidityLibMock.multiply( 293 | maxFixedAdd.plus(fixed1).toString(10), 294 | fixed1.multipliedBy(-2).toString(10), 295 | ); 296 | }, 'revert'); 297 | itShouldThrow('multiply(maxFixedAdd(),-2.5*fixed1())', async () => { 298 | await fixidityLibMock.multiply( 299 | maxFixedAdd.plus(fixed1).toString(10), 300 | fixed1.multipliedBy(-2.5).toString(10), 301 | ); 302 | }, 'revert'); 303 | itShouldThrow('multiply(maxFixedAdd(),-maxFixedAdd())', async () => { 304 | await fixidityLibMock.multiply( 305 | maxFixedAdd.toString(10), 306 | maxFixedAdd.multipliedBy(-1).toString(10), 307 | ); 308 | }, 'revert'); 309 | it('multiply(maxFixedMul(),-maxFixedMul()', async () => { 310 | const result = new BigNumber( 311 | await fixidityLibMock.multiply( 312 | maxFixedMul.toString(10), 313 | maxFixedMul.multipliedBy(-1).toString(10), 314 | ), 315 | ); 316 | result.should.be.bignumber.lte(maxInt256); 317 | }); 318 | itShouldThrow('multiply(maxFixedMul()+x,-maxFixedMul())', async () => { 319 | await fixidityLibMock.multiply( 320 | maxFixedMul.plus('30000000000000000000000000000000000').toString(10), 321 | maxFixedMul.multipliedBy(-1).toString(10), 322 | ); 323 | }, 'revert'); 324 | }); 325 | }); 326 | -------------------------------------------------------------------------------- /test/FixidityLibMock_newFixed.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - newFixed', () => { 11 | let fixidityLibMock; 12 | let fixed1; 13 | let maxNewFixed; 14 | let minNewFixed; 15 | 16 | before(async () => { 17 | fixidityLibMock = await FixidityLibMock.deployed(); 18 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 19 | maxNewFixed = new BigNumber(await fixidityLibMock.maxNewFixed()); 20 | minNewFixed = new BigNumber(await fixidityLibMock.minNewFixed()); 21 | }); 22 | 23 | describe('newFixed', () => { 24 | it('newFixed(0)', async () => { 25 | const result = new BigNumber( 26 | await fixidityLibMock.newFixed(0), 27 | ); 28 | result.should.be.bignumber.equal(0); 29 | }); 30 | it('newFixed(1)', async () => { 31 | const result = new BigNumber( 32 | await fixidityLibMock.newFixed(1), 33 | ); 34 | result.should.be.bignumber.equal(fixed1); 35 | }); 36 | it('newFixed(maxNewFixed())', async () => { 37 | const result = new BigNumber( 38 | await fixidityLibMock.newFixed(maxNewFixed.toString(10)), 39 | ); 40 | result.should.be.bignumber.equal(fixed1.multipliedBy(maxNewFixed)); 41 | }); 42 | itShouldThrow( 43 | 'newFixed(maxNewFixed()+1)', 44 | async () => { 45 | await fixidityLibMock 46 | .newFixed(maxNewFixed.plus(1).toString(10)); 47 | }, 48 | 'revert', 49 | ); 50 | it('newFixed(-1)', async () => { 51 | const result = new BigNumber(await fixidityLibMock.newFixed(-1)); 52 | result.should.be.bignumber.equal(fixed1.multipliedBy(-1)); 53 | }); 54 | it('newFixed(minNewFixed())', async () => { 55 | const result = new BigNumber( 56 | await fixidityLibMock.newFixed(minNewFixed.toString(10)), 57 | ); 58 | result.should.be.bignumber.equal(fixed1.multipliedBy(minNewFixed)); 59 | }); 60 | itShouldThrow( 61 | 'newFixed(minNewFixed()-1)', 62 | async () => { 63 | await fixidityLibMock 64 | .newFixed(minNewFixed.minus(1).toString(10)); 65 | }, 66 | 'revert', 67 | ); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /test/FixidityLibMock_newFixedFraction.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - newFixedFraction', () => { 11 | let fixidityLibMock; 12 | let fixed1; 13 | let maxFixedDiv; 14 | 15 | before(async () => { 16 | fixidityLibMock = await FixidityLibMock.deployed(); 17 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 18 | maxFixedDiv = new BigNumber(await fixidityLibMock.maxFixedDiv()); 19 | }); 20 | 21 | describe('newFixedFraction', () => { 22 | itShouldThrow( 23 | 'newFixedFraction(maxFixedDiv()+1,1)', 24 | async () => { 25 | await fixidityLibMock 26 | .newFixedFraction(maxFixedDiv.plus(1).toString(10), 1); 27 | }, 28 | 'revert', 29 | ); 30 | itShouldThrow( 31 | 'newFixedFraction(1,maxFixedDiv()+1)', 32 | async () => { 33 | await fixidityLibMock 34 | .newFixedFraction(1, maxFixedDiv.plus(1).toString(10)); 35 | }, 36 | 'revert', 37 | ); 38 | itShouldThrow( 39 | 'newFixedFraction(1,0)', 40 | async () => { 41 | await fixidityLibMock 42 | .newFixedFraction(1, 0); 43 | }, 44 | 'revert', 45 | ); 46 | it('newFixedFraction(0,1)', async () => { 47 | const result = new BigNumber( 48 | await fixidityLibMock.newFixedFraction(0, 1), 49 | ); 50 | result.should.be.bignumber.equal(0); 51 | }); 52 | it('newFixedFraction(1,1)', async () => { 53 | const result = new BigNumber( 54 | await fixidityLibMock.newFixedFraction(1, 1), 55 | ); 56 | result.should.be.bignumber.equal(fixed1); 57 | }); 58 | it('newFixedFraction(maxFixedDiv(),1)', async () => { 59 | const result = new BigNumber( 60 | await fixidityLibMock.newFixedFraction(maxFixedDiv.toString(10), 1), 61 | ); 62 | result.should.be.bignumber.equal(maxFixedDiv.multipliedBy(fixed1)); 63 | }); 64 | it('newFixedFraction(1,fixed1())', async () => { 65 | const result = new BigNumber( 66 | await fixidityLibMock.newFixedFraction(1, fixed1.toString(10)), 67 | ); 68 | result.should.be.bignumber.equal(1); 69 | }); 70 | itShouldThrow( 71 | 'newFixedFraction(10, maxFixedDiv()*10)', 72 | async () => { 73 | await fixidityLibMock.newFixedFraction( 74 | 10, 75 | maxFixedDiv.multipliedBy(10).toString(10), 76 | ); 77 | }, 78 | 'revert', 79 | ); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /test/FixidityLibMock_reciprocal.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | const { itShouldThrow } = require('./utils'); 6 | // use default BigNumber 7 | chai.use(require('chai-bignumber')()).should(); 8 | 9 | 10 | contract('FixidityLibMock - reciprocal', () => { 11 | let fixidityLibMock; 12 | let fixed1; 13 | 14 | before(async () => { 15 | fixidityLibMock = await FixidityLibMock.deployed(); 16 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 17 | }); 18 | 19 | describe('reciprocal', () => { 20 | itShouldThrow('reciprocal(0)', async () => { 21 | await fixidityLibMock.reciprocal(0); 22 | }, 'revert'); 23 | it('reciprocal(fixed1())', async () => { 24 | const result = new BigNumber( 25 | await fixidityLibMock.reciprocal( 26 | fixed1.toString(10), 27 | ), 28 | ); 29 | result.should.be.bignumber.equal( 30 | fixed1, 31 | ); 32 | }); 33 | it('reciprocal(fixed1()*2)', async () => { 34 | const result = new BigNumber( 35 | await fixidityLibMock.reciprocal( 36 | fixed1.multipliedBy(2).toString(10), 37 | ), 38 | ); 39 | result.should.be.bignumber.equal( 40 | fixed1.dividedBy(2), 41 | ); 42 | }); 43 | it('reciprocal(2.5)', async () => { 44 | const result = new BigNumber( 45 | await fixidityLibMock.reciprocal( 46 | fixed1.multipliedBy(2.5).toString(10), 47 | ), 48 | ); 49 | result.should.be.bignumber.equal( 50 | fixed1.div(2.5).dp(0, 1), 51 | ); 52 | }); 53 | it('reciprocal(fixed1()*fixed1())', async () => { 54 | const result = new BigNumber( 55 | await fixidityLibMock.reciprocal( 56 | fixed1.multipliedBy(fixed1).toString(10), 57 | ), 58 | ); 59 | result.should.be.bignumber.equal( 60 | 1, 61 | ); 62 | }); 63 | it('reciprocal(2*fixed1()*fixed1())', async () => { 64 | const result = new BigNumber( 65 | await fixidityLibMock.reciprocal( 66 | new BigNumber(2).multipliedBy(fixed1).multipliedBy(fixed1).toString(10), 67 | ), 68 | ); 69 | result.should.be.bignumber.equal( 70 | 0, 71 | ); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /test/FixidityLibMock_subtract.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | // const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | // use default BigNumber 6 | chai.use(require('chai-bignumber')()).should(); 7 | 8 | 9 | contract('FixidityLibMock - subtract', () => { 10 | let fixidityLibMock; 11 | 12 | before(async () => { 13 | fixidityLibMock = await FixidityLibMock.deployed(); 14 | }); 15 | 16 | describe('subtract', () => { 17 | it('subtract', async () => { 18 | await fixidityLibMock.subtract(4, 2); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/FixidityLibMock_variables.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const BigNumber = require('bignumber.js'); 3 | const chai = require('chai'); 4 | 5 | // use default BigNumber 6 | chai.use(require('chai-bignumber')()).should(); 7 | 8 | 9 | contract('FixidityLibMock - variables', () => { 10 | let fixidityLibMock; 11 | let digits; 12 | let fixed1; 13 | let mulPrecision; 14 | let maxInt256; 15 | let minInt256; 16 | let maxNewFixed; 17 | let minNewFixed; 18 | let maxFixedAdd; 19 | let maxFixedSub; 20 | 21 | before(async () => { 22 | fixidityLibMock = await FixidityLibMock.deployed(); 23 | digits = new BigNumber(await fixidityLibMock.digits()); 24 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 25 | mulPrecision = BigNumber(await fixidityLibMock.mulPrecision()); 26 | maxInt256 = BigNumber(await fixidityLibMock.maxInt256()); 27 | minInt256 = BigNumber(await fixidityLibMock.minInt256()); 28 | maxNewFixed = BigNumber(await fixidityLibMock.maxNewFixed()); 29 | minNewFixed = BigNumber(await fixidityLibMock.minNewFixed()); 30 | maxFixedAdd = BigNumber(await fixidityLibMock.maxFixedAdd()); 31 | maxFixedSub = BigNumber(await fixidityLibMock.maxFixedSub()); 32 | }); 33 | 34 | it('fixed1() equals 10**digits()', async () => { 35 | fixed1.should.be.bignumber.equal(new BigNumber('10').pow(digits)); 36 | }); 37 | 38 | it('mulPrecision() equals sqrt(fixed1())', async () => { 39 | mulPrecision.should.be.bignumber.equal(new BigNumber(fixed1).sqrt()); 40 | }); 41 | 42 | it('maxInt256() equals (2^255) - 1', async () => { 43 | maxInt256.should.be.bignumber.equal(new BigNumber(2).pow(255).minus(1)); 44 | }); 45 | 46 | it('minInt256() equals (2^255)*(-1)', async () => { 47 | minInt256.should.be.bignumber.equal(new BigNumber(2).pow(255).multipliedBy(-1)); 48 | }); 49 | 50 | it('maxNewFixed() equals maxInt256() / fixed1()', async () => { 51 | maxNewFixed.should.be.bignumber.equal(maxInt256.div(fixed1).dp(0, 1)); 52 | }); 53 | 54 | it('minNewFixed() equals -(maxInt256()) / fixed1()', async () => { 55 | minNewFixed.should.be.bignumber.equal(maxInt256.div(fixed1).multipliedBy(-1).dp(0, 1)); 56 | }); 57 | 58 | it('maxFixedAdd() equals maxInt256()-1 / 2', async () => { 59 | maxFixedAdd.should.be.bignumber.equal(maxInt256.minus(1).div(2).dp(0, 1)); 60 | }); 61 | 62 | it('maxFixedSub() equals minInt256() / 2', async () => { 63 | maxFixedSub.should.be.bignumber.equal(minInt256.div(2).dp(0, 1)); 64 | }); 65 | 66 | /* it('maxFixedMul equals sqrt(maxNewFixed())', async () => { 67 | maxFixedMul.should.be.bignumber.equal(maxNewFixed.sqrt().dp(0, 1)); 68 | }); */ 69 | 70 | /* it('maxFixedDiv() equals maxInt256()/fixed1()', async () => { 71 | maxFixedDiv.should.be.bignumber.equal(maxInt256.div(fixed1)); 72 | }); */ 73 | }); 74 | -------------------------------------------------------------------------------- /test/LogarithmLibMock.js: -------------------------------------------------------------------------------- 1 | const FixidityLibMock = artifacts.require('./FixidityLibMock.sol'); 2 | const LogarithmLibMock = artifacts.require('./LogarithmLibMock.sol'); 3 | const BigNumber = require('bignumber.js'); 4 | const chai = require('chai'); 5 | 6 | const { itShouldThrow } = require('./utils'); 7 | // use default BigNumber 8 | chai.use(require('chai-bignumber')()).should(); 9 | 10 | contract('LogarithmLibMock', () => { 11 | let fixidityLibMock; 12 | let logarithmLibMock; 13 | let fixed1; 14 | let fixedE; 15 | let mulPrecision; 16 | let maxNewFixed; 17 | 18 | before(async () => { 19 | fixidityLibMock = await FixidityLibMock.deployed(); 20 | logarithmLibMock = await LogarithmLibMock.deployed(); 21 | fixed1 = new BigNumber(await fixidityLibMock.fixed1()); 22 | fixedE = new BigNumber(await logarithmLibMock.fixedE()); 23 | mulPrecision = new BigNumber(await fixidityLibMock.mulPrecision()); 24 | maxNewFixed = new BigNumber(await fixidityLibMock.maxNewFixed()); 25 | }); 26 | 27 | /* 28 | * Test ln(0) fails 29 | * Test ln(-fixed1()) fails 30 | * Test ln(fixed1()) returns 0 31 | * Test ln(fixedE()) returns fixed1() 32 | * Test ln(fixedE()*fixedE()) returns ln(fixedE())+ln(fixedE()) 33 | * Test ln(maxNewFixed*fixed1()) returns 93859467695000404205515674067419529216 34 | * Test ln(1) returns -82 35 | */ 36 | itShouldThrow('ln(0)', async () => { 37 | await logarithmLibMock.ln(0); 38 | }, 'revert'); 39 | itShouldThrow('ln(-1)', async () => { 40 | await logarithmLibMock.ln(-1); 41 | }, 'revert'); 42 | it('ln(fixed1())', async () => { 43 | const result = new BigNumber( 44 | await logarithmLibMock.ln(fixed1.toString(10)), 45 | ); 46 | result.should.be.bignumber.equal(0); 47 | }); 48 | it('ln(fixedE())', async () => { 49 | const result = new BigNumber( 50 | await logarithmLibMock.ln(fixedE.toString(10)), 51 | ); 52 | result.should.be.bignumber.equal(fixed1); 53 | }); 54 | it('ln(fixedE()*fixedE())', async () => { // 1/(10**16)% deviation at e**2 55 | const result = new BigNumber( 56 | await logarithmLibMock.ln( 57 | await fixidityLibMock.multiply( 58 | fixedE.toString(10), 59 | fixedE.toString(10), 60 | ), 61 | ), 62 | ); 63 | result.should.be.bignumber.gte(fixed1.minus(mulPrecision).multipliedBy(2)); 64 | result.should.be.bignumber.lte(fixed1.plus(mulPrecision).multipliedBy(2)); 65 | }); 66 | it('ln(maxNewFixed())', async () => { // 1000% deviation at maxNewFixed() 67 | const result = new BigNumber( 68 | await logarithmLibMock.ln(maxNewFixed.toString(10)), 69 | ); 70 | const logMax = new BigNumber('93859467695000404205515674'); 71 | result.should.be.bignumber.gte(logMax.multipliedBy(0.1)); 72 | result.should.be.bignumber.lte(logMax.multipliedBy(10)); 73 | }); 74 | it('ln(1)', async () => { // 33% deviation at the lower precision limit 75 | const result = new BigNumber( 76 | await logarithmLibMock.ln(1), 77 | ); 78 | result.should.be.bignumber.gte(fixed1.plus(fixed1.dividedBy(3)).multipliedBy(-82)); 79 | result.should.be.bignumber.lte(fixed1.minus(fixed1.dividedBy(3)).multipliedBy(-82)); 80 | }); 81 | it('ln(10*fixed1)', async () => { // 10**-15 deviation at 1.0 82 | const result = new BigNumber( 83 | await logarithmLibMock.ln(fixed1.multipliedBy(10).toString(10)), 84 | ); 85 | result.should.be.bignumber.gte(new BigNumber('2302585092994045000000000')); 86 | result.should.be.bignumber.lte(new BigNumber('2302585092994046000000000')); 87 | }); 88 | it('log(10,11*fixed1)', async () => { // 10**-11 deviation at 11.0 89 | const result = new BigNumber( 90 | await logarithmLibMock.log_b(fixed1.multipliedBy(10).toString(10), fixed1.multipliedBy(11).toString(10)), 91 | ); 92 | result.should.be.bignumber.gte(new BigNumber('1041392685157000000000000')); 93 | result.should.be.bignumber.lte(new BigNumber('1041392685158000000000000')); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | const BigNumber = require('bignumber.js'); 2 | 3 | const itShouldThrow = (reason, fun, expectedMessage) => { 4 | it(reason, async () => { 5 | let error = false; 6 | try { 7 | await Promise.resolve(fun()).catch((e) => { 8 | error = e; 9 | }); 10 | } catch (e) { 11 | error = e; 12 | } 13 | 14 | // No error was returned or raised - make the test fail plain and simple. 15 | if (!error) { 16 | assert.ok(false, 'expected to throw, did not'); 17 | } 18 | 19 | // No exception message was provided, we'll only test against the important VM ones. 20 | if (expectedMessage === undefined) { 21 | assert.match( 22 | error.message, 23 | /invalid JUMP|invalid opcode|out of gas|The contract code couldn't be stored, please check your gas amount/, 24 | ); 25 | // An expected exception message was passed - match it. 26 | } else if (error.message.length > 0) { 27 | // Get the error message from require method within the contract 28 | const errorReason = error.message.match('Reason given: (.*)\\.'); 29 | // If there's no message error provided, check for default errors 30 | if (errorReason === null) { 31 | assert.ok( 32 | error.message.indexOf(expectedMessage) >= 0, 33 | 'threw the wrong exception type', 34 | ); 35 | } else { 36 | assert.equal( 37 | expectedMessage, 38 | errorReason[1], 39 | 'threw the wrong exception type', 40 | ); 41 | } 42 | // In case that nothing matches! 43 | } else { 44 | assert.ok(false, `something went wrong with asserts. Given error ${error}`); 45 | } 46 | }); 47 | }; 48 | 49 | const tokenNumber = (decimals, tokens) => new BigNumber(10) 50 | .pow(decimals) 51 | .multipliedBy(tokens) 52 | .toString(10); 53 | 54 | module.exports = { 55 | itShouldThrow, 56 | tokenNumber, 57 | }; 58 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | const HDWalletProvider = require('truffle-hdwallet-provider'); 2 | const fs = require('fs'); 3 | 4 | const infuraKey = 'your-key'; 5 | const mnemonic = ''; // fs.readFileSync('.secret').toString().trim(); 6 | 7 | module.exports = { 8 | networks: { 9 | development: { 10 | host: '127.0.0.1', 11 | port: 8545, 12 | gas: 6721975, 13 | gasPrice: 20000000000, 14 | network_id: '*', 15 | }, 16 | ropsten: { 17 | provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/${infuraKey}`), 18 | network_id: 3, 19 | gas: 5500000, 20 | confirmations: 2, 21 | timeoutBlocks: 200, 22 | skipDryRun: true, 23 | }, 24 | }, 25 | 26 | mocha: { 27 | // see more here: https://www.npmjs.com/package/eth-gas-reporter 28 | // reporter: 'eth-gas-reporter', 29 | }, 30 | 31 | solc: { 32 | optimizer: { 33 | enabled: true, 34 | runs: 200, 35 | }, 36 | }, 37 | 38 | compilers: { 39 | solc: { 40 | version: '0.5.2', 41 | settings: { 42 | optimizer: { 43 | enabled: true, 44 | runs: 200, 45 | }, 46 | }, 47 | }, 48 | }, 49 | }; 50 | --------------------------------------------------------------------------------