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