forked from keep-starknet-strange/alexandria
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add wad_ray_math with tests (keep-starknet-strange#215)
<!--- Please provide a general summary of your changes in the title above --> ## Pull Request type <!-- Please try to limit your pull request to one type; submit multiple pull requests if needed. --> Please check the type of change your PR introduces: - [ ] Bugfix - [X] Feature - [ ] Code style update (formatting, renaming) - [ ] Refactoring (no functional changes, no API changes) - [ ] Build-related changes - [ ] Documentation content changes - [ ] Other (please describe): ## What is the current behavior? Handle Wad & Ray mul/div <!-- Please describe the current behavior that you are modifying, or link to a relevant issue. --> Issue Number: keep-starknet-strange#211 ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> Add new functions to handle 18 & 27 decimals base maths ## Does this introduce a breaking change? - [ ] Yes - [X] No <!-- If this does introduce a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR, such as screenshots of how the component looks before and after the change. -->
- Loading branch information
1 parent
d8473bb
commit d32162a
Showing
4 changed files
with
262 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
use alexandria_math::wad_ray_math::{ | ||
ray_div, ray_mul, wad_div, wad_mul, ray_to_wad, wad_to_ray, ray, wad, half_ray, half_wad | ||
}; | ||
use alexandria_math::{pow}; | ||
|
||
// conversion | ||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_wad_to_ray_conversion() { | ||
let a = 5 * pow(10, 17); // 0.5e18 | ||
let expected = 5 * pow(10, 26); // 0.5e27 | ||
assert(wad_to_ray(a) == expected, 'Wrong wad_to_ray conversion'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_ray_to_wad_conversion() { | ||
let a = 5 * pow(10, 26); // 0.5e27 | ||
let expected = 5 * pow(10, 17); // 0.5e18 | ||
assert(ray_to_wad(a) == expected, 'Wrong ray_to_wad conversion'); | ||
} | ||
|
||
// wad | ||
#[test] | ||
#[available_gas(2000000)] | ||
#[should_panic()] | ||
fn test_revertWhen_wad_mul_overflow() { | ||
wad_mul(pow(2, 128), pow(2, 128)); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_wad_mul_trivial() { | ||
assert(wad_mul(pow(2, 128) - 1, wad()) == pow(2, 128) - 1, 'Wrong result: 2**128 -1 * 1e18'); | ||
assert(wad_mul(0, 0) == 0, 'Wrong result: 0 * 0'); | ||
assert(wad_mul(0, wad()) == 0, 'Wrong result: 0 * 1e18'); | ||
assert(wad_mul(wad(), 0) == 0, 'Wrong result: 1e18 * 0'); | ||
assert(wad_mul(wad(), wad()) == wad(), 'Wrong result: 1e18 * 1e18 '); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_wad_mul_fractions() { | ||
let val: u256 = 2 * pow(10, 17); // 0.2e18 | ||
assert(wad_mul(wad(), val) == val, 'Wrong result: 1e18 * 0.2e18'); | ||
assert(wad_mul(wad() * 2, val) == val * 2, 'Wrong result: 2e18 * 0.2e18'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
#[should_panic()] | ||
fn test_revertWhen_wad_div_zero() { | ||
wad_div(wad(), 0); | ||
} | ||
|
||
#[test] | ||
#[available_gas(3000000)] | ||
fn test_wad_div_trivial() { | ||
assert(wad_div(pow(2, 128) - 1, wad()) == pow(2, 128) - 1, 'Wrong result: 2**128 -1 / 1e18'); | ||
assert(wad_div(0, pow(2, 128) - 1) == 0, 'Wrong result: 0 / 2**128 -1'); | ||
assert(wad_div(wad(), wad()) == wad(), 'Wrong result: 1e18 / 1e18'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_wad_div_fractions() { | ||
assert(wad_div(wad() * 2, wad() * 2) == wad(), 'Wrong result: 2e18 / 2e18'); | ||
assert(wad_div(wad(), wad() * 2) == half_wad(), 'Wrong result: 1e18 / 2e18'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_wad_mul_rounding() { | ||
let a = 950000000000005647; | ||
let b = 1000000000; | ||
let expected = 950000000; | ||
assert(wad_mul(a, b) == expected, 'Wrong rounding down: a * b'); | ||
assert(wad_mul(b, a) == expected, 'Wrong rounding down: b * a'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_wad_mul_rounding_up() { | ||
let a = pow(10, 18) - 1; | ||
let b = 2; | ||
let expected = 2; | ||
assert(wad_mul(a, b) == expected, 'Wrong rounding: a * b'); | ||
assert(wad_mul(b, a) == expected, 'Wrong rounding: b * a'); | ||
} | ||
|
||
|
||
// wad | ||
#[test] | ||
#[available_gas(2000000)] | ||
#[should_panic()] | ||
fn test_revertWhen_ray_mul_overflow() { | ||
ray_mul(pow(2, 128), pow(2, 128)); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_ray_mul_trivial() { | ||
assert(ray_mul(pow(2, 128) - 1, ray()) == pow(2, 128) - 1, 'Wrong result: 2**128 -1 * 1e27'); | ||
assert(ray_mul(0, 0) == 0, 'Wrong result: 0 * 0'); | ||
assert(ray_mul(0, ray()) == 0, 'Wrong result: 0 * 1e27'); | ||
assert(ray_mul(ray(), 0) == 0, 'Wrong result: 1e27 * 0'); | ||
assert(ray_mul(ray(), ray()) == ray(), 'Wrong result: 1e27 * 1e27 '); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_ray_mul_fractions() { | ||
let val: u256 = 2 * pow(10, 26); // 0.2e27 | ||
assert(ray_mul(ray(), val) == val, 'Wrong result: 1e27 * 0.2e27'); | ||
assert(ray_mul(ray() * 2, val) == val * 2, 'Wrong result: 2e27 * 0.2e27'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
#[should_panic()] | ||
fn test_revertWhen_ray_div_zero() { | ||
ray_div(ray(), 0); | ||
} | ||
|
||
#[test] | ||
#[available_gas(3000000)] | ||
fn test_ray_div_trivial() { | ||
assert(ray_div(pow(2, 128) - 1, ray()) == pow(2, 128) - 1, 'Wrong result: 2**128 -1 / 1e27'); | ||
assert(ray_div(0, pow(2, 128) - 1) == 0, 'Wrong result: 0 / 2**128 -1'); | ||
assert(ray_div(ray(), ray()) == ray(), 'Wrong result: 1e27 / 1e27'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_ray_div_fractions() { | ||
assert(ray_div(ray() * 2, ray() * 2) == ray(), 'Wrong result: 2e27 / 2e27'); | ||
assert(ray_div(ray(), ray() * 2) == half_ray(), 'Wrong result: 1e27 / 2e27'); | ||
} | ||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_ray_mul_rounding() { | ||
let a = pow(10, 18); | ||
let b = 95 * pow(10, 26) + 5647; | ||
let expected = 95 * pow(10, 17); | ||
assert(ray_mul(a, b) == expected, 'Wrong rounding down: a * b'); | ||
assert(ray_mul(b, a) == expected, 'Wrong rounding down: b * a'); | ||
} | ||
|
||
|
||
#[test] | ||
#[available_gas(2000000)] | ||
fn test_ray_mul_rounding_up() { | ||
let a = pow(10, 27) - 1; | ||
let b = 2; | ||
let expected = 2; | ||
assert(ray_mul(a, b) == expected, 'Wrong rounding up: a * b'); | ||
assert(ray_mul(b, a) == expected, 'Wrong rounding up: b * a'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/// Provides functions to perform calculations with Wad and Ray units | ||
/// @dev Provides mul and div function for wads (decimal numbers with 18 digits of precision) and rays (decimal numbers | ||
/// with 27 digits of precision) | ||
/// Operations are rounded. If a value is >=.5, will be rounded up, otherwise rounded down. | ||
/// https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/libraries/math/WadRayMath.sol | ||
|
||
const WAD: u256 = 1_000_000_000_000_000_000; // 1e18 | ||
const HALF_WAD: u256 = 500_000_000_000_000_000; // 0.5e18 | ||
const RAY: u256 = 1_000_000_000_000_000_000_000_000_000; // 1e27 | ||
const HALF_RAY: u256 = 500_000_000_000_000_000_000_000_000; // 0.5e27 | ||
const WAD_RAY_RATIO: u256 = 1_000_000_000; // 1e9 | ||
const HALF_WAD_RAY_RATIO: u256 = 500_000_000; // 0.5e9 | ||
|
||
|
||
/// Return the wad value | ||
/// # Returns | ||
/// * `u256` - The value | ||
fn wad() -> u256 { | ||
return WAD; | ||
} | ||
|
||
/// Return the ray value | ||
/// # Returns | ||
/// * `u256` - The value | ||
fn ray() -> u256 { | ||
return RAY; | ||
} | ||
|
||
/// Return the half wad value | ||
/// # Returns | ||
/// * `u256` - The value | ||
fn half_wad() -> u256 { | ||
return HALF_WAD; | ||
} | ||
|
||
/// Return the half ray value | ||
/// # Returns | ||
/// * `u256` - The value | ||
fn half_ray() -> u256 { | ||
return HALF_RAY; | ||
} | ||
|
||
|
||
/// Multiplies two wad, rounding half up to the nearest wad | ||
/// # Arguments | ||
/// * a Wad | ||
/// * b Wad | ||
/// # Returns | ||
/// * a*b, in wad | ||
fn wad_mul(a: u256, b: u256) -> u256 { | ||
return (a * b + HALF_WAD) / WAD; | ||
} | ||
|
||
/// Divides two wad, rounding half up to the nearest wad | ||
/// # Arguments | ||
/// * a Wad | ||
/// * b Wad | ||
/// # Returns | ||
/// * a/b, in wad | ||
fn wad_div(a: u256, b: u256) -> u256 { | ||
return (a * WAD + (b / 2)) / b; | ||
} | ||
|
||
/// Multiplies two ray, rounding half up to the nearest ray | ||
/// # Arguments | ||
/// * a Ray | ||
/// * b Ray | ||
/// # Returns | ||
/// * a raymul b | ||
fn ray_mul(a: u256, b: u256) -> u256 { | ||
return (a * b + HALF_RAY) / RAY; | ||
} | ||
|
||
/// Divides two ray, rounding half up to the nearest ray | ||
/// # Arguments | ||
/// * a Ray | ||
/// * b Ray | ||
/// # Returns | ||
/// * a raydiv b | ||
fn ray_div(a: u256, b: u256) -> u256 { | ||
return (a * RAY + (b / 2)) / b; | ||
} | ||
|
||
/// Casts ray down to wad | ||
/// # Arguments | ||
/// * a Ray | ||
/// # Returns | ||
/// * a converted to wad, rounded half up to the nearest wad | ||
fn ray_to_wad(a: u256) -> u256 { | ||
return (HALF_WAD_RAY_RATIO + a) / WAD_RAY_RATIO; | ||
} | ||
|
||
/// Converts wad up to ray | ||
/// # Arguments | ||
/// * a Wad | ||
/// # Returns | ||
/// * a converted to ray | ||
fn wad_to_ray(a: u256) -> u256 { | ||
return a * WAD_RAY_RATIO; | ||
} | ||
|