Cairo-math-64x61 - Fixed point 64.61 math library for Cairo / Starknet

Overview

Cairo Math 64x61

A fixed point 64.61 math library for Cairo & Starknet

Signed 64.61 Fixed Point Numbers

A signed 64.61-bit fixed point number is a fraction in which the numerator is a signed 125-bit integer and the denominator is 2^61. Since the denominator stays the same there is no need to store it (as in a floating point value).

64.61 is utilized as the 125 bit representation allows for overflow up to 2^125 * 2^125 (250 bits) during calculation taking advantage of Cairo's 251 bit felts.

Can represent values in the range of -2^64 to 2^64 with precision to 4.34e-19.

Standard Library

Math64x61 includes implementation of mul, div, sqrt, exp, ln, log2, log10, and pow as well as conversion and assertion methods.

Trigonometry Library

Trig64x61 includes implementation of sin, cos, tan and their inverses.

Hyperbolic Library

Hyp64x61 includes implementation of sinh, cosh, tanh, and their inverses.

Extensibility

This library strives to adhere to the OpenZeppelin extensibility pattern: https://github.com/OpenZeppelin/cairo-contracts/blob/main/docs/Extensibility.md

Comments
  • dev: add namespaces

    dev: add namespaces

    Hey,

    I was wondering if you'd accept a PR to introduce namespaces to your lib. Using a namespace is the current accepted best practice, it's much easier on the eyes and to work with from a developer experience perspective.

    See the changes to Math64x61Mock.cairo to get the feel for the difference.

    So far, this PR only has changes in the Math module, but if you're ok with it, I can update Hyp, Trig and Vec as well.

    opened by milancermak 2
  • Function to convert oracle prices

    Function to convert oracle prices

    This PR adds functions that help with using different oracles(https://www.stork.network/, https://empiric.network/, etc). These oracles return prices multiplied by 10**18 and converting these prices to the Math64x61 format can sometimes be quite tricky due to errors in overflow etc.

    Functions proposed here address this problem and can convert such prices to the desired Match64x61 format. Tests are provided as well.

    opened by Chepelau 1
  • OZ standards and PyPi update

    OZ standards and PyPi update

    • Updated to adhere to open zeppelin lib extensibility standards (breaking change, requires changing imports / method refs)
    • Switched from npm to pip module installation to better support cairo / python ecosystem
    • removed starknet language declarations to allow for usage in cairo projects (see #3)
    opened by clexmond 0
  • Rounding bug when using library

    Rounding bug when using library

    Hi, we have a precision bug when converting felts with the library and would like to get some help.

    We have a fee rate that we store globally and per account. The value of the fee rate is 0.0004 but before the value is sent to the contract function we add some quantum precision to it by doing (i.e 0.0004 * 10^8) and then send it as 40000. In the function where the fee rate is used, we remove this precision by doing a Math.to_decimal8(feeRate). All Math.to_decimal8(feeRate) does is remove the quantum precision before the fee rate is stored in storage.

    To further illustrate this, when we try to retrieve the fee rate stored, instead of getting 40000, the value returned is 39999. But it does not stop there. We also noticed that when the fee rate is a multiple of 5, the exact value is returned with no change in precision. Eg 0.0005 (or 50000) returns 50000. But any other value that is not a multiple of 5 loses precision.

    A code sample to demonstrate this is attached below.

    // SPDX-License-Identifier: Apache-2.0
    %lang starknet
    
    from cairo_math_64x61.math64x61 import Math64x61
    from starkware.cairo.common.bool import TRUE, FALSE
    from starkware.cairo.common.cairo_builtins import HashBuiltin
    
    struct FeeRate {
        exists: felt,
        maker: felt,
        taker: felt,
    }
    
    @storage_var
    func global_fee_rate() -> (feeRate: FeeRate) {
    }
    
    @storage_var
    func account_fee_rate(account: felt) -> (feeRate: FeeRate) {
    }
    
    namespace Math {
        const DOT8 = (10 ** 8) * Math64x61.FRACT_PART;
        func to_decimal8{range_check_ptr}(num: felt) -> felt {
           alloc_locals;
           // To fixed precision
           local _ans = Math64x61.fromFelt(num);
           // Remove quantum precision
           let ans = Math64x61.div(_ans, DOT8);
           return ans;
        }
    
        func to_felt8{range_check_ptr}(num: felt) -> felt {
            // Add quantum precision
            let _ans =  Math64x61.mul(num, DOT8);
            // Remove fixed precision
            let ans = Math64x61.toFelt(_ans);
            return ans;
        }
    }
    
    @external
    func convertAndSetGlobalFeeRate{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
        maker_fee: felt, taker_fee: felt
    ) {
        alloc_locals;
    
        let maker_fee_d = Math.to_decimal8(maker_fee);
        let taker_fee_d = Math.to_decimal8(taker_fee);
    
        let fee_rate_d = FeeRate(exists=1, maker=maker_fee_d, taker=taker_fee_d);
        global_fee_rate.write(fee_rate_d);
    
        return ();
    }
    
    @view
    func convertAndGetAccountFeeRate{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
        account: felt) -> (fee_rate: FeeRate) {
        alloc_locals;
        let (_account_fee_rate) = account_fee_rate.read(account);
    
        if (_account_fee_rate.exists != FALSE) {
            return (_account_fee_rate,);
        }
    
        // Return global fee rate if account fee rate is not set
        let (_global_fee_rate) = global_fee_rate.read();
        let maker_fee = Math.to_felt8(_global_fee_rate.maker);
        let taker_fee = Math.to_felt8(_global_fee_rate.taker);
    
        let fee_rate = FeeRate(
            exists=1,
            maker=maker_fee,
            taker=taker_fee,
        );
        return (fee_rate,);
    }
    
    

    Here's a test case that shows that converting the fee_rate to decimal_8 before storage and after retrieval

    import dataclasses
    import os
    
    import pytest
    from starkware.starknet.testing.starknet import Starknet
    from starkware.starkware_utils.error_handling import StarkException
    
    from .types import TokenAsset
    from .utils import str_to_felt, to_quantum
    
    FILE_DIR = os.path.dirname(__file__)
    CAIRO_PATH = [os.path.join(FILE_DIR, "../contracts")]
    ROUNDING_FILE = os.path.join(FILE_DIR, "../contracts/test/Rounding.cairo")
    ACCOUNT_ADDRESS = str_to_felt("ACCOUNT ADDRESS")
    
    @pytest.fixture()
    async def contracts():
        starknet = await Starknet.empty()
        rounding_contract = await starknet.deploy(
            source=ROUNDING_FILE, cairo_path=CAIRO_PATH, disable_hint_validation=True
        )
    
        return rounding_contract
    
    async def test_fee_rate_with_rounding(contracts):
        rounding_contract = contracts
        maker_fee_rate = to_quantum(0.0001)
        taker_fee_rate = to_quantum(0.0004)
        await rounding_contract.convertAndSetGlobalFeeRate(
            maker_fee_rate,
            taker_fee_rate
        ).execute()
    
        account_fee_rates = await rounding_contract.convertAndGetAccountFeeRate(ACCOUNT_ADDRESS).call()
        assert not (account_fee_rates.result.fee_rate.maker == maker_fee_rate)
        assert not (account_fee_rates.result.fee_rate.taker == taker_fee_rate)
    

    I will be happy to provide further information to help debug this issue. Thanks!

    opened by mayowaparadigm 0
  • A bug in the function`ceil`

    A bug in the function`ceil`

    If the input of the ceil function is an integer x(that is, x modulo FRACT_PART is equal to 0), it will return x+1. But I think this does not match the usual semantics of ceil function in mathematics.

    The bug is found by Medjai, a symbolic execution tool for the Cairo program. The spec we write for ceil is:

    func ceil_spec{range_check_ptr}():
        alloc_locals
        let (local x) = SymbolicMath64x61()
        let (local res) = Math64x61.ceil(x)
        verify_le_signed(x, res)
        verify_lt_signed(res - Math64x61.ONE, x)
        let (_, rem) = signed_div_rem(res, Math64x61.ONE, Math64x61.BOUND)
        medjai_assert_eq_felt(rem, 0)
        return ()
    end
    
    opened by DOFYPXY 0
  • toUint256() function should return the number without the floating part

    toUint256() function should return the number without the floating part

    Thanks to the great lib.

    I just have one remark. I expected the toUint256() function to return the number rounded as Uint256. For example: passing 12,3456 I expect to get 12 from toUint256() To get the right result I have to pass my 12,3456 into the toFelt() function and then the toUint256().

    Also we can add what type of rounding we want as param to the function.

    Best,

    opened by FabienCoutant 0
  • Function for converting oracles

    Function for converting oracles

    Starknet oracles (Empiric network, Stork etc.) provide prices of assets multiplied by 10^18. This can present a challenge when we want to end with price multiplied by 2**61 instead, due to overflow etc. For this reason, I'd like to add a function that manages to convert such prices to the Math64x61 format. Tested to 5e-15 precision.

    opened by Chepelau 0
  • Add 'unsafe' versions of each function

    Add 'unsafe' versions of each function

    Math64x61_assert64x61 is expensive! I was able to reduce the step count of a function by close to 60% just by getting rid of that assert where it wasn't necessary (meaning the fixed-point operations were guaranteed to not overflow).

    Of course these should be used very carefully, but I think they'd be a useful addition.

    opened by bllu404 0
Releases(v2.1.0)
Owner
Influence
A grand strategy game set in an asteroid belt and built on Ethereum.
Influence
Odoo. Open Source Apps To Grow Your Business.

Odoo Odoo is a suite of web based open source business apps. The main Odoo Apps include an Open Source CRM, Website Builder, eCommerce, Warehouse Mana

Odoo 27.6k Jan 09, 2023
Why write code when you can import it directly from GitHub Copilot?

Copilot Importer Why write code when you can import it directly from GitHub Copilot? What is Copilot Importer? The copilot python module will dynamica

Mythic 41 Jan 04, 2023
Package to provide translation methods for pyramid, and means to reload translations without stopping the application

Package to provide translation methods for pyramid, and means to reload translations without stopping the application

Grzegorz Śliwiński 4 Nov 20, 2022
github action test, because I dont know it.

mad-y testing testing pip install -r requirements.txt add the DISCORD_TOKEN value to your env vars. and run mad-y how to Deploy ` docker build -t mad-

Mit 1 Oct 29, 2021
NFT generator for Solana!

Solseum NFT Generator for Solana! Check this guide here! Creating your randomized uniques NFTs, getting rarity information and displaying it on a webp

Solseum™ VR NFTs 145 Dec 30, 2022
Nextstrain build targeted to Omicron

About This repository analyzes viral genomes using Nextstrain to understand how SARS-CoV-2, the virus that is responsible for the COVID-19 pandemic, e

Bedford Lab 9 May 25, 2022
Install packages with pip as if you were in the past!

A PyPI time machine Do you wish you could just install packages with pip as if you were at some fixed date in the past? If so, the PyPI time machine i

Thomas Robitaille 51 Jan 09, 2023
Library for Memory Trace Statistics in Python

Memory Search Library for Memory Trace Statistics in Python The library uses tracemalloc as a core module, which is why it is only available for Pytho

Memory Search 1 Dec 20, 2021
A simple projects to help your seo optimizing has been written with python

python-seo-projects it is a very simple projects to help your seo optimizing has been written with python broken link checker with python(it will give

Amirmohammad Razmy 3 Dec 25, 2021
Gerador de dafaces

🎴 DefaceGenerator Obs: esse script foi criado com a intenção de ajudar pessoas iniciantes no hacking que ainda não conseguem criar suas próprias defa

LordShinigami 3 Jan 09, 2022
PyLaboratory 0 Feb 07, 2022
A simple weather app.

keather A simple weather app. This is currently not finished. Dependencies: yay -S python-beautifulsoup4 tk

1 Jan 09, 2022
Script to produce `.tex` files of example GAP sessions

Introduction The main file GapToTex.py in this directory is used to produce .tex files of example GAP sessions. Instructions Run python GapToTex.py [G

Friedrich Rober 2 Oct 06, 2022
Tutorial on Tempo, Beat and Downbeat estimation

Tempo, Beat and Downbeat Estimation By Matthew E. P. Davies, Sebastian Böck and Magdalena Fuentes Resources and Jupyter Book for the ISMIR 2021 tutori

49 Nov 06, 2022
Insert a Spotify Playlist, Get a list of YouTube URLs from it.

spotbee This is a module that spits out YouTube URLs from Spotify Playlist URLs Why use this? It is asynchronous which makes it compatible to use with

Nishant Sapkota 10 Apr 06, 2022
This module extends twarc to allow you to print out tweets as text for easy testing on the command line

twarc-text This module extends twarc to allow you to print out tweets as text for easy testing on the command line. Maybe it's useful for spot checkin

Documenting the Now 2 Oct 12, 2021
Minutaria is a basic educational Python timer used to learn python and software testing libraries.

minutaria minutaria is a basic educational Python timer. The project is educational, it aims to teach myself programming, python programming, python's

1 Jul 16, 2021
Custom SLURM wrapper scripts to make finding job histories and system resource usage more easily accessible

SLURM Wrappers Executables job-history A simple wrapper for grabbing data for completed and running jobs. nodes-busy Developed for the HPC systems at

Sara 2 Dec 13, 2021
JurjenLang, an interpreted programming language

JurjenLang An interpreted programming language Getting started Follow these three steps on your computer to get started git clone https://github.com/J

JVerbruggen 5 May 03, 2022
Paimon is a pixie (or script) who was made for anyone from {EPITECH} who are struggling with the Coding Style.

Paimon Paimon is a pixie (or script) who was made for anyone from {EPITECH} who are struggling with the Coding Style. Her goal is to assist you in you

Lyy 2 Oct 17, 2021