UNPKG

@web3-onboard/hw-common

Version:

Web3-Onboard makes it simple to connect Ethereum hardware and software wallets to your dapp. Features standardised spec compliant web3 providers for all supported wallets, framework agnostic modern javascript UI with code splitting, CSS customization, mul

1,485 lines (1,338 loc) 192 kB
import { Subject, take, firstValueFrom } from 'rxjs'; import Joi from 'joi'; import { chainValidation, validate } from '@web3-onboard/common'; function noop() { } const identity = x => x; function assign(tar, src) { // @ts-ignore for (const k in src) tar[k] = src[k]; return tar; } function run(fn) { return fn(); } function blank_object() { return Object.create(null); } function run_all(fns) { fns.forEach(run); } function is_function(thing) { return typeof thing === 'function'; } function safe_not_equal(a, b) { return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); } function is_empty(obj) { return Object.keys(obj).length === 0; } function create_slot(definition, ctx, $$scope, fn) { if (definition) { const slot_ctx = get_slot_context(definition, ctx, $$scope, fn); return definition[0](slot_ctx); } } function get_slot_context(definition, ctx, $$scope, fn) { return definition[1] && fn ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx; } function get_slot_changes(definition, $$scope, dirty, fn) { if (definition[2] && fn) { const lets = definition[2](fn(dirty)); if ($$scope.dirty === undefined) { return lets; } if (typeof lets === 'object') { const merged = []; const len = Math.max($$scope.dirty.length, lets.length); for (let i = 0; i < len; i += 1) { merged[i] = $$scope.dirty[i] | lets[i]; } return merged; } return $$scope.dirty | lets; } return $$scope.dirty; } function update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) { if (slot_changes) { const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); slot.p(slot_context, slot_changes); } } function get_all_dirty_from_scope($$scope) { if ($$scope.ctx.length > 32) { const dirty = []; const length = $$scope.ctx.length / 32; for (let i = 0; i < length; i++) { dirty[i] = -1; } return dirty; } return -1; } const is_client = typeof window !== 'undefined'; let now = is_client ? () => window.performance.now() : () => Date.now(); let raf = is_client ? cb => requestAnimationFrame(cb) : noop; const tasks = new Set(); function run_tasks(now) { tasks.forEach(task => { if (!task.c(now)) { tasks.delete(task); task.f(); } }); if (tasks.size !== 0) raf(run_tasks); } /** * Creates a new task that runs on each raf frame * until it returns a falsy value or is aborted */ function loop(callback) { let task; if (tasks.size === 0) raf(run_tasks); return { promise: new Promise(fulfill => { tasks.add(task = { c: callback, f: fulfill }); }), abort() { tasks.delete(task); } }; } function append(target, node) { target.appendChild(node); } function append_styles(target, style_sheet_id, styles) { const append_styles_to = get_root_for_style(target); if (!append_styles_to.getElementById(style_sheet_id)) { const style = element('style'); style.id = style_sheet_id; style.textContent = styles; append_stylesheet(append_styles_to, style); } } function get_root_for_style(node) { if (!node) return document; const root = node.getRootNode ? node.getRootNode() : node.ownerDocument; if (root && root.host) { return root; } return node.ownerDocument; } function append_empty_stylesheet(node) { const style_element = element('style'); append_stylesheet(get_root_for_style(node), style_element); return style_element.sheet; } function append_stylesheet(node, style) { append(node.head || node, style); return style.sheet; } function insert(target, node, anchor) { target.insertBefore(node, anchor || null); } function detach(node) { if (node.parentNode) { node.parentNode.removeChild(node); } } function destroy_each(iterations, detaching) { for (let i = 0; i < iterations.length; i += 1) { if (iterations[i]) iterations[i].d(detaching); } } function element(name) { return document.createElement(name); } function svg_element(name) { return document.createElementNS('http://www.w3.org/2000/svg', name); } function text(data) { return document.createTextNode(data); } function space() { return text(' '); } function empty() { return text(''); } function listen(node, event, handler, options) { node.addEventListener(event, handler, options); return () => node.removeEventListener(event, handler, options); } function attr(node, attribute, value) { if (value == null) node.removeAttribute(attribute); else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value); } function children(element) { return Array.from(element.childNodes); } function set_data(text, data) { data = '' + data; if (text.data === data) return; text.data = data; } function set_style(node, key, value, important) { if (value == null) { node.style.removeProperty(key); } else { node.style.setProperty(key, value, important ? 'important' : ''); } } function select_option(select, value, mounting) { for (let i = 0; i < select.options.length; i += 1) { const option = select.options[i]; if (option.__value === value) { option.selected = true; return; } } if (!mounting || value !== undefined) { select.selectedIndex = -1; // no option should be selected } } function select_value(select) { const selected_option = select.querySelector(':checked'); return selected_option && selected_option.__value; } function toggle_class(element, name, toggle) { element.classList[toggle ? 'add' : 'remove'](name); } function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) { const e = document.createEvent('CustomEvent'); e.initCustomEvent(type, bubbles, cancelable, detail); return e; } // we need to store the information for multiple documents because a Svelte application could also contain iframes // https://github.com/sveltejs/svelte/issues/3624 const managed_styles = new Map(); let active = 0; // https://github.com/darkskyapp/string-hash/blob/master/index.js function hash(str) { let hash = 5381; let i = str.length; while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i); return hash >>> 0; } function create_style_information(doc, node) { const info = { stylesheet: append_empty_stylesheet(node), rules: {} }; managed_styles.set(doc, info); return info; } function create_rule(node, a, b, duration, delay, ease, fn, uid = 0) { const step = 16.666 / duration; let keyframes = '{\n'; for (let p = 0; p <= 1; p += step) { const t = a + (b - a) * ease(p); keyframes += p * 100 + `%{${fn(t, 1 - t)}}\n`; } const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`; const name = `__svelte_${hash(rule)}_${uid}`; const doc = get_root_for_style(node); const { stylesheet, rules } = managed_styles.get(doc) || create_style_information(doc, node); if (!rules[name]) { rules[name] = true; stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length); } const animation = node.style.animation || ''; node.style.animation = `${animation ? `${animation}, ` : ''}${name} ${duration}ms linear ${delay}ms 1 both`; active += 1; return name; } function delete_rule(node, name) { const previous = (node.style.animation || '').split(', '); const next = previous.filter(name ? anim => anim.indexOf(name) < 0 // remove specific animation : anim => anim.indexOf('__svelte') === -1 // remove all Svelte animations ); const deleted = previous.length - next.length; if (deleted) { node.style.animation = next.join(', '); active -= deleted; if (!active) clear_rules(); } } function clear_rules() { raf(() => { if (active) return; managed_styles.forEach(info => { const { ownerNode } = info.stylesheet; // there is no ownerNode if it runs on jsdom. if (ownerNode) detach(ownerNode); }); managed_styles.clear(); }); } let current_component; function set_current_component(component) { current_component = component; } const dirty_components = []; const binding_callbacks = []; let render_callbacks = []; const flush_callbacks = []; const resolved_promise = /* @__PURE__ */ Promise.resolve(); let update_scheduled = false; function schedule_update() { if (!update_scheduled) { update_scheduled = true; resolved_promise.then(flush); } } function add_render_callback(fn) { render_callbacks.push(fn); } function add_flush_callback(fn) { flush_callbacks.push(fn); } // flush() calls callbacks in this order: // 1. All beforeUpdate callbacks, in order: parents before children // 2. All bind:this callbacks, in reverse order: children before parents. // 3. All afterUpdate callbacks, in order: parents before children. EXCEPT // for afterUpdates called during the initial onMount, which are called in // reverse order: children before parents. // Since callbacks might update component values, which could trigger another // call to flush(), the following steps guard against this: // 1. During beforeUpdate, any updated components will be added to the // dirty_components array and will cause a reentrant call to flush(). Because // the flush index is kept outside the function, the reentrant call will pick // up where the earlier call left off and go through all dirty components. The // current_component value is saved and restored so that the reentrant call will // not interfere with the "parent" flush() call. // 2. bind:this callbacks cannot trigger new flush() calls. // 3. During afterUpdate, any updated components will NOT have their afterUpdate // callback called a second time; the seen_callbacks set, outside the flush() // function, guarantees this behavior. const seen_callbacks = new Set(); let flushidx = 0; // Do *not* move this inside the flush() function function flush() { // Do not reenter flush while dirty components are updated, as this can // result in an infinite loop. Instead, let the inner flush handle it. // Reentrancy is ok afterwards for bindings etc. if (flushidx !== 0) { return; } const saved_component = current_component; do { // first, call beforeUpdate functions // and update components try { while (flushidx < dirty_components.length) { const component = dirty_components[flushidx]; flushidx++; set_current_component(component); update(component.$$); } } catch (e) { // reset dirty state to not end up in a deadlocked state and then rethrow dirty_components.length = 0; flushidx = 0; throw e; } set_current_component(null); dirty_components.length = 0; flushidx = 0; while (binding_callbacks.length) binding_callbacks.pop()(); // then, once components are updated, call // afterUpdate functions. This may cause // subsequent updates... for (let i = 0; i < render_callbacks.length; i += 1) { const callback = render_callbacks[i]; if (!seen_callbacks.has(callback)) { // ...so guard against infinite loops seen_callbacks.add(callback); callback(); } } render_callbacks.length = 0; } while (dirty_components.length); while (flush_callbacks.length) { flush_callbacks.pop()(); } update_scheduled = false; seen_callbacks.clear(); set_current_component(saved_component); } function update($$) { if ($$.fragment !== null) { $$.update(); run_all($$.before_update); const dirty = $$.dirty; $$.dirty = [-1]; $$.fragment && $$.fragment.p($$.ctx, dirty); $$.after_update.forEach(add_render_callback); } } /** * Useful for example to execute remaining `afterUpdate` callbacks before executing `destroy`. */ function flush_render_callbacks(fns) { const filtered = []; const targets = []; render_callbacks.forEach((c) => fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c)); targets.forEach((c) => c()); render_callbacks = filtered; } let promise; function wait() { if (!promise) { promise = Promise.resolve(); promise.then(() => { promise = null; }); } return promise; } function dispatch(node, direction, kind) { node.dispatchEvent(custom_event(`${direction ? 'intro' : 'outro'}${kind}`)); } const outroing = new Set(); let outros; function group_outros() { outros = { r: 0, c: [], p: outros // parent group }; } function check_outros() { if (!outros.r) { run_all(outros.c); } outros = outros.p; } function transition_in(block, local) { if (block && block.i) { outroing.delete(block); block.i(local); } } function transition_out(block, local, detach, callback) { if (block && block.o) { if (outroing.has(block)) return; outroing.add(block); outros.c.push(() => { outroing.delete(block); if (callback) { if (detach) block.d(1); callback(); } }); block.o(local); } else if (callback) { callback(); } } const null_transition = { duration: 0 }; function create_bidirectional_transition(node, fn, params, intro) { const options = { direction: 'both' }; let config = fn(node, params, options); let t = intro ? 0 : 1; let running_program = null; let pending_program = null; let animation_name = null; function clear_animation() { if (animation_name) delete_rule(node, animation_name); } function init(program, duration) { const d = (program.b - t); duration *= Math.abs(d); return { a: t, b: program.b, d, duration, start: program.start, end: program.start + duration, group: program.group }; } function go(b) { const { delay = 0, duration = 300, easing = identity, tick = noop, css } = config || null_transition; const program = { start: now() + delay, b }; if (!b) { // @ts-ignore todo: improve typings program.group = outros; outros.r += 1; } if (running_program || pending_program) { pending_program = program; } else { // if this is an intro, and there's a delay, we need to do // an initial tick and/or apply CSS animation immediately if (css) { clear_animation(); animation_name = create_rule(node, t, b, duration, delay, easing, css); } if (b) tick(0, 1); running_program = init(program, duration); add_render_callback(() => dispatch(node, b, 'start')); loop(now => { if (pending_program && now > pending_program.start) { running_program = init(pending_program, duration); pending_program = null; dispatch(node, running_program.b, 'start'); if (css) { clear_animation(); animation_name = create_rule(node, t, running_program.b, running_program.duration, 0, easing, config.css); } } if (running_program) { if (now >= running_program.end) { tick(t = running_program.b, 1 - t); dispatch(node, running_program.b, 'end'); if (!pending_program) { // we're done if (running_program.b) { // intro — we can tidy up immediately clear_animation(); } else { // outro — needs to be coordinated if (!--running_program.group.r) run_all(running_program.group.c); } } running_program = null; } else if (now >= running_program.start) { const p = now - running_program.start; t = running_program.a + running_program.d * easing(p / running_program.duration); tick(t, 1 - t); } } return !!(running_program || pending_program); }); } } return { run(b) { if (is_function(config)) { wait().then(() => { // @ts-ignore config = config(options); go(b); }); } else { go(b); } }, end() { clear_animation(); running_program = pending_program = null; } }; } function bind(component, name, callback) { const index = component.$$.props[name]; if (index !== undefined) { component.$$.bound[index] = callback; callback(component.$$.ctx[index]); } } function create_component(block) { block && block.c(); } function mount_component(component, target, anchor, customElement) { const { fragment, after_update } = component.$$; fragment && fragment.m(target, anchor); if (!customElement) { // onMount happens before the initial afterUpdate add_render_callback(() => { const new_on_destroy = component.$$.on_mount.map(run).filter(is_function); // if the component was destroyed immediately // it will update the `$$.on_destroy` reference to `null`. // the destructured on_destroy may still reference to the old array if (component.$$.on_destroy) { component.$$.on_destroy.push(...new_on_destroy); } else { // Edge case - component was destroyed immediately, // most likely as a result of a binding initialising run_all(new_on_destroy); } component.$$.on_mount = []; }); } after_update.forEach(add_render_callback); } function destroy_component(component, detaching) { const $$ = component.$$; if ($$.fragment !== null) { flush_render_callbacks($$.after_update); run_all($$.on_destroy); $$.fragment && $$.fragment.d(detaching); // TODO null out other refs, including component.$$ (but need to // preserve final state?) $$.on_destroy = $$.fragment = null; $$.ctx = []; } } function make_dirty(component, i) { if (component.$$.dirty[0] === -1) { dirty_components.push(component); schedule_update(); component.$$.dirty.fill(0); } component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31)); } function init(component, options, instance, create_fragment, not_equal, props, append_styles, dirty = [-1]) { const parent_component = current_component; set_current_component(component); const $$ = component.$$ = { fragment: null, ctx: [], // state props, update: noop, not_equal, bound: blank_object(), // lifecycle on_mount: [], on_destroy: [], on_disconnect: [], before_update: [], after_update: [], context: new Map(options.context || (parent_component ? parent_component.$$.context : [])), // everything else callbacks: blank_object(), dirty, skip_bound: false, root: options.target || parent_component.$$.root }; append_styles && append_styles($$.root); let ready = false; $$.ctx = instance ? instance(component, options.props || {}, (i, ret, ...rest) => { const value = rest.length ? rest[0] : ret; if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) { if (!$$.skip_bound && $$.bound[i]) $$.bound[i](value); if (ready) make_dirty(component, i); } return ret; }) : []; $$.update(); ready = true; run_all($$.before_update); // `false` as a special case of no DOM component $$.fragment = create_fragment ? create_fragment($$.ctx) : false; if (options.target) { if (options.hydrate) { const nodes = children(options.target); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion $$.fragment && $$.fragment.l(nodes); nodes.forEach(detach); } else { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion $$.fragment && $$.fragment.c(); } if (options.intro) transition_in(component.$$.fragment); mount_component(component, options.target, options.anchor, options.customElement); flush(); } set_current_component(parent_component); } /** * Base class for Svelte components. Used when dev=false. */ class SvelteComponent { $destroy() { destroy_component(this, 1); this.$destroy = noop; } $on(type, callback) { if (!is_function(callback)) { return noop; } const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = [])); callbacks.push(callback); return () => { const index = callbacks.indexOf(callback); if (index !== -1) callbacks.splice(index, 1); }; } $set($$props) { if (this.$$set && !is_empty($$props)) { this.$$.skip_bound = true; this.$$set($$props); this.$$.skip_bound = false; } } } function fade(node, { delay = 0, duration = 400, easing = identity } = {}) { const o = +getComputedStyle(node).opacity; return { delay, duration, easing, css: t => `opacity: ${t * o}` }; } var closeIcon = ` <svg width="100%" height="100%" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M11.6569 1.75736L7.41429 6L11.6569 10.2426L10.2427 11.6569L6.00008 7.41421L1.75744 11.6569L0.343227 10.2426L4.58587 6L0.343227 1.75736L1.75744 0.343146L6.00008 4.58579L10.2427 0.343146L11.6569 1.75736Z" fill="currentColor"/> </svg> `; /* src/elements/CloseButton.svelte generated by Svelte v3.59.2 */ function add_css$6(target) { append_styles(target, "svelte-1jp3yas", ".close-button.svelte-1jp3yas.svelte-1jp3yas{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;height:2rem;width:2rem;border-radius:2rem;cursor:pointer;color:var(--onboard-close-button-color, inherit)}.close-button.svelte-1jp3yas.svelte-1jp3yas:hover::before{opacity:0.2}.close-button.svelte-1jp3yas:hover .svg-box.svelte-1jp3yas{opacity:1}.close-button.svelte-1jp3yas.svelte-1jp3yas::before{content:'';position:absolute;height:inherit;width:inherit;opacity:0.1;background:currentColor;transition:300ms ease-in-out opacity}.svg-box.svelte-1jp3yas.svelte-1jp3yas{display:flex;position:absolute;height:14px;width:14px;opacity:0.6;transition:300ms ease-in-out opacity}"); } function create_fragment$6(ctx) { let div2; let div1; let div0; return { c() { div2 = element("div"); div1 = element("div"); div0 = element("div"); attr(div0, "class", "svg-box svelte-1jp3yas"); attr(div1, "class", "close-button svelte-1jp3yas"); attr(div2, "class", "close-button-container"); }, m(target, anchor) { insert(target, div2, anchor); append(div2, div1); append(div1, div0); div0.innerHTML = closeIcon; }, p: noop, i: noop, o: noop, d(detaching) { if (detaching) detach(div2); } }; } class CloseButton extends SvelteComponent { constructor(options) { super(); init(this, options, null, create_fragment$6, safe_not_equal, {}, add_css$6); } } /* * bignumber.js v9.1.2 * A JavaScript library for arbitrary-precision arithmetic. * https://github.com/MikeMcl/bignumber.js * Copyright (c) 2022 Michael Mclaughlin <M8ch88l@gmail.com> * MIT Licensed. * * BigNumber.prototype methods | BigNumber methods * | * absoluteValue abs | clone * comparedTo | config set * decimalPlaces dp | DECIMAL_PLACES * dividedBy div | ROUNDING_MODE * dividedToIntegerBy idiv | EXPONENTIAL_AT * exponentiatedBy pow | RANGE * integerValue | CRYPTO * isEqualTo eq | MODULO_MODE * isFinite | POW_PRECISION * isGreaterThan gt | FORMAT * isGreaterThanOrEqualTo gte | ALPHABET * isInteger | isBigNumber * isLessThan lt | maximum max * isLessThanOrEqualTo lte | minimum min * isNaN | random * isNegative | sum * isPositive | * isZero | * minus | * modulo mod | * multipliedBy times | * negated | * plus | * precision sd | * shiftedBy | * squareRoot sqrt | * toExponential | * toFixed | * toFormat | * toFraction | * toJSON | * toNumber | * toPrecision | * toString | * valueOf | * */ var isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i, mathceil = Math.ceil, mathfloor = Math.floor, bignumberError = '[BigNumber Error] ', tooManyDigits = bignumberError + 'Number primitive has more than 15 significant digits: ', BASE = 1e14, LOG_BASE = 14, MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1 // MAX_INT32 = 0x7fffffff, // 2^31 - 1 POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], SQRT_BASE = 1e7, // EDITABLE // The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and // the arguments to toExponential, toFixed, toFormat, and toPrecision. MAX = 1E9; // 0 to MAX_INT32 /* * Create and return a BigNumber constructor. */ function clone(configObject) { var div, convertBase, parseNumeric, P = BigNumber.prototype = { constructor: BigNumber, toString: null, valueOf: null }, ONE = new BigNumber(1), //----------------------------- EDITABLE CONFIG DEFAULTS ------------------------------- // The default values below must be integers within the inclusive ranges stated. // The values can also be changed at run-time using BigNumber.set. // The maximum number of decimal places for operations involving division. DECIMAL_PLACES = 20, // 0 to MAX // The rounding mode used when rounding to the above decimal places, and when using // toExponential, toFixed, toFormat and toPrecision, and round (default value). // UP 0 Away from zero. // DOWN 1 Towards zero. // CEIL 2 Towards +Infinity. // FLOOR 3 Towards -Infinity. // HALF_UP 4 Towards nearest neighbour. If equidistant, up. // HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. // HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. // HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. // HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. ROUNDING_MODE = 4, // 0 to 8 // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS] // The exponent value at and beneath which toString returns exponential notation. // Number type: -7 TO_EXP_NEG = -7, // 0 to -MAX // The exponent value at and above which toString returns exponential notation. // Number type: 21 TO_EXP_POS = 21, // 0 to MAX // RANGE : [MIN_EXP, MAX_EXP] // The minimum exponent value, beneath which underflow to zero occurs. // Number type: -324 (5e-324) MIN_EXP = -1e7, // -1 to -MAX // The maximum exponent value, above which overflow to Infinity occurs. // Number type: 308 (1.7976931348623157e+308) // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow. MAX_EXP = 1e7, // 1 to MAX // Whether to use cryptographically-secure random number generation, if available. CRYPTO = false, // true or false // The modulo mode used when calculating the modulus: a mod n. // The quotient (q = a / n) is calculated according to the corresponding rounding mode. // The remainder (r) is calculated as: r = a - n * q. // // UP 0 The remainder is positive if the dividend is negative, else is negative. // DOWN 1 The remainder has the same sign as the dividend. // This modulo mode is commonly known as 'truncated division' and is // equivalent to (a % n) in JavaScript. // FLOOR 3 The remainder has the same sign as the divisor (Python %). // HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function. // EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). // The remainder is always positive. // // The truncated division, floored division, Euclidian division and IEEE 754 remainder // modes are commonly used for the modulus operation. // Although the other rounding modes can also be used, they may not give useful results. MODULO_MODE = 1, // 0 to 9 // The maximum number of significant digits of the result of the exponentiatedBy operation. // If POW_PRECISION is 0, there will be unlimited significant digits. POW_PRECISION = 0, // 0 to MAX // The format specification used by the BigNumber.prototype.toFormat method. FORMAT = { prefix: '', groupSize: 3, secondaryGroupSize: 0, groupSeparator: ',', decimalSeparator: '.', fractionGroupSize: 0, fractionGroupSeparator: '\xA0', // non-breaking space suffix: '' }, // The alphabet used for base conversion. It must be at least 2 characters long, with no '+', // '-', '.', whitespace, or repeated character. // '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_' ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz', alphabetHasNormalDecimalDigits = true; //------------------------------------------------------------------------------------------ // CONSTRUCTOR /* * The BigNumber constructor and exported function. * Create and return a new instance of a BigNumber object. * * v {number|string|BigNumber} A numeric value. * [b] {number} The base of v. Integer, 2 to ALPHABET.length inclusive. */ function BigNumber(v, b) { var alphabet, c, caseChanged, e, i, isNum, len, str, x = this; // Enable constructor call without `new`. if (!(x instanceof BigNumber)) return new BigNumber(v, b); if (b == null) { if (v && v._isBigNumber === true) { x.s = v.s; if (!v.c || v.e > MAX_EXP) { x.c = x.e = null; } else if (v.e < MIN_EXP) { x.c = [x.e = 0]; } else { x.e = v.e; x.c = v.c.slice(); } return; } if ((isNum = typeof v == 'number') && v * 0 == 0) { // Use `1 / n` to handle minus zero also. x.s = 1 / v < 0 ? (v = -v, -1) : 1; // Fast path for integers, where n < 2147483648 (2**31). if (v === ~~v) { for (e = 0, i = v; i >= 10; i /= 10, e++); if (e > MAX_EXP) { x.c = x.e = null; } else { x.e = e; x.c = [v]; } return; } str = String(v); } else { if (!isNumeric.test(str = String(v))) return parseNumeric(x, str, isNum); x.s = str.charCodeAt(0) == 45 ? (str = str.slice(1), -1) : 1; } // Decimal point? if ((e = str.indexOf('.')) > -1) str = str.replace('.', ''); // Exponential form? if ((i = str.search(/e/i)) > 0) { // Determine exponent. if (e < 0) e = i; e += +str.slice(i + 1); str = str.substring(0, i); } else if (e < 0) { // Integer. e = str.length; } } else { // '[BigNumber Error] Base {not a primitive number|not an integer|out of range}: {b}' intCheck(b, 2, ALPHABET.length, 'Base'); // Allow exponential notation to be used with base 10 argument, while // also rounding to DECIMAL_PLACES as with other bases. if (b == 10 && alphabetHasNormalDecimalDigits) { x = new BigNumber(v); return round(x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE); } str = String(v); if (isNum = typeof v == 'number') { // Avoid potential interpretation of Infinity and NaN as base 44+ values. if (v * 0 != 0) return parseNumeric(x, str, isNum, b); x.s = 1 / v < 0 ? (str = str.slice(1), -1) : 1; // '[BigNumber Error] Number primitive has more than 15 significant digits: {n}' if (BigNumber.DEBUG && str.replace(/^0\.0*|\./, '').length > 15) { throw Error (tooManyDigits + v); } } else { x.s = str.charCodeAt(0) === 45 ? (str = str.slice(1), -1) : 1; } alphabet = ALPHABET.slice(0, b); e = i = 0; // Check that str is a valid base b number. // Don't use RegExp, so alphabet can contain special characters. for (len = str.length; i < len; i++) { if (alphabet.indexOf(c = str.charAt(i)) < 0) { if (c == '.') { // If '.' is not the first character and it has not be found before. if (i > e) { e = len; continue; } } else if (!caseChanged) { // Allow e.g. hexadecimal 'FF' as well as 'ff'. if (str == str.toUpperCase() && (str = str.toLowerCase()) || str == str.toLowerCase() && (str = str.toUpperCase())) { caseChanged = true; i = -1; e = 0; continue; } } return parseNumeric(x, String(v), isNum, b); } } // Prevent later check for length on converted number. isNum = false; str = convertBase(str, b, 10, x.s); // Decimal point? if ((e = str.indexOf('.')) > -1) str = str.replace('.', ''); else e = str.length; } // Determine leading zeros. for (i = 0; str.charCodeAt(i) === 48; i++); // Determine trailing zeros. for (len = str.length; str.charCodeAt(--len) === 48;); if (str = str.slice(i, ++len)) { len -= i; // '[BigNumber Error] Number primitive has more than 15 significant digits: {n}' if (isNum && BigNumber.DEBUG && len > 15 && (v > MAX_SAFE_INTEGER || v !== mathfloor(v))) { throw Error (tooManyDigits + (x.s * v)); } // Overflow? if ((e = e - i - 1) > MAX_EXP) { // Infinity. x.c = x.e = null; // Underflow? } else if (e < MIN_EXP) { // Zero. x.c = [x.e = 0]; } else { x.e = e; x.c = []; // Transform base // e is the base 10 exponent. // i is where to slice str to get the first element of the coefficient array. i = (e + 1) % LOG_BASE; if (e < 0) i += LOG_BASE; // i < 1 if (i < len) { if (i) x.c.push(+str.slice(0, i)); for (len -= LOG_BASE; i < len;) { x.c.push(+str.slice(i, i += LOG_BASE)); } i = LOG_BASE - (str = str.slice(i)).length; } else { i -= len; } for (; i--; str += '0'); x.c.push(+str); } } else { // Zero. x.c = [x.e = 0]; } } // CONSTRUCTOR PROPERTIES BigNumber.clone = clone; BigNumber.ROUND_UP = 0; BigNumber.ROUND_DOWN = 1; BigNumber.ROUND_CEIL = 2; BigNumber.ROUND_FLOOR = 3; BigNumber.ROUND_HALF_UP = 4; BigNumber.ROUND_HALF_DOWN = 5; BigNumber.ROUND_HALF_EVEN = 6; BigNumber.ROUND_HALF_CEIL = 7; BigNumber.ROUND_HALF_FLOOR = 8; BigNumber.EUCLID = 9; /* * Configure infrequently-changing library-wide settings. * * Accept an object with the following optional properties (if the value of a property is * a number, it must be an integer within the inclusive range stated): * * DECIMAL_PLACES {number} 0 to MAX * ROUNDING_MODE {number} 0 to 8 * EXPONENTIAL_AT {number|number[]} -MAX to MAX or [-MAX to 0, 0 to MAX] * RANGE {number|number[]} -MAX to MAX (not zero) or [-MAX to -1, 1 to MAX] * CRYPTO {boolean} true or false * MODULO_MODE {number} 0 to 9 * POW_PRECISION {number} 0 to MAX * ALPHABET {string} A string of two or more unique characters which does * not contain '.'. * FORMAT {object} An object with some of the following properties: * prefix {string} * groupSize {number} * secondaryGroupSize {number} * groupSeparator {string} * decimalSeparator {string} * fractionGroupSize {number} * fractionGroupSeparator {string} * suffix {string} * * (The values assigned to the above FORMAT object properties are not checked for validity.) * * E.g. * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 }) * * Ignore properties/parameters set to null or undefined, except for ALPHABET. * * Return an object with the properties current values. */ BigNumber.config = BigNumber.set = function (obj) { var p, v; if (obj != null) { if (typeof obj == 'object') { // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive. // '[BigNumber Error] DECIMAL_PLACES {not a primitive number|not an integer|out of range}: {v}' if (obj.hasOwnProperty(p = 'DECIMAL_PLACES')) { v = obj[p]; intCheck(v, 0, MAX, p); DECIMAL_PLACES = v; } // ROUNDING_MODE {number} Integer, 0 to 8 inclusive. // '[BigNumber Error] ROUNDING_MODE {not a primitive number|not an integer|out of range}: {v}' if (obj.hasOwnProperty(p = 'ROUNDING_MODE')) { v = obj[p]; intCheck(v, 0, 8, p); ROUNDING_MODE = v; } // EXPONENTIAL_AT {number|number[]} // Integer, -MAX to MAX inclusive or // [integer -MAX to 0 inclusive, 0 to MAX inclusive]. // '[BigNumber Error] EXPONENTIAL_AT {not a primitive number|not an integer|out of range}: {v}' if (obj.hasOwnProperty(p = 'EXPONENTIAL_AT')) { v = obj[p]; if (v && v.pop) { intCheck(v[0], -MAX, 0, p); intCheck(v[1], 0, MAX, p); TO_EXP_NEG = v[0]; TO_EXP_POS = v[1]; } else { intCheck(v, -MAX, MAX, p); TO_EXP_NEG = -(TO_EXP_POS = v < 0 ? -v : v); } } // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive]. // '[BigNumber Error] RANGE {not a primitive number|not an integer|out of range|cannot be zero}: {v}' if (obj.hasOwnProperty(p = 'RANGE')) { v = obj[p]; if (v && v.pop) { intCheck(v[0], -MAX, -1, p); intCheck(v[1], 1, MAX, p); MIN_EXP = v[0]; MAX_EXP = v[1]; } else { intCheck(v, -MAX, MAX, p); if (v) { MIN_EXP = -(MAX_EXP = v < 0 ? -v : v); } else { throw Error (bignumberError + p + ' cannot be zero: ' + v); } } } // CRYPTO {boolean} true or false. // '[BigNumber Error] CRYPTO not true or false: {v}' // '[BigNumber Error] crypto unavailable' if (obj.hasOwnProperty(p = 'CRYPTO')) { v = obj[p]; if (v === !!v) { if (v) { if (typeof crypto != 'undefined' && crypto && (crypto.getRandomValues || crypto.randomBytes)) { CRYPTO = v; } else { CRYPTO = !v; throw Error (bignumberError + 'crypto unavailable'); } } else { CRYPTO = v; } } else { throw Error (bignumberError + p + ' not true or false: ' + v); } } // MODULO_MODE {number} Integer, 0 to 9 inclusive. // '[BigNumber Error] MODULO_MODE {not a primitive number|not an integer|out of range}: {v}' if (obj.hasOwnProperty(p = 'MODULO_MODE')) { v = obj[p]; intCheck(v, 0, 9, p); MODULO_MODE = v; } // POW_PRECISION {number} Integer, 0 to MAX inclusive. // '[BigNumber Error] POW_PRECISION {not a primitive number|not an integer|out of range}: {v}' if (obj.hasOwnProperty(p = 'POW_PRECISION')) { v = obj[p]; intCheck(v, 0, MAX, p); POW_PRECISION = v; } // FORMAT {object} // '[BigNumber Error] FORMAT not an object: {v}' if (obj.hasOwnProperty(p = 'FORMAT')) { v = obj[p]; if (typeof v == 'object') FORMAT = v; else throw Error (bignumberError + p + ' not an object: ' + v); } // ALPHABET {string} // '[BigNumber Error] ALPHABET invalid: {v}' if (obj.hasOwnProperty(p = 'ALPHABET')) { v = obj[p]; // Disallow if less than two characters, // or if it contains '+', '-', '.', whitespace, or a repeated character. if (typeof v == 'string' && !/^.?$|[+\-.\s]|(.).*\1/.test(v)) { alphabetHasNormalDecimalDigits = v.slice(0, 10) == '0123456789'; ALPHABET = v; } else { throw Error (bignumberError + p + ' invalid: ' + v); } } } else { // '[BigNumber Error] Object expected: {v}' throw Error (bignumberError + 'Object expected: ' + obj); } } return { DECIMAL_PLACES: DECIMAL_PLACES, ROUNDING_MODE: ROUNDING_MODE, EXPONENTIAL_AT: [TO_EXP_NEG, TO_EXP_POS], RANGE: [MIN_EXP, MAX_EXP], CRYPTO: CRYPTO, MODULO_MODE: MODULO_MODE, POW_PRECISION: POW_PRECISION, FORMAT: FORMAT, ALPHABET: ALPHABET }; }; /* * Return true if v is a BigNumber instance, otherwise return false. * * If BigNumber.DEBUG is true, throw if a BigNumber instance is not well-formed. * * v {any} * * '[BigNumber Error] Invalid BigNumber: {v}' */ BigNumber.isBigNumber = function (v) { if (!v || v._isBigNumber !== true) return false; if (!BigNumber.DEBUG) return true; var i, n, c = v.c, e = v.e, s = v.s; out: if ({}.toString.call(c) == '[object Array]') { if ((s === 1 || s === -1) && e >= -MAX && e <= MAX && e === mathfloor(e)) { // If the first element is zero, the BigNumber value must be zero. if (c[0] === 0) { if (e === 0 && c.length === 1) return true; break out; } // Calculate number of digits that c[0] should have, based on the exponent. i = (e + 1) % LOG_BASE; if (i < 1) i += LOG_BASE; // Calculate number of digits of c[0]. //if (Math.ceil(Math.log(c[0] + 1) / Math.LN10) == i) { if (String(c[0]).length == i) { for (i = 0; i < c.length; i++) { n = c[i]; if (n < 0 || n >= BASE || n !== mathfloor(n)) break out; } // Last element cannot be zero, unless it is the only element. if (n !== 0) return true; } } // Infinity/NaN } else if (c === null && e === null && (s === null || s === 1 || s === -1)) { return true; } throw Error (bignumberError + 'Invalid BigNumber: ' + v); }; /* * Return a new BigNumber whose value is the maximum of the arguments. * * arguments {number|string|BigNumber} */ BigNumber.maximum = BigNumber.max = function () { return maxOrMin(arguments, -1); }; /* * Return a new BigNumber whose value is the minimum of the arguments. * * arguments {number|string|BigNumber} */ BigNumber.minimum = BigNumber.min = function () { return maxOrMin(arguments, 1); }; /* * Return a new BigNumber with a random value equal to or greater than 0 and less than 1, * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing * zeros are produced). * * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. * * '[BigNumber Error] Argument {not a primitive number|not an integer|out of range}: {dp}' * '[BigNumber Error] crypto unavailable' */ BigNumber.random = (function () { var pow2_53 = 0x20000000000000; // Return a 53 bit integer n, where 0 <= n < 9007199254740992. // Check if Math.random() produces more than 32 bits of randomness. // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits. // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1. var random53bitInt = (Math.random() * pow2_53) & 0x1fffff ? function () { return mathfloor(Math.random() * pow2_53); } : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) + (Math.random() * 0x800000 | 0); }; return function (dp) { var a, b, e, k, v, i = 0, c = [], rand = new BigNumber(ONE); if (dp == null) dp = DECIMAL_PLACES; else intCheck(dp, 0, MAX); k = mathceil(dp / LOG_BASE); if (CRYPTO) { // Browsers supporting crypto.getRandomValues. if (crypto.getRandomValues) { a = crypto.getRandomValues(new Uint32Array(k *= 2)); for (; i < k;) { // 53 bits: // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2) // 11111 11111111 11111111 11111111 11100000 00000000 00000000 // ((Math.pow(2, 32) - 1) >>> 11).toString(2) // 11111 11111111 11111111 // 0x20000 is 2^21. v = a[i] * 0x20000 + (a[i + 1] >>> 11); // Rejection sampling: // 0 <= v < 9007199254740992 // Probability that v >= 9e15, is // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251 if (v >= 9e15) { b = crypto.getRandomValues(new Uint32Array(2)); a[i] = b[0]; a[i + 1] = b[1]; } else { // 0 <= v <= 8999999999999999 // 0 <= (v % 1e14) <= 99999999999999 c.push(v % 1e14); i += 2; } } i = k / 2; // Node.js supporting crypto.randomBytes. } else if (crypto.randomBytes) {