Awesome
WadRay library for Cairo
This library implements two types of fixed-point decimal numbers, "wad" (18 decimals of precision) and "ray" (27 decimals of decimal numbers), available in signed (SignedWad
and SignedRay
) and unsigned (Wad
and Ray
) versions, written in Cairo for Starknet.
Wad
and Ray
are implemented as structs with a single u128
member for the value, while SignedWad
and SignedRay
are implemented as structs with a u128
member for the value and bool
member for the sign
(i.e. if the sign
is true
, then the value is negative).
Overview
This library includes arithmetic, comparison and conversion functions.
Arithmetic
Addition and Subtraction
Addition and subtraction can be performed via the Add
, AddEq
, Sub
and SubEq
traits as follows:
a + b
a += b
a - b
a -= b
where both a
and b
are of the same type.
Multiplication and Division
Multiplication and division can be performed via the the Mul
, MulEq
, Div
and DivEq
traits as follows:
a * b
a *= b
a / b
a /= b
where botha
andb
are of the same type.
There is also a set of functions for operations involving a Wad
and a Ray
:
wmul_wr
/wmul_rw
: Multiply aWad
value with aRay
value, and divide the product by oneWad
scale to return aRay
wdiv_rw
: Scale up aRay
value by oneWad
scale and divide the scaled value by aWad
value to return aRay
rmul_wr
/rmul_rw
: Multiply aWad
value with aRay
value, and divide the product by oneRay
scale to return aWad
rdiv_wr
: Scale up aWad
value by oneRay
scale and divide the scaled value by aRay
to return aWad
rdiv_ww
: Scale up aWad
value by oneRay
scale and divide the scaled value by aWad
to return aRay
For multiplication, the prefixes w
and r
denote whether the product is divided (i.e. scaled down) by a Wad
or Ray
respectively. For division, the prefixes w
and r
denote whether the first operand is multiplied (i.e. scaled up) by a Wad
or Ray
before the division respectively.
As these are fixed point operations, do take note that there will be a loss of precision.
Zero and one values
The following values and functions for both Wad
and Ray
, and SignedWad
and SignedRay
, are available via the Zeroable
and Oneable
traits.
Unsigned
WadZeroable::zero()
/RayZeroable::zero()
: Returns the zero value forWad
andRay
respectivelyis_zero()
: Returns true if theWad
orRay
value is zerois_non_zero()
Returns true if theWad
orRay
value is not zeroWadOneable::one()
/RayOneable::one()
: Returns the scale value forWad
(i.e. 10<sup>18</sup>) andRay
(i.e. 10<sup>27</sup>) respectivelyis_one()
: Returns true if theWad
orRay
value is the scale value (i.e. 10<sup>18</sup> and 10<sup>27</sup> respectively)is_non_one()
Returns true if theWad
orRay
value is not the scale value (i.e. 10<sup>18</sup> and 10<sup>27</sup> respectively)
Signed
SignedWadZeroable::zero()
/SignedRayZeroable::zero()
: Returns the zero value forWad
andRay
respectivelyis_zero()
: Returns true if theSignedWad
orSignedRay
value is zero, regardless of thesign
.is_non_zero()
Returns true if theSignedWad
orSignedRay
value is not zeroSignedWadOneable::one()
/SignedRayOneable::one()
: Returns the positive scale value for "wad" (i.e. 10<sup>18</sup>) and "ray" (i.e. 10<sup>27</sup>) respectivelyis_one()
: Returns true if theSignedWad
orSignedRay
value is the positive scale value (i.e. 10<sup>18</sup> and 10<sup>27</sup> respectively)is_non_one()
Returns true if theSignedWad
orSignedRay
value is not the positive scale value (i.e. 10<sup>18</sup> and 10<sup>27</sup> respectively)
Bound values
The bound values for both Wad
and Ray
can be obtained via the BoundedInt
trait.
BoundedWad::max()
: Returns the maximumWad
value of 2<sup>128</sup> - 1BoundedWad::min()
: Returns the minimumWad
value of 0BoundedRay::max()
: Returns the maximumRay
value of 2<sup>128</sup> - 1BoundedRay::min()
: Returns the minimumRay
value of 0
Comparisons
Comparison for both Wad
and Ray
, and SignedWad
and SignedRay
, can be performed via the PartialEq
and PartialOrd
traits as follows:
a == b
a != b
a > b
a >= b
a < b
a <= b
where both a
and b
are of the same type.
Conversion
Type Casting
Any type that can be converted to a u128
via the Into
trait can similarly be converted to a Wad
or Ray
via the Into
trait.
Additionally, the following conversions from integer types are supported for SignedWad
and SignedRay
via the Into
trait`:
u128
->SignedWad
: Convert au128
to aSignedWad
without modifying the value, with thesign
set tofalse
u128
->SignedRay
: Convert au128
to aSignedRay
without modifying the value, with thesign
set tofalse
The following conversions from this library's types can also be performed via the Into
trait:
Wad
->felt252
: Convert aWad
to afelt252
without modifying the valueWad
->u256
: Convert aWad
to au256
without modifying the valueWad
->SignedWad
: Convert aWad
to aSignedWad
without modifying the value, with thesign
set tofalse
Ray
->SignedRay
: Convert aRay
to aSignedRay
without modifying the value, with thesign
set tofalse
SignedWad
->felt252
: Convert aSignedWad
to afelt252
without modifying the valueSignedRay
->felt252
: Convert aSignedRay
to afelt252
without modifying the value
The following conversions can be performed via the TryInto
trait:
u256
->Option::<Wad>
: ReturnsOption::Some<Wad>
if the value is within bounds ofu128
orOption::None
otherwiseSignedWad
->Option::<Wad>
: ReturnsOption::Some<Wad>
ifsign
is false orOption::None
otherwiseSignedRay
->Option::<Ray>
: ReturnsOption::Some<Ray>
ifsign
is false orOption::None
otherwise
Scaling
The following functions can be used to scale between Wad
and Ray
:
fn ray_to_wad(x: Ray) -> Wad
: Divide theRay
value by 10<sup>9</sup> and return aWad
fn wad_to_ray(x: Wad) -> Option::<Ray>
: Multiply theWad
value by 10<sup>9</sup> and returnOption::Some<Ray>
if there is no overflow orOption::None
otherwise
Additional notes on conversion between Wad
and Ray
Overview
Starting from v0.5.0
of this library, we have made significant changes to how Wad
values are converted to Ray
values and vice versa. This aims to improve type safety and align with the semantics of Rust's Into
trait.
Key Changes
- Previously,
Into<Wad, Ray>
scaled the value by 10<sup>9</sup> whileInto<Ray, Wad>
scaled the value by 10<sup>-9</sup>. Both now perform direct type cast without value modification - Introduced
wad_to_ray()
andray_to_wad()
functions for value-preserving conversions
Recommended Usage
- Prefer
wad_to_ray()
andray_to_wad()
for most conversions betweenWad
andRay
. - Use the
Into
trait only when a simple type cast is required (expected to be rare).
Signed
The following functions are available for SignedWad
and SignedRay
via the Signed
trait:
is_negative()
: Returns true if the value is less than zerois_positive()
: Returns true if the value is greater than zero
Usage
To use this library, add the repository as a dependency in your Scarb.toml
:
[dependencies]
wadray = "0.5.0"
then add the following line in your .cairo
file
use wadray::Wad;
fn add_wad(a: Wad, b: Wad) -> Wad {
a + b
}
You can also refer to the test file src/test_wadray.cairo
for another example.
Development
Prerequisites
Run tests
To run the tests:
scarb test
Formal Verification
This library has been formally verified using our tool Aegis. Specifications and their correctness proof can be found in this repository, the verification currently refers to revision 30f7664 of this repo.
Contribute
We welcome contributions of any kind! Please feel free to submit an issue or open a PR if you have a solution to an existing bug.
License
This library is released under the MIT License.