#currency #money #cryptocurrency #dollar

no-std currencies

Allows for generic manipulation of currencies (both real-world and cryptocurrencies) with optionally compile-time enforced checked math and support for all ISO-4217 currencies

11 releases (4 breaking)

0.4.1 Jun 21, 2024
0.4.0 Jun 5, 2024
0.3.2 Apr 4, 2024
0.2.0 Mar 26, 2024
0.0.1 Aug 13, 2023

#3 in #dollar

Download history 78/week @ 2024-07-19 81/week @ 2024-07-26 226/week @ 2024-08-02 78/week @ 2024-08-09 276/week @ 2024-08-16 217/week @ 2024-08-23 52/week @ 2024-08-30 18/week @ 2024-09-06 92/week @ 2024-09-13 139/week @ 2024-09-20 123/week @ 2024-09-27 69/week @ 2024-10-04 129/week @ 2024-10-11 134/week @ 2024-10-18 133/week @ 2024-10-25 83/week @ 2024-11-01

487 downloads per month

MIT license

74KB
1.5K SLoC

💰 currencies

Crates.io docs.rs Build Status MIT License

This crate provides a generic Currency and corresponding Amount type that can handle basic arithmetic operations and formatting of arbitrary currencies and cryptocurrencies. Main features include:

Features

  • Built-in support for all ISO-4217 currencies with proper precision and formatting
  • Support for a variety of cryptocurrencies, also with proper underlying data types and formatting. Accurate implementations for ETH, BTC, DOT, and a variety of other cryptocurrencies are included.
  • The ability to specify whether an Amount is forced to only make use of unchecked math, or not, at compile-time. Normally this is impossible to control since the core:ops operators are set up such that the checked operators require their unchecked counterparts to be implemented on the host type, however I have gone out of my way to make it possible to implement unchecked math only, and control it easily with a Amount<ETH, Checked>-style switch. This is extremely desirable for scenarios where panicking could cause a catastrophic issue, and the way it is set up, programmers are forced to consume the Option returned by the checked ops.
  • An easy-to-use macro, define_currency! that can define new currencies on-the-fly.
  • A painstakingly wrapped version of primitive_types::U256 that implements many more useful num-traits and num-integer traits than what Parity includes with the num-traits feature, and are often required when working with amounts of a currency.
  • All provided currencies implement most useful num-traits and num-integer traits.
  • Thorough testing of all of the above.

Examples

#[test]
fn show_off_currency_math() {
    use currency::*;

    let apple_cost = amt!(USD, "$3.24");
    let orange_cost = Amount::<USD>::from_raw(7_97);
    assert!(apple_cost < orange_cost);
    assert!(apple_cost + orange_cost > orange_cost);
    assert_eq!(format!("{}", apple_cost * orange_cost), "$25.82");
    assert_eq!(format!("{}", apple_cost * 3), "$9.72");

    let mut total = amt!(DOT, "57622449841.0000000004 DOT");
    total -= amt!(DOT, "1000.0 DOT");
    total *= Amount::from_raw(2_0000000000u64.into());
    assert_eq!(format!("{}", total), "115244897682.0000000008 DOT");
}

#[test]
fn show_off_checked_math() {
    use currency::*;
    use safety::*;

    // When using currency amounts with `Safety = Checked`, the Amount struct has been specially set
    // up so that only checked math will be allowed, and you can still use the normal
    // operator-based syntax. Thus currency amounts like this should never panic and are
    // suitable for use in critical/infallible environments.
    let drink_cost = amt_checked!(USD, "$6.29");
    let movie_cost = Amount::<USD, Checked>::from_raw(24_99);
    let Some(outing_cost) = drink_cost + movie_cost else {
      unimplemented!("compiler forces you to handle this!")
    };
    assert_eq!(format!("{}", outing_cost), "$31.28");
}

Future Work

  • Additional macros for defining an Amount via a decimal literal
  • Currency conversion facilities, possibly including an online data source
  • Add Signedness support to Amount
  • Additional testing
  • Support for negative amounts via an additional const generic defaulting to Positive

Dependencies

~3.5–5MB
~95K SLoC