Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1339x 1339x 1339x 1339x 1339x 1339x 1339x 1339x 1339x 589x 589x 589x 750x 750x 750x 1x 1x 1x 1x 1x 1x 1x 1x 3199x 3199x 3199x 3199x 3199x 3199x 649x 649x 649x 649x 649x 649x 3199x 2550x 2550x 2550x 2550x 2550x 2550x 2550x 1x 1x 1x 1x 1x 7707x 7707x 7707x 7707x 1x 1x 1x 1x 1x 1x 3182976x 3182976x 3182976x 430597x 430597x 430597x 3182976x 496538x 496538x 496538x 641x 641x 495896x 496538x 3x 3x 3182976x 3182976x 3182976x 1x 1x 1x 1x 1x 1x 1500125x 1500125x 1500125x 1500125x 1500125x 1500125x 1x 1x 1x 1x 1x 1x 1x 1x 42656x 42656x 42656x 2264992x 2264992x 2264992x 42656x 42656x 1x 1x 1x 1x 1x 1x 259870x 259870x 49645x 49645x 259870x 168298x 168298x 168298x 259870x 41926x 41926x 41925x 41926x 3x 3x 259870x 259870x 259870x 1x 1x 1x 1x 1x 1x 1x 7340x 7340x 1x 1x 1x 1x 1x 1x 36027x 36027x 36027x 36027x 36027x 1x 1x 36027x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 36025x 1x 1x 1x 1x 1x 1455052x 1455052x 1455052x 931542x 931542x 1455052x 931542x 931542x 1455052x 11235156x 11235156x 11235156x 931542x 931542x 931542x 1x 1x 1x 1x 1x 1x 1x 1x 1x 171x 171x 171x 171x 171x | /** * Some mathematic operations. * * @_subsection: api/utils:Math Helpers [about-maths] */ import { hexlify, isBytesLike } from "./data.js"; import { assert, assertArgument } from "./errors.js"; import type { BytesLike } from "./data.js"; /** * Any type that can be used where a numeric value is needed. */ export type Numeric = number | bigint; /** * Any type that can be used where a big number is needed. */ export type BigNumberish = string | Numeric; const BN_0 = BigInt(0); const BN_1 = BigInt(1); //const BN_Max256 = (BN_1 << BigInt(256)) - BN_1; // IEEE 754 support 53-bits of mantissa const maxValue = 0x1fffffffffffff; /** * Convert %%value%% from a twos-compliment representation of %%width%% * bits to its value. * * If the highest bit is ``1``, the result will be negative. */ export function fromTwos(_value: BigNumberish, _width: Numeric): bigint { const value = getUint(_value, "value"); const width = BigInt(getNumber(_width, "width")); assert((value >> width) === BN_0, "overflow", "NUMERIC_FAULT", { operation: "fromTwos", fault: "overflow", value: _value }); // Top bit set; treat as a negative value if (value >> (width - BN_1)) { const mask = (BN_1 << width) - BN_1; return -(((~value) & mask) + BN_1); } return value; } /** * Convert %%value%% to a twos-compliment representation of * %%width%% bits. * * The result will always be positive. */ export function toTwos(_value: BigNumberish, _width: Numeric): bigint { let value = getBigInt(_value, "value"); const width = BigInt(getNumber(_width, "width")); const limit = (BN_1 << (width - BN_1)); if (value < BN_0) { value = -value; assert(value <= limit, "too low", "NUMERIC_FAULT", { operation: "toTwos", fault: "overflow", value: _value }); const mask = (BN_1 << width) - BN_1; return ((~value) & mask) + BN_1; } else { assert(value < limit, "too high", "NUMERIC_FAULT", { operation: "toTwos", fault: "overflow", value: _value }); } return value; } /** * Mask %%value%% with a bitmask of %%bits%% ones. */ export function mask(_value: BigNumberish, _bits: Numeric): bigint { const value = getUint(_value, "value"); const bits = BigInt(getNumber(_bits, "bits")); return value & ((BN_1 << bits) - BN_1); } /** * Gets a BigInt from %%value%%. If it is an invalid value for * a BigInt, then an ArgumentError will be thrown for %%name%%. */ export function getBigInt(value: BigNumberish, name?: string): bigint { switch (typeof(value)) { case "bigint": return value; case "number": assertArgument(Number.isInteger(value), "underflow", name || "value", value); assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value); return BigInt(value); case "string": try { if (value === "") { throw new Error("empty string"); } if (value[0] === "-" && value[1] !== "-") { return -BigInt(value.substring(1)); } return BigInt(value); } catch(e: any) { assertArgument(false, `invalid BigNumberish string: ${ e.message }`, name || "value", value); } } assertArgument(false, "invalid BigNumberish value", name || "value", value); } /** * Returns %%value%% as a bigint, validating it is valid as a bigint * value and that it is positive. */ export function getUint(value: BigNumberish, name?: string): bigint { const result = getBigInt(value, name); assert(result >= BN_0, "unsigned value cannot be negative", "NUMERIC_FAULT", { fault: "overflow", operation: "getUint", value }); return result; } const Nibbles = "0123456789abcdef"; /* * Converts %%value%% to a BigInt. If %%value%% is a Uint8Array, it * is treated as Big Endian data. */ export function toBigInt(value: BigNumberish | Uint8Array): bigint { if (value instanceof Uint8Array) { let result = "0x0"; for (const v of value) { result += Nibbles[v >> 4]; result += Nibbles[v & 0x0f]; } return BigInt(result); } return getBigInt(value); } /** * Gets a //number// from %%value%%. If it is an invalid value for * a //number//, then an ArgumentError will be thrown for %%name%%. */ export function getNumber(value: BigNumberish, name?: string): number { switch (typeof(value)) { case "bigint": assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value); return Number(value); case "number": assertArgument(Number.isInteger(value), "underflow", name || "value", value); assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value); return value; case "string": try { if (value === "") { throw new Error("empty string"); } return getNumber(BigInt(value), name); } catch(e: any) { assertArgument(false, `invalid numeric string: ${ e.message }`, name || "value", value); } } assertArgument(false, "invalid numeric value", name || "value", value); } /** * Converts %%value%% to a number. If %%value%% is a Uint8Array, it * is treated as Big Endian data. Throws if the value is not safe. */ export function toNumber(value: BigNumberish | Uint8Array): number { return getNumber(toBigInt(value)); } /** * Converts %%value%% to a Big Endian hexstring, optionally padded to * %%width%% bytes. */ export function toBeHex(_value: BigNumberish, _width?: Numeric): string { const value = getUint(_value, "value"); let result = value.toString(16); if (_width == null) { // Ensure the value is of even length if (result.length % 2) { result = "0" + result; } } else { const width = getNumber(_width, "width"); assert(width * 2 >= result.length, `value exceeds width (${ width } bytes)`, "NUMERIC_FAULT", { operation: "toBeHex", fault: "overflow", value: _value }); // Pad the value to the required width while (result.length < (width * 2)) { result = "0" + result; } } return "0x" + result; } /** * Converts %%value%% to a Big Endian Uint8Array. */ export function toBeArray(_value: BigNumberish): Uint8Array { const value = getUint(_value, "value"); if (value === BN_0) { return new Uint8Array([ ]); } let hex = value.toString(16); if (hex.length % 2) { hex = "0" + hex; } const result = new Uint8Array(hex.length / 2); for (let i = 0; i < result.length; i++) { const offset = i * 2; result[i] = parseInt(hex.substring(offset, offset + 2), 16); } return result; } /** * Returns a [[HexString]] for %%value%% safe to use as a //Quantity//. * * A //Quantity// does not have and leading 0 values unless the value is * the literal value `0x0`. This is most commonly used for JSSON-RPC * numeric values. */ export function toQuantity(value: BytesLike | BigNumberish): string { let result = hexlify(isBytesLike(value) ? value: toBeArray(value)).substring(2); while (result.startsWith("0")) { result = result.substring(1); } if (result === "") { result = "0"; } return "0x" + result; } |