maths.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.toQuantity = exports.toBeArray = exports.toBeHex = exports.toNumber = exports.getNumber = exports.toBigInt = exports.getUint = exports.getBigInt = exports.mask = exports.toTwos = exports.fromTwos = void 0;
  4. /**
  5. * Some mathematic operations.
  6. *
  7. * @_subsection: api/utils:Math Helpers [about-maths]
  8. */
  9. const data_js_1 = require("./data.js");
  10. const errors_js_1 = require("./errors.js");
  11. const BN_0 = BigInt(0);
  12. const BN_1 = BigInt(1);
  13. //const BN_Max256 = (BN_1 << BigInt(256)) - BN_1;
  14. // IEEE 754 support 53-bits of mantissa
  15. const maxValue = 0x1fffffffffffff;
  16. /**
  17. * Convert %%value%% from a twos-compliment representation of %%width%%
  18. * bits to its value.
  19. *
  20. * If the highest bit is ``1``, the result will be negative.
  21. */
  22. function fromTwos(_value, _width) {
  23. const value = getUint(_value, "value");
  24. const width = BigInt(getNumber(_width, "width"));
  25. (0, errors_js_1.assert)((value >> width) === BN_0, "overflow", "NUMERIC_FAULT", {
  26. operation: "fromTwos", fault: "overflow", value: _value
  27. });
  28. // Top bit set; treat as a negative value
  29. if (value >> (width - BN_1)) {
  30. const mask = (BN_1 << width) - BN_1;
  31. return -(((~value) & mask) + BN_1);
  32. }
  33. return value;
  34. }
  35. exports.fromTwos = fromTwos;
  36. /**
  37. * Convert %%value%% to a twos-compliment representation of
  38. * %%width%% bits.
  39. *
  40. * The result will always be positive.
  41. */
  42. function toTwos(_value, _width) {
  43. let value = getBigInt(_value, "value");
  44. const width = BigInt(getNumber(_width, "width"));
  45. const limit = (BN_1 << (width - BN_1));
  46. if (value < BN_0) {
  47. value = -value;
  48. (0, errors_js_1.assert)(value <= limit, "too low", "NUMERIC_FAULT", {
  49. operation: "toTwos", fault: "overflow", value: _value
  50. });
  51. const mask = (BN_1 << width) - BN_1;
  52. return ((~value) & mask) + BN_1;
  53. }
  54. else {
  55. (0, errors_js_1.assert)(value < limit, "too high", "NUMERIC_FAULT", {
  56. operation: "toTwos", fault: "overflow", value: _value
  57. });
  58. }
  59. return value;
  60. }
  61. exports.toTwos = toTwos;
  62. /**
  63. * Mask %%value%% with a bitmask of %%bits%% ones.
  64. */
  65. function mask(_value, _bits) {
  66. const value = getUint(_value, "value");
  67. const bits = BigInt(getNumber(_bits, "bits"));
  68. return value & ((BN_1 << bits) - BN_1);
  69. }
  70. exports.mask = mask;
  71. /**
  72. * Gets a BigInt from %%value%%. If it is an invalid value for
  73. * a BigInt, then an ArgumentError will be thrown for %%name%%.
  74. */
  75. function getBigInt(value, name) {
  76. switch (typeof (value)) {
  77. case "bigint": return value;
  78. case "number":
  79. (0, errors_js_1.assertArgument)(Number.isInteger(value), "underflow", name || "value", value);
  80. (0, errors_js_1.assertArgument)(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
  81. return BigInt(value);
  82. case "string":
  83. try {
  84. if (value === "") {
  85. throw new Error("empty string");
  86. }
  87. if (value[0] === "-" && value[1] !== "-") {
  88. return -BigInt(value.substring(1));
  89. }
  90. return BigInt(value);
  91. }
  92. catch (e) {
  93. (0, errors_js_1.assertArgument)(false, `invalid BigNumberish string: ${e.message}`, name || "value", value);
  94. }
  95. }
  96. (0, errors_js_1.assertArgument)(false, "invalid BigNumberish value", name || "value", value);
  97. }
  98. exports.getBigInt = getBigInt;
  99. /**
  100. * Returns %%value%% as a bigint, validating it is valid as a bigint
  101. * value and that it is positive.
  102. */
  103. function getUint(value, name) {
  104. const result = getBigInt(value, name);
  105. (0, errors_js_1.assert)(result >= BN_0, "unsigned value cannot be negative", "NUMERIC_FAULT", {
  106. fault: "overflow", operation: "getUint", value
  107. });
  108. return result;
  109. }
  110. exports.getUint = getUint;
  111. const Nibbles = "0123456789abcdef";
  112. /*
  113. * Converts %%value%% to a BigInt. If %%value%% is a Uint8Array, it
  114. * is treated as Big Endian data.
  115. */
  116. function toBigInt(value) {
  117. if (value instanceof Uint8Array) {
  118. let result = "0x0";
  119. for (const v of value) {
  120. result += Nibbles[v >> 4];
  121. result += Nibbles[v & 0x0f];
  122. }
  123. return BigInt(result);
  124. }
  125. return getBigInt(value);
  126. }
  127. exports.toBigInt = toBigInt;
  128. /**
  129. * Gets a //number// from %%value%%. If it is an invalid value for
  130. * a //number//, then an ArgumentError will be thrown for %%name%%.
  131. */
  132. function getNumber(value, name) {
  133. switch (typeof (value)) {
  134. case "bigint":
  135. (0, errors_js_1.assertArgument)(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
  136. return Number(value);
  137. case "number":
  138. (0, errors_js_1.assertArgument)(Number.isInteger(value), "underflow", name || "value", value);
  139. (0, errors_js_1.assertArgument)(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
  140. return value;
  141. case "string":
  142. try {
  143. if (value === "") {
  144. throw new Error("empty string");
  145. }
  146. return getNumber(BigInt(value), name);
  147. }
  148. catch (e) {
  149. (0, errors_js_1.assertArgument)(false, `invalid numeric string: ${e.message}`, name || "value", value);
  150. }
  151. }
  152. (0, errors_js_1.assertArgument)(false, "invalid numeric value", name || "value", value);
  153. }
  154. exports.getNumber = getNumber;
  155. /**
  156. * Converts %%value%% to a number. If %%value%% is a Uint8Array, it
  157. * is treated as Big Endian data. Throws if the value is not safe.
  158. */
  159. function toNumber(value) {
  160. return getNumber(toBigInt(value));
  161. }
  162. exports.toNumber = toNumber;
  163. /**
  164. * Converts %%value%% to a Big Endian hexstring, optionally padded to
  165. * %%width%% bytes.
  166. */
  167. function toBeHex(_value, _width) {
  168. const value = getUint(_value, "value");
  169. let result = value.toString(16);
  170. if (_width == null) {
  171. // Ensure the value is of even length
  172. if (result.length % 2) {
  173. result = "0" + result;
  174. }
  175. }
  176. else {
  177. const width = getNumber(_width, "width");
  178. (0, errors_js_1.assert)(width * 2 >= result.length, `value exceeds width (${width} bytes)`, "NUMERIC_FAULT", {
  179. operation: "toBeHex",
  180. fault: "overflow",
  181. value: _value
  182. });
  183. // Pad the value to the required width
  184. while (result.length < (width * 2)) {
  185. result = "0" + result;
  186. }
  187. }
  188. return "0x" + result;
  189. }
  190. exports.toBeHex = toBeHex;
  191. /**
  192. * Converts %%value%% to a Big Endian Uint8Array.
  193. */
  194. function toBeArray(_value) {
  195. const value = getUint(_value, "value");
  196. if (value === BN_0) {
  197. return new Uint8Array([]);
  198. }
  199. let hex = value.toString(16);
  200. if (hex.length % 2) {
  201. hex = "0" + hex;
  202. }
  203. const result = new Uint8Array(hex.length / 2);
  204. for (let i = 0; i < result.length; i++) {
  205. const offset = i * 2;
  206. result[i] = parseInt(hex.substring(offset, offset + 2), 16);
  207. }
  208. return result;
  209. }
  210. exports.toBeArray = toBeArray;
  211. /**
  212. * Returns a [[HexString]] for %%value%% safe to use as a //Quantity//.
  213. *
  214. * A //Quantity// does not have and leading 0 values unless the value is
  215. * the literal value `0x0`. This is most commonly used for JSSON-RPC
  216. * numeric values.
  217. */
  218. function toQuantity(value) {
  219. let result = (0, data_js_1.hexlify)((0, data_js_1.isBytesLike)(value) ? value : toBeArray(value)).substring(2);
  220. while (result.startsWith("0")) {
  221. result = result.substring(1);
  222. }
  223. if (result === "") {
  224. result = "0";
  225. }
  226. return "0x" + result;
  227. }
  228. exports.toQuantity = toQuantity;
  229. //# sourceMappingURL=maths.js.map