currency.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import decimal
  2. from decimal import (
  3. localcontext,
  4. )
  5. from typing import (
  6. Union,
  7. )
  8. from .types import (
  9. is_integer,
  10. is_string,
  11. )
  12. from .units import (
  13. units,
  14. )
  15. class denoms:
  16. wei = int(units["wei"])
  17. kwei = int(units["kwei"])
  18. babbage = int(units["babbage"])
  19. femtoether = int(units["femtoether"])
  20. mwei = int(units["mwei"])
  21. lovelace = int(units["lovelace"])
  22. picoether = int(units["picoether"])
  23. gwei = int(units["gwei"])
  24. shannon = int(units["shannon"])
  25. nanoether = int(units["nanoether"])
  26. nano = int(units["nano"])
  27. szabo = int(units["szabo"])
  28. microether = int(units["microether"])
  29. micro = int(units["micro"])
  30. finney = int(units["finney"])
  31. milliether = int(units["milliether"])
  32. milli = int(units["milli"])
  33. ether = int(units["ether"])
  34. kether = int(units["kether"])
  35. grand = int(units["grand"])
  36. mether = int(units["mether"])
  37. gether = int(units["gether"])
  38. tether = int(units["tether"])
  39. MIN_WEI = 0
  40. MAX_WEI = 2**256 - 1
  41. _NumberType = Union[int, float, str, decimal.Decimal]
  42. def _from_wei(number: int, unit_value: decimal.Decimal) -> Union[int, decimal.Decimal]:
  43. if number == 0:
  44. return 0
  45. if number < MIN_WEI or number > MAX_WEI:
  46. raise ValueError("value must be between 0 and 2**256 - 1")
  47. with localcontext() as ctx:
  48. ctx.prec = 999
  49. d_number = decimal.Decimal(value=number, context=ctx)
  50. result_value = d_number / unit_value
  51. return result_value
  52. def _to_wei(number: _NumberType, unit_value: decimal.Decimal) -> int:
  53. if is_integer(number) or is_string(number):
  54. d_number = decimal.Decimal(value=number)
  55. elif isinstance(number, float):
  56. d_number = decimal.Decimal(value=str(number))
  57. elif isinstance(number, decimal.Decimal):
  58. d_number = number
  59. else:
  60. raise TypeError("Unsupported type. Must be one of integer, float, or string")
  61. if d_number == decimal.Decimal(0):
  62. return 0
  63. s_number = str(number)
  64. if d_number < 1 and "." in s_number:
  65. with localcontext() as ctx:
  66. multiplier = len(s_number) - s_number.index(".") - 1
  67. ctx.prec = multiplier
  68. d_number = decimal.Decimal(value=number, context=ctx) * 10**multiplier
  69. unit_value /= 10**multiplier
  70. with localcontext() as ctx:
  71. ctx.prec = 999
  72. result_value = decimal.Decimal(value=d_number, context=ctx) * unit_value
  73. if result_value < MIN_WEI or result_value > MAX_WEI:
  74. raise ValueError("Resulting wei value must be between 0 and 2**256 - 1")
  75. return int(result_value)
  76. def from_wei(number: int, unit: str) -> Union[int, decimal.Decimal]:
  77. """
  78. Takes a number of wei and converts it to any other ether unit.
  79. """
  80. if unit.lower() not in units:
  81. raise ValueError(f"Unknown unit. Must be one of {'/'.join(units.keys())}")
  82. unit_value = units[unit.lower()]
  83. return _from_wei(number, unit_value)
  84. def to_wei(number: _NumberType, unit: str) -> int:
  85. """
  86. Takes a number of a unit and converts it to wei.
  87. """
  88. if unit.lower() not in units:
  89. raise ValueError(f"Unknown unit. Must be one of {'/'.join(units.keys())}")
  90. unit_value = units[unit.lower()]
  91. return _to_wei(number, unit_value)
  92. def from_wei_decimals(number: int, decimals: int) -> Union[int, decimal.Decimal]:
  93. """
  94. Takes a number of wei and converts it to a decimal with the specified
  95. number of decimals.
  96. """
  97. unit_value = decimal.Decimal(10) ** decimal.Decimal(value=decimals)
  98. return _from_wei(number, unit_value)
  99. def to_wei_decimals(number: _NumberType, decimals: int) -> int:
  100. """
  101. Takes a number of a unit and converts it to wei with the specified
  102. number of decimals.
  103. """
  104. unit_value = decimal.Decimal(10) ** decimal.Decimal(value=decimals)
  105. return _to_wei(number, unit_value)