units.ts 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /**
  2. * Most interactions with Ethereum requires integer values, which use
  3. * the smallest magnitude unit.
  4. *
  5. * For example, imagine dealing with dollars and cents. Since dollars
  6. * are divisible, non-integer values are possible, such as ``$10.77``.
  7. * By using the smallest indivisible unit (i.e. cents), the value can
  8. * be kept as the integer ``1077``.
  9. *
  10. * When receiving decimal input from the user (as a decimal string),
  11. * the value should be converted to an integer and when showing a user
  12. * a value, the integer value should be converted to a decimal string.
  13. *
  14. * This creates a clear distinction, between values to be used by code
  15. * (integers) and values used for display logic to users (decimals).
  16. *
  17. * The native unit in Ethereum, //ether// is divisible to 18 decimal places,
  18. * where each individual unit is called a //wei//.
  19. *
  20. * @_subsection api/utils:Unit Conversion [about-units]
  21. */
  22. import { assertArgument } from "./errors.js";
  23. import { FixedNumber } from "./fixednumber.js";
  24. import { getNumber } from "./maths.js";
  25. import type { BigNumberish, Numeric } from "../utils/index.js";
  26. const names = [
  27. "wei",
  28. "kwei",
  29. "mwei",
  30. "gwei",
  31. "szabo",
  32. "finney",
  33. "ether",
  34. ];
  35. /**
  36. * Converts %%value%% into a //decimal string//, assuming %%unit%% decimal
  37. * places. The %%unit%% may be the number of decimal places or the name of
  38. * a unit (e.g. ``"gwei"`` for 9 decimal places).
  39. *
  40. */
  41. export function formatUnits(value: BigNumberish, unit?: string | Numeric): string {
  42. let decimals = 18;
  43. if (typeof(unit) === "string") {
  44. const index = names.indexOf(unit);
  45. assertArgument(index >= 0, "invalid unit", "unit", unit);
  46. decimals = 3 * index;
  47. } else if (unit != null) {
  48. decimals = getNumber(unit, "unit");
  49. }
  50. return FixedNumber.fromValue(value, decimals, { decimals, width: 512 }).toString();
  51. }
  52. /**
  53. * Converts the //decimal string// %%value%% to a BigInt, assuming
  54. * %%unit%% decimal places. The %%unit%% may the number of decimal places
  55. * or the name of a unit (e.g. ``"gwei"`` for 9 decimal places).
  56. */
  57. export function parseUnits(value: string, unit?: string | Numeric): bigint {
  58. assertArgument(typeof(value) === "string", "value must be a string", "value", value);
  59. let decimals = 18;
  60. if (typeof(unit) === "string") {
  61. const index = names.indexOf(unit);
  62. assertArgument(index >= 0, "invalid unit", "unit", unit);
  63. decimals = 3 * index;
  64. } else if (unit != null) {
  65. decimals = getNumber(unit, "unit");
  66. }
  67. return FixedNumber.fromString(value, { decimals, width: 512 }).value;
  68. }
  69. /**
  70. * Converts %%value%% into a //decimal string// using 18 decimal places.
  71. */
  72. export function formatEther(wei: BigNumberish): string {
  73. return formatUnits(wei, 18);
  74. }
  75. /**
  76. * Converts the //decimal string// %%ether%% to a BigInt, using 18
  77. * decimal places.
  78. */
  79. export function parseEther(ether: string): bigint {
  80. return parseUnits(ether, 18);
  81. }