taler_amount_lib.h (20744B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014, 2015, 2020 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file include/taler/taler_amount_lib.h 18 * @brief amount-representation utility functions 19 * @author Sree Harsha Totakura <sreeharsha@totakura.in> 20 */ 21 #if ! defined (__TALER_UTIL_LIB_H_INSIDE__) 22 #error "Only <taler_util.h> can be included directly." 23 #endif 24 25 #ifndef TALER_AMOUNT_LIB_H 26 #define TALER_AMOUNT_LIB_H 27 28 #include <stdint.h> 29 #include <gnunet/gnunet_common.h> 30 31 #ifdef __cplusplus 32 extern "C" 33 { 34 #if 0 /* keep Emacsens' auto-indent happy */ 35 } 36 #endif 37 #endif 38 39 40 /** 41 * @brief Number of characters (plus 1 for 0-termination) we use to 42 * represent currency names (i.e. EUR, USD, etc.). We use 8+4 for 43 * alignment in the `struct TALER_Amount`. The amount is typically an 44 * ISO 4217 currency code when an alphanumeric 3-digit code is used. 45 * For regional currencies, the first character should be a "*" followed 46 * by a region-specific name (i.e. "*BRETAGNEFR"). 47 */ 48 #define TALER_CURRENCY_LEN 12 49 50 /** 51 * Taler currency length as a string. 52 */ 53 #define TALER_CURRENCY_LEN_STR "12" 54 55 /** 56 * @brief The "fraction" value in a `struct TALER_Amount` represents which 57 * fraction of the "main" value? 58 * 59 * Note that we need sub-cent precision here as transaction fees might 60 * be that low, and as we want to support microdonations. 61 * 62 * An actual `struct Amount a` thus represents 63 * "a.value + (a.fraction / #TALER_AMOUNT_FRAC_BASE)" units of "a.currency". 64 */ 65 #define TALER_AMOUNT_FRAC_BASE 100000000 66 67 /** 68 * @brief How many digits behind the comma are required to represent the 69 * fractional value in human readable decimal format? Must match 70 * lg(#TALER_AMOUNT_FRAC_BASE). 71 */ 72 #define TALER_AMOUNT_FRAC_LEN 8 73 74 /** 75 * Maximum legal 'value' for an amount, based on IEEE double (for JavaScript compatibility). 76 */ 77 #define TALER_AMOUNT_MAX_VALUE (1LLU << 52) 78 79 80 GNUNET_NETWORK_STRUCT_BEGIN 81 82 83 /** 84 * @brief Amount, encoded for network transmission. 85 */ 86 struct TALER_AmountNBO 87 { 88 /** 89 * Value in the main currency, in NBO. 90 */ 91 uint64_t value GNUNET_PACKED; 92 93 /** 94 * Fraction (integer multiples of #TALER_AMOUNT_FRAC_BASE), in NBO. 95 */ 96 uint32_t fraction GNUNET_PACKED; 97 98 /** 99 * Type of the currency being represented. 100 */ 101 char currency[TALER_CURRENCY_LEN]; 102 }; 103 104 GNUNET_NETWORK_STRUCT_END 105 106 107 /** 108 * @brief Representation of monetary value in a given currency. 109 */ 110 struct TALER_Amount 111 { 112 /** 113 * Value (numerator of fraction) 114 */ 115 uint64_t value; 116 117 /** 118 * Fraction (integer multiples of #TALER_AMOUNT_FRAC_BASE). 119 */ 120 uint32_t fraction; 121 122 /** 123 * Currency string, left adjusted and padded with zeros. All zeros 124 * for "invalid" values. 125 */ 126 char currency[TALER_CURRENCY_LEN]; 127 }; 128 129 130 /** 131 * Check that the currency code in @a str is well-formed. 132 * 133 * @param str currency code name to validate 134 * @return #GNUNET_OK if @a str is a valid currency code 135 */ 136 enum GNUNET_GenericReturnValue 137 TALER_check_currency (const char *str); 138 139 140 /** 141 * Parse monetary amount, in the format "T:V.F". 142 * 143 * @param str amount string 144 * @param[out] amount amount to write the result to 145 * @return #GNUNET_OK if the string is a valid monetary amount specification, 146 * #GNUNET_SYSERR if it is invalid. 147 */ 148 enum GNUNET_GenericReturnValue 149 TALER_string_to_amount (const char *str, 150 struct TALER_Amount *amount); 151 152 153 /** 154 * Parse monetary amount, in the format "T:V.F". 155 * The result is stored in network byte order (NBO). 156 * 157 * @param str amount string 158 * @param[out] amount_nbo amount to write the result to 159 * @return #GNUNET_OK if the string is a valid amount specification, 160 * #GNUNET_SYSERR if it is invalid. 161 */ 162 enum GNUNET_GenericReturnValue 163 TALER_string_to_amount_nbo (const char *str, 164 struct TALER_AmountNBO *amount_nbo); 165 166 167 /** 168 * Get the value of "zero" in a particular currency. 169 * 170 * @param cur currency description 171 * @param[out] amount amount to write the result to 172 * @return #GNUNET_OK if @a cur is a valid currency specification, 173 * #GNUNET_SYSERR if it is invalid. 174 */ 175 enum GNUNET_GenericReturnValue 176 TALER_amount_set_zero (const char *cur, 177 struct TALER_Amount *amount); 178 179 180 /** 181 * Test if the given @a amount is zero. 182 * 183 * @param amount amount to compare to zero 184 * @return true if the amount is zero, 185 * false if it is non-zero or invalid 186 */ 187 bool 188 TALER_amount_is_zero (const struct TALER_Amount *amount); 189 190 191 /** 192 * Test if the given amount is valid. 193 * 194 * @param amount amount to check 195 * @return #GNUNET_OK if @a amount is valid 196 */ 197 enum GNUNET_GenericReturnValue 198 TALER_amount_is_valid (const struct TALER_Amount *amount); 199 200 201 /** 202 * Test if the given amount is in the given currency 203 * 204 * @param amount amount to check 205 * @param currency currency to check for 206 * @return #GNUNET_OK if @a amount is in @a currency 207 */ 208 enum GNUNET_GenericReturnValue 209 TALER_amount_is_currency (const struct TALER_Amount *amount, 210 const char *currency); 211 212 213 /** 214 * Convert amount from host to network representation. 215 * 216 * @param[out] res where to store amount in network representation 217 * @param d amount in host representation 218 */ 219 void 220 TALER_amount_hton (struct TALER_AmountNBO *res, 221 const struct TALER_Amount *d); 222 223 224 /** 225 * Convert amount from network to host representation. 226 * 227 * @param[out] res where to store amount in host representation 228 * @param dn amount in network representation 229 */ 230 void 231 TALER_amount_ntoh (struct TALER_Amount *res, 232 const struct TALER_AmountNBO *dn); 233 234 235 /** 236 * Compare the value/fraction of two amounts. Does not compare the currency. 237 * Comparing amounts of different currencies will cause the program to abort(). 238 * If unsure, check with #TALER_amount_cmp_currency() first to be sure that 239 * the currencies of the two amounts are identical. 240 * 241 * @param a1 first amount 242 * @param a2 second amount 243 * @return result of the comparison 244 * -1 if `a1 < a2` 245 * 1 if `a1 > a2` 246 * 0 if `a1 == a2`. 247 */ 248 int 249 TALER_amount_cmp (const struct TALER_Amount *a1, 250 const struct TALER_Amount *a2); 251 252 253 /** 254 * Compute maximum of two amounts. 255 * 256 * @param[out] ma set to maximum of @a a1 and @a a2 257 * @param a1 first amount 258 * @param a2 second amount 259 * @return #GNUNET_OK on success 260 */ 261 enum GNUNET_GenericReturnValue 262 TALER_amount_max (struct TALER_Amount *ma, 263 const struct TALER_Amount *a1, 264 const struct TALER_Amount *a2); 265 266 267 /** 268 * Compute minimum of two amounts. 269 * 270 * @param[out] mi set to minimum of @a a1 and @a a2 271 * @param a1 first amount 272 * @param a2 second amount 273 * @return #GNUNET_OK on success 274 */ 275 enum GNUNET_GenericReturnValue 276 TALER_amount_min (struct TALER_Amount *mi, 277 const struct TALER_Amount *a1, 278 const struct TALER_Amount *a2); 279 280 281 /** 282 * Compare the value/fraction of two amounts. Does not compare the currency. 283 * Comparing amounts of different currencies will cause the program to abort(). 284 * If unsure, check with #TALER_amount_cmp_currency() first to be sure that 285 * the currencies of the two amounts are identical. NBO variant. 286 * 287 * @param a1 first amount 288 * @param a2 second amount 289 * @return result of the comparison 290 * -1 if `a1 < a2` 291 * 1 if `a1 > a2` 292 * 0 if `a1 == a2`. 293 */ 294 int 295 TALER_amount_cmp_nbo (const struct TALER_AmountNBO *a1, 296 const struct TALER_AmountNBO *a2); 297 298 299 /** 300 * Test if @a a1 and @a a2 are the same currency. 301 * 302 * @param a1 amount to test 303 * @param a2 amount to test 304 * @return #GNUNET_YES if @a a1 and @a a2 are the same currency 305 * #GNUNET_NO if the currencies are different 306 * #GNUNET_SYSERR if either amount is invalid 307 */ 308 enum GNUNET_GenericReturnValue 309 TALER_amount_cmp_currency (const struct TALER_Amount *a1, 310 const struct TALER_Amount *a2); 311 312 313 /** 314 * Test if @a a1 and @a a2 are the same currency, NBO variant. 315 * 316 * @param a1 amount to test 317 * @param a2 amount to test 318 * @return #GNUNET_YES if @a a1 and @a a2 are the same currency 319 * #GNUNET_NO if the currencies are different 320 * #GNUNET_SYSERR if either amount is invalid 321 */ 322 enum GNUNET_GenericReturnValue 323 TALER_amount_cmp_currency_nbo (const struct TALER_AmountNBO *a1, 324 const struct TALER_AmountNBO *a2); 325 326 327 /** 328 * Possible results from calling #TALER_amount_subtract() and 329 * possibly other arithmetic operations. Negative values 330 * indicate that the operation did not generate a result. 331 */ 332 enum TALER_AmountArithmeticResult 333 { 334 335 /** 336 * Operation succeeded, result is positive. 337 */ 338 TALER_AAR_RESULT_POSITIVE = 1, 339 340 /** 341 * Operation succeeded, result is exactly zero. 342 */ 343 TALER_AAR_RESULT_ZERO = 0, 344 345 /** 346 * Operation failed, the result would have been negative. 347 */ 348 TALER_AAR_INVALID_NEGATIVE_RESULT = -1, 349 350 /** 351 * Operation failed, result outside of the representable range. 352 */ 353 TALER_AAR_INVALID_RESULT_OVERFLOW = -2, 354 355 /** 356 * Operation failed, inputs could not be normalized. 357 */ 358 TALER_AAR_INVALID_NORMALIZATION_FAILED = -3, 359 360 /** 361 * Operation failed, input currencies were not identical. 362 */ 363 TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE = -4 364 365 }; 366 367 /** 368 * Perform saturating subtraction of amounts. 369 * 370 * @param[out] diff where to store (@a a1 - @a a2), or invalid if @a a2 > @a a1 371 * @param a1 amount to subtract from 372 * @param a2 amount to subtract 373 * @return operation status, negative on failures 374 */ 375 enum TALER_AmountArithmeticResult 376 TALER_amount_subtract (struct TALER_Amount *diff, 377 const struct TALER_Amount *a1, 378 const struct TALER_Amount *a2); 379 380 381 /** 382 * Perform addition of amounts. 383 * 384 * @param[out] sum where to store @a a1 + @a a2, set to "invalid" on overflow 385 * @param a1 first amount to add 386 * @param a2 second amount to add 387 * @return operation status, negative on failures 388 */ 389 enum TALER_AmountArithmeticResult 390 TALER_amount_add (struct TALER_Amount *sum, 391 const struct TALER_Amount *a1, 392 const struct TALER_Amount *a2); 393 394 395 /** 396 * Divide an amount by a @ divisor. Note that this function 397 * may introduce a rounding error! 398 * 399 * @param[out] result where to store @a dividend / @a divisor 400 * @param dividend amount to divide 401 * @param divisor by what to divide, must be positive 402 */ 403 void 404 TALER_amount_divide (struct TALER_Amount *result, 405 const struct TALER_Amount *dividend, 406 uint32_t divisor); 407 408 /** 409 * Divide one amount by another. Note that this function 410 * may introduce a rounding error. It rounds down. 411 * 412 * @param dividend amount to divide 413 * @param divisor by what to divide, must be positive 414 * @return @a dividend / @a divisor, rounded down. -1 on currency mismatch, 415 * INT_MAX for division by zero 416 */ 417 int 418 TALER_amount_divide2 (const struct TALER_Amount *dividend, 419 const struct TALER_Amount *divisor); 420 421 422 /** 423 * Multiply an @a amount by a @ factor. 424 * 425 * @param[out] result where to store @a amount * @a factor 426 * @param amount amount to multiply 427 * @param factor factor by which to multiply 428 */ 429 enum TALER_AmountArithmeticResult 430 TALER_amount_multiply (struct TALER_Amount *result, 431 const struct TALER_Amount *amount, 432 uint32_t factor); 433 434 435 /** 436 * Normalize the given amount. 437 * 438 * @param[in,out] amount amount to normalize 439 * @return #GNUNET_OK if normalization worked 440 * #GNUNET_NO if value was already normalized 441 * #GNUNET_SYSERR if value was invalid or could not be normalized 442 */ 443 enum GNUNET_GenericReturnValue 444 TALER_amount_normalize (struct TALER_Amount *amount); 445 446 447 /** 448 * Convert amount to string. 449 * 450 * @param amount amount to convert to string 451 * @return freshly allocated string representation, 452 * NULL if the @a amount was invalid 453 */ 454 char * 455 TALER_amount_to_string (const struct TALER_Amount *amount); 456 457 458 /** 459 * Convert amount to string. 460 * 461 * @param amount amount to convert to string 462 * @return statically allocated buffer with string representation, 463 * NULL if the @a amount was invalid 464 */ 465 const char * 466 TALER_amount2s (const struct TALER_Amount *amount); 467 468 469 /** 470 * Round the amount to something that can be transferred on the wire. 471 * The rounding mode is specified via the smallest transferable unit, 472 * which must only have a fractional part *or* only a value (either 473 * of the two must be zero!). 474 * 475 * @param[in,out] amount amount to round down 476 * @param[in] round_unit unit that should be rounded down to, and 477 * either value part or the faction must be zero (but not both) 478 * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary, 479 * #GNUNET_SYSERR if the amount or currency or @a round_unit was invalid 480 */ 481 enum GNUNET_GenericReturnValue 482 TALER_amount_round_down (struct TALER_Amount *amount, 483 const struct TALER_Amount *round_unit); 484 485 486 /** 487 * Represents a set of amounts in different currencies. 488 * Useful when adding up various amounts in different 489 * currencies. 490 */ 491 struct TALER_AmountSet 492 { 493 /** 494 * Array of amounts. Each currency should have at most one entry. 495 */ 496 struct TALER_Amount *taa; 497 498 /** 499 * Length of the @e taa array. 500 */ 501 unsigned int taa_size; 502 503 }; 504 505 506 /** 507 * Free memory allocated within @a as, but not @a as itself. 508 * Effectively sets the total amount in @a as also back to zero. 509 * 510 * @param[in,out] as set to free (turned into an empty set) 511 */ 512 void 513 TALER_amount_set_free (struct TALER_AmountSet *as); 514 515 516 /** 517 * Add amount @a a to the total amount represented by @a as. 518 * 519 * @param[in,out] as set of amounts to update by adding @a a 520 * @param val amount to add 521 * @param cap cap for the sums to enforce, can be NULL; 522 * if given, then #TALER_AAR_INVALID_RESULT_OVERFLOW is impossible 523 * as we will use @a cap as a maximum value for this currency 524 * @return operation status, negative on failures; 525 * #TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE is impossible, 526 * except if @a cap does not match @a val 527 */ 528 enum TALER_AmountArithmeticResult 529 TALER_amount_set_add (struct TALER_AmountSet *as, 530 const struct TALER_Amount *val, 531 const struct TALER_Amount *cap); 532 533 534 /** 535 * Test if the amount @a b is available in @a as, that is if 536 * the total amount added to @a as in the currency of @a b 537 * is not below @a b. In other words, returns true if 538 * the available amount in @a as would suffice to pay for @a b. 539 * 540 * @param as set to compare 541 * @param b amount to check if it falls into the range 542 * @return true if b <= as(b.currency) 543 */ 544 bool 545 TALER_amount_set_test_above (const struct TALER_AmountSet *as, 546 const struct TALER_Amount *b); 547 548 549 /** 550 * Find amount by @a currency in @a as. If @a as is not 551 * found, an amount of zero is returned in @a currency. 552 * This function is not reentrant, repeated calls may 553 * overwrite previously returned results. 554 * 555 * @param currency currency to search for 556 * @param as set to search 557 * @return NULL if @a currency is not a valid currency string 558 */ 559 const struct TALER_Amount * 560 TALER_amount_set_find (const char *currency, 561 const struct TALER_AmountSet *as); 562 563 564 /** 565 * A list of amounts in distinct currencies, all denoting the 566 * same thing priced differently --- a price list. 567 * 568 * Do not confuse this with a `struct TALER_AmountSet`, which has the 569 * same memory layout but the opposite invariants: a set is an 570 * accumulator, a list is a price list. In particular, a currency 571 * that is absent from a list is *not offered*, which is distinct 572 * from being offered at zero, and #TALER_amount_list_find() thus 573 * returns NULL for it instead of synthesizing a zero amount. 574 * 575 * Each currency occurs at most once. The order is significant: 576 * the first entry is the primary currency. 577 */ 578 struct TALER_AmountList 579 { 580 /** 581 * Array of amounts, at most one per currency. 582 */ 583 struct TALER_Amount *tal; 584 585 /** 586 * Length of the @e tal array. 587 */ 588 unsigned int tal_len; 589 590 }; 591 592 593 /** 594 * Free memory allocated within @a al, but not @a al itself. 595 * 596 * @param[in,out] al list to free (turned into an empty list) 597 */ 598 void 599 TALER_amount_list_free (struct TALER_AmountList *al); 600 601 602 /** 603 * Parse a price list of the form "EUR:1.1;CHF:1;USD:2". 604 * 605 * Fails if any component is empty or not a valid amount, or if a 606 * currency is given more than once. The empty string parses into 607 * the empty list, which is the canonical way to say "free". 608 * 609 * @param str string to parse 610 * @param[out] al list to initialize, only modified on success; 611 * the caller must eventually free it using 612 * #TALER_amount_list_free() 613 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure 614 */ 615 enum GNUNET_GenericReturnValue 616 TALER_string_to_amount_list (const char *str, 617 struct TALER_AmountList *al); 618 619 620 /** 621 * Convert the price list @a al to a string, the inverse of 622 * #TALER_string_to_amount_list(). This function is not reentrant, 623 * repeated calls may overwrite previously returned results. 624 * 625 * @param al list to convert 626 * @return statically allocated buffer with the string representation, 627 * NULL if any amount in @a al was invalid 628 */ 629 const char * 630 TALER_amount_list2s (const struct TALER_AmountList *al); 631 632 633 /** 634 * Find the price in @a currency in the price list @a al. 635 * 636 * Deliberately unlike #TALER_amount_set_find(), a currency that 637 * @a al does not offer yields NULL and not a zero amount: for a 638 * price list, "not offered" and "free" are different answers, and 639 * confusing them would make an unpriced currency look free. 640 * 641 * @param al list to search 642 * @param currency currency to search for 643 * @return NULL if @a al does not offer @a currency 644 */ 645 const struct TALER_Amount * 646 TALER_amount_list_find (const struct TALER_AmountList *al, 647 const char *currency); 648 649 650 /** 651 * Check that @a al prices uniformly, that is that it does not 652 * offer the same thing for free in one currency and for money in 653 * another. 654 * 655 * @param al list to check 656 * @return #GNUNET_OK if every entry is non-zero (a real price), 657 * #GNUNET_NO if every entry is zero or @a al is empty (free), 658 * #GNUNET_SYSERR if some entries are zero and others are not 659 */ 660 enum GNUNET_GenericReturnValue 661 TALER_amount_list_check_uniform (const struct TALER_AmountList *al); 662 663 664 /** 665 * Check that @a al prices in exactly the @a currencies_len 666 * currencies given in @a currencies, no more and no fewer. 667 * 668 * @param al list to check 669 * @param currencies array of currency names that must be covered 670 * @param currencies_len length of the @a currencies array 671 * @return true if @a al holds exactly one entry per currency 672 * in @a currencies and no others 673 */ 674 bool 675 TALER_amount_list_covers (const struct TALER_AmountList *al, 676 const char *const *currencies, 677 unsigned int currencies_len); 678 679 680 /** 681 * Multiply every price in @a al by @a n, for example to turn a 682 * per-year price into the price of @a n years. 683 * 684 * Either all currencies are updated or none is: an overflow in any 685 * one of them fails the entire call and leaves @a al untouched. 686 * 687 * @param[in,out] al list to multiply in place 688 * @param n factor to multiply by, must not be zero (zero would turn 689 * a priced list into a free one, which is never intended) 690 * @return #GNUNET_OK on success, 691 * #GNUNET_SYSERR on overflow or if @a n is zero 692 */ 693 enum GNUNET_GenericReturnValue 694 TALER_amount_list_multiply (struct TALER_AmountList *al, 695 uint32_t n); 696 697 698 /** 699 * Make a deep copy of the price list @a src. 700 * 701 * @param[out] dst list to initialize, must not hold anything yet; 702 * the caller must eventually free it using 703 * #TALER_amount_list_free() 704 * @param src list to copy 705 */ 706 void 707 TALER_amount_list_copy (struct TALER_AmountList *dst, 708 const struct TALER_AmountList *src); 709 710 711 #if 0 /* keep Emacsens' auto-indent happy */ 712 { 713 #endif 714 #ifdef __cplusplus 715 } 716 #endif 717 718 719 #endif