26337 lines
844 KiB
JavaScript
26337 lines
844 KiB
JavaScript
var solanaWeb3 = (function (exports) {
|
||
'use strict';
|
||
|
||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||
|
||
function getDefaultExportFromCjs (x) {
|
||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||
}
|
||
|
||
function getAugmentedNamespace(n) {
|
||
if (n.__esModule) return n;
|
||
var f = n.default;
|
||
if (typeof f == "function") {
|
||
var a = function a () {
|
||
if (this instanceof a) {
|
||
return Reflect.construct(f, arguments, this.constructor);
|
||
}
|
||
return f.apply(this, arguments);
|
||
};
|
||
a.prototype = f.prototype;
|
||
} else a = {};
|
||
Object.defineProperty(a, '__esModule', {value: true});
|
||
Object.keys(n).forEach(function (k) {
|
||
var d = Object.getOwnPropertyDescriptor(n, k);
|
||
Object.defineProperty(a, k, d.get ? d : {
|
||
enumerable: true,
|
||
get: function () {
|
||
return n[k];
|
||
}
|
||
});
|
||
});
|
||
return a;
|
||
}
|
||
|
||
var buffer = {};
|
||
|
||
var base64Js = {};
|
||
|
||
base64Js.byteLength = byteLength;
|
||
base64Js.toByteArray = toByteArray;
|
||
base64Js.fromByteArray = fromByteArray;
|
||
|
||
var lookup = [];
|
||
var revLookup = [];
|
||
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
|
||
|
||
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||
for (var i$1 = 0, len = code.length; i$1 < len; ++i$1) {
|
||
lookup[i$1] = code[i$1];
|
||
revLookup[code.charCodeAt(i$1)] = i$1;
|
||
}
|
||
|
||
// Support decoding URL-safe base64 strings, as Node.js does.
|
||
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
|
||
revLookup['-'.charCodeAt(0)] = 62;
|
||
revLookup['_'.charCodeAt(0)] = 63;
|
||
|
||
function getLens (b64) {
|
||
var len = b64.length;
|
||
|
||
if (len % 4 > 0) {
|
||
throw new Error('Invalid string. Length must be a multiple of 4')
|
||
}
|
||
|
||
// Trim off extra bytes after placeholder bytes are found
|
||
// See: https://github.com/beatgammit/base64-js/issues/42
|
||
var validLen = b64.indexOf('=');
|
||
if (validLen === -1) validLen = len;
|
||
|
||
var placeHoldersLen = validLen === len
|
||
? 0
|
||
: 4 - (validLen % 4);
|
||
|
||
return [validLen, placeHoldersLen]
|
||
}
|
||
|
||
// base64 is 4/3 + up to two characters of the original data
|
||
function byteLength (b64) {
|
||
var lens = getLens(b64);
|
||
var validLen = lens[0];
|
||
var placeHoldersLen = lens[1];
|
||
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||
}
|
||
|
||
function _byteLength (b64, validLen, placeHoldersLen) {
|
||
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||
}
|
||
|
||
function toByteArray (b64) {
|
||
var tmp;
|
||
var lens = getLens(b64);
|
||
var validLen = lens[0];
|
||
var placeHoldersLen = lens[1];
|
||
|
||
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));
|
||
|
||
var curByte = 0;
|
||
|
||
// if there are placeholders, only get up to the last complete 4 chars
|
||
var len = placeHoldersLen > 0
|
||
? validLen - 4
|
||
: validLen;
|
||
|
||
var i;
|
||
for (i = 0; i < len; i += 4) {
|
||
tmp =
|
||
(revLookup[b64.charCodeAt(i)] << 18) |
|
||
(revLookup[b64.charCodeAt(i + 1)] << 12) |
|
||
(revLookup[b64.charCodeAt(i + 2)] << 6) |
|
||
revLookup[b64.charCodeAt(i + 3)];
|
||
arr[curByte++] = (tmp >> 16) & 0xFF;
|
||
arr[curByte++] = (tmp >> 8) & 0xFF;
|
||
arr[curByte++] = tmp & 0xFF;
|
||
}
|
||
|
||
if (placeHoldersLen === 2) {
|
||
tmp =
|
||
(revLookup[b64.charCodeAt(i)] << 2) |
|
||
(revLookup[b64.charCodeAt(i + 1)] >> 4);
|
||
arr[curByte++] = tmp & 0xFF;
|
||
}
|
||
|
||
if (placeHoldersLen === 1) {
|
||
tmp =
|
||
(revLookup[b64.charCodeAt(i)] << 10) |
|
||
(revLookup[b64.charCodeAt(i + 1)] << 4) |
|
||
(revLookup[b64.charCodeAt(i + 2)] >> 2);
|
||
arr[curByte++] = (tmp >> 8) & 0xFF;
|
||
arr[curByte++] = tmp & 0xFF;
|
||
}
|
||
|
||
return arr
|
||
}
|
||
|
||
function tripletToBase64 (num) {
|
||
return lookup[num >> 18 & 0x3F] +
|
||
lookup[num >> 12 & 0x3F] +
|
||
lookup[num >> 6 & 0x3F] +
|
||
lookup[num & 0x3F]
|
||
}
|
||
|
||
function encodeChunk (uint8, start, end) {
|
||
var tmp;
|
||
var output = [];
|
||
for (var i = start; i < end; i += 3) {
|
||
tmp =
|
||
((uint8[i] << 16) & 0xFF0000) +
|
||
((uint8[i + 1] << 8) & 0xFF00) +
|
||
(uint8[i + 2] & 0xFF);
|
||
output.push(tripletToBase64(tmp));
|
||
}
|
||
return output.join('')
|
||
}
|
||
|
||
function fromByteArray (uint8) {
|
||
var tmp;
|
||
var len = uint8.length;
|
||
var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
|
||
var parts = [];
|
||
var maxChunkLength = 16383; // must be multiple of 3
|
||
|
||
// go through the array every three bytes, we'll deal with trailing stuff later
|
||
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
||
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)));
|
||
}
|
||
|
||
// pad the end with zeros, but make sure to not forget the extra bytes
|
||
if (extraBytes === 1) {
|
||
tmp = uint8[len - 1];
|
||
parts.push(
|
||
lookup[tmp >> 2] +
|
||
lookup[(tmp << 4) & 0x3F] +
|
||
'=='
|
||
);
|
||
} else if (extraBytes === 2) {
|
||
tmp = (uint8[len - 2] << 8) + uint8[len - 1];
|
||
parts.push(
|
||
lookup[tmp >> 10] +
|
||
lookup[(tmp >> 4) & 0x3F] +
|
||
lookup[(tmp << 2) & 0x3F] +
|
||
'='
|
||
);
|
||
}
|
||
|
||
return parts.join('')
|
||
}
|
||
|
||
var ieee754 = {};
|
||
|
||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||
|
||
ieee754.read = function (buffer, offset, isLE, mLen, nBytes) {
|
||
var e, m;
|
||
var eLen = (nBytes * 8) - mLen - 1;
|
||
var eMax = (1 << eLen) - 1;
|
||
var eBias = eMax >> 1;
|
||
var nBits = -7;
|
||
var i = isLE ? (nBytes - 1) : 0;
|
||
var d = isLE ? -1 : 1;
|
||
var s = buffer[offset + i];
|
||
|
||
i += d;
|
||
|
||
e = s & ((1 << (-nBits)) - 1);
|
||
s >>= (-nBits);
|
||
nBits += eLen;
|
||
for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
|
||
|
||
m = e & ((1 << (-nBits)) - 1);
|
||
e >>= (-nBits);
|
||
nBits += mLen;
|
||
for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
|
||
|
||
if (e === 0) {
|
||
e = 1 - eBias;
|
||
} else if (e === eMax) {
|
||
return m ? NaN : ((s ? -1 : 1) * Infinity)
|
||
} else {
|
||
m = m + Math.pow(2, mLen);
|
||
e = e - eBias;
|
||
}
|
||
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
|
||
};
|
||
|
||
ieee754.write = function (buffer, value, offset, isLE, mLen, nBytes) {
|
||
var e, m, c;
|
||
var eLen = (nBytes * 8) - mLen - 1;
|
||
var eMax = (1 << eLen) - 1;
|
||
var eBias = eMax >> 1;
|
||
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);
|
||
var i = isLE ? 0 : (nBytes - 1);
|
||
var d = isLE ? 1 : -1;
|
||
var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
|
||
|
||
value = Math.abs(value);
|
||
|
||
if (isNaN(value) || value === Infinity) {
|
||
m = isNaN(value) ? 1 : 0;
|
||
e = eMax;
|
||
} else {
|
||
e = Math.floor(Math.log(value) / Math.LN2);
|
||
if (value * (c = Math.pow(2, -e)) < 1) {
|
||
e--;
|
||
c *= 2;
|
||
}
|
||
if (e + eBias >= 1) {
|
||
value += rt / c;
|
||
} else {
|
||
value += rt * Math.pow(2, 1 - eBias);
|
||
}
|
||
if (value * c >= 2) {
|
||
e++;
|
||
c /= 2;
|
||
}
|
||
|
||
if (e + eBias >= eMax) {
|
||
m = 0;
|
||
e = eMax;
|
||
} else if (e + eBias >= 1) {
|
||
m = ((value * c) - 1) * Math.pow(2, mLen);
|
||
e = e + eBias;
|
||
} else {
|
||
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
|
||
e = 0;
|
||
}
|
||
}
|
||
|
||
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
|
||
|
||
e = (e << mLen) | m;
|
||
eLen += mLen;
|
||
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
|
||
|
||
buffer[offset + i - d] |= s * 128;
|
||
};
|
||
|
||
/*!
|
||
* The buffer module from node.js, for the browser.
|
||
*
|
||
* @author Feross Aboukhadijeh <https://feross.org>
|
||
* @license MIT
|
||
*/
|
||
|
||
(function (exports) {
|
||
|
||
const base64 = base64Js;
|
||
const ieee754$1 = ieee754;
|
||
const customInspectSymbol =
|
||
(typeof Symbol === 'function' && typeof Symbol['for'] === 'function') // eslint-disable-line dot-notation
|
||
? Symbol['for']('nodejs.util.inspect.custom') // eslint-disable-line dot-notation
|
||
: null;
|
||
|
||
exports.Buffer = Buffer;
|
||
exports.SlowBuffer = SlowBuffer;
|
||
exports.INSPECT_MAX_BYTES = 50;
|
||
|
||
const K_MAX_LENGTH = 0x7fffffff;
|
||
exports.kMaxLength = K_MAX_LENGTH;
|
||
|
||
/**
|
||
* If `Buffer.TYPED_ARRAY_SUPPORT`:
|
||
* === true Use Uint8Array implementation (fastest)
|
||
* === false Print warning and recommend using `buffer` v4.x which has an Object
|
||
* implementation (most compatible, even IE6)
|
||
*
|
||
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
|
||
* Opera 11.6+, iOS 4.2+.
|
||
*
|
||
* We report that the browser does not support typed arrays if the are not subclassable
|
||
* using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`
|
||
* (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
|
||
* for __proto__ and has a buggy typed array implementation.
|
||
*/
|
||
Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport();
|
||
|
||
if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
|
||
typeof console.error === 'function') {
|
||
console.error(
|
||
'This browser lacks typed array (Uint8Array) support which is required by ' +
|
||
'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
|
||
);
|
||
}
|
||
|
||
function typedArraySupport () {
|
||
// Can typed array instances can be augmented?
|
||
try {
|
||
const arr = new Uint8Array(1);
|
||
const proto = { foo: function () { return 42 } };
|
||
Object.setPrototypeOf(proto, Uint8Array.prototype);
|
||
Object.setPrototypeOf(arr, proto);
|
||
return arr.foo() === 42
|
||
} catch (e) {
|
||
return false
|
||
}
|
||
}
|
||
|
||
Object.defineProperty(Buffer.prototype, 'parent', {
|
||
enumerable: true,
|
||
get: function () {
|
||
if (!Buffer.isBuffer(this)) return undefined
|
||
return this.buffer
|
||
}
|
||
});
|
||
|
||
Object.defineProperty(Buffer.prototype, 'offset', {
|
||
enumerable: true,
|
||
get: function () {
|
||
if (!Buffer.isBuffer(this)) return undefined
|
||
return this.byteOffset
|
||
}
|
||
});
|
||
|
||
function createBuffer (length) {
|
||
if (length > K_MAX_LENGTH) {
|
||
throw new RangeError('The value "' + length + '" is invalid for option "size"')
|
||
}
|
||
// Return an augmented `Uint8Array` instance
|
||
const buf = new Uint8Array(length);
|
||
Object.setPrototypeOf(buf, Buffer.prototype);
|
||
return buf
|
||
}
|
||
|
||
/**
|
||
* The Buffer constructor returns instances of `Uint8Array` that have their
|
||
* prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
|
||
* `Uint8Array`, so the returned instances will have all the node `Buffer` methods
|
||
* and the `Uint8Array` methods. Square bracket notation works as expected -- it
|
||
* returns a single octet.
|
||
*
|
||
* The `Uint8Array` prototype remains unmodified.
|
||
*/
|
||
|
||
function Buffer (arg, encodingOrOffset, length) {
|
||
// Common case.
|
||
if (typeof arg === 'number') {
|
||
if (typeof encodingOrOffset === 'string') {
|
||
throw new TypeError(
|
||
'The "string" argument must be of type string. Received type number'
|
||
)
|
||
}
|
||
return allocUnsafe(arg)
|
||
}
|
||
return from(arg, encodingOrOffset, length)
|
||
}
|
||
|
||
Buffer.poolSize = 8192; // not used by this implementation
|
||
|
||
function from (value, encodingOrOffset, length) {
|
||
if (typeof value === 'string') {
|
||
return fromString(value, encodingOrOffset)
|
||
}
|
||
|
||
if (ArrayBuffer.isView(value)) {
|
||
return fromArrayView(value)
|
||
}
|
||
|
||
if (value == null) {
|
||
throw new TypeError(
|
||
'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
|
||
'or Array-like Object. Received type ' + (typeof value)
|
||
)
|
||
}
|
||
|
||
if (isInstance(value, ArrayBuffer) ||
|
||
(value && isInstance(value.buffer, ArrayBuffer))) {
|
||
return fromArrayBuffer(value, encodingOrOffset, length)
|
||
}
|
||
|
||
if (typeof SharedArrayBuffer !== 'undefined' &&
|
||
(isInstance(value, SharedArrayBuffer) ||
|
||
(value && isInstance(value.buffer, SharedArrayBuffer)))) {
|
||
return fromArrayBuffer(value, encodingOrOffset, length)
|
||
}
|
||
|
||
if (typeof value === 'number') {
|
||
throw new TypeError(
|
||
'The "value" argument must not be of type number. Received type number'
|
||
)
|
||
}
|
||
|
||
const valueOf = value.valueOf && value.valueOf();
|
||
if (valueOf != null && valueOf !== value) {
|
||
return Buffer.from(valueOf, encodingOrOffset, length)
|
||
}
|
||
|
||
const b = fromObject(value);
|
||
if (b) return b
|
||
|
||
if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&
|
||
typeof value[Symbol.toPrimitive] === 'function') {
|
||
return Buffer.from(value[Symbol.toPrimitive]('string'), encodingOrOffset, length)
|
||
}
|
||
|
||
throw new TypeError(
|
||
'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
|
||
'or Array-like Object. Received type ' + (typeof value)
|
||
)
|
||
}
|
||
|
||
/**
|
||
* Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
|
||
* if value is a number.
|
||
* Buffer.from(str[, encoding])
|
||
* Buffer.from(array)
|
||
* Buffer.from(buffer)
|
||
* Buffer.from(arrayBuffer[, byteOffset[, length]])
|
||
**/
|
||
Buffer.from = function (value, encodingOrOffset, length) {
|
||
return from(value, encodingOrOffset, length)
|
||
};
|
||
|
||
// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
|
||
// https://github.com/feross/buffer/pull/148
|
||
Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype);
|
||
Object.setPrototypeOf(Buffer, Uint8Array);
|
||
|
||
function assertSize (size) {
|
||
if (typeof size !== 'number') {
|
||
throw new TypeError('"size" argument must be of type number')
|
||
} else if (size < 0) {
|
||
throw new RangeError('The value "' + size + '" is invalid for option "size"')
|
||
}
|
||
}
|
||
|
||
function alloc (size, fill, encoding) {
|
||
assertSize(size);
|
||
if (size <= 0) {
|
||
return createBuffer(size)
|
||
}
|
||
if (fill !== undefined) {
|
||
// Only pay attention to encoding if it's a string. This
|
||
// prevents accidentally sending in a number that would
|
||
// be interpreted as a start offset.
|
||
return typeof encoding === 'string'
|
||
? createBuffer(size).fill(fill, encoding)
|
||
: createBuffer(size).fill(fill)
|
||
}
|
||
return createBuffer(size)
|
||
}
|
||
|
||
/**
|
||
* Creates a new filled Buffer instance.
|
||
* alloc(size[, fill[, encoding]])
|
||
**/
|
||
Buffer.alloc = function (size, fill, encoding) {
|
||
return alloc(size, fill, encoding)
|
||
};
|
||
|
||
function allocUnsafe (size) {
|
||
assertSize(size);
|
||
return createBuffer(size < 0 ? 0 : checked(size) | 0)
|
||
}
|
||
|
||
/**
|
||
* Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
|
||
* */
|
||
Buffer.allocUnsafe = function (size) {
|
||
return allocUnsafe(size)
|
||
};
|
||
/**
|
||
* Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
|
||
*/
|
||
Buffer.allocUnsafeSlow = function (size) {
|
||
return allocUnsafe(size)
|
||
};
|
||
|
||
function fromString (string, encoding) {
|
||
if (typeof encoding !== 'string' || encoding === '') {
|
||
encoding = 'utf8';
|
||
}
|
||
|
||
if (!Buffer.isEncoding(encoding)) {
|
||
throw new TypeError('Unknown encoding: ' + encoding)
|
||
}
|
||
|
||
const length = byteLength(string, encoding) | 0;
|
||
let buf = createBuffer(length);
|
||
|
||
const actual = buf.write(string, encoding);
|
||
|
||
if (actual !== length) {
|
||
// Writing a hex string, for example, that contains invalid characters will
|
||
// cause everything after the first invalid character to be ignored. (e.g.
|
||
// 'abxxcd' will be treated as 'ab')
|
||
buf = buf.slice(0, actual);
|
||
}
|
||
|
||
return buf
|
||
}
|
||
|
||
function fromArrayLike (array) {
|
||
const length = array.length < 0 ? 0 : checked(array.length) | 0;
|
||
const buf = createBuffer(length);
|
||
for (let i = 0; i < length; i += 1) {
|
||
buf[i] = array[i] & 255;
|
||
}
|
||
return buf
|
||
}
|
||
|
||
function fromArrayView (arrayView) {
|
||
if (isInstance(arrayView, Uint8Array)) {
|
||
const copy = new Uint8Array(arrayView);
|
||
return fromArrayBuffer(copy.buffer, copy.byteOffset, copy.byteLength)
|
||
}
|
||
return fromArrayLike(arrayView)
|
||
}
|
||
|
||
function fromArrayBuffer (array, byteOffset, length) {
|
||
if (byteOffset < 0 || array.byteLength < byteOffset) {
|
||
throw new RangeError('"offset" is outside of buffer bounds')
|
||
}
|
||
|
||
if (array.byteLength < byteOffset + (length || 0)) {
|
||
throw new RangeError('"length" is outside of buffer bounds')
|
||
}
|
||
|
||
let buf;
|
||
if (byteOffset === undefined && length === undefined) {
|
||
buf = new Uint8Array(array);
|
||
} else if (length === undefined) {
|
||
buf = new Uint8Array(array, byteOffset);
|
||
} else {
|
||
buf = new Uint8Array(array, byteOffset, length);
|
||
}
|
||
|
||
// Return an augmented `Uint8Array` instance
|
||
Object.setPrototypeOf(buf, Buffer.prototype);
|
||
|
||
return buf
|
||
}
|
||
|
||
function fromObject (obj) {
|
||
if (Buffer.isBuffer(obj)) {
|
||
const len = checked(obj.length) | 0;
|
||
const buf = createBuffer(len);
|
||
|
||
if (buf.length === 0) {
|
||
return buf
|
||
}
|
||
|
||
obj.copy(buf, 0, 0, len);
|
||
return buf
|
||
}
|
||
|
||
if (obj.length !== undefined) {
|
||
if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
|
||
return createBuffer(0)
|
||
}
|
||
return fromArrayLike(obj)
|
||
}
|
||
|
||
if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
|
||
return fromArrayLike(obj.data)
|
||
}
|
||
}
|
||
|
||
function checked (length) {
|
||
// Note: cannot use `length < K_MAX_LENGTH` here because that fails when
|
||
// length is NaN (which is otherwise coerced to zero.)
|
||
if (length >= K_MAX_LENGTH) {
|
||
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
|
||
'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')
|
||
}
|
||
return length | 0
|
||
}
|
||
|
||
function SlowBuffer (length) {
|
||
if (+length != length) { // eslint-disable-line eqeqeq
|
||
length = 0;
|
||
}
|
||
return Buffer.alloc(+length)
|
||
}
|
||
|
||
Buffer.isBuffer = function isBuffer (b) {
|
||
return b != null && b._isBuffer === true &&
|
||
b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false
|
||
};
|
||
|
||
Buffer.compare = function compare (a, b) {
|
||
if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength);
|
||
if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength);
|
||
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
|
||
throw new TypeError(
|
||
'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'
|
||
)
|
||
}
|
||
|
||
if (a === b) return 0
|
||
|
||
let x = a.length;
|
||
let y = b.length;
|
||
|
||
for (let i = 0, len = Math.min(x, y); i < len; ++i) {
|
||
if (a[i] !== b[i]) {
|
||
x = a[i];
|
||
y = b[i];
|
||
break
|
||
}
|
||
}
|
||
|
||
if (x < y) return -1
|
||
if (y < x) return 1
|
||
return 0
|
||
};
|
||
|
||
Buffer.isEncoding = function isEncoding (encoding) {
|
||
switch (String(encoding).toLowerCase()) {
|
||
case 'hex':
|
||
case 'utf8':
|
||
case 'utf-8':
|
||
case 'ascii':
|
||
case 'latin1':
|
||
case 'binary':
|
||
case 'base64':
|
||
case 'ucs2':
|
||
case 'ucs-2':
|
||
case 'utf16le':
|
||
case 'utf-16le':
|
||
return true
|
||
default:
|
||
return false
|
||
}
|
||
};
|
||
|
||
Buffer.concat = function concat (list, length) {
|
||
if (!Array.isArray(list)) {
|
||
throw new TypeError('"list" argument must be an Array of Buffers')
|
||
}
|
||
|
||
if (list.length === 0) {
|
||
return Buffer.alloc(0)
|
||
}
|
||
|
||
let i;
|
||
if (length === undefined) {
|
||
length = 0;
|
||
for (i = 0; i < list.length; ++i) {
|
||
length += list[i].length;
|
||
}
|
||
}
|
||
|
||
const buffer = Buffer.allocUnsafe(length);
|
||
let pos = 0;
|
||
for (i = 0; i < list.length; ++i) {
|
||
let buf = list[i];
|
||
if (isInstance(buf, Uint8Array)) {
|
||
if (pos + buf.length > buffer.length) {
|
||
if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf);
|
||
buf.copy(buffer, pos);
|
||
} else {
|
||
Uint8Array.prototype.set.call(
|
||
buffer,
|
||
buf,
|
||
pos
|
||
);
|
||
}
|
||
} else if (!Buffer.isBuffer(buf)) {
|
||
throw new TypeError('"list" argument must be an Array of Buffers')
|
||
} else {
|
||
buf.copy(buffer, pos);
|
||
}
|
||
pos += buf.length;
|
||
}
|
||
return buffer
|
||
};
|
||
|
||
function byteLength (string, encoding) {
|
||
if (Buffer.isBuffer(string)) {
|
||
return string.length
|
||
}
|
||
if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {
|
||
return string.byteLength
|
||
}
|
||
if (typeof string !== 'string') {
|
||
throw new TypeError(
|
||
'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' +
|
||
'Received type ' + typeof string
|
||
)
|
||
}
|
||
|
||
const len = string.length;
|
||
const mustMatch = (arguments.length > 2 && arguments[2] === true);
|
||
if (!mustMatch && len === 0) return 0
|
||
|
||
// Use a for loop to avoid recursion
|
||
let loweredCase = false;
|
||
for (;;) {
|
||
switch (encoding) {
|
||
case 'ascii':
|
||
case 'latin1':
|
||
case 'binary':
|
||
return len
|
||
case 'utf8':
|
||
case 'utf-8':
|
||
return utf8ToBytes(string).length
|
||
case 'ucs2':
|
||
case 'ucs-2':
|
||
case 'utf16le':
|
||
case 'utf-16le':
|
||
return len * 2
|
||
case 'hex':
|
||
return len >>> 1
|
||
case 'base64':
|
||
return base64ToBytes(string).length
|
||
default:
|
||
if (loweredCase) {
|
||
return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8
|
||
}
|
||
encoding = ('' + encoding).toLowerCase();
|
||
loweredCase = true;
|
||
}
|
||
}
|
||
}
|
||
Buffer.byteLength = byteLength;
|
||
|
||
function slowToString (encoding, start, end) {
|
||
let loweredCase = false;
|
||
|
||
// No need to verify that "this.length <= MAX_UINT32" since it's a read-only
|
||
// property of a typed array.
|
||
|
||
// This behaves neither like String nor Uint8Array in that we set start/end
|
||
// to their upper/lower bounds if the value passed is out of range.
|
||
// undefined is handled specially as per ECMA-262 6th Edition,
|
||
// Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
|
||
if (start === undefined || start < 0) {
|
||
start = 0;
|
||
}
|
||
// Return early if start > this.length. Done here to prevent potential uint32
|
||
// coercion fail below.
|
||
if (start > this.length) {
|
||
return ''
|
||
}
|
||
|
||
if (end === undefined || end > this.length) {
|
||
end = this.length;
|
||
}
|
||
|
||
if (end <= 0) {
|
||
return ''
|
||
}
|
||
|
||
// Force coercion to uint32. This will also coerce falsey/NaN values to 0.
|
||
end >>>= 0;
|
||
start >>>= 0;
|
||
|
||
if (end <= start) {
|
||
return ''
|
||
}
|
||
|
||
if (!encoding) encoding = 'utf8';
|
||
|
||
while (true) {
|
||
switch (encoding) {
|
||
case 'hex':
|
||
return hexSlice(this, start, end)
|
||
|
||
case 'utf8':
|
||
case 'utf-8':
|
||
return utf8Slice(this, start, end)
|
||
|
||
case 'ascii':
|
||
return asciiSlice(this, start, end)
|
||
|
||
case 'latin1':
|
||
case 'binary':
|
||
return latin1Slice(this, start, end)
|
||
|
||
case 'base64':
|
||
return base64Slice(this, start, end)
|
||
|
||
case 'ucs2':
|
||
case 'ucs-2':
|
||
case 'utf16le':
|
||
case 'utf-16le':
|
||
return utf16leSlice(this, start, end)
|
||
|
||
default:
|
||
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
|
||
encoding = (encoding + '').toLowerCase();
|
||
loweredCase = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
|
||
// to detect a Buffer instance. It's not possible to use `instanceof Buffer`
|
||
// reliably in a browserify context because there could be multiple different
|
||
// copies of the 'buffer' package in use. This method works even for Buffer
|
||
// instances that were created from another copy of the `buffer` package.
|
||
// See: https://github.com/feross/buffer/issues/154
|
||
Buffer.prototype._isBuffer = true;
|
||
|
||
function swap (b, n, m) {
|
||
const i = b[n];
|
||
b[n] = b[m];
|
||
b[m] = i;
|
||
}
|
||
|
||
Buffer.prototype.swap16 = function swap16 () {
|
||
const len = this.length;
|
||
if (len % 2 !== 0) {
|
||
throw new RangeError('Buffer size must be a multiple of 16-bits')
|
||
}
|
||
for (let i = 0; i < len; i += 2) {
|
||
swap(this, i, i + 1);
|
||
}
|
||
return this
|
||
};
|
||
|
||
Buffer.prototype.swap32 = function swap32 () {
|
||
const len = this.length;
|
||
if (len % 4 !== 0) {
|
||
throw new RangeError('Buffer size must be a multiple of 32-bits')
|
||
}
|
||
for (let i = 0; i < len; i += 4) {
|
||
swap(this, i, i + 3);
|
||
swap(this, i + 1, i + 2);
|
||
}
|
||
return this
|
||
};
|
||
|
||
Buffer.prototype.swap64 = function swap64 () {
|
||
const len = this.length;
|
||
if (len % 8 !== 0) {
|
||
throw new RangeError('Buffer size must be a multiple of 64-bits')
|
||
}
|
||
for (let i = 0; i < len; i += 8) {
|
||
swap(this, i, i + 7);
|
||
swap(this, i + 1, i + 6);
|
||
swap(this, i + 2, i + 5);
|
||
swap(this, i + 3, i + 4);
|
||
}
|
||
return this
|
||
};
|
||
|
||
Buffer.prototype.toString = function toString () {
|
||
const length = this.length;
|
||
if (length === 0) return ''
|
||
if (arguments.length === 0) return utf8Slice(this, 0, length)
|
||
return slowToString.apply(this, arguments)
|
||
};
|
||
|
||
Buffer.prototype.toLocaleString = Buffer.prototype.toString;
|
||
|
||
Buffer.prototype.equals = function equals (b) {
|
||
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
|
||
if (this === b) return true
|
||
return Buffer.compare(this, b) === 0
|
||
};
|
||
|
||
Buffer.prototype.inspect = function inspect () {
|
||
let str = '';
|
||
const max = exports.INSPECT_MAX_BYTES;
|
||
str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim();
|
||
if (this.length > max) str += ' ... ';
|
||
return '<Buffer ' + str + '>'
|
||
};
|
||
if (customInspectSymbol) {
|
||
Buffer.prototype[customInspectSymbol] = Buffer.prototype.inspect;
|
||
}
|
||
|
||
Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
|
||
if (isInstance(target, Uint8Array)) {
|
||
target = Buffer.from(target, target.offset, target.byteLength);
|
||
}
|
||
if (!Buffer.isBuffer(target)) {
|
||
throw new TypeError(
|
||
'The "target" argument must be one of type Buffer or Uint8Array. ' +
|
||
'Received type ' + (typeof target)
|
||
)
|
||
}
|
||
|
||
if (start === undefined) {
|
||
start = 0;
|
||
}
|
||
if (end === undefined) {
|
||
end = target ? target.length : 0;
|
||
}
|
||
if (thisStart === undefined) {
|
||
thisStart = 0;
|
||
}
|
||
if (thisEnd === undefined) {
|
||
thisEnd = this.length;
|
||
}
|
||
|
||
if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
|
||
throw new RangeError('out of range index')
|
||
}
|
||
|
||
if (thisStart >= thisEnd && start >= end) {
|
||
return 0
|
||
}
|
||
if (thisStart >= thisEnd) {
|
||
return -1
|
||
}
|
||
if (start >= end) {
|
||
return 1
|
||
}
|
||
|
||
start >>>= 0;
|
||
end >>>= 0;
|
||
thisStart >>>= 0;
|
||
thisEnd >>>= 0;
|
||
|
||
if (this === target) return 0
|
||
|
||
let x = thisEnd - thisStart;
|
||
let y = end - start;
|
||
const len = Math.min(x, y);
|
||
|
||
const thisCopy = this.slice(thisStart, thisEnd);
|
||
const targetCopy = target.slice(start, end);
|
||
|
||
for (let i = 0; i < len; ++i) {
|
||
if (thisCopy[i] !== targetCopy[i]) {
|
||
x = thisCopy[i];
|
||
y = targetCopy[i];
|
||
break
|
||
}
|
||
}
|
||
|
||
if (x < y) return -1
|
||
if (y < x) return 1
|
||
return 0
|
||
};
|
||
|
||
// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
|
||
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
|
||
//
|
||
// Arguments:
|
||
// - buffer - a Buffer to search
|
||
// - val - a string, Buffer, or number
|
||
// - byteOffset - an index into `buffer`; will be clamped to an int32
|
||
// - encoding - an optional encoding, relevant is val is a string
|
||
// - dir - true for indexOf, false for lastIndexOf
|
||
function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
|
||
// Empty buffer means no match
|
||
if (buffer.length === 0) return -1
|
||
|
||
// Normalize byteOffset
|
||
if (typeof byteOffset === 'string') {
|
||
encoding = byteOffset;
|
||
byteOffset = 0;
|
||
} else if (byteOffset > 0x7fffffff) {
|
||
byteOffset = 0x7fffffff;
|
||
} else if (byteOffset < -0x80000000) {
|
||
byteOffset = -0x80000000;
|
||
}
|
||
byteOffset = +byteOffset; // Coerce to Number.
|
||
if (numberIsNaN(byteOffset)) {
|
||
// byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
|
||
byteOffset = dir ? 0 : (buffer.length - 1);
|
||
}
|
||
|
||
// Normalize byteOffset: negative offsets start from the end of the buffer
|
||
if (byteOffset < 0) byteOffset = buffer.length + byteOffset;
|
||
if (byteOffset >= buffer.length) {
|
||
if (dir) return -1
|
||
else byteOffset = buffer.length - 1;
|
||
} else if (byteOffset < 0) {
|
||
if (dir) byteOffset = 0;
|
||
else return -1
|
||
}
|
||
|
||
// Normalize val
|
||
if (typeof val === 'string') {
|
||
val = Buffer.from(val, encoding);
|
||
}
|
||
|
||
// Finally, search either indexOf (if dir is true) or lastIndexOf
|
||
if (Buffer.isBuffer(val)) {
|
||
// Special case: looking for empty string/buffer always fails
|
||
if (val.length === 0) {
|
||
return -1
|
||
}
|
||
return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
|
||
} else if (typeof val === 'number') {
|
||
val = val & 0xFF; // Search for a byte value [0-255]
|
||
if (typeof Uint8Array.prototype.indexOf === 'function') {
|
||
if (dir) {
|
||
return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
|
||
} else {
|
||
return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
|
||
}
|
||
}
|
||
return arrayIndexOf(buffer, [val], byteOffset, encoding, dir)
|
||
}
|
||
|
||
throw new TypeError('val must be string, number or Buffer')
|
||
}
|
||
|
||
function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
|
||
let indexSize = 1;
|
||
let arrLength = arr.length;
|
||
let valLength = val.length;
|
||
|
||
if (encoding !== undefined) {
|
||
encoding = String(encoding).toLowerCase();
|
||
if (encoding === 'ucs2' || encoding === 'ucs-2' ||
|
||
encoding === 'utf16le' || encoding === 'utf-16le') {
|
||
if (arr.length < 2 || val.length < 2) {
|
||
return -1
|
||
}
|
||
indexSize = 2;
|
||
arrLength /= 2;
|
||
valLength /= 2;
|
||
byteOffset /= 2;
|
||
}
|
||
}
|
||
|
||
function read (buf, i) {
|
||
if (indexSize === 1) {
|
||
return buf[i]
|
||
} else {
|
||
return buf.readUInt16BE(i * indexSize)
|
||
}
|
||
}
|
||
|
||
let i;
|
||
if (dir) {
|
||
let foundIndex = -1;
|
||
for (i = byteOffset; i < arrLength; i++) {
|
||
if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
|
||
if (foundIndex === -1) foundIndex = i;
|
||
if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
|
||
} else {
|
||
if (foundIndex !== -1) i -= i - foundIndex;
|
||
foundIndex = -1;
|
||
}
|
||
}
|
||
} else {
|
||
if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;
|
||
for (i = byteOffset; i >= 0; i--) {
|
||
let found = true;
|
||
for (let j = 0; j < valLength; j++) {
|
||
if (read(arr, i + j) !== read(val, j)) {
|
||
found = false;
|
||
break
|
||
}
|
||
}
|
||
if (found) return i
|
||
}
|
||
}
|
||
|
||
return -1
|
||
}
|
||
|
||
Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
|
||
return this.indexOf(val, byteOffset, encoding) !== -1
|
||
};
|
||
|
||
Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
|
||
return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
|
||
};
|
||
|
||
Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
|
||
return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
|
||
};
|
||
|
||
function hexWrite (buf, string, offset, length) {
|
||
offset = Number(offset) || 0;
|
||
const remaining = buf.length - offset;
|
||
if (!length) {
|
||
length = remaining;
|
||
} else {
|
||
length = Number(length);
|
||
if (length > remaining) {
|
||
length = remaining;
|
||
}
|
||
}
|
||
|
||
const strLen = string.length;
|
||
|
||
if (length > strLen / 2) {
|
||
length = strLen / 2;
|
||
}
|
||
let i;
|
||
for (i = 0; i < length; ++i) {
|
||
const parsed = parseInt(string.substr(i * 2, 2), 16);
|
||
if (numberIsNaN(parsed)) return i
|
||
buf[offset + i] = parsed;
|
||
}
|
||
return i
|
||
}
|
||
|
||
function utf8Write (buf, string, offset, length) {
|
||
return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
|
||
}
|
||
|
||
function asciiWrite (buf, string, offset, length) {
|
||
return blitBuffer(asciiToBytes(string), buf, offset, length)
|
||
}
|
||
|
||
function base64Write (buf, string, offset, length) {
|
||
return blitBuffer(base64ToBytes(string), buf, offset, length)
|
||
}
|
||
|
||
function ucs2Write (buf, string, offset, length) {
|
||
return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
|
||
}
|
||
|
||
Buffer.prototype.write = function write (string, offset, length, encoding) {
|
||
// Buffer#write(string)
|
||
if (offset === undefined) {
|
||
encoding = 'utf8';
|
||
length = this.length;
|
||
offset = 0;
|
||
// Buffer#write(string, encoding)
|
||
} else if (length === undefined && typeof offset === 'string') {
|
||
encoding = offset;
|
||
length = this.length;
|
||
offset = 0;
|
||
// Buffer#write(string, offset[, length][, encoding])
|
||
} else if (isFinite(offset)) {
|
||
offset = offset >>> 0;
|
||
if (isFinite(length)) {
|
||
length = length >>> 0;
|
||
if (encoding === undefined) encoding = 'utf8';
|
||
} else {
|
||
encoding = length;
|
||
length = undefined;
|
||
}
|
||
} else {
|
||
throw new Error(
|
||
'Buffer.write(string, encoding, offset[, length]) is no longer supported'
|
||
)
|
||
}
|
||
|
||
const remaining = this.length - offset;
|
||
if (length === undefined || length > remaining) length = remaining;
|
||
|
||
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
|
||
throw new RangeError('Attempt to write outside buffer bounds')
|
||
}
|
||
|
||
if (!encoding) encoding = 'utf8';
|
||
|
||
let loweredCase = false;
|
||
for (;;) {
|
||
switch (encoding) {
|
||
case 'hex':
|
||
return hexWrite(this, string, offset, length)
|
||
|
||
case 'utf8':
|
||
case 'utf-8':
|
||
return utf8Write(this, string, offset, length)
|
||
|
||
case 'ascii':
|
||
case 'latin1':
|
||
case 'binary':
|
||
return asciiWrite(this, string, offset, length)
|
||
|
||
case 'base64':
|
||
// Warning: maxLength not taken into account in base64Write
|
||
return base64Write(this, string, offset, length)
|
||
|
||
case 'ucs2':
|
||
case 'ucs-2':
|
||
case 'utf16le':
|
||
case 'utf-16le':
|
||
return ucs2Write(this, string, offset, length)
|
||
|
||
default:
|
||
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
|
||
encoding = ('' + encoding).toLowerCase();
|
||
loweredCase = true;
|
||
}
|
||
}
|
||
};
|
||
|
||
Buffer.prototype.toJSON = function toJSON () {
|
||
return {
|
||
type: 'Buffer',
|
||
data: Array.prototype.slice.call(this._arr || this, 0)
|
||
}
|
||
};
|
||
|
||
function base64Slice (buf, start, end) {
|
||
if (start === 0 && end === buf.length) {
|
||
return base64.fromByteArray(buf)
|
||
} else {
|
||
return base64.fromByteArray(buf.slice(start, end))
|
||
}
|
||
}
|
||
|
||
function utf8Slice (buf, start, end) {
|
||
end = Math.min(buf.length, end);
|
||
const res = [];
|
||
|
||
let i = start;
|
||
while (i < end) {
|
||
const firstByte = buf[i];
|
||
let codePoint = null;
|
||
let bytesPerSequence = (firstByte > 0xEF)
|
||
? 4
|
||
: (firstByte > 0xDF)
|
||
? 3
|
||
: (firstByte > 0xBF)
|
||
? 2
|
||
: 1;
|
||
|
||
if (i + bytesPerSequence <= end) {
|
||
let secondByte, thirdByte, fourthByte, tempCodePoint;
|
||
|
||
switch (bytesPerSequence) {
|
||
case 1:
|
||
if (firstByte < 0x80) {
|
||
codePoint = firstByte;
|
||
}
|
||
break
|
||
case 2:
|
||
secondByte = buf[i + 1];
|
||
if ((secondByte & 0xC0) === 0x80) {
|
||
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F);
|
||
if (tempCodePoint > 0x7F) {
|
||
codePoint = tempCodePoint;
|
||
}
|
||
}
|
||
break
|
||
case 3:
|
||
secondByte = buf[i + 1];
|
||
thirdByte = buf[i + 2];
|
||
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
|
||
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F);
|
||
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
|
||
codePoint = tempCodePoint;
|
||
}
|
||
}
|
||
break
|
||
case 4:
|
||
secondByte = buf[i + 1];
|
||
thirdByte = buf[i + 2];
|
||
fourthByte = buf[i + 3];
|
||
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
|
||
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F);
|
||
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
|
||
codePoint = tempCodePoint;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (codePoint === null) {
|
||
// we did not generate a valid codePoint so insert a
|
||
// replacement char (U+FFFD) and advance only 1 byte
|
||
codePoint = 0xFFFD;
|
||
bytesPerSequence = 1;
|
||
} else if (codePoint > 0xFFFF) {
|
||
// encode to utf16 (surrogate pair dance)
|
||
codePoint -= 0x10000;
|
||
res.push(codePoint >>> 10 & 0x3FF | 0xD800);
|
||
codePoint = 0xDC00 | codePoint & 0x3FF;
|
||
}
|
||
|
||
res.push(codePoint);
|
||
i += bytesPerSequence;
|
||
}
|
||
|
||
return decodeCodePointsArray(res)
|
||
}
|
||
|
||
// Based on http://stackoverflow.com/a/22747272/680742, the browser with
|
||
// the lowest limit is Chrome, with 0x10000 args.
|
||
// We go 1 magnitude less, for safety
|
||
const MAX_ARGUMENTS_LENGTH = 0x1000;
|
||
|
||
function decodeCodePointsArray (codePoints) {
|
||
const len = codePoints.length;
|
||
if (len <= MAX_ARGUMENTS_LENGTH) {
|
||
return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
|
||
}
|
||
|
||
// Decode in chunks to avoid "call stack size exceeded".
|
||
let res = '';
|
||
let i = 0;
|
||
while (i < len) {
|
||
res += String.fromCharCode.apply(
|
||
String,
|
||
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
|
||
);
|
||
}
|
||
return res
|
||
}
|
||
|
||
function asciiSlice (buf, start, end) {
|
||
let ret = '';
|
||
end = Math.min(buf.length, end);
|
||
|
||
for (let i = start; i < end; ++i) {
|
||
ret += String.fromCharCode(buf[i] & 0x7F);
|
||
}
|
||
return ret
|
||
}
|
||
|
||
function latin1Slice (buf, start, end) {
|
||
let ret = '';
|
||
end = Math.min(buf.length, end);
|
||
|
||
for (let i = start; i < end; ++i) {
|
||
ret += String.fromCharCode(buf[i]);
|
||
}
|
||
return ret
|
||
}
|
||
|
||
function hexSlice (buf, start, end) {
|
||
const len = buf.length;
|
||
|
||
if (!start || start < 0) start = 0;
|
||
if (!end || end < 0 || end > len) end = len;
|
||
|
||
let out = '';
|
||
for (let i = start; i < end; ++i) {
|
||
out += hexSliceLookupTable[buf[i]];
|
||
}
|
||
return out
|
||
}
|
||
|
||
function utf16leSlice (buf, start, end) {
|
||
const bytes = buf.slice(start, end);
|
||
let res = '';
|
||
// If bytes.length is odd, the last 8 bits must be ignored (same as node.js)
|
||
for (let i = 0; i < bytes.length - 1; i += 2) {
|
||
res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256));
|
||
}
|
||
return res
|
||
}
|
||
|
||
Buffer.prototype.slice = function slice (start, end) {
|
||
const len = this.length;
|
||
start = ~~start;
|
||
end = end === undefined ? len : ~~end;
|
||
|
||
if (start < 0) {
|
||
start += len;
|
||
if (start < 0) start = 0;
|
||
} else if (start > len) {
|
||
start = len;
|
||
}
|
||
|
||
if (end < 0) {
|
||
end += len;
|
||
if (end < 0) end = 0;
|
||
} else if (end > len) {
|
||
end = len;
|
||
}
|
||
|
||
if (end < start) end = start;
|
||
|
||
const newBuf = this.subarray(start, end);
|
||
// Return an augmented `Uint8Array` instance
|
||
Object.setPrototypeOf(newBuf, Buffer.prototype);
|
||
|
||
return newBuf
|
||
};
|
||
|
||
/*
|
||
* Need to make sure that buffer isn't trying to write out of bounds.
|
||
*/
|
||
function checkOffset (offset, ext, length) {
|
||
if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
|
||
if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
|
||
}
|
||
|
||
Buffer.prototype.readUintLE =
|
||
Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
|
||
offset = offset >>> 0;
|
||
byteLength = byteLength >>> 0;
|
||
if (!noAssert) checkOffset(offset, byteLength, this.length);
|
||
|
||
let val = this[offset];
|
||
let mul = 1;
|
||
let i = 0;
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
val += this[offset + i] * mul;
|
||
}
|
||
|
||
return val
|
||
};
|
||
|
||
Buffer.prototype.readUintBE =
|
||
Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
|
||
offset = offset >>> 0;
|
||
byteLength = byteLength >>> 0;
|
||
if (!noAssert) {
|
||
checkOffset(offset, byteLength, this.length);
|
||
}
|
||
|
||
let val = this[offset + --byteLength];
|
||
let mul = 1;
|
||
while (byteLength > 0 && (mul *= 0x100)) {
|
||
val += this[offset + --byteLength] * mul;
|
||
}
|
||
|
||
return val
|
||
};
|
||
|
||
Buffer.prototype.readUint8 =
|
||
Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 1, this.length);
|
||
return this[offset]
|
||
};
|
||
|
||
Buffer.prototype.readUint16LE =
|
||
Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 2, this.length);
|
||
return this[offset] | (this[offset + 1] << 8)
|
||
};
|
||
|
||
Buffer.prototype.readUint16BE =
|
||
Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 2, this.length);
|
||
return (this[offset] << 8) | this[offset + 1]
|
||
};
|
||
|
||
Buffer.prototype.readUint32LE =
|
||
Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 4, this.length);
|
||
|
||
return ((this[offset]) |
|
||
(this[offset + 1] << 8) |
|
||
(this[offset + 2] << 16)) +
|
||
(this[offset + 3] * 0x1000000)
|
||
};
|
||
|
||
Buffer.prototype.readUint32BE =
|
||
Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 4, this.length);
|
||
|
||
return (this[offset] * 0x1000000) +
|
||
((this[offset + 1] << 16) |
|
||
(this[offset + 2] << 8) |
|
||
this[offset + 3])
|
||
};
|
||
|
||
Buffer.prototype.readBigUInt64LE = defineBigIntMethod(function readBigUInt64LE (offset) {
|
||
offset = offset >>> 0;
|
||
validateNumber(offset, 'offset');
|
||
const first = this[offset];
|
||
const last = this[offset + 7];
|
||
if (first === undefined || last === undefined) {
|
||
boundsError(offset, this.length - 8);
|
||
}
|
||
|
||
const lo = first +
|
||
this[++offset] * 2 ** 8 +
|
||
this[++offset] * 2 ** 16 +
|
||
this[++offset] * 2 ** 24;
|
||
|
||
const hi = this[++offset] +
|
||
this[++offset] * 2 ** 8 +
|
||
this[++offset] * 2 ** 16 +
|
||
last * 2 ** 24;
|
||
|
||
return BigInt(lo) + (BigInt(hi) << BigInt(32))
|
||
});
|
||
|
||
Buffer.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE (offset) {
|
||
offset = offset >>> 0;
|
||
validateNumber(offset, 'offset');
|
||
const first = this[offset];
|
||
const last = this[offset + 7];
|
||
if (first === undefined || last === undefined) {
|
||
boundsError(offset, this.length - 8);
|
||
}
|
||
|
||
const hi = first * 2 ** 24 +
|
||
this[++offset] * 2 ** 16 +
|
||
this[++offset] * 2 ** 8 +
|
||
this[++offset];
|
||
|
||
const lo = this[++offset] * 2 ** 24 +
|
||
this[++offset] * 2 ** 16 +
|
||
this[++offset] * 2 ** 8 +
|
||
last;
|
||
|
||
return (BigInt(hi) << BigInt(32)) + BigInt(lo)
|
||
});
|
||
|
||
Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
|
||
offset = offset >>> 0;
|
||
byteLength = byteLength >>> 0;
|
||
if (!noAssert) checkOffset(offset, byteLength, this.length);
|
||
|
||
let val = this[offset];
|
||
let mul = 1;
|
||
let i = 0;
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
val += this[offset + i] * mul;
|
||
}
|
||
mul *= 0x80;
|
||
|
||
if (val >= mul) val -= Math.pow(2, 8 * byteLength);
|
||
|
||
return val
|
||
};
|
||
|
||
Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
|
||
offset = offset >>> 0;
|
||
byteLength = byteLength >>> 0;
|
||
if (!noAssert) checkOffset(offset, byteLength, this.length);
|
||
|
||
let i = byteLength;
|
||
let mul = 1;
|
||
let val = this[offset + --i];
|
||
while (i > 0 && (mul *= 0x100)) {
|
||
val += this[offset + --i] * mul;
|
||
}
|
||
mul *= 0x80;
|
||
|
||
if (val >= mul) val -= Math.pow(2, 8 * byteLength);
|
||
|
||
return val
|
||
};
|
||
|
||
Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 1, this.length);
|
||
if (!(this[offset] & 0x80)) return (this[offset])
|
||
return ((0xff - this[offset] + 1) * -1)
|
||
};
|
||
|
||
Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 2, this.length);
|
||
const val = this[offset] | (this[offset + 1] << 8);
|
||
return (val & 0x8000) ? val | 0xFFFF0000 : val
|
||
};
|
||
|
||
Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 2, this.length);
|
||
const val = this[offset + 1] | (this[offset] << 8);
|
||
return (val & 0x8000) ? val | 0xFFFF0000 : val
|
||
};
|
||
|
||
Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 4, this.length);
|
||
|
||
return (this[offset]) |
|
||
(this[offset + 1] << 8) |
|
||
(this[offset + 2] << 16) |
|
||
(this[offset + 3] << 24)
|
||
};
|
||
|
||
Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 4, this.length);
|
||
|
||
return (this[offset] << 24) |
|
||
(this[offset + 1] << 16) |
|
||
(this[offset + 2] << 8) |
|
||
(this[offset + 3])
|
||
};
|
||
|
||
Buffer.prototype.readBigInt64LE = defineBigIntMethod(function readBigInt64LE (offset) {
|
||
offset = offset >>> 0;
|
||
validateNumber(offset, 'offset');
|
||
const first = this[offset];
|
||
const last = this[offset + 7];
|
||
if (first === undefined || last === undefined) {
|
||
boundsError(offset, this.length - 8);
|
||
}
|
||
|
||
const val = this[offset + 4] +
|
||
this[offset + 5] * 2 ** 8 +
|
||
this[offset + 6] * 2 ** 16 +
|
||
(last << 24); // Overflow
|
||
|
||
return (BigInt(val) << BigInt(32)) +
|
||
BigInt(first +
|
||
this[++offset] * 2 ** 8 +
|
||
this[++offset] * 2 ** 16 +
|
||
this[++offset] * 2 ** 24)
|
||
});
|
||
|
||
Buffer.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE (offset) {
|
||
offset = offset >>> 0;
|
||
validateNumber(offset, 'offset');
|
||
const first = this[offset];
|
||
const last = this[offset + 7];
|
||
if (first === undefined || last === undefined) {
|
||
boundsError(offset, this.length - 8);
|
||
}
|
||
|
||
const val = (first << 24) + // Overflow
|
||
this[++offset] * 2 ** 16 +
|
||
this[++offset] * 2 ** 8 +
|
||
this[++offset];
|
||
|
||
return (BigInt(val) << BigInt(32)) +
|
||
BigInt(this[++offset] * 2 ** 24 +
|
||
this[++offset] * 2 ** 16 +
|
||
this[++offset] * 2 ** 8 +
|
||
last)
|
||
});
|
||
|
||
Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 4, this.length);
|
||
return ieee754$1.read(this, offset, true, 23, 4)
|
||
};
|
||
|
||
Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 4, this.length);
|
||
return ieee754$1.read(this, offset, false, 23, 4)
|
||
};
|
||
|
||
Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 8, this.length);
|
||
return ieee754$1.read(this, offset, true, 52, 8)
|
||
};
|
||
|
||
Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkOffset(offset, 8, this.length);
|
||
return ieee754$1.read(this, offset, false, 52, 8)
|
||
};
|
||
|
||
function checkInt (buf, value, offset, ext, max, min) {
|
||
if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
|
||
if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
|
||
if (offset + ext > buf.length) throw new RangeError('Index out of range')
|
||
}
|
||
|
||
Buffer.prototype.writeUintLE =
|
||
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
byteLength = byteLength >>> 0;
|
||
if (!noAssert) {
|
||
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
||
checkInt(this, value, offset, byteLength, maxBytes, 0);
|
||
}
|
||
|
||
let mul = 1;
|
||
let i = 0;
|
||
this[offset] = value & 0xFF;
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
this[offset + i] = (value / mul) & 0xFF;
|
||
}
|
||
|
||
return offset + byteLength
|
||
};
|
||
|
||
Buffer.prototype.writeUintBE =
|
||
Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
byteLength = byteLength >>> 0;
|
||
if (!noAssert) {
|
||
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
||
checkInt(this, value, offset, byteLength, maxBytes, 0);
|
||
}
|
||
|
||
let i = byteLength - 1;
|
||
let mul = 1;
|
||
this[offset + i] = value & 0xFF;
|
||
while (--i >= 0 && (mul *= 0x100)) {
|
||
this[offset + i] = (value / mul) & 0xFF;
|
||
}
|
||
|
||
return offset + byteLength
|
||
};
|
||
|
||
Buffer.prototype.writeUint8 =
|
||
Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0);
|
||
this[offset] = (value & 0xff);
|
||
return offset + 1
|
||
};
|
||
|
||
Buffer.prototype.writeUint16LE =
|
||
Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);
|
||
this[offset] = (value & 0xff);
|
||
this[offset + 1] = (value >>> 8);
|
||
return offset + 2
|
||
};
|
||
|
||
Buffer.prototype.writeUint16BE =
|
||
Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);
|
||
this[offset] = (value >>> 8);
|
||
this[offset + 1] = (value & 0xff);
|
||
return offset + 2
|
||
};
|
||
|
||
Buffer.prototype.writeUint32LE =
|
||
Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);
|
||
this[offset + 3] = (value >>> 24);
|
||
this[offset + 2] = (value >>> 16);
|
||
this[offset + 1] = (value >>> 8);
|
||
this[offset] = (value & 0xff);
|
||
return offset + 4
|
||
};
|
||
|
||
Buffer.prototype.writeUint32BE =
|
||
Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);
|
||
this[offset] = (value >>> 24);
|
||
this[offset + 1] = (value >>> 16);
|
||
this[offset + 2] = (value >>> 8);
|
||
this[offset + 3] = (value & 0xff);
|
||
return offset + 4
|
||
};
|
||
|
||
function wrtBigUInt64LE (buf, value, offset, min, max) {
|
||
checkIntBI(value, min, max, buf, offset, 7);
|
||
|
||
let lo = Number(value & BigInt(0xffffffff));
|
||
buf[offset++] = lo;
|
||
lo = lo >> 8;
|
||
buf[offset++] = lo;
|
||
lo = lo >> 8;
|
||
buf[offset++] = lo;
|
||
lo = lo >> 8;
|
||
buf[offset++] = lo;
|
||
let hi = Number(value >> BigInt(32) & BigInt(0xffffffff));
|
||
buf[offset++] = hi;
|
||
hi = hi >> 8;
|
||
buf[offset++] = hi;
|
||
hi = hi >> 8;
|
||
buf[offset++] = hi;
|
||
hi = hi >> 8;
|
||
buf[offset++] = hi;
|
||
return offset
|
||
}
|
||
|
||
function wrtBigUInt64BE (buf, value, offset, min, max) {
|
||
checkIntBI(value, min, max, buf, offset, 7);
|
||
|
||
let lo = Number(value & BigInt(0xffffffff));
|
||
buf[offset + 7] = lo;
|
||
lo = lo >> 8;
|
||
buf[offset + 6] = lo;
|
||
lo = lo >> 8;
|
||
buf[offset + 5] = lo;
|
||
lo = lo >> 8;
|
||
buf[offset + 4] = lo;
|
||
let hi = Number(value >> BigInt(32) & BigInt(0xffffffff));
|
||
buf[offset + 3] = hi;
|
||
hi = hi >> 8;
|
||
buf[offset + 2] = hi;
|
||
hi = hi >> 8;
|
||
buf[offset + 1] = hi;
|
||
hi = hi >> 8;
|
||
buf[offset] = hi;
|
||
return offset + 8
|
||
}
|
||
|
||
Buffer.prototype.writeBigUInt64LE = defineBigIntMethod(function writeBigUInt64LE (value, offset = 0) {
|
||
return wrtBigUInt64LE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff'))
|
||
});
|
||
|
||
Buffer.prototype.writeBigUInt64BE = defineBigIntMethod(function writeBigUInt64BE (value, offset = 0) {
|
||
return wrtBigUInt64BE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff'))
|
||
});
|
||
|
||
Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) {
|
||
const limit = Math.pow(2, (8 * byteLength) - 1);
|
||
|
||
checkInt(this, value, offset, byteLength, limit - 1, -limit);
|
||
}
|
||
|
||
let i = 0;
|
||
let mul = 1;
|
||
let sub = 0;
|
||
this[offset] = value & 0xFF;
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
|
||
sub = 1;
|
||
}
|
||
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;
|
||
}
|
||
|
||
return offset + byteLength
|
||
};
|
||
|
||
Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) {
|
||
const limit = Math.pow(2, (8 * byteLength) - 1);
|
||
|
||
checkInt(this, value, offset, byteLength, limit - 1, -limit);
|
||
}
|
||
|
||
let i = byteLength - 1;
|
||
let mul = 1;
|
||
let sub = 0;
|
||
this[offset + i] = value & 0xFF;
|
||
while (--i >= 0 && (mul *= 0x100)) {
|
||
if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
|
||
sub = 1;
|
||
}
|
||
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;
|
||
}
|
||
|
||
return offset + byteLength
|
||
};
|
||
|
||
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80);
|
||
if (value < 0) value = 0xff + value + 1;
|
||
this[offset] = (value & 0xff);
|
||
return offset + 1
|
||
};
|
||
|
||
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
|
||
this[offset] = (value & 0xff);
|
||
this[offset + 1] = (value >>> 8);
|
||
return offset + 2
|
||
};
|
||
|
||
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
|
||
this[offset] = (value >>> 8);
|
||
this[offset + 1] = (value & 0xff);
|
||
return offset + 2
|
||
};
|
||
|
||
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
|
||
this[offset] = (value & 0xff);
|
||
this[offset + 1] = (value >>> 8);
|
||
this[offset + 2] = (value >>> 16);
|
||
this[offset + 3] = (value >>> 24);
|
||
return offset + 4
|
||
};
|
||
|
||
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
|
||
if (value < 0) value = 0xffffffff + value + 1;
|
||
this[offset] = (value >>> 24);
|
||
this[offset + 1] = (value >>> 16);
|
||
this[offset + 2] = (value >>> 8);
|
||
this[offset + 3] = (value & 0xff);
|
||
return offset + 4
|
||
};
|
||
|
||
Buffer.prototype.writeBigInt64LE = defineBigIntMethod(function writeBigInt64LE (value, offset = 0) {
|
||
return wrtBigUInt64LE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff'))
|
||
});
|
||
|
||
Buffer.prototype.writeBigInt64BE = defineBigIntMethod(function writeBigInt64BE (value, offset = 0) {
|
||
return wrtBigUInt64BE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff'))
|
||
});
|
||
|
||
function checkIEEE754 (buf, value, offset, ext, max, min) {
|
||
if (offset + ext > buf.length) throw new RangeError('Index out of range')
|
||
if (offset < 0) throw new RangeError('Index out of range')
|
||
}
|
||
|
||
function writeFloat (buf, value, offset, littleEndian, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) {
|
||
checkIEEE754(buf, value, offset, 4);
|
||
}
|
||
ieee754$1.write(buf, value, offset, littleEndian, 23, 4);
|
||
return offset + 4
|
||
}
|
||
|
||
Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
|
||
return writeFloat(this, value, offset, true, noAssert)
|
||
};
|
||
|
||
Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
|
||
return writeFloat(this, value, offset, false, noAssert)
|
||
};
|
||
|
||
function writeDouble (buf, value, offset, littleEndian, noAssert) {
|
||
value = +value;
|
||
offset = offset >>> 0;
|
||
if (!noAssert) {
|
||
checkIEEE754(buf, value, offset, 8);
|
||
}
|
||
ieee754$1.write(buf, value, offset, littleEndian, 52, 8);
|
||
return offset + 8
|
||
}
|
||
|
||
Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
|
||
return writeDouble(this, value, offset, true, noAssert)
|
||
};
|
||
|
||
Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
|
||
return writeDouble(this, value, offset, false, noAssert)
|
||
};
|
||
|
||
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
||
Buffer.prototype.copy = function copy (target, targetStart, start, end) {
|
||
if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer')
|
||
if (!start) start = 0;
|
||
if (!end && end !== 0) end = this.length;
|
||
if (targetStart >= target.length) targetStart = target.length;
|
||
if (!targetStart) targetStart = 0;
|
||
if (end > 0 && end < start) end = start;
|
||
|
||
// Copy 0 bytes; we're done
|
||
if (end === start) return 0
|
||
if (target.length === 0 || this.length === 0) return 0
|
||
|
||
// Fatal error conditions
|
||
if (targetStart < 0) {
|
||
throw new RangeError('targetStart out of bounds')
|
||
}
|
||
if (start < 0 || start >= this.length) throw new RangeError('Index out of range')
|
||
if (end < 0) throw new RangeError('sourceEnd out of bounds')
|
||
|
||
// Are we oob?
|
||
if (end > this.length) end = this.length;
|
||
if (target.length - targetStart < end - start) {
|
||
end = target.length - targetStart + start;
|
||
}
|
||
|
||
const len = end - start;
|
||
|
||
if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {
|
||
// Use built-in when available, missing from IE11
|
||
this.copyWithin(targetStart, start, end);
|
||
} else {
|
||
Uint8Array.prototype.set.call(
|
||
target,
|
||
this.subarray(start, end),
|
||
targetStart
|
||
);
|
||
}
|
||
|
||
return len
|
||
};
|
||
|
||
// Usage:
|
||
// buffer.fill(number[, offset[, end]])
|
||
// buffer.fill(buffer[, offset[, end]])
|
||
// buffer.fill(string[, offset[, end]][, encoding])
|
||
Buffer.prototype.fill = function fill (val, start, end, encoding) {
|
||
// Handle string cases:
|
||
if (typeof val === 'string') {
|
||
if (typeof start === 'string') {
|
||
encoding = start;
|
||
start = 0;
|
||
end = this.length;
|
||
} else if (typeof end === 'string') {
|
||
encoding = end;
|
||
end = this.length;
|
||
}
|
||
if (encoding !== undefined && typeof encoding !== 'string') {
|
||
throw new TypeError('encoding must be a string')
|
||
}
|
||
if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
|
||
throw new TypeError('Unknown encoding: ' + encoding)
|
||
}
|
||
if (val.length === 1) {
|
||
const code = val.charCodeAt(0);
|
||
if ((encoding === 'utf8' && code < 128) ||
|
||
encoding === 'latin1') {
|
||
// Fast path: If `val` fits into a single byte, use that numeric value.
|
||
val = code;
|
||
}
|
||
}
|
||
} else if (typeof val === 'number') {
|
||
val = val & 255;
|
||
} else if (typeof val === 'boolean') {
|
||
val = Number(val);
|
||
}
|
||
|
||
// Invalid ranges are not set to a default, so can range check early.
|
||
if (start < 0 || this.length < start || this.length < end) {
|
||
throw new RangeError('Out of range index')
|
||
}
|
||
|
||
if (end <= start) {
|
||
return this
|
||
}
|
||
|
||
start = start >>> 0;
|
||
end = end === undefined ? this.length : end >>> 0;
|
||
|
||
if (!val) val = 0;
|
||
|
||
let i;
|
||
if (typeof val === 'number') {
|
||
for (i = start; i < end; ++i) {
|
||
this[i] = val;
|
||
}
|
||
} else {
|
||
const bytes = Buffer.isBuffer(val)
|
||
? val
|
||
: Buffer.from(val, encoding);
|
||
const len = bytes.length;
|
||
if (len === 0) {
|
||
throw new TypeError('The value "' + val +
|
||
'" is invalid for argument "value"')
|
||
}
|
||
for (i = 0; i < end - start; ++i) {
|
||
this[i + start] = bytes[i % len];
|
||
}
|
||
}
|
||
|
||
return this
|
||
};
|
||
|
||
// CUSTOM ERRORS
|
||
// =============
|
||
|
||
// Simplified versions from Node, changed for Buffer-only usage
|
||
const errors = {};
|
||
function E (sym, getMessage, Base) {
|
||
errors[sym] = class NodeError extends Base {
|
||
constructor () {
|
||
super();
|
||
|
||
Object.defineProperty(this, 'message', {
|
||
value: getMessage.apply(this, arguments),
|
||
writable: true,
|
||
configurable: true
|
||
});
|
||
|
||
// Add the error code to the name to include it in the stack trace.
|
||
this.name = `${this.name} [${sym}]`;
|
||
// Access the stack to generate the error message including the error code
|
||
// from the name.
|
||
this.stack; // eslint-disable-line no-unused-expressions
|
||
// Reset the name to the actual name.
|
||
delete this.name;
|
||
}
|
||
|
||
get code () {
|
||
return sym
|
||
}
|
||
|
||
set code (value) {
|
||
Object.defineProperty(this, 'code', {
|
||
configurable: true,
|
||
enumerable: true,
|
||
value,
|
||
writable: true
|
||
});
|
||
}
|
||
|
||
toString () {
|
||
return `${this.name} [${sym}]: ${this.message}`
|
||
}
|
||
};
|
||
}
|
||
|
||
E('ERR_BUFFER_OUT_OF_BOUNDS',
|
||
function (name) {
|
||
if (name) {
|
||
return `${name} is outside of buffer bounds`
|
||
}
|
||
|
||
return 'Attempt to access memory outside buffer bounds'
|
||
}, RangeError);
|
||
E('ERR_INVALID_ARG_TYPE',
|
||
function (name, actual) {
|
||
return `The "${name}" argument must be of type number. Received type ${typeof actual}`
|
||
}, TypeError);
|
||
E('ERR_OUT_OF_RANGE',
|
||
function (str, range, input) {
|
||
let msg = `The value of "${str}" is out of range.`;
|
||
let received = input;
|
||
if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) {
|
||
received = addNumericalSeparator(String(input));
|
||
} else if (typeof input === 'bigint') {
|
||
received = String(input);
|
||
if (input > BigInt(2) ** BigInt(32) || input < -(BigInt(2) ** BigInt(32))) {
|
||
received = addNumericalSeparator(received);
|
||
}
|
||
received += 'n';
|
||
}
|
||
msg += ` It must be ${range}. Received ${received}`;
|
||
return msg
|
||
}, RangeError);
|
||
|
||
function addNumericalSeparator (val) {
|
||
let res = '';
|
||
let i = val.length;
|
||
const start = val[0] === '-' ? 1 : 0;
|
||
for (; i >= start + 4; i -= 3) {
|
||
res = `_${val.slice(i - 3, i)}${res}`;
|
||
}
|
||
return `${val.slice(0, i)}${res}`
|
||
}
|
||
|
||
// CHECK FUNCTIONS
|
||
// ===============
|
||
|
||
function checkBounds (buf, offset, byteLength) {
|
||
validateNumber(offset, 'offset');
|
||
if (buf[offset] === undefined || buf[offset + byteLength] === undefined) {
|
||
boundsError(offset, buf.length - (byteLength + 1));
|
||
}
|
||
}
|
||
|
||
function checkIntBI (value, min, max, buf, offset, byteLength) {
|
||
if (value > max || value < min) {
|
||
const n = typeof min === 'bigint' ? 'n' : '';
|
||
let range;
|
||
if (byteLength > 3) {
|
||
if (min === 0 || min === BigInt(0)) {
|
||
range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`;
|
||
} else {
|
||
range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and < 2 ** ` +
|
||
`${(byteLength + 1) * 8 - 1}${n}`;
|
||
}
|
||
} else {
|
||
range = `>= ${min}${n} and <= ${max}${n}`;
|
||
}
|
||
throw new errors.ERR_OUT_OF_RANGE('value', range, value)
|
||
}
|
||
checkBounds(buf, offset, byteLength);
|
||
}
|
||
|
||
function validateNumber (value, name) {
|
||
if (typeof value !== 'number') {
|
||
throw new errors.ERR_INVALID_ARG_TYPE(name, 'number', value)
|
||
}
|
||
}
|
||
|
||
function boundsError (value, length, type) {
|
||
if (Math.floor(value) !== value) {
|
||
validateNumber(value, type);
|
||
throw new errors.ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value)
|
||
}
|
||
|
||
if (length < 0) {
|
||
throw new errors.ERR_BUFFER_OUT_OF_BOUNDS()
|
||
}
|
||
|
||
throw new errors.ERR_OUT_OF_RANGE(type || 'offset',
|
||
`>= ${type ? 1 : 0} and <= ${length}`,
|
||
value)
|
||
}
|
||
|
||
// HELPER FUNCTIONS
|
||
// ================
|
||
|
||
const INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g;
|
||
|
||
function base64clean (str) {
|
||
// Node takes equal signs as end of the Base64 encoding
|
||
str = str.split('=')[0];
|
||
// Node strips out invalid characters like \n and \t from the string, base64-js does not
|
||
str = str.trim().replace(INVALID_BASE64_RE, '');
|
||
// Node converts strings with length < 2 to ''
|
||
if (str.length < 2) return ''
|
||
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
|
||
while (str.length % 4 !== 0) {
|
||
str = str + '=';
|
||
}
|
||
return str
|
||
}
|
||
|
||
function utf8ToBytes (string, units) {
|
||
units = units || Infinity;
|
||
let codePoint;
|
||
const length = string.length;
|
||
let leadSurrogate = null;
|
||
const bytes = [];
|
||
|
||
for (let i = 0; i < length; ++i) {
|
||
codePoint = string.charCodeAt(i);
|
||
|
||
// is surrogate component
|
||
if (codePoint > 0xD7FF && codePoint < 0xE000) {
|
||
// last char was a lead
|
||
if (!leadSurrogate) {
|
||
// no lead yet
|
||
if (codePoint > 0xDBFF) {
|
||
// unexpected trail
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
|
||
continue
|
||
} else if (i + 1 === length) {
|
||
// unpaired lead
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
|
||
continue
|
||
}
|
||
|
||
// valid lead
|
||
leadSurrogate = codePoint;
|
||
|
||
continue
|
||
}
|
||
|
||
// 2 leads in a row
|
||
if (codePoint < 0xDC00) {
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
|
||
leadSurrogate = codePoint;
|
||
continue
|
||
}
|
||
|
||
// valid surrogate pair
|
||
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;
|
||
} else if (leadSurrogate) {
|
||
// valid bmp char, but last char was a lead
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
|
||
}
|
||
|
||
leadSurrogate = null;
|
||
|
||
// encode utf8
|
||
if (codePoint < 0x80) {
|
||
if ((units -= 1) < 0) break
|
||
bytes.push(codePoint);
|
||
} else if (codePoint < 0x800) {
|
||
if ((units -= 2) < 0) break
|
||
bytes.push(
|
||
codePoint >> 0x6 | 0xC0,
|
||
codePoint & 0x3F | 0x80
|
||
);
|
||
} else if (codePoint < 0x10000) {
|
||
if ((units -= 3) < 0) break
|
||
bytes.push(
|
||
codePoint >> 0xC | 0xE0,
|
||
codePoint >> 0x6 & 0x3F | 0x80,
|
||
codePoint & 0x3F | 0x80
|
||
);
|
||
} else if (codePoint < 0x110000) {
|
||
if ((units -= 4) < 0) break
|
||
bytes.push(
|
||
codePoint >> 0x12 | 0xF0,
|
||
codePoint >> 0xC & 0x3F | 0x80,
|
||
codePoint >> 0x6 & 0x3F | 0x80,
|
||
codePoint & 0x3F | 0x80
|
||
);
|
||
} else {
|
||
throw new Error('Invalid code point')
|
||
}
|
||
}
|
||
|
||
return bytes
|
||
}
|
||
|
||
function asciiToBytes (str) {
|
||
const byteArray = [];
|
||
for (let i = 0; i < str.length; ++i) {
|
||
// Node's code seems to be doing this and not & 0x7F..
|
||
byteArray.push(str.charCodeAt(i) & 0xFF);
|
||
}
|
||
return byteArray
|
||
}
|
||
|
||
function utf16leToBytes (str, units) {
|
||
let c, hi, lo;
|
||
const byteArray = [];
|
||
for (let i = 0; i < str.length; ++i) {
|
||
if ((units -= 2) < 0) break
|
||
|
||
c = str.charCodeAt(i);
|
||
hi = c >> 8;
|
||
lo = c % 256;
|
||
byteArray.push(lo);
|
||
byteArray.push(hi);
|
||
}
|
||
|
||
return byteArray
|
||
}
|
||
|
||
function base64ToBytes (str) {
|
||
return base64.toByteArray(base64clean(str))
|
||
}
|
||
|
||
function blitBuffer (src, dst, offset, length) {
|
||
let i;
|
||
for (i = 0; i < length; ++i) {
|
||
if ((i + offset >= dst.length) || (i >= src.length)) break
|
||
dst[i + offset] = src[i];
|
||
}
|
||
return i
|
||
}
|
||
|
||
// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
|
||
// the `instanceof` check but they should be treated as of that type.
|
||
// See: https://github.com/feross/buffer/issues/166
|
||
function isInstance (obj, type) {
|
||
return obj instanceof type ||
|
||
(obj != null && obj.constructor != null && obj.constructor.name != null &&
|
||
obj.constructor.name === type.name)
|
||
}
|
||
function numberIsNaN (obj) {
|
||
// For IE11 support
|
||
return obj !== obj // eslint-disable-line no-self-compare
|
||
}
|
||
|
||
// Create lookup table for `toString('hex')`
|
||
// See: https://github.com/feross/buffer/issues/219
|
||
const hexSliceLookupTable = (function () {
|
||
const alphabet = '0123456789abcdef';
|
||
const table = new Array(256);
|
||
for (let i = 0; i < 16; ++i) {
|
||
const i16 = i * 16;
|
||
for (let j = 0; j < 16; ++j) {
|
||
table[i16 + j] = alphabet[i] + alphabet[j];
|
||
}
|
||
}
|
||
return table
|
||
})();
|
||
|
||
// Return not function with Error if BigInt not supported
|
||
function defineBigIntMethod (fn) {
|
||
return typeof BigInt === 'undefined' ? BufferBigIntNotDefined : fn
|
||
}
|
||
|
||
function BufferBigIntNotDefined () {
|
||
throw new Error('BigInt not supported')
|
||
}
|
||
} (buffer));
|
||
|
||
function number$2(n) {
|
||
if (!Number.isSafeInteger(n) || n < 0)
|
||
throw new Error(`positive integer expected, not ${n}`);
|
||
}
|
||
// copied from utils
|
||
function isBytes$3(a) {
|
||
return (a instanceof Uint8Array ||
|
||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
|
||
}
|
||
function bytes$1(b, ...lengths) {
|
||
if (!isBytes$3(b))
|
||
throw new Error('Uint8Array expected');
|
||
if (lengths.length > 0 && !lengths.includes(b.length))
|
||
throw new Error(`Uint8Array expected of length ${lengths}, not of length=${b.length}`);
|
||
}
|
||
function hash(h) {
|
||
if (typeof h !== 'function' || typeof h.create !== 'function')
|
||
throw new Error('Hash should be wrapped by utils.wrapConstructor');
|
||
number$2(h.outputLen);
|
||
number$2(h.blockLen);
|
||
}
|
||
function exists$1(instance, checkFinished = true) {
|
||
if (instance.destroyed)
|
||
throw new Error('Hash instance has been destroyed');
|
||
if (checkFinished && instance.finished)
|
||
throw new Error('Hash#digest() has already been called');
|
||
}
|
||
function output$1(out, instance) {
|
||
bytes$1(out);
|
||
const min = instance.outputLen;
|
||
if (out.length < min) {
|
||
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
|
||
}
|
||
}
|
||
|
||
const crypto$1 = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;
|
||
|
||
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
|
||
// node.js versions earlier than v19 don't declare it in global scope.
|
||
// For node.js, package.json#exports field mapping rewrites import
|
||
// from `crypto` to `cryptoNode`, which imports native module.
|
||
// Makes the utils un-importable in browsers without a bundler.
|
||
// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
|
||
// Cast array to view
|
||
const createView$1 = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
||
// The rotate right (circular right shift) operation for uint32
|
||
const rotr$1 = (word, shift) => (word << (32 - shift)) | (word >>> shift);
|
||
new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
|
||
/**
|
||
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
||
*/
|
||
function utf8ToBytes$2(str) {
|
||
if (typeof str !== 'string')
|
||
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
||
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
|
||
}
|
||
/**
|
||
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
|
||
* Warning: when Uint8Array is passed, it would NOT get copied.
|
||
* Keep in mind for future mutable operations.
|
||
*/
|
||
function toBytes$1(data) {
|
||
if (typeof data === 'string')
|
||
data = utf8ToBytes$2(data);
|
||
bytes$1(data);
|
||
return data;
|
||
}
|
||
/**
|
||
* Copies several Uint8Arrays into one.
|
||
*/
|
||
function concatBytes$1(...arrays) {
|
||
let sum = 0;
|
||
for (let i = 0; i < arrays.length; i++) {
|
||
const a = arrays[i];
|
||
bytes$1(a);
|
||
sum += a.length;
|
||
}
|
||
const res = new Uint8Array(sum);
|
||
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
||
const a = arrays[i];
|
||
res.set(a, pad);
|
||
pad += a.length;
|
||
}
|
||
return res;
|
||
}
|
||
// For runtime check if class implements interface
|
||
let Hash$1 = class Hash {
|
||
// Safe version that clones internal state
|
||
clone() {
|
||
return this._cloneInto();
|
||
}
|
||
};
|
||
function wrapConstructor$1(hashCons) {
|
||
const hashC = (msg) => hashCons().update(toBytes$1(msg)).digest();
|
||
const tmp = hashCons();
|
||
hashC.outputLen = tmp.outputLen;
|
||
hashC.blockLen = tmp.blockLen;
|
||
hashC.create = () => hashCons();
|
||
return hashC;
|
||
}
|
||
/**
|
||
* Secure PRNG. Uses `crypto.getRandomValues`, which defers to OS.
|
||
*/
|
||
function randomBytes(bytesLength = 32) {
|
||
if (crypto$1 && typeof crypto$1.getRandomValues === 'function') {
|
||
return crypto$1.getRandomValues(new Uint8Array(bytesLength));
|
||
}
|
||
throw new Error('crypto.getRandomValues must be defined');
|
||
}
|
||
|
||
// Polyfill for Safari 14
|
||
function setBigUint64$1(view, byteOffset, value, isLE) {
|
||
if (typeof view.setBigUint64 === 'function')
|
||
return view.setBigUint64(byteOffset, value, isLE);
|
||
const _32n = BigInt(32);
|
||
const _u32_max = BigInt(0xffffffff);
|
||
const wh = Number((value >> _32n) & _u32_max);
|
||
const wl = Number(value & _u32_max);
|
||
const h = isLE ? 4 : 0;
|
||
const l = isLE ? 0 : 4;
|
||
view.setUint32(byteOffset + h, wh, isLE);
|
||
view.setUint32(byteOffset + l, wl, isLE);
|
||
}
|
||
// Choice: a ? b : c
|
||
const Chi$1 = (a, b, c) => (a & b) ^ (~a & c);
|
||
// Majority function, true if any two inpust is true
|
||
const Maj$1 = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
|
||
/**
|
||
* Merkle-Damgard hash construction base class.
|
||
* Could be used to create MD5, RIPEMD, SHA1, SHA2.
|
||
*/
|
||
class HashMD extends Hash$1 {
|
||
constructor(blockLen, outputLen, padOffset, isLE) {
|
||
super();
|
||
this.blockLen = blockLen;
|
||
this.outputLen = outputLen;
|
||
this.padOffset = padOffset;
|
||
this.isLE = isLE;
|
||
this.finished = false;
|
||
this.length = 0;
|
||
this.pos = 0;
|
||
this.destroyed = false;
|
||
this.buffer = new Uint8Array(blockLen);
|
||
this.view = createView$1(this.buffer);
|
||
}
|
||
update(data) {
|
||
exists$1(this);
|
||
const { view, buffer, blockLen } = this;
|
||
data = toBytes$1(data);
|
||
const len = data.length;
|
||
for (let pos = 0; pos < len;) {
|
||
const take = Math.min(blockLen - this.pos, len - pos);
|
||
// Fast path: we have at least one block in input, cast it to view and process
|
||
if (take === blockLen) {
|
||
const dataView = createView$1(data);
|
||
for (; blockLen <= len - pos; pos += blockLen)
|
||
this.process(dataView, pos);
|
||
continue;
|
||
}
|
||
buffer.set(data.subarray(pos, pos + take), this.pos);
|
||
this.pos += take;
|
||
pos += take;
|
||
if (this.pos === blockLen) {
|
||
this.process(view, 0);
|
||
this.pos = 0;
|
||
}
|
||
}
|
||
this.length += data.length;
|
||
this.roundClean();
|
||
return this;
|
||
}
|
||
digestInto(out) {
|
||
exists$1(this);
|
||
output$1(out, this);
|
||
this.finished = true;
|
||
// Padding
|
||
// We can avoid allocation of buffer for padding completely if it
|
||
// was previously not allocated here. But it won't change performance.
|
||
const { buffer, view, blockLen, isLE } = this;
|
||
let { pos } = this;
|
||
// append the bit '1' to the message
|
||
buffer[pos++] = 0b10000000;
|
||
this.buffer.subarray(pos).fill(0);
|
||
// we have less than padOffset left in buffer, so we cannot put length in
|
||
// current block, need process it and pad again
|
||
if (this.padOffset > blockLen - pos) {
|
||
this.process(view, 0);
|
||
pos = 0;
|
||
}
|
||
// Pad until full block byte with zeros
|
||
for (let i = pos; i < blockLen; i++)
|
||
buffer[i] = 0;
|
||
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
|
||
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
|
||
// So we just write lowest 64 bits of that value.
|
||
setBigUint64$1(view, blockLen - 8, BigInt(this.length * 8), isLE);
|
||
this.process(view, 0);
|
||
const oview = createView$1(out);
|
||
const len = this.outputLen;
|
||
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
|
||
if (len % 4)
|
||
throw new Error('_sha2: outputLen should be aligned to 32bit');
|
||
const outLen = len / 4;
|
||
const state = this.get();
|
||
if (outLen > state.length)
|
||
throw new Error('_sha2: outputLen bigger than state');
|
||
for (let i = 0; i < outLen; i++)
|
||
oview.setUint32(4 * i, state[i], isLE);
|
||
}
|
||
digest() {
|
||
const { buffer, outputLen } = this;
|
||
this.digestInto(buffer);
|
||
const res = buffer.slice(0, outputLen);
|
||
this.destroy();
|
||
return res;
|
||
}
|
||
_cloneInto(to) {
|
||
to || (to = new this.constructor());
|
||
to.set(...this.get());
|
||
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
||
to.length = length;
|
||
to.pos = pos;
|
||
to.finished = finished;
|
||
to.destroyed = destroyed;
|
||
if (length % blockLen)
|
||
to.buffer.set(buffer);
|
||
return to;
|
||
}
|
||
}
|
||
|
||
const U32_MASK64$1 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
||
const _32n$1 = /* @__PURE__ */ BigInt(32);
|
||
// We are not using BigUint64Array, because they are extremely slow as per 2022
|
||
function fromBig$1(n, le = false) {
|
||
if (le)
|
||
return { h: Number(n & U32_MASK64$1), l: Number((n >> _32n$1) & U32_MASK64$1) };
|
||
return { h: Number((n >> _32n$1) & U32_MASK64$1) | 0, l: Number(n & U32_MASK64$1) | 0 };
|
||
}
|
||
function split$1(lst, le = false) {
|
||
let Ah = new Uint32Array(lst.length);
|
||
let Al = new Uint32Array(lst.length);
|
||
for (let i = 0; i < lst.length; i++) {
|
||
const { h, l } = fromBig$1(lst[i], le);
|
||
[Ah[i], Al[i]] = [h, l];
|
||
}
|
||
return [Ah, Al];
|
||
}
|
||
const toBig = (h, l) => (BigInt(h >>> 0) << _32n$1) | BigInt(l >>> 0);
|
||
// for Shift in [0, 32)
|
||
const shrSH = (h, _l, s) => h >>> s;
|
||
const shrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);
|
||
// Right rotate for Shift in [1, 32)
|
||
const rotrSH = (h, l, s) => (h >>> s) | (l << (32 - s));
|
||
const rotrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);
|
||
// Right rotate for Shift in (32, 64), NOTE: 32 is special case.
|
||
const rotrBH = (h, l, s) => (h << (64 - s)) | (l >>> (s - 32));
|
||
const rotrBL = (h, l, s) => (h >>> (s - 32)) | (l << (64 - s));
|
||
// Right rotate for shift===32 (just swaps l&h)
|
||
const rotr32H = (_h, l) => l;
|
||
const rotr32L = (h, _l) => h;
|
||
// Left rotate for Shift in [1, 32)
|
||
const rotlSH$1 = (h, l, s) => (h << s) | (l >>> (32 - s));
|
||
const rotlSL$1 = (h, l, s) => (l << s) | (h >>> (32 - s));
|
||
// Left rotate for Shift in (32, 64), NOTE: 32 is special case.
|
||
const rotlBH$1 = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s));
|
||
const rotlBL$1 = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s));
|
||
// JS uses 32-bit signed integers for bitwise operations which means we cannot
|
||
// simple take carry out of low bit sum by shift, we need to use division.
|
||
function add(Ah, Al, Bh, Bl) {
|
||
const l = (Al >>> 0) + (Bl >>> 0);
|
||
return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };
|
||
}
|
||
// Addition with more than 2 elements
|
||
const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
|
||
const add3H = (low, Ah, Bh, Ch) => (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;
|
||
const add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
|
||
const add4H = (low, Ah, Bh, Ch, Dh) => (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;
|
||
const add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
|
||
const add5H = (low, Ah, Bh, Ch, Dh, Eh) => (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;
|
||
// prettier-ignore
|
||
const u64$1 = {
|
||
fromBig: fromBig$1, split: split$1, toBig,
|
||
shrSH, shrSL,
|
||
rotrSH, rotrSL, rotrBH, rotrBL,
|
||
rotr32H, rotr32L,
|
||
rotlSH: rotlSH$1, rotlSL: rotlSL$1, rotlBH: rotlBH$1, rotlBL: rotlBL$1,
|
||
add, add3L, add3H, add4L, add4H, add5H, add5L,
|
||
};
|
||
|
||
// Round contants (first 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409):
|
||
// prettier-ignore
|
||
const [SHA512_Kh, SHA512_Kl] = /* @__PURE__ */ (() => u64$1.split([
|
||
'0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',
|
||
'0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',
|
||
'0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',
|
||
'0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',
|
||
'0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',
|
||
'0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',
|
||
'0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',
|
||
'0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',
|
||
'0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',
|
||
'0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',
|
||
'0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',
|
||
'0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',
|
||
'0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',
|
||
'0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',
|
||
'0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',
|
||
'0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',
|
||
'0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',
|
||
'0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',
|
||
'0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',
|
||
'0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'
|
||
].map(n => BigInt(n))))();
|
||
// Temporary buffer, not used to store anything between runs
|
||
const SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);
|
||
const SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);
|
||
class SHA512 extends HashMD {
|
||
constructor() {
|
||
super(128, 64, 16, false);
|
||
// We cannot use array here since array allows indexing by variable which means optimizer/compiler cannot use registers.
|
||
// Also looks cleaner and easier to verify with spec.
|
||
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
|
||
// h -- high 32 bits, l -- low 32 bits
|
||
this.Ah = 0x6a09e667 | 0;
|
||
this.Al = 0xf3bcc908 | 0;
|
||
this.Bh = 0xbb67ae85 | 0;
|
||
this.Bl = 0x84caa73b | 0;
|
||
this.Ch = 0x3c6ef372 | 0;
|
||
this.Cl = 0xfe94f82b | 0;
|
||
this.Dh = 0xa54ff53a | 0;
|
||
this.Dl = 0x5f1d36f1 | 0;
|
||
this.Eh = 0x510e527f | 0;
|
||
this.El = 0xade682d1 | 0;
|
||
this.Fh = 0x9b05688c | 0;
|
||
this.Fl = 0x2b3e6c1f | 0;
|
||
this.Gh = 0x1f83d9ab | 0;
|
||
this.Gl = 0xfb41bd6b | 0;
|
||
this.Hh = 0x5be0cd19 | 0;
|
||
this.Hl = 0x137e2179 | 0;
|
||
}
|
||
// prettier-ignore
|
||
get() {
|
||
const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
||
return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];
|
||
}
|
||
// prettier-ignore
|
||
set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) {
|
||
this.Ah = Ah | 0;
|
||
this.Al = Al | 0;
|
||
this.Bh = Bh | 0;
|
||
this.Bl = Bl | 0;
|
||
this.Ch = Ch | 0;
|
||
this.Cl = Cl | 0;
|
||
this.Dh = Dh | 0;
|
||
this.Dl = Dl | 0;
|
||
this.Eh = Eh | 0;
|
||
this.El = El | 0;
|
||
this.Fh = Fh | 0;
|
||
this.Fl = Fl | 0;
|
||
this.Gh = Gh | 0;
|
||
this.Gl = Gl | 0;
|
||
this.Hh = Hh | 0;
|
||
this.Hl = Hl | 0;
|
||
}
|
||
process(view, offset) {
|
||
// Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array
|
||
for (let i = 0; i < 16; i++, offset += 4) {
|
||
SHA512_W_H[i] = view.getUint32(offset);
|
||
SHA512_W_L[i] = view.getUint32((offset += 4));
|
||
}
|
||
for (let i = 16; i < 80; i++) {
|
||
// s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)
|
||
const W15h = SHA512_W_H[i - 15] | 0;
|
||
const W15l = SHA512_W_L[i - 15] | 0;
|
||
const s0h = u64$1.rotrSH(W15h, W15l, 1) ^ u64$1.rotrSH(W15h, W15l, 8) ^ u64$1.shrSH(W15h, W15l, 7);
|
||
const s0l = u64$1.rotrSL(W15h, W15l, 1) ^ u64$1.rotrSL(W15h, W15l, 8) ^ u64$1.shrSL(W15h, W15l, 7);
|
||
// s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)
|
||
const W2h = SHA512_W_H[i - 2] | 0;
|
||
const W2l = SHA512_W_L[i - 2] | 0;
|
||
const s1h = u64$1.rotrSH(W2h, W2l, 19) ^ u64$1.rotrBH(W2h, W2l, 61) ^ u64$1.shrSH(W2h, W2l, 6);
|
||
const s1l = u64$1.rotrSL(W2h, W2l, 19) ^ u64$1.rotrBL(W2h, W2l, 61) ^ u64$1.shrSL(W2h, W2l, 6);
|
||
// SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];
|
||
const SUMl = u64$1.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);
|
||
const SUMh = u64$1.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);
|
||
SHA512_W_H[i] = SUMh | 0;
|
||
SHA512_W_L[i] = SUMl | 0;
|
||
}
|
||
let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
||
// Compression function main loop, 80 rounds
|
||
for (let i = 0; i < 80; i++) {
|
||
// S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)
|
||
const sigma1h = u64$1.rotrSH(Eh, El, 14) ^ u64$1.rotrSH(Eh, El, 18) ^ u64$1.rotrBH(Eh, El, 41);
|
||
const sigma1l = u64$1.rotrSL(Eh, El, 14) ^ u64$1.rotrSL(Eh, El, 18) ^ u64$1.rotrBL(Eh, El, 41);
|
||
//const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
|
||
const CHIh = (Eh & Fh) ^ (~Eh & Gh);
|
||
const CHIl = (El & Fl) ^ (~El & Gl);
|
||
// T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]
|
||
// prettier-ignore
|
||
const T1ll = u64$1.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);
|
||
const T1h = u64$1.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);
|
||
const T1l = T1ll | 0;
|
||
// S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)
|
||
const sigma0h = u64$1.rotrSH(Ah, Al, 28) ^ u64$1.rotrBH(Ah, Al, 34) ^ u64$1.rotrBH(Ah, Al, 39);
|
||
const sigma0l = u64$1.rotrSL(Ah, Al, 28) ^ u64$1.rotrBL(Ah, Al, 34) ^ u64$1.rotrBL(Ah, Al, 39);
|
||
const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);
|
||
const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);
|
||
Hh = Gh | 0;
|
||
Hl = Gl | 0;
|
||
Gh = Fh | 0;
|
||
Gl = Fl | 0;
|
||
Fh = Eh | 0;
|
||
Fl = El | 0;
|
||
({ h: Eh, l: El } = u64$1.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
|
||
Dh = Ch | 0;
|
||
Dl = Cl | 0;
|
||
Ch = Bh | 0;
|
||
Cl = Bl | 0;
|
||
Bh = Ah | 0;
|
||
Bl = Al | 0;
|
||
const All = u64$1.add3L(T1l, sigma0l, MAJl);
|
||
Ah = u64$1.add3H(All, T1h, sigma0h, MAJh);
|
||
Al = All | 0;
|
||
}
|
||
// Add the compressed chunk to the current hash value
|
||
({ h: Ah, l: Al } = u64$1.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
|
||
({ h: Bh, l: Bl } = u64$1.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
|
||
({ h: Ch, l: Cl } = u64$1.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
|
||
({ h: Dh, l: Dl } = u64$1.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
|
||
({ h: Eh, l: El } = u64$1.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
|
||
({ h: Fh, l: Fl } = u64$1.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
|
||
({ h: Gh, l: Gl } = u64$1.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
|
||
({ h: Hh, l: Hl } = u64$1.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
|
||
this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
|
||
}
|
||
roundClean() {
|
||
SHA512_W_H.fill(0);
|
||
SHA512_W_L.fill(0);
|
||
}
|
||
destroy() {
|
||
this.buffer.fill(0);
|
||
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||
}
|
||
}
|
||
const sha512 = /* @__PURE__ */ wrapConstructor$1(() => new SHA512());
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// 100 lines of code in the file are duplicated from noble-hashes (utils).
|
||
// This is OK: `abstract` directory does not use noble-hashes.
|
||
// User may opt-in into using different hashing library. This way, noble-hashes
|
||
// won't be included into their bundle.
|
||
const _0n$5 = BigInt(0);
|
||
const _1n$7 = BigInt(1);
|
||
const _2n$5 = BigInt(2);
|
||
function isBytes$2(a) {
|
||
return (a instanceof Uint8Array ||
|
||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
|
||
}
|
||
function abytes(item) {
|
||
if (!isBytes$2(item))
|
||
throw new Error('Uint8Array expected');
|
||
}
|
||
// Array where index 0xf0 (240) is mapped to string 'f0'
|
||
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
|
||
/**
|
||
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
|
||
*/
|
||
function bytesToHex(bytes) {
|
||
abytes(bytes);
|
||
// pre-caching improves the speed 6x
|
||
let hex = '';
|
||
for (let i = 0; i < bytes.length; i++) {
|
||
hex += hexes[bytes[i]];
|
||
}
|
||
return hex;
|
||
}
|
||
function numberToHexUnpadded(num) {
|
||
const hex = num.toString(16);
|
||
return hex.length & 1 ? `0${hex}` : hex;
|
||
}
|
||
function hexToNumber(hex) {
|
||
if (typeof hex !== 'string')
|
||
throw new Error('hex string expected, got ' + typeof hex);
|
||
// Big Endian
|
||
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
||
}
|
||
// We use optimized technique to convert hex string to byte array
|
||
const asciis = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 };
|
||
function asciiToBase16(char) {
|
||
if (char >= asciis._0 && char <= asciis._9)
|
||
return char - asciis._0;
|
||
if (char >= asciis._A && char <= asciis._F)
|
||
return char - (asciis._A - 10);
|
||
if (char >= asciis._a && char <= asciis._f)
|
||
return char - (asciis._a - 10);
|
||
return;
|
||
}
|
||
/**
|
||
* @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
|
||
*/
|
||
function hexToBytes(hex) {
|
||
if (typeof hex !== 'string')
|
||
throw new Error('hex string expected, got ' + typeof hex);
|
||
const hl = hex.length;
|
||
const al = hl / 2;
|
||
if (hl % 2)
|
||
throw new Error('padded hex string expected, got unpadded hex of length ' + hl);
|
||
const array = new Uint8Array(al);
|
||
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
||
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
||
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
||
if (n1 === undefined || n2 === undefined) {
|
||
const char = hex[hi] + hex[hi + 1];
|
||
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
||
}
|
||
array[ai] = n1 * 16 + n2;
|
||
}
|
||
return array;
|
||
}
|
||
// BE: Big Endian, LE: Little Endian
|
||
function bytesToNumberBE(bytes) {
|
||
return hexToNumber(bytesToHex(bytes));
|
||
}
|
||
function bytesToNumberLE(bytes) {
|
||
abytes(bytes);
|
||
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
||
}
|
||
function numberToBytesBE(n, len) {
|
||
return hexToBytes(n.toString(16).padStart(len * 2, '0'));
|
||
}
|
||
function numberToBytesLE(n, len) {
|
||
return numberToBytesBE(n, len).reverse();
|
||
}
|
||
// Unpadded, rarely used
|
||
function numberToVarBytesBE(n) {
|
||
return hexToBytes(numberToHexUnpadded(n));
|
||
}
|
||
/**
|
||
* Takes hex string or Uint8Array, converts to Uint8Array.
|
||
* Validates output length.
|
||
* Will throw error for other types.
|
||
* @param title descriptive title for an error e.g. 'private key'
|
||
* @param hex hex string or Uint8Array
|
||
* @param expectedLength optional, will compare to result array's length
|
||
* @returns
|
||
*/
|
||
function ensureBytes(title, hex, expectedLength) {
|
||
let res;
|
||
if (typeof hex === 'string') {
|
||
try {
|
||
res = hexToBytes(hex);
|
||
}
|
||
catch (e) {
|
||
throw new Error(`${title} must be valid hex string, got "${hex}". Cause: ${e}`);
|
||
}
|
||
}
|
||
else if (isBytes$2(hex)) {
|
||
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||
res = Uint8Array.from(hex);
|
||
}
|
||
else {
|
||
throw new Error(`${title} must be hex string or Uint8Array`);
|
||
}
|
||
const len = res.length;
|
||
if (typeof expectedLength === 'number' && len !== expectedLength)
|
||
throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`);
|
||
return res;
|
||
}
|
||
/**
|
||
* Copies several Uint8Arrays into one.
|
||
*/
|
||
function concatBytes(...arrays) {
|
||
let sum = 0;
|
||
for (let i = 0; i < arrays.length; i++) {
|
||
const a = arrays[i];
|
||
abytes(a);
|
||
sum += a.length;
|
||
}
|
||
const res = new Uint8Array(sum);
|
||
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
||
const a = arrays[i];
|
||
res.set(a, pad);
|
||
pad += a.length;
|
||
}
|
||
return res;
|
||
}
|
||
// Compares 2 u8a-s in kinda constant time
|
||
function equalBytes(a, b) {
|
||
if (a.length !== b.length)
|
||
return false;
|
||
let diff = 0;
|
||
for (let i = 0; i < a.length; i++)
|
||
diff |= a[i] ^ b[i];
|
||
return diff === 0;
|
||
}
|
||
/**
|
||
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
||
*/
|
||
function utf8ToBytes$1(str) {
|
||
if (typeof str !== 'string')
|
||
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
||
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
|
||
}
|
||
// Bit operations
|
||
/**
|
||
* Calculates amount of bits in a bigint.
|
||
* Same as `n.toString(2).length`
|
||
*/
|
||
function bitLen(n) {
|
||
let len;
|
||
for (len = 0; n > _0n$5; n >>= _1n$7, len += 1)
|
||
;
|
||
return len;
|
||
}
|
||
/**
|
||
* Gets single bit at position.
|
||
* NOTE: first bit position is 0 (same as arrays)
|
||
* Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
|
||
*/
|
||
function bitGet(n, pos) {
|
||
return (n >> BigInt(pos)) & _1n$7;
|
||
}
|
||
/**
|
||
* Sets single bit at position.
|
||
*/
|
||
function bitSet(n, pos, value) {
|
||
return n | ((value ? _1n$7 : _0n$5) << BigInt(pos));
|
||
}
|
||
/**
|
||
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
|
||
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
|
||
*/
|
||
const bitMask = (n) => (_2n$5 << BigInt(n - 1)) - _1n$7;
|
||
// DRBG
|
||
const u8n = (data) => new Uint8Array(data); // creates Uint8Array
|
||
const u8fr = (arr) => Uint8Array.from(arr); // another shortcut
|
||
/**
|
||
* Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
|
||
* @returns function that will call DRBG until 2nd arg returns something meaningful
|
||
* @example
|
||
* const drbg = createHmacDRBG<Key>(32, 32, hmac);
|
||
* drbg(seed, bytesToKey); // bytesToKey must return Key or undefined
|
||
*/
|
||
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
||
if (typeof hashLen !== 'number' || hashLen < 2)
|
||
throw new Error('hashLen must be a number');
|
||
if (typeof qByteLen !== 'number' || qByteLen < 2)
|
||
throw new Error('qByteLen must be a number');
|
||
if (typeof hmacFn !== 'function')
|
||
throw new Error('hmacFn must be a function');
|
||
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
|
||
let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
|
||
let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
|
||
let i = 0; // Iterations counter, will throw when over 1000
|
||
const reset = () => {
|
||
v.fill(1);
|
||
k.fill(0);
|
||
i = 0;
|
||
};
|
||
const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
|
||
const reseed = (seed = u8n()) => {
|
||
// HMAC-DRBG reseed() function. Steps D-G
|
||
k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)
|
||
v = h(); // v = hmac(k || v)
|
||
if (seed.length === 0)
|
||
return;
|
||
k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)
|
||
v = h(); // v = hmac(k || v)
|
||
};
|
||
const gen = () => {
|
||
// HMAC-DRBG generate() function
|
||
if (i++ >= 1000)
|
||
throw new Error('drbg: tried 1000 values');
|
||
let len = 0;
|
||
const out = [];
|
||
while (len < qByteLen) {
|
||
v = h();
|
||
const sl = v.slice();
|
||
out.push(sl);
|
||
len += v.length;
|
||
}
|
||
return concatBytes(...out);
|
||
};
|
||
const genUntil = (seed, pred) => {
|
||
reset();
|
||
reseed(seed); // Steps D-G
|
||
let res = undefined; // Step H: grind until k is in [1..n-1]
|
||
while (!(res = pred(gen())))
|
||
reseed();
|
||
reset();
|
||
return res;
|
||
};
|
||
return genUntil;
|
||
}
|
||
// Validating curves and fields
|
||
const validatorFns = {
|
||
bigint: (val) => typeof val === 'bigint',
|
||
function: (val) => typeof val === 'function',
|
||
boolean: (val) => typeof val === 'boolean',
|
||
string: (val) => typeof val === 'string',
|
||
stringOrUint8Array: (val) => typeof val === 'string' || isBytes$2(val),
|
||
isSafeInteger: (val) => Number.isSafeInteger(val),
|
||
array: (val) => Array.isArray(val),
|
||
field: (val, object) => object.Fp.isValid(val),
|
||
hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
||
};
|
||
// type Record<K extends string | number | symbol, T> = { [P in K]: T; }
|
||
function validateObject(object, validators, optValidators = {}) {
|
||
const checkField = (fieldName, type, isOptional) => {
|
||
const checkVal = validatorFns[type];
|
||
if (typeof checkVal !== 'function')
|
||
throw new Error(`Invalid validator "${type}", expected function`);
|
||
const val = object[fieldName];
|
||
if (isOptional && val === undefined)
|
||
return;
|
||
if (!checkVal(val, object)) {
|
||
throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`);
|
||
}
|
||
};
|
||
for (const [fieldName, type] of Object.entries(validators))
|
||
checkField(fieldName, type, false);
|
||
for (const [fieldName, type] of Object.entries(optValidators))
|
||
checkField(fieldName, type, true);
|
||
return object;
|
||
}
|
||
// validate type tests
|
||
// const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };
|
||
// const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!
|
||
// // Should fail type-check
|
||
// const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });
|
||
// const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });
|
||
// const z3 = validateObject(o, { test: 'boolean', z: 'bug' });
|
||
// const z4 = validateObject(o, { a: 'boolean', z: 'bug' });
|
||
|
||
var ut = /*#__PURE__*/Object.freeze({
|
||
__proto__: null,
|
||
abytes: abytes,
|
||
bitGet: bitGet,
|
||
bitLen: bitLen,
|
||
bitMask: bitMask,
|
||
bitSet: bitSet,
|
||
bytesToHex: bytesToHex,
|
||
bytesToNumberBE: bytesToNumberBE,
|
||
bytesToNumberLE: bytesToNumberLE,
|
||
concatBytes: concatBytes,
|
||
createHmacDrbg: createHmacDrbg,
|
||
ensureBytes: ensureBytes,
|
||
equalBytes: equalBytes,
|
||
hexToBytes: hexToBytes,
|
||
hexToNumber: hexToNumber,
|
||
isBytes: isBytes$2,
|
||
numberToBytesBE: numberToBytesBE,
|
||
numberToBytesLE: numberToBytesLE,
|
||
numberToHexUnpadded: numberToHexUnpadded,
|
||
numberToVarBytesBE: numberToVarBytesBE,
|
||
utf8ToBytes: utf8ToBytes$1,
|
||
validateObject: validateObject
|
||
});
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// Utilities for modular arithmetics and finite fields
|
||
// prettier-ignore
|
||
const _0n$4 = BigInt(0), _1n$6 = BigInt(1), _2n$4 = BigInt(2), _3n$1 = BigInt(3);
|
||
// prettier-ignore
|
||
const _4n = BigInt(4), _5n$1 = BigInt(5), _8n$1 = BigInt(8);
|
||
// prettier-ignore
|
||
BigInt(9); BigInt(16);
|
||
// Calculates a modulo b
|
||
function mod(a, b) {
|
||
const result = a % b;
|
||
return result >= _0n$4 ? result : b + result;
|
||
}
|
||
/**
|
||
* Efficiently raise num to power and do modular division.
|
||
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
||
* @example
|
||
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
||
*/
|
||
// TODO: use field version && remove
|
||
function pow(num, power, modulo) {
|
||
if (modulo <= _0n$4 || power < _0n$4)
|
||
throw new Error('Expected power/modulo > 0');
|
||
if (modulo === _1n$6)
|
||
return _0n$4;
|
||
let res = _1n$6;
|
||
while (power > _0n$4) {
|
||
if (power & _1n$6)
|
||
res = (res * num) % modulo;
|
||
num = (num * num) % modulo;
|
||
power >>= _1n$6;
|
||
}
|
||
return res;
|
||
}
|
||
// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
|
||
function pow2(x, power, modulo) {
|
||
let res = x;
|
||
while (power-- > _0n$4) {
|
||
res *= res;
|
||
res %= modulo;
|
||
}
|
||
return res;
|
||
}
|
||
// Inverses number over modulo
|
||
function invert(number, modulo) {
|
||
if (number === _0n$4 || modulo <= _0n$4) {
|
||
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
|
||
}
|
||
// Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
||
// Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
|
||
let a = mod(number, modulo);
|
||
let b = modulo;
|
||
// prettier-ignore
|
||
let x = _0n$4, u = _1n$6;
|
||
while (a !== _0n$4) {
|
||
// JIT applies optimization if those two lines follow each other
|
||
const q = b / a;
|
||
const r = b % a;
|
||
const m = x - u * q;
|
||
// prettier-ignore
|
||
b = a, a = r, x = u, u = m;
|
||
}
|
||
const gcd = b;
|
||
if (gcd !== _1n$6)
|
||
throw new Error('invert: does not exist');
|
||
return mod(x, modulo);
|
||
}
|
||
/**
|
||
* Tonelli-Shanks square root search algorithm.
|
||
* 1. https://eprint.iacr.org/2012/685.pdf (page 12)
|
||
* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
|
||
* Will start an infinite loop if field order P is not prime.
|
||
* @param P field order
|
||
* @returns function that takes field Fp (created from P) and number n
|
||
*/
|
||
function tonelliShanks(P) {
|
||
// Legendre constant: used to calculate Legendre symbol (a | p),
|
||
// which denotes the value of a^((p-1)/2) (mod p).
|
||
// (a | p) ≡ 1 if a is a square (mod p)
|
||
// (a | p) ≡ -1 if a is not a square (mod p)
|
||
// (a | p) ≡ 0 if a ≡ 0 (mod p)
|
||
const legendreC = (P - _1n$6) / _2n$4;
|
||
let Q, S, Z;
|
||
// Step 1: By factoring out powers of 2 from p - 1,
|
||
// find q and s such that p - 1 = q*(2^s) with q odd
|
||
for (Q = P - _1n$6, S = 0; Q % _2n$4 === _0n$4; Q /= _2n$4, S++)
|
||
;
|
||
// Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
|
||
for (Z = _2n$4; Z < P && pow(Z, legendreC, P) !== P - _1n$6; Z++)
|
||
;
|
||
// Fast-path
|
||
if (S === 1) {
|
||
const p1div4 = (P + _1n$6) / _4n;
|
||
return function tonelliFast(Fp, n) {
|
||
const root = Fp.pow(n, p1div4);
|
||
if (!Fp.eql(Fp.sqr(root), n))
|
||
throw new Error('Cannot find square root');
|
||
return root;
|
||
};
|
||
}
|
||
// Slow-path
|
||
const Q1div2 = (Q + _1n$6) / _2n$4;
|
||
return function tonelliSlow(Fp, n) {
|
||
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
||
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
|
||
throw new Error('Cannot find square root');
|
||
let r = S;
|
||
// TODO: will fail at Fp2/etc
|
||
let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
|
||
let x = Fp.pow(n, Q1div2); // first guess at the square root
|
||
let b = Fp.pow(n, Q); // first guess at the fudge factor
|
||
while (!Fp.eql(b, Fp.ONE)) {
|
||
if (Fp.eql(b, Fp.ZERO))
|
||
return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
|
||
// Find m such b^(2^m)==1
|
||
let m = 1;
|
||
for (let t2 = Fp.sqr(b); m < r; m++) {
|
||
if (Fp.eql(t2, Fp.ONE))
|
||
break;
|
||
t2 = Fp.sqr(t2); // t2 *= t2
|
||
}
|
||
// NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
|
||
const ge = Fp.pow(g, _1n$6 << BigInt(r - m - 1)); // ge = 2^(r-m-1)
|
||
g = Fp.sqr(ge); // g = ge * ge
|
||
x = Fp.mul(x, ge); // x *= ge
|
||
b = Fp.mul(b, g); // b *= g
|
||
r = m;
|
||
}
|
||
return x;
|
||
};
|
||
}
|
||
function FpSqrt(P) {
|
||
// NOTE: different algorithms can give different roots, it is up to user to decide which one they want.
|
||
// For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
||
// P ≡ 3 (mod 4)
|
||
// √n = n^((P+1)/4)
|
||
if (P % _4n === _3n$1) {
|
||
// Not all roots possible!
|
||
// const ORDER =
|
||
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
||
// const NUM = 72057594037927816n;
|
||
const p1div4 = (P + _1n$6) / _4n;
|
||
return function sqrt3mod4(Fp, n) {
|
||
const root = Fp.pow(n, p1div4);
|
||
// Throw if root**2 != n
|
||
if (!Fp.eql(Fp.sqr(root), n))
|
||
throw new Error('Cannot find square root');
|
||
return root;
|
||
};
|
||
}
|
||
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
||
if (P % _8n$1 === _5n$1) {
|
||
const c1 = (P - _5n$1) / _8n$1;
|
||
return function sqrt5mod8(Fp, n) {
|
||
const n2 = Fp.mul(n, _2n$4);
|
||
const v = Fp.pow(n2, c1);
|
||
const nv = Fp.mul(n, v);
|
||
const i = Fp.mul(Fp.mul(nv, _2n$4), v);
|
||
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
||
if (!Fp.eql(Fp.sqr(root), n))
|
||
throw new Error('Cannot find square root');
|
||
return root;
|
||
};
|
||
}
|
||
// Other cases: Tonelli-Shanks algorithm
|
||
return tonelliShanks(P);
|
||
}
|
||
// Little-endian check for first LE bit (last BE bit);
|
||
const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n$6) === _1n$6;
|
||
// prettier-ignore
|
||
const FIELD_FIELDS = [
|
||
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
|
||
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
||
'addN', 'subN', 'mulN', 'sqrN'
|
||
];
|
||
function validateField(field) {
|
||
const initial = {
|
||
ORDER: 'bigint',
|
||
MASK: 'bigint',
|
||
BYTES: 'isSafeInteger',
|
||
BITS: 'isSafeInteger',
|
||
};
|
||
const opts = FIELD_FIELDS.reduce((map, val) => {
|
||
map[val] = 'function';
|
||
return map;
|
||
}, initial);
|
||
return validateObject(field, opts);
|
||
}
|
||
// Generic field functions
|
||
/**
|
||
* Same as `pow` but for Fp: non-constant-time.
|
||
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
||
*/
|
||
function FpPow(f, num, power) {
|
||
// Should have same speed as pow for bigints
|
||
// TODO: benchmark!
|
||
if (power < _0n$4)
|
||
throw new Error('Expected power > 0');
|
||
if (power === _0n$4)
|
||
return f.ONE;
|
||
if (power === _1n$6)
|
||
return num;
|
||
let p = f.ONE;
|
||
let d = num;
|
||
while (power > _0n$4) {
|
||
if (power & _1n$6)
|
||
p = f.mul(p, d);
|
||
d = f.sqr(d);
|
||
power >>= _1n$6;
|
||
}
|
||
return p;
|
||
}
|
||
/**
|
||
* Efficiently invert an array of Field elements.
|
||
* `inv(0)` will return `undefined` here: make sure to throw an error.
|
||
*/
|
||
function FpInvertBatch(f, nums) {
|
||
const tmp = new Array(nums.length);
|
||
// Walk from first to last, multiply them by each other MOD p
|
||
const lastMultiplied = nums.reduce((acc, num, i) => {
|
||
if (f.is0(num))
|
||
return acc;
|
||
tmp[i] = acc;
|
||
return f.mul(acc, num);
|
||
}, f.ONE);
|
||
// Invert last element
|
||
const inverted = f.inv(lastMultiplied);
|
||
// Walk from last to first, multiply them by inverted each other MOD p
|
||
nums.reduceRight((acc, num, i) => {
|
||
if (f.is0(num))
|
||
return acc;
|
||
tmp[i] = f.mul(acc, tmp[i]);
|
||
return f.mul(acc, num);
|
||
}, inverted);
|
||
return tmp;
|
||
}
|
||
// CURVE.n lengths
|
||
function nLength(n, nBitLength) {
|
||
// Bit size, byte size of CURVE.n
|
||
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
||
const nByteLength = Math.ceil(_nBitLength / 8);
|
||
return { nBitLength: _nBitLength, nByteLength };
|
||
}
|
||
/**
|
||
* Initializes a finite field over prime. **Non-primes are not supported.**
|
||
* Do not init in loop: slow. Very fragile: always run a benchmark on a change.
|
||
* Major performance optimizations:
|
||
* * a) denormalized operations like mulN instead of mul
|
||
* * b) same object shape: never add or remove keys
|
||
* * c) Object.freeze
|
||
* @param ORDER prime positive bigint
|
||
* @param bitLen how many bits the field consumes
|
||
* @param isLE (def: false) if encoding / decoding should be in little-endian
|
||
* @param redef optional faster redefinitions of sqrt and other methods
|
||
*/
|
||
function Field(ORDER, bitLen, isLE = false, redef = {}) {
|
||
if (ORDER <= _0n$4)
|
||
throw new Error(`Expected Field ORDER > 0, got ${ORDER}`);
|
||
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
||
if (BYTES > 2048)
|
||
throw new Error('Field lengths over 2048 bytes are not supported');
|
||
const sqrtP = FpSqrt(ORDER);
|
||
const f = Object.freeze({
|
||
ORDER,
|
||
BITS,
|
||
BYTES,
|
||
MASK: bitMask(BITS),
|
||
ZERO: _0n$4,
|
||
ONE: _1n$6,
|
||
create: (num) => mod(num, ORDER),
|
||
isValid: (num) => {
|
||
if (typeof num !== 'bigint')
|
||
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
|
||
return _0n$4 <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
||
},
|
||
is0: (num) => num === _0n$4,
|
||
isOdd: (num) => (num & _1n$6) === _1n$6,
|
||
neg: (num) => mod(-num, ORDER),
|
||
eql: (lhs, rhs) => lhs === rhs,
|
||
sqr: (num) => mod(num * num, ORDER),
|
||
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
||
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
||
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
||
pow: (num, power) => FpPow(f, num, power),
|
||
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
||
// Same as above, but doesn't normalize
|
||
sqrN: (num) => num * num,
|
||
addN: (lhs, rhs) => lhs + rhs,
|
||
subN: (lhs, rhs) => lhs - rhs,
|
||
mulN: (lhs, rhs) => lhs * rhs,
|
||
inv: (num) => invert(num, ORDER),
|
||
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
|
||
invertBatch: (lst) => FpInvertBatch(f, lst),
|
||
// TODO: do we really need constant cmov?
|
||
// We don't have const-time bigints anyway, so probably will be not very useful
|
||
cmov: (a, b, c) => (c ? b : a),
|
||
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
|
||
fromBytes: (bytes) => {
|
||
if (bytes.length !== BYTES)
|
||
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
|
||
return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
||
},
|
||
});
|
||
return Object.freeze(f);
|
||
}
|
||
function FpSqrtEven(Fp, elm) {
|
||
if (!Fp.isOdd)
|
||
throw new Error(`Field doesn't have isOdd`);
|
||
const root = Fp.sqrt(elm);
|
||
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
||
}
|
||
/**
|
||
* Returns total number of bytes consumed by the field element.
|
||
* For example, 32 bytes for usual 256-bit weierstrass curve.
|
||
* @param fieldOrder number of field elements, usually CURVE.n
|
||
* @returns byte length of field
|
||
*/
|
||
function getFieldBytesLength(fieldOrder) {
|
||
if (typeof fieldOrder !== 'bigint')
|
||
throw new Error('field order must be bigint');
|
||
const bitLength = fieldOrder.toString(2).length;
|
||
return Math.ceil(bitLength / 8);
|
||
}
|
||
/**
|
||
* Returns minimal amount of bytes that can be safely reduced
|
||
* by field order.
|
||
* Should be 2^-128 for 128-bit curve such as P256.
|
||
* @param fieldOrder number of field elements, usually CURVE.n
|
||
* @returns byte length of target hash
|
||
*/
|
||
function getMinHashLength(fieldOrder) {
|
||
const length = getFieldBytesLength(fieldOrder);
|
||
return length + Math.ceil(length / 2);
|
||
}
|
||
/**
|
||
* "Constant-time" private key generation utility.
|
||
* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
|
||
* and convert them into private scalar, with the modulo bias being negligible.
|
||
* Needs at least 48 bytes of input for 32-byte private key.
|
||
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
||
* FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
|
||
* RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
|
||
* @param hash hash output from SHA3 or a similar function
|
||
* @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
|
||
* @param isLE interpret hash bytes as LE num
|
||
* @returns valid private scalar
|
||
*/
|
||
function mapHashToField(key, fieldOrder, isLE = false) {
|
||
const len = key.length;
|
||
const fieldLen = getFieldBytesLength(fieldOrder);
|
||
const minLen = getMinHashLength(fieldOrder);
|
||
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
||
if (len < 16 || len < minLen || len > 1024)
|
||
throw new Error(`expected ${minLen}-1024 bytes of input, got ${len}`);
|
||
const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
|
||
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
||
const reduced = mod(num, fieldOrder - _1n$6) + _1n$6;
|
||
return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
|
||
}
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// Abelian group utilities
|
||
const _0n$3 = BigInt(0);
|
||
const _1n$5 = BigInt(1);
|
||
// Elliptic curve multiplication of Point by scalar. Fragile.
|
||
// Scalars should always be less than curve order: this should be checked inside of a curve itself.
|
||
// Creates precomputation tables for fast multiplication:
|
||
// - private scalar is split by fixed size windows of W bits
|
||
// - every window point is collected from window's table & added to accumulator
|
||
// - since windows are different, same point inside tables won't be accessed more than once per calc
|
||
// - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)
|
||
// - +1 window is neccessary for wNAF
|
||
// - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
|
||
// TODO: Research returning 2d JS array of windows, instead of a single window. This would allow
|
||
// windows to be in different memory locations
|
||
function wNAF(c, bits) {
|
||
const constTimeNegate = (condition, item) => {
|
||
const neg = item.negate();
|
||
return condition ? neg : item;
|
||
};
|
||
const opts = (W) => {
|
||
const windows = Math.ceil(bits / W) + 1; // +1, because
|
||
const windowSize = 2 ** (W - 1); // -1 because we skip zero
|
||
return { windows, windowSize };
|
||
};
|
||
return {
|
||
constTimeNegate,
|
||
// non-const time multiplication ladder
|
||
unsafeLadder(elm, n) {
|
||
let p = c.ZERO;
|
||
let d = elm;
|
||
while (n > _0n$3) {
|
||
if (n & _1n$5)
|
||
p = p.add(d);
|
||
d = d.double();
|
||
n >>= _1n$5;
|
||
}
|
||
return p;
|
||
},
|
||
/**
|
||
* Creates a wNAF precomputation window. Used for caching.
|
||
* Default window size is set by `utils.precompute()` and is equal to 8.
|
||
* Number of precomputed points depends on the curve size:
|
||
* 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
|
||
* - 𝑊 is the window size
|
||
* - 𝑛 is the bitlength of the curve order.
|
||
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
||
* @returns precomputed point tables flattened to a single array
|
||
*/
|
||
precomputeWindow(elm, W) {
|
||
const { windows, windowSize } = opts(W);
|
||
const points = [];
|
||
let p = elm;
|
||
let base = p;
|
||
for (let window = 0; window < windows; window++) {
|
||
base = p;
|
||
points.push(base);
|
||
// =1, because we skip zero
|
||
for (let i = 1; i < windowSize; i++) {
|
||
base = base.add(p);
|
||
points.push(base);
|
||
}
|
||
p = base.double();
|
||
}
|
||
return points;
|
||
},
|
||
/**
|
||
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
|
||
* @param W window size
|
||
* @param precomputes precomputed tables
|
||
* @param n scalar (we don't check here, but should be less than curve order)
|
||
* @returns real and fake (for const-time) points
|
||
*/
|
||
wNAF(W, precomputes, n) {
|
||
// TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise
|
||
// But need to carefully remove other checks before wNAF. ORDER == bits here
|
||
const { windows, windowSize } = opts(W);
|
||
let p = c.ZERO;
|
||
let f = c.BASE;
|
||
const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.
|
||
const maxNumber = 2 ** W;
|
||
const shiftBy = BigInt(W);
|
||
for (let window = 0; window < windows; window++) {
|
||
const offset = window * windowSize;
|
||
// Extract W bits.
|
||
let wbits = Number(n & mask);
|
||
// Shift number by W bits.
|
||
n >>= shiftBy;
|
||
// If the bits are bigger than max size, we'll split those.
|
||
// +224 => 256 - 32
|
||
if (wbits > windowSize) {
|
||
wbits -= maxNumber;
|
||
n += _1n$5;
|
||
}
|
||
// This code was first written with assumption that 'f' and 'p' will never be infinity point:
|
||
// since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
|
||
// there is negate now: it is possible that negated element from low value
|
||
// would be the same as high element, which will create carry into next window.
|
||
// It's not obvious how this can fail, but still worth investigating later.
|
||
// Check if we're onto Zero point.
|
||
// Add random point inside current window to f.
|
||
const offset1 = offset;
|
||
const offset2 = offset + Math.abs(wbits) - 1; // -1 because we skip zero
|
||
const cond1 = window % 2 !== 0;
|
||
const cond2 = wbits < 0;
|
||
if (wbits === 0) {
|
||
// The most important part for const-time getPublicKey
|
||
f = f.add(constTimeNegate(cond1, precomputes[offset1]));
|
||
}
|
||
else {
|
||
p = p.add(constTimeNegate(cond2, precomputes[offset2]));
|
||
}
|
||
}
|
||
// JIT-compiler should not eliminate f here, since it will later be used in normalizeZ()
|
||
// Even if the variable is still unused, there are some checks which will
|
||
// throw an exception, so compiler needs to prove they won't happen, which is hard.
|
||
// At this point there is a way to F be infinity-point even if p is not,
|
||
// which makes it less const-time: around 1 bigint multiply.
|
||
return { p, f };
|
||
},
|
||
wNAFCached(P, precomputesMap, n, transform) {
|
||
// @ts-ignore
|
||
const W = P._WINDOW_SIZE || 1;
|
||
// Calculate precomputes on a first run, reuse them after
|
||
let comp = precomputesMap.get(P);
|
||
if (!comp) {
|
||
comp = this.precomputeWindow(P, W);
|
||
if (W !== 1) {
|
||
precomputesMap.set(P, transform(comp));
|
||
}
|
||
}
|
||
return this.wNAF(W, comp, n);
|
||
},
|
||
};
|
||
}
|
||
function validateBasic(curve) {
|
||
validateField(curve.Fp);
|
||
validateObject(curve, {
|
||
n: 'bigint',
|
||
h: 'bigint',
|
||
Gx: 'field',
|
||
Gy: 'field',
|
||
}, {
|
||
nBitLength: 'isSafeInteger',
|
||
nByteLength: 'isSafeInteger',
|
||
});
|
||
// Set defaults
|
||
return Object.freeze({
|
||
...nLength(curve.n, curve.nBitLength),
|
||
...curve,
|
||
...{ p: curve.Fp.ORDER },
|
||
});
|
||
}
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
||
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
||
// prettier-ignore
|
||
const _0n$2 = BigInt(0), _1n$4 = BigInt(1), _2n$3 = BigInt(2), _8n = BigInt(8);
|
||
// verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:
|
||
const VERIFY_DEFAULT = { zip215: true };
|
||
function validateOpts$1(curve) {
|
||
const opts = validateBasic(curve);
|
||
validateObject(curve, {
|
||
hash: 'function',
|
||
a: 'bigint',
|
||
d: 'bigint',
|
||
randomBytes: 'function',
|
||
}, {
|
||
adjustScalarBytes: 'function',
|
||
domain: 'function',
|
||
uvRatio: 'function',
|
||
mapToCurve: 'function',
|
||
});
|
||
// Set defaults
|
||
return Object.freeze({ ...opts });
|
||
}
|
||
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
|
||
function twistedEdwards(curveDef) {
|
||
const CURVE = validateOpts$1(curveDef);
|
||
const { Fp, n: CURVE_ORDER, prehash: prehash, hash: cHash, randomBytes, nByteLength, h: cofactor, } = CURVE;
|
||
const MASK = _2n$3 << (BigInt(nByteLength * 8) - _1n$4);
|
||
const modP = Fp.create; // Function overrides
|
||
// sqrt(u/v)
|
||
const uvRatio = CURVE.uvRatio ||
|
||
((u, v) => {
|
||
try {
|
||
return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };
|
||
}
|
||
catch (e) {
|
||
return { isValid: false, value: _0n$2 };
|
||
}
|
||
});
|
||
const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes); // NOOP
|
||
const domain = CURVE.domain ||
|
||
((data, ctx, phflag) => {
|
||
if (ctx.length || phflag)
|
||
throw new Error('Contexts/pre-hash are not supported');
|
||
return data;
|
||
}); // NOOP
|
||
const inBig = (n) => typeof n === 'bigint' && _0n$2 < n; // n in [1..]
|
||
const inRange = (n, max) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
|
||
const in0MaskRange = (n) => n === _0n$2 || inRange(n, MASK); // n in [0..MASK-1]
|
||
function assertInRange(n, max) {
|
||
// n in [1..max-1]
|
||
if (inRange(n, max))
|
||
return n;
|
||
throw new Error(`Expected valid scalar < ${max}, got ${typeof n} ${n}`);
|
||
}
|
||
function assertGE0(n) {
|
||
// n in [0..CURVE_ORDER-1]
|
||
return n === _0n$2 ? n : assertInRange(n, CURVE_ORDER); // GE = prime subgroup, not full group
|
||
}
|
||
const pointPrecomputes = new Map();
|
||
function isPoint(other) {
|
||
if (!(other instanceof Point))
|
||
throw new Error('ExtendedPoint expected');
|
||
}
|
||
// Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
|
||
// https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
|
||
class Point {
|
||
constructor(ex, ey, ez, et) {
|
||
this.ex = ex;
|
||
this.ey = ey;
|
||
this.ez = ez;
|
||
this.et = et;
|
||
if (!in0MaskRange(ex))
|
||
throw new Error('x required');
|
||
if (!in0MaskRange(ey))
|
||
throw new Error('y required');
|
||
if (!in0MaskRange(ez))
|
||
throw new Error('z required');
|
||
if (!in0MaskRange(et))
|
||
throw new Error('t required');
|
||
}
|
||
get x() {
|
||
return this.toAffine().x;
|
||
}
|
||
get y() {
|
||
return this.toAffine().y;
|
||
}
|
||
static fromAffine(p) {
|
||
if (p instanceof Point)
|
||
throw new Error('extended point not allowed');
|
||
const { x, y } = p || {};
|
||
if (!in0MaskRange(x) || !in0MaskRange(y))
|
||
throw new Error('invalid affine point');
|
||
return new Point(x, y, _1n$4, modP(x * y));
|
||
}
|
||
static normalizeZ(points) {
|
||
const toInv = Fp.invertBatch(points.map((p) => p.ez));
|
||
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
||
}
|
||
// "Private method", don't use it directly
|
||
_setWindowSize(windowSize) {
|
||
this._WINDOW_SIZE = windowSize;
|
||
pointPrecomputes.delete(this);
|
||
}
|
||
// Not required for fromHex(), which always creates valid points.
|
||
// Could be useful for fromAffine().
|
||
assertValidity() {
|
||
const { a, d } = CURVE;
|
||
if (this.is0())
|
||
throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
|
||
// Equation in affine coordinates: ax² + y² = 1 + dx²y²
|
||
// Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
|
||
const { ex: X, ey: Y, ez: Z, et: T } = this;
|
||
const X2 = modP(X * X); // X²
|
||
const Y2 = modP(Y * Y); // Y²
|
||
const Z2 = modP(Z * Z); // Z²
|
||
const Z4 = modP(Z2 * Z2); // Z⁴
|
||
const aX2 = modP(X2 * a); // aX²
|
||
const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²
|
||
const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
|
||
if (left !== right)
|
||
throw new Error('bad point: equation left != right (1)');
|
||
// In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
|
||
const XY = modP(X * Y);
|
||
const ZT = modP(Z * T);
|
||
if (XY !== ZT)
|
||
throw new Error('bad point: equation left != right (2)');
|
||
}
|
||
// Compare one point to another.
|
||
equals(other) {
|
||
isPoint(other);
|
||
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
||
const { ex: X2, ey: Y2, ez: Z2 } = other;
|
||
const X1Z2 = modP(X1 * Z2);
|
||
const X2Z1 = modP(X2 * Z1);
|
||
const Y1Z2 = modP(Y1 * Z2);
|
||
const Y2Z1 = modP(Y2 * Z1);
|
||
return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
|
||
}
|
||
is0() {
|
||
return this.equals(Point.ZERO);
|
||
}
|
||
negate() {
|
||
// Flips point sign to a negative one (-x, y in affine coords)
|
||
return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et));
|
||
}
|
||
// Fast algo for doubling Extended Point.
|
||
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
|
||
// Cost: 4M + 4S + 1*a + 6add + 1*2.
|
||
double() {
|
||
const { a } = CURVE;
|
||
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
||
const A = modP(X1 * X1); // A = X12
|
||
const B = modP(Y1 * Y1); // B = Y12
|
||
const C = modP(_2n$3 * modP(Z1 * Z1)); // C = 2*Z12
|
||
const D = modP(a * A); // D = a*A
|
||
const x1y1 = X1 + Y1;
|
||
const E = modP(modP(x1y1 * x1y1) - A - B); // E = (X1+Y1)2-A-B
|
||
const G = D + B; // G = D+B
|
||
const F = G - C; // F = G-C
|
||
const H = D - B; // H = D-B
|
||
const X3 = modP(E * F); // X3 = E*F
|
||
const Y3 = modP(G * H); // Y3 = G*H
|
||
const T3 = modP(E * H); // T3 = E*H
|
||
const Z3 = modP(F * G); // Z3 = F*G
|
||
return new Point(X3, Y3, Z3, T3);
|
||
}
|
||
// Fast algo for adding 2 Extended Points.
|
||
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd
|
||
// Cost: 9M + 1*a + 1*d + 7add.
|
||
add(other) {
|
||
isPoint(other);
|
||
const { a, d } = CURVE;
|
||
const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
|
||
const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
|
||
// Faster algo for adding 2 Extended Points when curve's a=-1.
|
||
// http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-4
|
||
// Cost: 8M + 8add + 2*2.
|
||
// Note: It does not check whether the `other` point is valid.
|
||
if (a === BigInt(-1)) {
|
||
const A = modP((Y1 - X1) * (Y2 + X2));
|
||
const B = modP((Y1 + X1) * (Y2 - X2));
|
||
const F = modP(B - A);
|
||
if (F === _0n$2)
|
||
return this.double(); // Same point. Tests say it doesn't affect timing
|
||
const C = modP(Z1 * _2n$3 * T2);
|
||
const D = modP(T1 * _2n$3 * Z2);
|
||
const E = D + C;
|
||
const G = B + A;
|
||
const H = D - C;
|
||
const X3 = modP(E * F);
|
||
const Y3 = modP(G * H);
|
||
const T3 = modP(E * H);
|
||
const Z3 = modP(F * G);
|
||
return new Point(X3, Y3, Z3, T3);
|
||
}
|
||
const A = modP(X1 * X2); // A = X1*X2
|
||
const B = modP(Y1 * Y2); // B = Y1*Y2
|
||
const C = modP(T1 * d * T2); // C = T1*d*T2
|
||
const D = modP(Z1 * Z2); // D = Z1*Z2
|
||
const E = modP((X1 + Y1) * (X2 + Y2) - A - B); // E = (X1+Y1)*(X2+Y2)-A-B
|
||
const F = D - C; // F = D-C
|
||
const G = D + C; // G = D+C
|
||
const H = modP(B - a * A); // H = B-a*A
|
||
const X3 = modP(E * F); // X3 = E*F
|
||
const Y3 = modP(G * H); // Y3 = G*H
|
||
const T3 = modP(E * H); // T3 = E*H
|
||
const Z3 = modP(F * G); // Z3 = F*G
|
||
return new Point(X3, Y3, Z3, T3);
|
||
}
|
||
subtract(other) {
|
||
return this.add(other.negate());
|
||
}
|
||
wNAF(n) {
|
||
return wnaf.wNAFCached(this, pointPrecomputes, n, Point.normalizeZ);
|
||
}
|
||
// Constant-time multiplication.
|
||
multiply(scalar) {
|
||
const { p, f } = this.wNAF(assertInRange(scalar, CURVE_ORDER));
|
||
return Point.normalizeZ([p, f])[0];
|
||
}
|
||
// Non-constant-time multiplication. Uses double-and-add algorithm.
|
||
// It's faster, but should only be used when you don't care about
|
||
// an exposed private key e.g. sig verification.
|
||
// Does NOT allow scalars higher than CURVE.n.
|
||
multiplyUnsafe(scalar) {
|
||
let n = assertGE0(scalar); // 0 <= scalar < CURVE.n
|
||
if (n === _0n$2)
|
||
return I;
|
||
if (this.equals(I) || n === _1n$4)
|
||
return this;
|
||
if (this.equals(G))
|
||
return this.wNAF(n).p;
|
||
return wnaf.unsafeLadder(this, n);
|
||
}
|
||
// Checks if point is of small order.
|
||
// If you add something to small order point, you will have "dirty"
|
||
// point with torsion component.
|
||
// Multiplies point by cofactor and checks if the result is 0.
|
||
isSmallOrder() {
|
||
return this.multiplyUnsafe(cofactor).is0();
|
||
}
|
||
// Multiplies point by curve order and checks if the result is 0.
|
||
// Returns `false` is the point is dirty.
|
||
isTorsionFree() {
|
||
return wnaf.unsafeLadder(this, CURVE_ORDER).is0();
|
||
}
|
||
// Converts Extended point to default (x, y) coordinates.
|
||
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
||
toAffine(iz) {
|
||
const { ex: x, ey: y, ez: z } = this;
|
||
const is0 = this.is0();
|
||
if (iz == null)
|
||
iz = is0 ? _8n : Fp.inv(z); // 8 was chosen arbitrarily
|
||
const ax = modP(x * iz);
|
||
const ay = modP(y * iz);
|
||
const zz = modP(z * iz);
|
||
if (is0)
|
||
return { x: _0n$2, y: _1n$4 };
|
||
if (zz !== _1n$4)
|
||
throw new Error('invZ was invalid');
|
||
return { x: ax, y: ay };
|
||
}
|
||
clearCofactor() {
|
||
const { h: cofactor } = CURVE;
|
||
if (cofactor === _1n$4)
|
||
return this;
|
||
return this.multiplyUnsafe(cofactor);
|
||
}
|
||
// Converts hash string or Uint8Array to Point.
|
||
// Uses algo from RFC8032 5.1.3.
|
||
static fromHex(hex, zip215 = false) {
|
||
const { d, a } = CURVE;
|
||
const len = Fp.BYTES;
|
||
hex = ensureBytes('pointHex', hex, len); // copy hex to a new array
|
||
const normed = hex.slice(); // copy again, we'll manipulate it
|
||
const lastByte = hex[len - 1]; // select last byte
|
||
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
||
const y = bytesToNumberLE(normed);
|
||
if (y === _0n$2) ;
|
||
else {
|
||
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
||
if (zip215)
|
||
assertInRange(y, MASK); // zip215=true [1..P-1] (2^255-19-1 for ed25519)
|
||
else
|
||
assertInRange(y, Fp.ORDER); // zip215=false [1..MASK-1] (2^256-1 for ed25519)
|
||
}
|
||
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
||
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
|
||
const y2 = modP(y * y); // denominator is always non-0 mod p.
|
||
const u = modP(y2 - _1n$4); // u = y² - 1
|
||
const v = modP(d * y2 - a); // v = d y² + 1.
|
||
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
|
||
if (!isValid)
|
||
throw new Error('Point.fromHex: invalid y coordinate');
|
||
const isXOdd = (x & _1n$4) === _1n$4; // There are 2 square roots. Use x_0 bit to select proper
|
||
const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit
|
||
if (!zip215 && x === _0n$2 && isLastByteOdd)
|
||
// if x=0 and x_0 = 1, fail
|
||
throw new Error('Point.fromHex: x=0 and x_0=1');
|
||
if (isLastByteOdd !== isXOdd)
|
||
x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
||
return Point.fromAffine({ x, y });
|
||
}
|
||
static fromPrivateKey(privKey) {
|
||
return getExtendedPublicKey(privKey).point;
|
||
}
|
||
toRawBytes() {
|
||
const { x, y } = this.toAffine();
|
||
const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
||
bytes[bytes.length - 1] |= x & _1n$4 ? 0x80 : 0; // when compressing, it's enough to store y
|
||
return bytes; // and use the last byte to encode sign of x
|
||
}
|
||
toHex() {
|
||
return bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
|
||
}
|
||
}
|
||
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n$4, modP(CURVE.Gx * CURVE.Gy));
|
||
Point.ZERO = new Point(_0n$2, _1n$4, _1n$4, _0n$2); // 0, 1, 1, 0
|
||
const { BASE: G, ZERO: I } = Point;
|
||
const wnaf = wNAF(Point, nByteLength * 8);
|
||
function modN(a) {
|
||
return mod(a, CURVE_ORDER);
|
||
}
|
||
// Little-endian SHA512 with modulo n
|
||
function modN_LE(hash) {
|
||
return modN(bytesToNumberLE(hash));
|
||
}
|
||
/** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
|
||
function getExtendedPublicKey(key) {
|
||
const len = nByteLength;
|
||
key = ensureBytes('private key', key, len);
|
||
// Hash private key with curve's hash function to produce uniformingly random input
|
||
// Check byte lengths: ensure(64, h(ensure(32, key)))
|
||
const hashed = ensureBytes('hashed private key', cHash(key), 2 * len);
|
||
const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE
|
||
const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6)
|
||
const scalar = modN_LE(head); // The actual private scalar
|
||
const point = G.multiply(scalar); // Point on Edwards curve aka public key
|
||
const pointBytes = point.toRawBytes(); // Uint8Array representation
|
||
return { head, prefix, scalar, point, pointBytes };
|
||
}
|
||
// Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared
|
||
function getPublicKey(privKey) {
|
||
return getExtendedPublicKey(privKey).pointBytes;
|
||
}
|
||
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
|
||
function hashDomainToScalar(context = new Uint8Array(), ...msgs) {
|
||
const msg = concatBytes(...msgs);
|
||
return modN_LE(cHash(domain(msg, ensureBytes('context', context), !!prehash)));
|
||
}
|
||
/** Signs message with privateKey. RFC8032 5.1.6 */
|
||
function sign(msg, privKey, options = {}) {
|
||
msg = ensureBytes('message', msg);
|
||
if (prehash)
|
||
msg = prehash(msg); // for ed25519ph etc.
|
||
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
||
const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
||
const R = G.multiply(r).toRawBytes(); // R = rG
|
||
const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
|
||
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
||
assertGE0(s); // 0 <= s < l
|
||
const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES));
|
||
return ensureBytes('result', res, nByteLength * 2); // 64-byte signature
|
||
}
|
||
const verifyOpts = VERIFY_DEFAULT;
|
||
function verify(sig, msg, publicKey, options = verifyOpts) {
|
||
const { context, zip215 } = options;
|
||
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
||
sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.
|
||
msg = ensureBytes('message', msg);
|
||
if (prehash)
|
||
msg = prehash(msg); // for ed25519ph, etc
|
||
const s = bytesToNumberLE(sig.slice(len, 2 * len));
|
||
// zip215: true is good for consensus-critical apps and allows points < 2^256
|
||
// zip215: false follows RFC8032 / NIST186-5 and restricts points to CURVE.p
|
||
let A, R, SB;
|
||
try {
|
||
A = Point.fromHex(publicKey, zip215);
|
||
R = Point.fromHex(sig.slice(0, len), zip215);
|
||
SB = G.multiplyUnsafe(s); // 0 <= s < l is done inside
|
||
}
|
||
catch (error) {
|
||
return false;
|
||
}
|
||
if (!zip215 && A.isSmallOrder())
|
||
return false;
|
||
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
||
const RkA = R.add(A.multiplyUnsafe(k));
|
||
// [8][S]B = [8]R + [8][k]A'
|
||
return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
|
||
}
|
||
G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
||
const utils = {
|
||
getExtendedPublicKey,
|
||
// ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1.
|
||
randomPrivateKey: () => randomBytes(Fp.BYTES),
|
||
/**
|
||
* We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
|
||
* values. This slows down first getPublicKey() by milliseconds (see Speed section),
|
||
* but allows to speed-up subsequent getPublicKey() calls up to 20x.
|
||
* @param windowSize 2, 4, 8, 16
|
||
*/
|
||
precompute(windowSize = 8, point = Point.BASE) {
|
||
point._setWindowSize(windowSize);
|
||
point.multiply(BigInt(3));
|
||
return point;
|
||
},
|
||
};
|
||
return {
|
||
CURVE,
|
||
getPublicKey,
|
||
sign,
|
||
verify,
|
||
ExtendedPoint: Point,
|
||
utils,
|
||
};
|
||
}
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
/**
|
||
* ed25519 Twisted Edwards curve with following addons:
|
||
* - X25519 ECDH
|
||
* - Ristretto cofactor elimination
|
||
* - Elligator hash-to-group / point indistinguishability
|
||
*/
|
||
const ED25519_P = BigInt('57896044618658097711785492504343953926634992332820282019728792003956564819949');
|
||
// √(-1) aka √(a) aka 2^((p-1)/4)
|
||
const ED25519_SQRT_M1 = BigInt('19681161376707505956807079304988542015446066515923890162744021073123829784752');
|
||
// prettier-ignore
|
||
BigInt(0); const _1n$3 = BigInt(1), _2n$2 = BigInt(2), _5n = BigInt(5);
|
||
// prettier-ignore
|
||
const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
|
||
function ed25519_pow_2_252_3(x) {
|
||
const P = ED25519_P;
|
||
const x2 = (x * x) % P;
|
||
const b2 = (x2 * x) % P; // x^3, 11
|
||
const b4 = (pow2(b2, _2n$2, P) * b2) % P; // x^15, 1111
|
||
const b5 = (pow2(b4, _1n$3, P) * x) % P; // x^31
|
||
const b10 = (pow2(b5, _5n, P) * b5) % P;
|
||
const b20 = (pow2(b10, _10n, P) * b10) % P;
|
||
const b40 = (pow2(b20, _20n, P) * b20) % P;
|
||
const b80 = (pow2(b40, _40n, P) * b40) % P;
|
||
const b160 = (pow2(b80, _80n, P) * b80) % P;
|
||
const b240 = (pow2(b160, _80n, P) * b80) % P;
|
||
const b250 = (pow2(b240, _10n, P) * b10) % P;
|
||
const pow_p_5_8 = (pow2(b250, _2n$2, P) * x) % P;
|
||
// ^ To pow to (p+3)/8, multiply it by x.
|
||
return { pow_p_5_8, b2 };
|
||
}
|
||
function adjustScalarBytes(bytes) {
|
||
// Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,
|
||
// set the three least significant bits of the first byte
|
||
bytes[0] &= 248; // 0b1111_1000
|
||
// and the most significant bit of the last to zero,
|
||
bytes[31] &= 127; // 0b0111_1111
|
||
// set the second most significant bit of the last byte to 1
|
||
bytes[31] |= 64; // 0b0100_0000
|
||
return bytes;
|
||
}
|
||
// sqrt(u/v)
|
||
function uvRatio(u, v) {
|
||
const P = ED25519_P;
|
||
const v3 = mod(v * v * v, P); // v³
|
||
const v7 = mod(v3 * v3 * v, P); // v⁷
|
||
// (p+3)/8 and (p-5)/8
|
||
const pow = ed25519_pow_2_252_3(u * v7).pow_p_5_8;
|
||
let x = mod(u * v3 * pow, P); // (uv³)(uv⁷)^(p-5)/8
|
||
const vx2 = mod(v * x * x, P); // vx²
|
||
const root1 = x; // First root candidate
|
||
const root2 = mod(x * ED25519_SQRT_M1, P); // Second root candidate
|
||
const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
|
||
const useRoot2 = vx2 === mod(-u, P); // If vx² = -u, set x <-- x * 2^((p-1)/4)
|
||
const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P); // There is no valid root, vx² = -u√(-1)
|
||
if (useRoot1)
|
||
x = root1;
|
||
if (useRoot2 || noRoot)
|
||
x = root2; // We return root2 anyway, for const-time
|
||
if (isNegativeLE(x, P))
|
||
x = mod(-x, P);
|
||
return { isValid: useRoot1 || useRoot2, value: x };
|
||
}
|
||
const Fp$1 = Field(ED25519_P, undefined, true);
|
||
const ed25519Defaults = {
|
||
// Param: a
|
||
a: BigInt(-1), // Fp.create(-1) is proper; our way still works and is faster
|
||
// d is equal to -121665/121666 over finite field.
|
||
// Negative number is P - number, and division is invert(number, P)
|
||
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
|
||
// Finite field 𝔽p over which we'll do calculations; 2n**255n - 19n
|
||
Fp: Fp$1,
|
||
// Subgroup order: how many points curve has
|
||
// 2n**252n + 27742317777372353535851937790883648493n;
|
||
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
|
||
// Cofactor
|
||
h: BigInt(8),
|
||
// Base point (x, y) aka generator point
|
||
Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
|
||
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
|
||
hash: sha512,
|
||
randomBytes,
|
||
adjustScalarBytes,
|
||
// dom2
|
||
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
|
||
// Constant-time, u/√v
|
||
uvRatio,
|
||
};
|
||
const ed25519 = /* @__PURE__ */ twistedEdwards(ed25519Defaults);
|
||
function ed25519_domain(data, ctx, phflag) {
|
||
if (ctx.length > 255)
|
||
throw new Error('Context is too big');
|
||
return concatBytes$1(utf8ToBytes$2('SigEd25519 no Ed25519 collisions'), new Uint8Array([phflag ? 1 : 0, ctx.length]), ctx, data);
|
||
}
|
||
/* @__PURE__ */ twistedEdwards({
|
||
...ed25519Defaults,
|
||
domain: ed25519_domain,
|
||
});
|
||
/* @__PURE__ */ twistedEdwards({
|
||
...ed25519Defaults,
|
||
domain: ed25519_domain,
|
||
prehash: sha512,
|
||
});
|
||
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
|
||
// NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since
|
||
// SageMath returns different root first and everything falls apart
|
||
const ELL2_C1 = (Fp$1.ORDER + BigInt(3)) / BigInt(8); // 1. c1 = (q + 3) / 8 # Integer arithmetic
|
||
Fp$1.pow(_2n$2, ELL2_C1); // 2. c2 = 2^c1
|
||
Fp$1.sqrt(Fp$1.neg(Fp$1.ONE)); // 3. c3 = sqrt(-1)
|
||
(Fp$1.ORDER - BigInt(5)) / BigInt(8); // 4. c4 = (q - 5) / 8 # Integer arithmetic
|
||
BigInt(486662);
|
||
FpSqrtEven(Fp$1, Fp$1.neg(BigInt(486664))); // sgn0(c1) MUST equal 0
|
||
// √(ad - 1)
|
||
BigInt('25063068953384623474111414158702152701244531502492656460079210482610430750235');
|
||
// 1 / √(a-d)
|
||
BigInt('54469307008909316920995813868745141605393597292927456921205312896311721017578');
|
||
// 1-d²
|
||
BigInt('1159843021668779879193775521855586647937357759715417654439879720876111806838');
|
||
// (d-1)²
|
||
BigInt('40440834346308536858101042469323190826248399146238708352240133220865137265952');
|
||
BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
||
|
||
/**
|
||
* A 64 byte secret key, the first 32 bytes of which is the
|
||
* private scalar and the last 32 bytes is the public key.
|
||
* Read more: https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/
|
||
*/
|
||
|
||
/**
|
||
* Ed25519 Keypair
|
||
*/
|
||
|
||
const generatePrivateKey = ed25519.utils.randomPrivateKey;
|
||
const generateKeypair = () => {
|
||
const privateScalar = ed25519.utils.randomPrivateKey();
|
||
const publicKey = getPublicKey(privateScalar);
|
||
const secretKey = new Uint8Array(64);
|
||
secretKey.set(privateScalar);
|
||
secretKey.set(publicKey, 32);
|
||
return {
|
||
publicKey,
|
||
secretKey
|
||
};
|
||
};
|
||
const getPublicKey = ed25519.getPublicKey;
|
||
function isOnCurve(publicKey) {
|
||
try {
|
||
ed25519.ExtendedPoint.fromHex(publicKey);
|
||
return true;
|
||
} catch {
|
||
return false;
|
||
}
|
||
}
|
||
const sign = (message, secretKey) => ed25519.sign(message, secretKey.slice(0, 32));
|
||
const verify = ed25519.verify;
|
||
|
||
const toBuffer = arr => {
|
||
if (buffer.Buffer.isBuffer(arr)) {
|
||
return arr;
|
||
} else if (arr instanceof Uint8Array) {
|
||
return buffer.Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
|
||
} else {
|
||
return buffer.Buffer.from(arr);
|
||
}
|
||
};
|
||
|
||
var bn = {exports: {}};
|
||
|
||
var _nodeResolve_empty = {};
|
||
|
||
var _nodeResolve_empty$1 = /*#__PURE__*/Object.freeze({
|
||
__proto__: null,
|
||
default: _nodeResolve_empty
|
||
});
|
||
|
||
var require$$0$1 = /*@__PURE__*/getAugmentedNamespace(_nodeResolve_empty$1);
|
||
|
||
bn.exports;
|
||
|
||
(function (module) {
|
||
(function (module, exports) {
|
||
|
||
// Utils
|
||
function assert (val, msg) {
|
||
if (!val) throw new Error(msg || 'Assertion failed');
|
||
}
|
||
|
||
// Could use `inherits` module, but don't want to move from single file
|
||
// architecture yet.
|
||
function inherits (ctor, superCtor) {
|
||
ctor.super_ = superCtor;
|
||
var TempCtor = function () {};
|
||
TempCtor.prototype = superCtor.prototype;
|
||
ctor.prototype = new TempCtor();
|
||
ctor.prototype.constructor = ctor;
|
||
}
|
||
|
||
// BN
|
||
|
||
function BN (number, base, endian) {
|
||
if (BN.isBN(number)) {
|
||
return number;
|
||
}
|
||
|
||
this.negative = 0;
|
||
this.words = null;
|
||
this.length = 0;
|
||
|
||
// Reduction context
|
||
this.red = null;
|
||
|
||
if (number !== null) {
|
||
if (base === 'le' || base === 'be') {
|
||
endian = base;
|
||
base = 10;
|
||
}
|
||
|
||
this._init(number || 0, base || 10, endian || 'be');
|
||
}
|
||
}
|
||
if (typeof module === 'object') {
|
||
module.exports = BN;
|
||
} else {
|
||
exports.BN = BN;
|
||
}
|
||
|
||
BN.BN = BN;
|
||
BN.wordSize = 26;
|
||
|
||
var Buffer;
|
||
try {
|
||
if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') {
|
||
Buffer = window.Buffer;
|
||
} else {
|
||
Buffer = require$$0$1.Buffer;
|
||
}
|
||
} catch (e) {
|
||
}
|
||
|
||
BN.isBN = function isBN (num) {
|
||
if (num instanceof BN) {
|
||
return true;
|
||
}
|
||
|
||
return num !== null && typeof num === 'object' &&
|
||
num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);
|
||
};
|
||
|
||
BN.max = function max (left, right) {
|
||
if (left.cmp(right) > 0) return left;
|
||
return right;
|
||
};
|
||
|
||
BN.min = function min (left, right) {
|
||
if (left.cmp(right) < 0) return left;
|
||
return right;
|
||
};
|
||
|
||
BN.prototype._init = function init (number, base, endian) {
|
||
if (typeof number === 'number') {
|
||
return this._initNumber(number, base, endian);
|
||
}
|
||
|
||
if (typeof number === 'object') {
|
||
return this._initArray(number, base, endian);
|
||
}
|
||
|
||
if (base === 'hex') {
|
||
base = 16;
|
||
}
|
||
assert(base === (base | 0) && base >= 2 && base <= 36);
|
||
|
||
number = number.toString().replace(/\s+/g, '');
|
||
var start = 0;
|
||
if (number[0] === '-') {
|
||
start++;
|
||
this.negative = 1;
|
||
}
|
||
|
||
if (start < number.length) {
|
||
if (base === 16) {
|
||
this._parseHex(number, start, endian);
|
||
} else {
|
||
this._parseBase(number, base, start);
|
||
if (endian === 'le') {
|
||
this._initArray(this.toArray(), base, endian);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
BN.prototype._initNumber = function _initNumber (number, base, endian) {
|
||
if (number < 0) {
|
||
this.negative = 1;
|
||
number = -number;
|
||
}
|
||
if (number < 0x4000000) {
|
||
this.words = [number & 0x3ffffff];
|
||
this.length = 1;
|
||
} else if (number < 0x10000000000000) {
|
||
this.words = [
|
||
number & 0x3ffffff,
|
||
(number / 0x4000000) & 0x3ffffff
|
||
];
|
||
this.length = 2;
|
||
} else {
|
||
assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)
|
||
this.words = [
|
||
number & 0x3ffffff,
|
||
(number / 0x4000000) & 0x3ffffff,
|
||
1
|
||
];
|
||
this.length = 3;
|
||
}
|
||
|
||
if (endian !== 'le') return;
|
||
|
||
// Reverse the bytes
|
||
this._initArray(this.toArray(), base, endian);
|
||
};
|
||
|
||
BN.prototype._initArray = function _initArray (number, base, endian) {
|
||
// Perhaps a Uint8Array
|
||
assert(typeof number.length === 'number');
|
||
if (number.length <= 0) {
|
||
this.words = [0];
|
||
this.length = 1;
|
||
return this;
|
||
}
|
||
|
||
this.length = Math.ceil(number.length / 3);
|
||
this.words = new Array(this.length);
|
||
for (var i = 0; i < this.length; i++) {
|
||
this.words[i] = 0;
|
||
}
|
||
|
||
var j, w;
|
||
var off = 0;
|
||
if (endian === 'be') {
|
||
for (i = number.length - 1, j = 0; i >= 0; i -= 3) {
|
||
w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);
|
||
this.words[j] |= (w << off) & 0x3ffffff;
|
||
this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
|
||
off += 24;
|
||
if (off >= 26) {
|
||
off -= 26;
|
||
j++;
|
||
}
|
||
}
|
||
} else if (endian === 'le') {
|
||
for (i = 0, j = 0; i < number.length; i += 3) {
|
||
w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);
|
||
this.words[j] |= (w << off) & 0x3ffffff;
|
||
this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
|
||
off += 24;
|
||
if (off >= 26) {
|
||
off -= 26;
|
||
j++;
|
||
}
|
||
}
|
||
}
|
||
return this._strip();
|
||
};
|
||
|
||
function parseHex4Bits (string, index) {
|
||
var c = string.charCodeAt(index);
|
||
// '0' - '9'
|
||
if (c >= 48 && c <= 57) {
|
||
return c - 48;
|
||
// 'A' - 'F'
|
||
} else if (c >= 65 && c <= 70) {
|
||
return c - 55;
|
||
// 'a' - 'f'
|
||
} else if (c >= 97 && c <= 102) {
|
||
return c - 87;
|
||
} else {
|
||
assert(false, 'Invalid character in ' + string);
|
||
}
|
||
}
|
||
|
||
function parseHexByte (string, lowerBound, index) {
|
||
var r = parseHex4Bits(string, index);
|
||
if (index - 1 >= lowerBound) {
|
||
r |= parseHex4Bits(string, index - 1) << 4;
|
||
}
|
||
return r;
|
||
}
|
||
|
||
BN.prototype._parseHex = function _parseHex (number, start, endian) {
|
||
// Create possibly bigger array to ensure that it fits the number
|
||
this.length = Math.ceil((number.length - start) / 6);
|
||
this.words = new Array(this.length);
|
||
for (var i = 0; i < this.length; i++) {
|
||
this.words[i] = 0;
|
||
}
|
||
|
||
// 24-bits chunks
|
||
var off = 0;
|
||
var j = 0;
|
||
|
||
var w;
|
||
if (endian === 'be') {
|
||
for (i = number.length - 1; i >= start; i -= 2) {
|
||
w = parseHexByte(number, start, i) << off;
|
||
this.words[j] |= w & 0x3ffffff;
|
||
if (off >= 18) {
|
||
off -= 18;
|
||
j += 1;
|
||
this.words[j] |= w >>> 26;
|
||
} else {
|
||
off += 8;
|
||
}
|
||
}
|
||
} else {
|
||
var parseLength = number.length - start;
|
||
for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) {
|
||
w = parseHexByte(number, start, i) << off;
|
||
this.words[j] |= w & 0x3ffffff;
|
||
if (off >= 18) {
|
||
off -= 18;
|
||
j += 1;
|
||
this.words[j] |= w >>> 26;
|
||
} else {
|
||
off += 8;
|
||
}
|
||
}
|
||
}
|
||
|
||
this._strip();
|
||
};
|
||
|
||
function parseBase (str, start, end, mul) {
|
||
var r = 0;
|
||
var b = 0;
|
||
var len = Math.min(str.length, end);
|
||
for (var i = start; i < len; i++) {
|
||
var c = str.charCodeAt(i) - 48;
|
||
|
||
r *= mul;
|
||
|
||
// 'a'
|
||
if (c >= 49) {
|
||
b = c - 49 + 0xa;
|
||
|
||
// 'A'
|
||
} else if (c >= 17) {
|
||
b = c - 17 + 0xa;
|
||
|
||
// '0' - '9'
|
||
} else {
|
||
b = c;
|
||
}
|
||
assert(c >= 0 && b < mul, 'Invalid character');
|
||
r += b;
|
||
}
|
||
return r;
|
||
}
|
||
|
||
BN.prototype._parseBase = function _parseBase (number, base, start) {
|
||
// Initialize as zero
|
||
this.words = [0];
|
||
this.length = 1;
|
||
|
||
// Find length of limb in base
|
||
for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {
|
||
limbLen++;
|
||
}
|
||
limbLen--;
|
||
limbPow = (limbPow / base) | 0;
|
||
|
||
var total = number.length - start;
|
||
var mod = total % limbLen;
|
||
var end = Math.min(total, total - mod) + start;
|
||
|
||
var word = 0;
|
||
for (var i = start; i < end; i += limbLen) {
|
||
word = parseBase(number, i, i + limbLen, base);
|
||
|
||
this.imuln(limbPow);
|
||
if (this.words[0] + word < 0x4000000) {
|
||
this.words[0] += word;
|
||
} else {
|
||
this._iaddn(word);
|
||
}
|
||
}
|
||
|
||
if (mod !== 0) {
|
||
var pow = 1;
|
||
word = parseBase(number, i, number.length, base);
|
||
|
||
for (i = 0; i < mod; i++) {
|
||
pow *= base;
|
||
}
|
||
|
||
this.imuln(pow);
|
||
if (this.words[0] + word < 0x4000000) {
|
||
this.words[0] += word;
|
||
} else {
|
||
this._iaddn(word);
|
||
}
|
||
}
|
||
|
||
this._strip();
|
||
};
|
||
|
||
BN.prototype.copy = function copy (dest) {
|
||
dest.words = new Array(this.length);
|
||
for (var i = 0; i < this.length; i++) {
|
||
dest.words[i] = this.words[i];
|
||
}
|
||
dest.length = this.length;
|
||
dest.negative = this.negative;
|
||
dest.red = this.red;
|
||
};
|
||
|
||
function move (dest, src) {
|
||
dest.words = src.words;
|
||
dest.length = src.length;
|
||
dest.negative = src.negative;
|
||
dest.red = src.red;
|
||
}
|
||
|
||
BN.prototype._move = function _move (dest) {
|
||
move(dest, this);
|
||
};
|
||
|
||
BN.prototype.clone = function clone () {
|
||
var r = new BN(null);
|
||
this.copy(r);
|
||
return r;
|
||
};
|
||
|
||
BN.prototype._expand = function _expand (size) {
|
||
while (this.length < size) {
|
||
this.words[this.length++] = 0;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
// Remove leading `0` from `this`
|
||
BN.prototype._strip = function strip () {
|
||
while (this.length > 1 && this.words[this.length - 1] === 0) {
|
||
this.length--;
|
||
}
|
||
return this._normSign();
|
||
};
|
||
|
||
BN.prototype._normSign = function _normSign () {
|
||
// -0 = 0
|
||
if (this.length === 1 && this.words[0] === 0) {
|
||
this.negative = 0;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
// Check Symbol.for because not everywhere where Symbol defined
|
||
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#Browser_compatibility
|
||
if (typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') {
|
||
try {
|
||
BN.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspect;
|
||
} catch (e) {
|
||
BN.prototype.inspect = inspect;
|
||
}
|
||
} else {
|
||
BN.prototype.inspect = inspect;
|
||
}
|
||
|
||
function inspect () {
|
||
return (this.red ? '<BN-R: ' : '<BN: ') + this.toString(16) + '>';
|
||
}
|
||
|
||
/*
|
||
|
||
var zeros = [];
|
||
var groupSizes = [];
|
||
var groupBases = [];
|
||
|
||
var s = '';
|
||
var i = -1;
|
||
while (++i < BN.wordSize) {
|
||
zeros[i] = s;
|
||
s += '0';
|
||
}
|
||
groupSizes[0] = 0;
|
||
groupSizes[1] = 0;
|
||
groupBases[0] = 0;
|
||
groupBases[1] = 0;
|
||
var base = 2 - 1;
|
||
while (++base < 36 + 1) {
|
||
var groupSize = 0;
|
||
var groupBase = 1;
|
||
while (groupBase < (1 << BN.wordSize) / base) {
|
||
groupBase *= base;
|
||
groupSize += 1;
|
||
}
|
||
groupSizes[base] = groupSize;
|
||
groupBases[base] = groupBase;
|
||
}
|
||
|
||
*/
|
||
|
||
var zeros = [
|
||
'',
|
||
'0',
|
||
'00',
|
||
'000',
|
||
'0000',
|
||
'00000',
|
||
'000000',
|
||
'0000000',
|
||
'00000000',
|
||
'000000000',
|
||
'0000000000',
|
||
'00000000000',
|
||
'000000000000',
|
||
'0000000000000',
|
||
'00000000000000',
|
||
'000000000000000',
|
||
'0000000000000000',
|
||
'00000000000000000',
|
||
'000000000000000000',
|
||
'0000000000000000000',
|
||
'00000000000000000000',
|
||
'000000000000000000000',
|
||
'0000000000000000000000',
|
||
'00000000000000000000000',
|
||
'000000000000000000000000',
|
||
'0000000000000000000000000'
|
||
];
|
||
|
||
var groupSizes = [
|
||
0, 0,
|
||
25, 16, 12, 11, 10, 9, 8,
|
||
8, 7, 7, 7, 7, 6, 6,
|
||
6, 6, 6, 6, 6, 5, 5,
|
||
5, 5, 5, 5, 5, 5, 5,
|
||
5, 5, 5, 5, 5, 5, 5
|
||
];
|
||
|
||
var groupBases = [
|
||
0, 0,
|
||
33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,
|
||
43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,
|
||
16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,
|
||
6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,
|
||
24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176
|
||
];
|
||
|
||
BN.prototype.toString = function toString (base, padding) {
|
||
base = base || 10;
|
||
padding = padding | 0 || 1;
|
||
|
||
var out;
|
||
if (base === 16 || base === 'hex') {
|
||
out = '';
|
||
var off = 0;
|
||
var carry = 0;
|
||
for (var i = 0; i < this.length; i++) {
|
||
var w = this.words[i];
|
||
var word = (((w << off) | carry) & 0xffffff).toString(16);
|
||
carry = (w >>> (24 - off)) & 0xffffff;
|
||
off += 2;
|
||
if (off >= 26) {
|
||
off -= 26;
|
||
i--;
|
||
}
|
||
if (carry !== 0 || i !== this.length - 1) {
|
||
out = zeros[6 - word.length] + word + out;
|
||
} else {
|
||
out = word + out;
|
||
}
|
||
}
|
||
if (carry !== 0) {
|
||
out = carry.toString(16) + out;
|
||
}
|
||
while (out.length % padding !== 0) {
|
||
out = '0' + out;
|
||
}
|
||
if (this.negative !== 0) {
|
||
out = '-' + out;
|
||
}
|
||
return out;
|
||
}
|
||
|
||
if (base === (base | 0) && base >= 2 && base <= 36) {
|
||
// var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));
|
||
var groupSize = groupSizes[base];
|
||
// var groupBase = Math.pow(base, groupSize);
|
||
var groupBase = groupBases[base];
|
||
out = '';
|
||
var c = this.clone();
|
||
c.negative = 0;
|
||
while (!c.isZero()) {
|
||
var r = c.modrn(groupBase).toString(base);
|
||
c = c.idivn(groupBase);
|
||
|
||
if (!c.isZero()) {
|
||
out = zeros[groupSize - r.length] + r + out;
|
||
} else {
|
||
out = r + out;
|
||
}
|
||
}
|
||
if (this.isZero()) {
|
||
out = '0' + out;
|
||
}
|
||
while (out.length % padding !== 0) {
|
||
out = '0' + out;
|
||
}
|
||
if (this.negative !== 0) {
|
||
out = '-' + out;
|
||
}
|
||
return out;
|
||
}
|
||
|
||
assert(false, 'Base should be between 2 and 36');
|
||
};
|
||
|
||
BN.prototype.toNumber = function toNumber () {
|
||
var ret = this.words[0];
|
||
if (this.length === 2) {
|
||
ret += this.words[1] * 0x4000000;
|
||
} else if (this.length === 3 && this.words[2] === 0x01) {
|
||
// NOTE: at this stage it is known that the top bit is set
|
||
ret += 0x10000000000000 + (this.words[1] * 0x4000000);
|
||
} else if (this.length > 2) {
|
||
assert(false, 'Number can only safely store up to 53 bits');
|
||
}
|
||
return (this.negative !== 0) ? -ret : ret;
|
||
};
|
||
|
||
BN.prototype.toJSON = function toJSON () {
|
||
return this.toString(16, 2);
|
||
};
|
||
|
||
if (Buffer) {
|
||
BN.prototype.toBuffer = function toBuffer (endian, length) {
|
||
return this.toArrayLike(Buffer, endian, length);
|
||
};
|
||
}
|
||
|
||
BN.prototype.toArray = function toArray (endian, length) {
|
||
return this.toArrayLike(Array, endian, length);
|
||
};
|
||
|
||
var allocate = function allocate (ArrayType, size) {
|
||
if (ArrayType.allocUnsafe) {
|
||
return ArrayType.allocUnsafe(size);
|
||
}
|
||
return new ArrayType(size);
|
||
};
|
||
|
||
BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {
|
||
this._strip();
|
||
|
||
var byteLength = this.byteLength();
|
||
var reqLength = length || Math.max(1, byteLength);
|
||
assert(byteLength <= reqLength, 'byte array longer than desired length');
|
||
assert(reqLength > 0, 'Requested array length <= 0');
|
||
|
||
var res = allocate(ArrayType, reqLength);
|
||
var postfix = endian === 'le' ? 'LE' : 'BE';
|
||
this['_toArrayLike' + postfix](res, byteLength);
|
||
return res;
|
||
};
|
||
|
||
BN.prototype._toArrayLikeLE = function _toArrayLikeLE (res, byteLength) {
|
||
var position = 0;
|
||
var carry = 0;
|
||
|
||
for (var i = 0, shift = 0; i < this.length; i++) {
|
||
var word = (this.words[i] << shift) | carry;
|
||
|
||
res[position++] = word & 0xff;
|
||
if (position < res.length) {
|
||
res[position++] = (word >> 8) & 0xff;
|
||
}
|
||
if (position < res.length) {
|
||
res[position++] = (word >> 16) & 0xff;
|
||
}
|
||
|
||
if (shift === 6) {
|
||
if (position < res.length) {
|
||
res[position++] = (word >> 24) & 0xff;
|
||
}
|
||
carry = 0;
|
||
shift = 0;
|
||
} else {
|
||
carry = word >>> 24;
|
||
shift += 2;
|
||
}
|
||
}
|
||
|
||
if (position < res.length) {
|
||
res[position++] = carry;
|
||
|
||
while (position < res.length) {
|
||
res[position++] = 0;
|
||
}
|
||
}
|
||
};
|
||
|
||
BN.prototype._toArrayLikeBE = function _toArrayLikeBE (res, byteLength) {
|
||
var position = res.length - 1;
|
||
var carry = 0;
|
||
|
||
for (var i = 0, shift = 0; i < this.length; i++) {
|
||
var word = (this.words[i] << shift) | carry;
|
||
|
||
res[position--] = word & 0xff;
|
||
if (position >= 0) {
|
||
res[position--] = (word >> 8) & 0xff;
|
||
}
|
||
if (position >= 0) {
|
||
res[position--] = (word >> 16) & 0xff;
|
||
}
|
||
|
||
if (shift === 6) {
|
||
if (position >= 0) {
|
||
res[position--] = (word >> 24) & 0xff;
|
||
}
|
||
carry = 0;
|
||
shift = 0;
|
||
} else {
|
||
carry = word >>> 24;
|
||
shift += 2;
|
||
}
|
||
}
|
||
|
||
if (position >= 0) {
|
||
res[position--] = carry;
|
||
|
||
while (position >= 0) {
|
||
res[position--] = 0;
|
||
}
|
||
}
|
||
};
|
||
|
||
if (Math.clz32) {
|
||
BN.prototype._countBits = function _countBits (w) {
|
||
return 32 - Math.clz32(w);
|
||
};
|
||
} else {
|
||
BN.prototype._countBits = function _countBits (w) {
|
||
var t = w;
|
||
var r = 0;
|
||
if (t >= 0x1000) {
|
||
r += 13;
|
||
t >>>= 13;
|
||
}
|
||
if (t >= 0x40) {
|
||
r += 7;
|
||
t >>>= 7;
|
||
}
|
||
if (t >= 0x8) {
|
||
r += 4;
|
||
t >>>= 4;
|
||
}
|
||
if (t >= 0x02) {
|
||
r += 2;
|
||
t >>>= 2;
|
||
}
|
||
return r + t;
|
||
};
|
||
}
|
||
|
||
BN.prototype._zeroBits = function _zeroBits (w) {
|
||
// Short-cut
|
||
if (w === 0) return 26;
|
||
|
||
var t = w;
|
||
var r = 0;
|
||
if ((t & 0x1fff) === 0) {
|
||
r += 13;
|
||
t >>>= 13;
|
||
}
|
||
if ((t & 0x7f) === 0) {
|
||
r += 7;
|
||
t >>>= 7;
|
||
}
|
||
if ((t & 0xf) === 0) {
|
||
r += 4;
|
||
t >>>= 4;
|
||
}
|
||
if ((t & 0x3) === 0) {
|
||
r += 2;
|
||
t >>>= 2;
|
||
}
|
||
if ((t & 0x1) === 0) {
|
||
r++;
|
||
}
|
||
return r;
|
||
};
|
||
|
||
// Return number of used bits in a BN
|
||
BN.prototype.bitLength = function bitLength () {
|
||
var w = this.words[this.length - 1];
|
||
var hi = this._countBits(w);
|
||
return (this.length - 1) * 26 + hi;
|
||
};
|
||
|
||
function toBitArray (num) {
|
||
var w = new Array(num.bitLength());
|
||
|
||
for (var bit = 0; bit < w.length; bit++) {
|
||
var off = (bit / 26) | 0;
|
||
var wbit = bit % 26;
|
||
|
||
w[bit] = (num.words[off] >>> wbit) & 0x01;
|
||
}
|
||
|
||
return w;
|
||
}
|
||
|
||
// Number of trailing zero bits
|
||
BN.prototype.zeroBits = function zeroBits () {
|
||
if (this.isZero()) return 0;
|
||
|
||
var r = 0;
|
||
for (var i = 0; i < this.length; i++) {
|
||
var b = this._zeroBits(this.words[i]);
|
||
r += b;
|
||
if (b !== 26) break;
|
||
}
|
||
return r;
|
||
};
|
||
|
||
BN.prototype.byteLength = function byteLength () {
|
||
return Math.ceil(this.bitLength() / 8);
|
||
};
|
||
|
||
BN.prototype.toTwos = function toTwos (width) {
|
||
if (this.negative !== 0) {
|
||
return this.abs().inotn(width).iaddn(1);
|
||
}
|
||
return this.clone();
|
||
};
|
||
|
||
BN.prototype.fromTwos = function fromTwos (width) {
|
||
if (this.testn(width - 1)) {
|
||
return this.notn(width).iaddn(1).ineg();
|
||
}
|
||
return this.clone();
|
||
};
|
||
|
||
BN.prototype.isNeg = function isNeg () {
|
||
return this.negative !== 0;
|
||
};
|
||
|
||
// Return negative clone of `this`
|
||
BN.prototype.neg = function neg () {
|
||
return this.clone().ineg();
|
||
};
|
||
|
||
BN.prototype.ineg = function ineg () {
|
||
if (!this.isZero()) {
|
||
this.negative ^= 1;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
// Or `num` with `this` in-place
|
||
BN.prototype.iuor = function iuor (num) {
|
||
while (this.length < num.length) {
|
||
this.words[this.length++] = 0;
|
||
}
|
||
|
||
for (var i = 0; i < num.length; i++) {
|
||
this.words[i] = this.words[i] | num.words[i];
|
||
}
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype.ior = function ior (num) {
|
||
assert((this.negative | num.negative) === 0);
|
||
return this.iuor(num);
|
||
};
|
||
|
||
// Or `num` with `this`
|
||
BN.prototype.or = function or (num) {
|
||
if (this.length > num.length) return this.clone().ior(num);
|
||
return num.clone().ior(this);
|
||
};
|
||
|
||
BN.prototype.uor = function uor (num) {
|
||
if (this.length > num.length) return this.clone().iuor(num);
|
||
return num.clone().iuor(this);
|
||
};
|
||
|
||
// And `num` with `this` in-place
|
||
BN.prototype.iuand = function iuand (num) {
|
||
// b = min-length(num, this)
|
||
var b;
|
||
if (this.length > num.length) {
|
||
b = num;
|
||
} else {
|
||
b = this;
|
||
}
|
||
|
||
for (var i = 0; i < b.length; i++) {
|
||
this.words[i] = this.words[i] & num.words[i];
|
||
}
|
||
|
||
this.length = b.length;
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype.iand = function iand (num) {
|
||
assert((this.negative | num.negative) === 0);
|
||
return this.iuand(num);
|
||
};
|
||
|
||
// And `num` with `this`
|
||
BN.prototype.and = function and (num) {
|
||
if (this.length > num.length) return this.clone().iand(num);
|
||
return num.clone().iand(this);
|
||
};
|
||
|
||
BN.prototype.uand = function uand (num) {
|
||
if (this.length > num.length) return this.clone().iuand(num);
|
||
return num.clone().iuand(this);
|
||
};
|
||
|
||
// Xor `num` with `this` in-place
|
||
BN.prototype.iuxor = function iuxor (num) {
|
||
// a.length > b.length
|
||
var a;
|
||
var b;
|
||
if (this.length > num.length) {
|
||
a = this;
|
||
b = num;
|
||
} else {
|
||
a = num;
|
||
b = this;
|
||
}
|
||
|
||
for (var i = 0; i < b.length; i++) {
|
||
this.words[i] = a.words[i] ^ b.words[i];
|
||
}
|
||
|
||
if (this !== a) {
|
||
for (; i < a.length; i++) {
|
||
this.words[i] = a.words[i];
|
||
}
|
||
}
|
||
|
||
this.length = a.length;
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype.ixor = function ixor (num) {
|
||
assert((this.negative | num.negative) === 0);
|
||
return this.iuxor(num);
|
||
};
|
||
|
||
// Xor `num` with `this`
|
||
BN.prototype.xor = function xor (num) {
|
||
if (this.length > num.length) return this.clone().ixor(num);
|
||
return num.clone().ixor(this);
|
||
};
|
||
|
||
BN.prototype.uxor = function uxor (num) {
|
||
if (this.length > num.length) return this.clone().iuxor(num);
|
||
return num.clone().iuxor(this);
|
||
};
|
||
|
||
// Not ``this`` with ``width`` bitwidth
|
||
BN.prototype.inotn = function inotn (width) {
|
||
assert(typeof width === 'number' && width >= 0);
|
||
|
||
var bytesNeeded = Math.ceil(width / 26) | 0;
|
||
var bitsLeft = width % 26;
|
||
|
||
// Extend the buffer with leading zeroes
|
||
this._expand(bytesNeeded);
|
||
|
||
if (bitsLeft > 0) {
|
||
bytesNeeded--;
|
||
}
|
||
|
||
// Handle complete words
|
||
for (var i = 0; i < bytesNeeded; i++) {
|
||
this.words[i] = ~this.words[i] & 0x3ffffff;
|
||
}
|
||
|
||
// Handle the residue
|
||
if (bitsLeft > 0) {
|
||
this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));
|
||
}
|
||
|
||
// And remove leading zeroes
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype.notn = function notn (width) {
|
||
return this.clone().inotn(width);
|
||
};
|
||
|
||
// Set `bit` of `this`
|
||
BN.prototype.setn = function setn (bit, val) {
|
||
assert(typeof bit === 'number' && bit >= 0);
|
||
|
||
var off = (bit / 26) | 0;
|
||
var wbit = bit % 26;
|
||
|
||
this._expand(off + 1);
|
||
|
||
if (val) {
|
||
this.words[off] = this.words[off] | (1 << wbit);
|
||
} else {
|
||
this.words[off] = this.words[off] & ~(1 << wbit);
|
||
}
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
// Add `num` to `this` in-place
|
||
BN.prototype.iadd = function iadd (num) {
|
||
var r;
|
||
|
||
// negative + positive
|
||
if (this.negative !== 0 && num.negative === 0) {
|
||
this.negative = 0;
|
||
r = this.isub(num);
|
||
this.negative ^= 1;
|
||
return this._normSign();
|
||
|
||
// positive + negative
|
||
} else if (this.negative === 0 && num.negative !== 0) {
|
||
num.negative = 0;
|
||
r = this.isub(num);
|
||
num.negative = 1;
|
||
return r._normSign();
|
||
}
|
||
|
||
// a.length > b.length
|
||
var a, b;
|
||
if (this.length > num.length) {
|
||
a = this;
|
||
b = num;
|
||
} else {
|
||
a = num;
|
||
b = this;
|
||
}
|
||
|
||
var carry = 0;
|
||
for (var i = 0; i < b.length; i++) {
|
||
r = (a.words[i] | 0) + (b.words[i] | 0) + carry;
|
||
this.words[i] = r & 0x3ffffff;
|
||
carry = r >>> 26;
|
||
}
|
||
for (; carry !== 0 && i < a.length; i++) {
|
||
r = (a.words[i] | 0) + carry;
|
||
this.words[i] = r & 0x3ffffff;
|
||
carry = r >>> 26;
|
||
}
|
||
|
||
this.length = a.length;
|
||
if (carry !== 0) {
|
||
this.words[this.length] = carry;
|
||
this.length++;
|
||
// Copy the rest of the words
|
||
} else if (a !== this) {
|
||
for (; i < a.length; i++) {
|
||
this.words[i] = a.words[i];
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
// Add `num` to `this`
|
||
BN.prototype.add = function add (num) {
|
||
var res;
|
||
if (num.negative !== 0 && this.negative === 0) {
|
||
num.negative = 0;
|
||
res = this.sub(num);
|
||
num.negative ^= 1;
|
||
return res;
|
||
} else if (num.negative === 0 && this.negative !== 0) {
|
||
this.negative = 0;
|
||
res = num.sub(this);
|
||
this.negative = 1;
|
||
return res;
|
||
}
|
||
|
||
if (this.length > num.length) return this.clone().iadd(num);
|
||
|
||
return num.clone().iadd(this);
|
||
};
|
||
|
||
// Subtract `num` from `this` in-place
|
||
BN.prototype.isub = function isub (num) {
|
||
// this - (-num) = this + num
|
||
if (num.negative !== 0) {
|
||
num.negative = 0;
|
||
var r = this.iadd(num);
|
||
num.negative = 1;
|
||
return r._normSign();
|
||
|
||
// -this - num = -(this + num)
|
||
} else if (this.negative !== 0) {
|
||
this.negative = 0;
|
||
this.iadd(num);
|
||
this.negative = 1;
|
||
return this._normSign();
|
||
}
|
||
|
||
// At this point both numbers are positive
|
||
var cmp = this.cmp(num);
|
||
|
||
// Optimization - zeroify
|
||
if (cmp === 0) {
|
||
this.negative = 0;
|
||
this.length = 1;
|
||
this.words[0] = 0;
|
||
return this;
|
||
}
|
||
|
||
// a > b
|
||
var a, b;
|
||
if (cmp > 0) {
|
||
a = this;
|
||
b = num;
|
||
} else {
|
||
a = num;
|
||
b = this;
|
||
}
|
||
|
||
var carry = 0;
|
||
for (var i = 0; i < b.length; i++) {
|
||
r = (a.words[i] | 0) - (b.words[i] | 0) + carry;
|
||
carry = r >> 26;
|
||
this.words[i] = r & 0x3ffffff;
|
||
}
|
||
for (; carry !== 0 && i < a.length; i++) {
|
||
r = (a.words[i] | 0) + carry;
|
||
carry = r >> 26;
|
||
this.words[i] = r & 0x3ffffff;
|
||
}
|
||
|
||
// Copy rest of the words
|
||
if (carry === 0 && i < a.length && a !== this) {
|
||
for (; i < a.length; i++) {
|
||
this.words[i] = a.words[i];
|
||
}
|
||
}
|
||
|
||
this.length = Math.max(this.length, i);
|
||
|
||
if (a !== this) {
|
||
this.negative = 1;
|
||
}
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
// Subtract `num` from `this`
|
||
BN.prototype.sub = function sub (num) {
|
||
return this.clone().isub(num);
|
||
};
|
||
|
||
function smallMulTo (self, num, out) {
|
||
out.negative = num.negative ^ self.negative;
|
||
var len = (self.length + num.length) | 0;
|
||
out.length = len;
|
||
len = (len - 1) | 0;
|
||
|
||
// Peel one iteration (compiler can't do it, because of code complexity)
|
||
var a = self.words[0] | 0;
|
||
var b = num.words[0] | 0;
|
||
var r = a * b;
|
||
|
||
var lo = r & 0x3ffffff;
|
||
var carry = (r / 0x4000000) | 0;
|
||
out.words[0] = lo;
|
||
|
||
for (var k = 1; k < len; k++) {
|
||
// Sum all words with the same `i + j = k` and accumulate `ncarry`,
|
||
// note that ncarry could be >= 0x3ffffff
|
||
var ncarry = carry >>> 26;
|
||
var rword = carry & 0x3ffffff;
|
||
var maxJ = Math.min(k, num.length - 1);
|
||
for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
|
||
var i = (k - j) | 0;
|
||
a = self.words[i] | 0;
|
||
b = num.words[j] | 0;
|
||
r = a * b + rword;
|
||
ncarry += (r / 0x4000000) | 0;
|
||
rword = r & 0x3ffffff;
|
||
}
|
||
out.words[k] = rword | 0;
|
||
carry = ncarry | 0;
|
||
}
|
||
if (carry !== 0) {
|
||
out.words[k] = carry | 0;
|
||
} else {
|
||
out.length--;
|
||
}
|
||
|
||
return out._strip();
|
||
}
|
||
|
||
// TODO(indutny): it may be reasonable to omit it for users who don't need
|
||
// to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit
|
||
// multiplication (like elliptic secp256k1).
|
||
var comb10MulTo = function comb10MulTo (self, num, out) {
|
||
var a = self.words;
|
||
var b = num.words;
|
||
var o = out.words;
|
||
var c = 0;
|
||
var lo;
|
||
var mid;
|
||
var hi;
|
||
var a0 = a[0] | 0;
|
||
var al0 = a0 & 0x1fff;
|
||
var ah0 = a0 >>> 13;
|
||
var a1 = a[1] | 0;
|
||
var al1 = a1 & 0x1fff;
|
||
var ah1 = a1 >>> 13;
|
||
var a2 = a[2] | 0;
|
||
var al2 = a2 & 0x1fff;
|
||
var ah2 = a2 >>> 13;
|
||
var a3 = a[3] | 0;
|
||
var al3 = a3 & 0x1fff;
|
||
var ah3 = a3 >>> 13;
|
||
var a4 = a[4] | 0;
|
||
var al4 = a4 & 0x1fff;
|
||
var ah4 = a4 >>> 13;
|
||
var a5 = a[5] | 0;
|
||
var al5 = a5 & 0x1fff;
|
||
var ah5 = a5 >>> 13;
|
||
var a6 = a[6] | 0;
|
||
var al6 = a6 & 0x1fff;
|
||
var ah6 = a6 >>> 13;
|
||
var a7 = a[7] | 0;
|
||
var al7 = a7 & 0x1fff;
|
||
var ah7 = a7 >>> 13;
|
||
var a8 = a[8] | 0;
|
||
var al8 = a8 & 0x1fff;
|
||
var ah8 = a8 >>> 13;
|
||
var a9 = a[9] | 0;
|
||
var al9 = a9 & 0x1fff;
|
||
var ah9 = a9 >>> 13;
|
||
var b0 = b[0] | 0;
|
||
var bl0 = b0 & 0x1fff;
|
||
var bh0 = b0 >>> 13;
|
||
var b1 = b[1] | 0;
|
||
var bl1 = b1 & 0x1fff;
|
||
var bh1 = b1 >>> 13;
|
||
var b2 = b[2] | 0;
|
||
var bl2 = b2 & 0x1fff;
|
||
var bh2 = b2 >>> 13;
|
||
var b3 = b[3] | 0;
|
||
var bl3 = b3 & 0x1fff;
|
||
var bh3 = b3 >>> 13;
|
||
var b4 = b[4] | 0;
|
||
var bl4 = b4 & 0x1fff;
|
||
var bh4 = b4 >>> 13;
|
||
var b5 = b[5] | 0;
|
||
var bl5 = b5 & 0x1fff;
|
||
var bh5 = b5 >>> 13;
|
||
var b6 = b[6] | 0;
|
||
var bl6 = b6 & 0x1fff;
|
||
var bh6 = b6 >>> 13;
|
||
var b7 = b[7] | 0;
|
||
var bl7 = b7 & 0x1fff;
|
||
var bh7 = b7 >>> 13;
|
||
var b8 = b[8] | 0;
|
||
var bl8 = b8 & 0x1fff;
|
||
var bh8 = b8 >>> 13;
|
||
var b9 = b[9] | 0;
|
||
var bl9 = b9 & 0x1fff;
|
||
var bh9 = b9 >>> 13;
|
||
|
||
out.negative = self.negative ^ num.negative;
|
||
out.length = 19;
|
||
/* k = 0 */
|
||
lo = Math.imul(al0, bl0);
|
||
mid = Math.imul(al0, bh0);
|
||
mid = (mid + Math.imul(ah0, bl0)) | 0;
|
||
hi = Math.imul(ah0, bh0);
|
||
var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;
|
||
w0 &= 0x3ffffff;
|
||
/* k = 1 */
|
||
lo = Math.imul(al1, bl0);
|
||
mid = Math.imul(al1, bh0);
|
||
mid = (mid + Math.imul(ah1, bl0)) | 0;
|
||
hi = Math.imul(ah1, bh0);
|
||
lo = (lo + Math.imul(al0, bl1)) | 0;
|
||
mid = (mid + Math.imul(al0, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh1)) | 0;
|
||
var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;
|
||
w1 &= 0x3ffffff;
|
||
/* k = 2 */
|
||
lo = Math.imul(al2, bl0);
|
||
mid = Math.imul(al2, bh0);
|
||
mid = (mid + Math.imul(ah2, bl0)) | 0;
|
||
hi = Math.imul(ah2, bh0);
|
||
lo = (lo + Math.imul(al1, bl1)) | 0;
|
||
mid = (mid + Math.imul(al1, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh1)) | 0;
|
||
lo = (lo + Math.imul(al0, bl2)) | 0;
|
||
mid = (mid + Math.imul(al0, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh2)) | 0;
|
||
var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;
|
||
w2 &= 0x3ffffff;
|
||
/* k = 3 */
|
||
lo = Math.imul(al3, bl0);
|
||
mid = Math.imul(al3, bh0);
|
||
mid = (mid + Math.imul(ah3, bl0)) | 0;
|
||
hi = Math.imul(ah3, bh0);
|
||
lo = (lo + Math.imul(al2, bl1)) | 0;
|
||
mid = (mid + Math.imul(al2, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh1)) | 0;
|
||
lo = (lo + Math.imul(al1, bl2)) | 0;
|
||
mid = (mid + Math.imul(al1, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh2)) | 0;
|
||
lo = (lo + Math.imul(al0, bl3)) | 0;
|
||
mid = (mid + Math.imul(al0, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh3)) | 0;
|
||
var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;
|
||
w3 &= 0x3ffffff;
|
||
/* k = 4 */
|
||
lo = Math.imul(al4, bl0);
|
||
mid = Math.imul(al4, bh0);
|
||
mid = (mid + Math.imul(ah4, bl0)) | 0;
|
||
hi = Math.imul(ah4, bh0);
|
||
lo = (lo + Math.imul(al3, bl1)) | 0;
|
||
mid = (mid + Math.imul(al3, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh1)) | 0;
|
||
lo = (lo + Math.imul(al2, bl2)) | 0;
|
||
mid = (mid + Math.imul(al2, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh2)) | 0;
|
||
lo = (lo + Math.imul(al1, bl3)) | 0;
|
||
mid = (mid + Math.imul(al1, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh3)) | 0;
|
||
lo = (lo + Math.imul(al0, bl4)) | 0;
|
||
mid = (mid + Math.imul(al0, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh4)) | 0;
|
||
var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;
|
||
w4 &= 0x3ffffff;
|
||
/* k = 5 */
|
||
lo = Math.imul(al5, bl0);
|
||
mid = Math.imul(al5, bh0);
|
||
mid = (mid + Math.imul(ah5, bl0)) | 0;
|
||
hi = Math.imul(ah5, bh0);
|
||
lo = (lo + Math.imul(al4, bl1)) | 0;
|
||
mid = (mid + Math.imul(al4, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh1)) | 0;
|
||
lo = (lo + Math.imul(al3, bl2)) | 0;
|
||
mid = (mid + Math.imul(al3, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh2)) | 0;
|
||
lo = (lo + Math.imul(al2, bl3)) | 0;
|
||
mid = (mid + Math.imul(al2, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh3)) | 0;
|
||
lo = (lo + Math.imul(al1, bl4)) | 0;
|
||
mid = (mid + Math.imul(al1, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh4)) | 0;
|
||
lo = (lo + Math.imul(al0, bl5)) | 0;
|
||
mid = (mid + Math.imul(al0, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh5)) | 0;
|
||
var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;
|
||
w5 &= 0x3ffffff;
|
||
/* k = 6 */
|
||
lo = Math.imul(al6, bl0);
|
||
mid = Math.imul(al6, bh0);
|
||
mid = (mid + Math.imul(ah6, bl0)) | 0;
|
||
hi = Math.imul(ah6, bh0);
|
||
lo = (lo + Math.imul(al5, bl1)) | 0;
|
||
mid = (mid + Math.imul(al5, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh1)) | 0;
|
||
lo = (lo + Math.imul(al4, bl2)) | 0;
|
||
mid = (mid + Math.imul(al4, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh2)) | 0;
|
||
lo = (lo + Math.imul(al3, bl3)) | 0;
|
||
mid = (mid + Math.imul(al3, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh3)) | 0;
|
||
lo = (lo + Math.imul(al2, bl4)) | 0;
|
||
mid = (mid + Math.imul(al2, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh4)) | 0;
|
||
lo = (lo + Math.imul(al1, bl5)) | 0;
|
||
mid = (mid + Math.imul(al1, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh5)) | 0;
|
||
lo = (lo + Math.imul(al0, bl6)) | 0;
|
||
mid = (mid + Math.imul(al0, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh6)) | 0;
|
||
var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;
|
||
w6 &= 0x3ffffff;
|
||
/* k = 7 */
|
||
lo = Math.imul(al7, bl0);
|
||
mid = Math.imul(al7, bh0);
|
||
mid = (mid + Math.imul(ah7, bl0)) | 0;
|
||
hi = Math.imul(ah7, bh0);
|
||
lo = (lo + Math.imul(al6, bl1)) | 0;
|
||
mid = (mid + Math.imul(al6, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh1)) | 0;
|
||
lo = (lo + Math.imul(al5, bl2)) | 0;
|
||
mid = (mid + Math.imul(al5, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh2)) | 0;
|
||
lo = (lo + Math.imul(al4, bl3)) | 0;
|
||
mid = (mid + Math.imul(al4, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh3)) | 0;
|
||
lo = (lo + Math.imul(al3, bl4)) | 0;
|
||
mid = (mid + Math.imul(al3, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh4)) | 0;
|
||
lo = (lo + Math.imul(al2, bl5)) | 0;
|
||
mid = (mid + Math.imul(al2, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh5)) | 0;
|
||
lo = (lo + Math.imul(al1, bl6)) | 0;
|
||
mid = (mid + Math.imul(al1, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh6)) | 0;
|
||
lo = (lo + Math.imul(al0, bl7)) | 0;
|
||
mid = (mid + Math.imul(al0, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh7)) | 0;
|
||
var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;
|
||
w7 &= 0x3ffffff;
|
||
/* k = 8 */
|
||
lo = Math.imul(al8, bl0);
|
||
mid = Math.imul(al8, bh0);
|
||
mid = (mid + Math.imul(ah8, bl0)) | 0;
|
||
hi = Math.imul(ah8, bh0);
|
||
lo = (lo + Math.imul(al7, bl1)) | 0;
|
||
mid = (mid + Math.imul(al7, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh1)) | 0;
|
||
lo = (lo + Math.imul(al6, bl2)) | 0;
|
||
mid = (mid + Math.imul(al6, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh2)) | 0;
|
||
lo = (lo + Math.imul(al5, bl3)) | 0;
|
||
mid = (mid + Math.imul(al5, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh3)) | 0;
|
||
lo = (lo + Math.imul(al4, bl4)) | 0;
|
||
mid = (mid + Math.imul(al4, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh4)) | 0;
|
||
lo = (lo + Math.imul(al3, bl5)) | 0;
|
||
mid = (mid + Math.imul(al3, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh5)) | 0;
|
||
lo = (lo + Math.imul(al2, bl6)) | 0;
|
||
mid = (mid + Math.imul(al2, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh6)) | 0;
|
||
lo = (lo + Math.imul(al1, bl7)) | 0;
|
||
mid = (mid + Math.imul(al1, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh7)) | 0;
|
||
lo = (lo + Math.imul(al0, bl8)) | 0;
|
||
mid = (mid + Math.imul(al0, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh8)) | 0;
|
||
var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;
|
||
w8 &= 0x3ffffff;
|
||
/* k = 9 */
|
||
lo = Math.imul(al9, bl0);
|
||
mid = Math.imul(al9, bh0);
|
||
mid = (mid + Math.imul(ah9, bl0)) | 0;
|
||
hi = Math.imul(ah9, bh0);
|
||
lo = (lo + Math.imul(al8, bl1)) | 0;
|
||
mid = (mid + Math.imul(al8, bh1)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl1)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh1)) | 0;
|
||
lo = (lo + Math.imul(al7, bl2)) | 0;
|
||
mid = (mid + Math.imul(al7, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh2)) | 0;
|
||
lo = (lo + Math.imul(al6, bl3)) | 0;
|
||
mid = (mid + Math.imul(al6, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh3)) | 0;
|
||
lo = (lo + Math.imul(al5, bl4)) | 0;
|
||
mid = (mid + Math.imul(al5, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh4)) | 0;
|
||
lo = (lo + Math.imul(al4, bl5)) | 0;
|
||
mid = (mid + Math.imul(al4, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh5)) | 0;
|
||
lo = (lo + Math.imul(al3, bl6)) | 0;
|
||
mid = (mid + Math.imul(al3, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh6)) | 0;
|
||
lo = (lo + Math.imul(al2, bl7)) | 0;
|
||
mid = (mid + Math.imul(al2, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh7)) | 0;
|
||
lo = (lo + Math.imul(al1, bl8)) | 0;
|
||
mid = (mid + Math.imul(al1, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh8)) | 0;
|
||
lo = (lo + Math.imul(al0, bl9)) | 0;
|
||
mid = (mid + Math.imul(al0, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah0, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah0, bh9)) | 0;
|
||
var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;
|
||
w9 &= 0x3ffffff;
|
||
/* k = 10 */
|
||
lo = Math.imul(al9, bl1);
|
||
mid = Math.imul(al9, bh1);
|
||
mid = (mid + Math.imul(ah9, bl1)) | 0;
|
||
hi = Math.imul(ah9, bh1);
|
||
lo = (lo + Math.imul(al8, bl2)) | 0;
|
||
mid = (mid + Math.imul(al8, bh2)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl2)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh2)) | 0;
|
||
lo = (lo + Math.imul(al7, bl3)) | 0;
|
||
mid = (mid + Math.imul(al7, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh3)) | 0;
|
||
lo = (lo + Math.imul(al6, bl4)) | 0;
|
||
mid = (mid + Math.imul(al6, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh4)) | 0;
|
||
lo = (lo + Math.imul(al5, bl5)) | 0;
|
||
mid = (mid + Math.imul(al5, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh5)) | 0;
|
||
lo = (lo + Math.imul(al4, bl6)) | 0;
|
||
mid = (mid + Math.imul(al4, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh6)) | 0;
|
||
lo = (lo + Math.imul(al3, bl7)) | 0;
|
||
mid = (mid + Math.imul(al3, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh7)) | 0;
|
||
lo = (lo + Math.imul(al2, bl8)) | 0;
|
||
mid = (mid + Math.imul(al2, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh8)) | 0;
|
||
lo = (lo + Math.imul(al1, bl9)) | 0;
|
||
mid = (mid + Math.imul(al1, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah1, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah1, bh9)) | 0;
|
||
var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;
|
||
w10 &= 0x3ffffff;
|
||
/* k = 11 */
|
||
lo = Math.imul(al9, bl2);
|
||
mid = Math.imul(al9, bh2);
|
||
mid = (mid + Math.imul(ah9, bl2)) | 0;
|
||
hi = Math.imul(ah9, bh2);
|
||
lo = (lo + Math.imul(al8, bl3)) | 0;
|
||
mid = (mid + Math.imul(al8, bh3)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl3)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh3)) | 0;
|
||
lo = (lo + Math.imul(al7, bl4)) | 0;
|
||
mid = (mid + Math.imul(al7, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh4)) | 0;
|
||
lo = (lo + Math.imul(al6, bl5)) | 0;
|
||
mid = (mid + Math.imul(al6, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh5)) | 0;
|
||
lo = (lo + Math.imul(al5, bl6)) | 0;
|
||
mid = (mid + Math.imul(al5, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh6)) | 0;
|
||
lo = (lo + Math.imul(al4, bl7)) | 0;
|
||
mid = (mid + Math.imul(al4, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh7)) | 0;
|
||
lo = (lo + Math.imul(al3, bl8)) | 0;
|
||
mid = (mid + Math.imul(al3, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh8)) | 0;
|
||
lo = (lo + Math.imul(al2, bl9)) | 0;
|
||
mid = (mid + Math.imul(al2, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah2, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah2, bh9)) | 0;
|
||
var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;
|
||
w11 &= 0x3ffffff;
|
||
/* k = 12 */
|
||
lo = Math.imul(al9, bl3);
|
||
mid = Math.imul(al9, bh3);
|
||
mid = (mid + Math.imul(ah9, bl3)) | 0;
|
||
hi = Math.imul(ah9, bh3);
|
||
lo = (lo + Math.imul(al8, bl4)) | 0;
|
||
mid = (mid + Math.imul(al8, bh4)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl4)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh4)) | 0;
|
||
lo = (lo + Math.imul(al7, bl5)) | 0;
|
||
mid = (mid + Math.imul(al7, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh5)) | 0;
|
||
lo = (lo + Math.imul(al6, bl6)) | 0;
|
||
mid = (mid + Math.imul(al6, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh6)) | 0;
|
||
lo = (lo + Math.imul(al5, bl7)) | 0;
|
||
mid = (mid + Math.imul(al5, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh7)) | 0;
|
||
lo = (lo + Math.imul(al4, bl8)) | 0;
|
||
mid = (mid + Math.imul(al4, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh8)) | 0;
|
||
lo = (lo + Math.imul(al3, bl9)) | 0;
|
||
mid = (mid + Math.imul(al3, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah3, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah3, bh9)) | 0;
|
||
var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;
|
||
w12 &= 0x3ffffff;
|
||
/* k = 13 */
|
||
lo = Math.imul(al9, bl4);
|
||
mid = Math.imul(al9, bh4);
|
||
mid = (mid + Math.imul(ah9, bl4)) | 0;
|
||
hi = Math.imul(ah9, bh4);
|
||
lo = (lo + Math.imul(al8, bl5)) | 0;
|
||
mid = (mid + Math.imul(al8, bh5)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl5)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh5)) | 0;
|
||
lo = (lo + Math.imul(al7, bl6)) | 0;
|
||
mid = (mid + Math.imul(al7, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh6)) | 0;
|
||
lo = (lo + Math.imul(al6, bl7)) | 0;
|
||
mid = (mid + Math.imul(al6, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh7)) | 0;
|
||
lo = (lo + Math.imul(al5, bl8)) | 0;
|
||
mid = (mid + Math.imul(al5, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh8)) | 0;
|
||
lo = (lo + Math.imul(al4, bl9)) | 0;
|
||
mid = (mid + Math.imul(al4, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah4, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah4, bh9)) | 0;
|
||
var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;
|
||
w13 &= 0x3ffffff;
|
||
/* k = 14 */
|
||
lo = Math.imul(al9, bl5);
|
||
mid = Math.imul(al9, bh5);
|
||
mid = (mid + Math.imul(ah9, bl5)) | 0;
|
||
hi = Math.imul(ah9, bh5);
|
||
lo = (lo + Math.imul(al8, bl6)) | 0;
|
||
mid = (mid + Math.imul(al8, bh6)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl6)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh6)) | 0;
|
||
lo = (lo + Math.imul(al7, bl7)) | 0;
|
||
mid = (mid + Math.imul(al7, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh7)) | 0;
|
||
lo = (lo + Math.imul(al6, bl8)) | 0;
|
||
mid = (mid + Math.imul(al6, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh8)) | 0;
|
||
lo = (lo + Math.imul(al5, bl9)) | 0;
|
||
mid = (mid + Math.imul(al5, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah5, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah5, bh9)) | 0;
|
||
var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;
|
||
w14 &= 0x3ffffff;
|
||
/* k = 15 */
|
||
lo = Math.imul(al9, bl6);
|
||
mid = Math.imul(al9, bh6);
|
||
mid = (mid + Math.imul(ah9, bl6)) | 0;
|
||
hi = Math.imul(ah9, bh6);
|
||
lo = (lo + Math.imul(al8, bl7)) | 0;
|
||
mid = (mid + Math.imul(al8, bh7)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl7)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh7)) | 0;
|
||
lo = (lo + Math.imul(al7, bl8)) | 0;
|
||
mid = (mid + Math.imul(al7, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh8)) | 0;
|
||
lo = (lo + Math.imul(al6, bl9)) | 0;
|
||
mid = (mid + Math.imul(al6, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah6, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah6, bh9)) | 0;
|
||
var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;
|
||
w15 &= 0x3ffffff;
|
||
/* k = 16 */
|
||
lo = Math.imul(al9, bl7);
|
||
mid = Math.imul(al9, bh7);
|
||
mid = (mid + Math.imul(ah9, bl7)) | 0;
|
||
hi = Math.imul(ah9, bh7);
|
||
lo = (lo + Math.imul(al8, bl8)) | 0;
|
||
mid = (mid + Math.imul(al8, bh8)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl8)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh8)) | 0;
|
||
lo = (lo + Math.imul(al7, bl9)) | 0;
|
||
mid = (mid + Math.imul(al7, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah7, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah7, bh9)) | 0;
|
||
var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;
|
||
w16 &= 0x3ffffff;
|
||
/* k = 17 */
|
||
lo = Math.imul(al9, bl8);
|
||
mid = Math.imul(al9, bh8);
|
||
mid = (mid + Math.imul(ah9, bl8)) | 0;
|
||
hi = Math.imul(ah9, bh8);
|
||
lo = (lo + Math.imul(al8, bl9)) | 0;
|
||
mid = (mid + Math.imul(al8, bh9)) | 0;
|
||
mid = (mid + Math.imul(ah8, bl9)) | 0;
|
||
hi = (hi + Math.imul(ah8, bh9)) | 0;
|
||
var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;
|
||
w17 &= 0x3ffffff;
|
||
/* k = 18 */
|
||
lo = Math.imul(al9, bl9);
|
||
mid = Math.imul(al9, bh9);
|
||
mid = (mid + Math.imul(ah9, bl9)) | 0;
|
||
hi = Math.imul(ah9, bh9);
|
||
var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
||
c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;
|
||
w18 &= 0x3ffffff;
|
||
o[0] = w0;
|
||
o[1] = w1;
|
||
o[2] = w2;
|
||
o[3] = w3;
|
||
o[4] = w4;
|
||
o[5] = w5;
|
||
o[6] = w6;
|
||
o[7] = w7;
|
||
o[8] = w8;
|
||
o[9] = w9;
|
||
o[10] = w10;
|
||
o[11] = w11;
|
||
o[12] = w12;
|
||
o[13] = w13;
|
||
o[14] = w14;
|
||
o[15] = w15;
|
||
o[16] = w16;
|
||
o[17] = w17;
|
||
o[18] = w18;
|
||
if (c !== 0) {
|
||
o[19] = c;
|
||
out.length++;
|
||
}
|
||
return out;
|
||
};
|
||
|
||
// Polyfill comb
|
||
if (!Math.imul) {
|
||
comb10MulTo = smallMulTo;
|
||
}
|
||
|
||
function bigMulTo (self, num, out) {
|
||
out.negative = num.negative ^ self.negative;
|
||
out.length = self.length + num.length;
|
||
|
||
var carry = 0;
|
||
var hncarry = 0;
|
||
for (var k = 0; k < out.length - 1; k++) {
|
||
// Sum all words with the same `i + j = k` and accumulate `ncarry`,
|
||
// note that ncarry could be >= 0x3ffffff
|
||
var ncarry = hncarry;
|
||
hncarry = 0;
|
||
var rword = carry & 0x3ffffff;
|
||
var maxJ = Math.min(k, num.length - 1);
|
||
for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
|
||
var i = k - j;
|
||
var a = self.words[i] | 0;
|
||
var b = num.words[j] | 0;
|
||
var r = a * b;
|
||
|
||
var lo = r & 0x3ffffff;
|
||
ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;
|
||
lo = (lo + rword) | 0;
|
||
rword = lo & 0x3ffffff;
|
||
ncarry = (ncarry + (lo >>> 26)) | 0;
|
||
|
||
hncarry += ncarry >>> 26;
|
||
ncarry &= 0x3ffffff;
|
||
}
|
||
out.words[k] = rword;
|
||
carry = ncarry;
|
||
ncarry = hncarry;
|
||
}
|
||
if (carry !== 0) {
|
||
out.words[k] = carry;
|
||
} else {
|
||
out.length--;
|
||
}
|
||
|
||
return out._strip();
|
||
}
|
||
|
||
function jumboMulTo (self, num, out) {
|
||
// Temporary disable, see https://github.com/indutny/bn.js/issues/211
|
||
// var fftm = new FFTM();
|
||
// return fftm.mulp(self, num, out);
|
||
return bigMulTo(self, num, out);
|
||
}
|
||
|
||
BN.prototype.mulTo = function mulTo (num, out) {
|
||
var res;
|
||
var len = this.length + num.length;
|
||
if (this.length === 10 && num.length === 10) {
|
||
res = comb10MulTo(this, num, out);
|
||
} else if (len < 63) {
|
||
res = smallMulTo(this, num, out);
|
||
} else if (len < 1024) {
|
||
res = bigMulTo(this, num, out);
|
||
} else {
|
||
res = jumboMulTo(this, num, out);
|
||
}
|
||
|
||
return res;
|
||
};
|
||
|
||
// Multiply `this` by `num`
|
||
BN.prototype.mul = function mul (num) {
|
||
var out = new BN(null);
|
||
out.words = new Array(this.length + num.length);
|
||
return this.mulTo(num, out);
|
||
};
|
||
|
||
// Multiply employing FFT
|
||
BN.prototype.mulf = function mulf (num) {
|
||
var out = new BN(null);
|
||
out.words = new Array(this.length + num.length);
|
||
return jumboMulTo(this, num, out);
|
||
};
|
||
|
||
// In-place Multiplication
|
||
BN.prototype.imul = function imul (num) {
|
||
return this.clone().mulTo(num, this);
|
||
};
|
||
|
||
BN.prototype.imuln = function imuln (num) {
|
||
var isNegNum = num < 0;
|
||
if (isNegNum) num = -num;
|
||
|
||
assert(typeof num === 'number');
|
||
assert(num < 0x4000000);
|
||
|
||
// Carry
|
||
var carry = 0;
|
||
for (var i = 0; i < this.length; i++) {
|
||
var w = (this.words[i] | 0) * num;
|
||
var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);
|
||
carry >>= 26;
|
||
carry += (w / 0x4000000) | 0;
|
||
// NOTE: lo is 27bit maximum
|
||
carry += lo >>> 26;
|
||
this.words[i] = lo & 0x3ffffff;
|
||
}
|
||
|
||
if (carry !== 0) {
|
||
this.words[i] = carry;
|
||
this.length++;
|
||
}
|
||
|
||
return isNegNum ? this.ineg() : this;
|
||
};
|
||
|
||
BN.prototype.muln = function muln (num) {
|
||
return this.clone().imuln(num);
|
||
};
|
||
|
||
// `this` * `this`
|
||
BN.prototype.sqr = function sqr () {
|
||
return this.mul(this);
|
||
};
|
||
|
||
// `this` * `this` in-place
|
||
BN.prototype.isqr = function isqr () {
|
||
return this.imul(this.clone());
|
||
};
|
||
|
||
// Math.pow(`this`, `num`)
|
||
BN.prototype.pow = function pow (num) {
|
||
var w = toBitArray(num);
|
||
if (w.length === 0) return new BN(1);
|
||
|
||
// Skip leading zeroes
|
||
var res = this;
|
||
for (var i = 0; i < w.length; i++, res = res.sqr()) {
|
||
if (w[i] !== 0) break;
|
||
}
|
||
|
||
if (++i < w.length) {
|
||
for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {
|
||
if (w[i] === 0) continue;
|
||
|
||
res = res.mul(q);
|
||
}
|
||
}
|
||
|
||
return res;
|
||
};
|
||
|
||
// Shift-left in-place
|
||
BN.prototype.iushln = function iushln (bits) {
|
||
assert(typeof bits === 'number' && bits >= 0);
|
||
var r = bits % 26;
|
||
var s = (bits - r) / 26;
|
||
var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);
|
||
var i;
|
||
|
||
if (r !== 0) {
|
||
var carry = 0;
|
||
|
||
for (i = 0; i < this.length; i++) {
|
||
var newCarry = this.words[i] & carryMask;
|
||
var c = ((this.words[i] | 0) - newCarry) << r;
|
||
this.words[i] = c | carry;
|
||
carry = newCarry >>> (26 - r);
|
||
}
|
||
|
||
if (carry) {
|
||
this.words[i] = carry;
|
||
this.length++;
|
||
}
|
||
}
|
||
|
||
if (s !== 0) {
|
||
for (i = this.length - 1; i >= 0; i--) {
|
||
this.words[i + s] = this.words[i];
|
||
}
|
||
|
||
for (i = 0; i < s; i++) {
|
||
this.words[i] = 0;
|
||
}
|
||
|
||
this.length += s;
|
||
}
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype.ishln = function ishln (bits) {
|
||
// TODO(indutny): implement me
|
||
assert(this.negative === 0);
|
||
return this.iushln(bits);
|
||
};
|
||
|
||
// Shift-right in-place
|
||
// NOTE: `hint` is a lowest bit before trailing zeroes
|
||
// NOTE: if `extended` is present - it will be filled with destroyed bits
|
||
BN.prototype.iushrn = function iushrn (bits, hint, extended) {
|
||
assert(typeof bits === 'number' && bits >= 0);
|
||
var h;
|
||
if (hint) {
|
||
h = (hint - (hint % 26)) / 26;
|
||
} else {
|
||
h = 0;
|
||
}
|
||
|
||
var r = bits % 26;
|
||
var s = Math.min((bits - r) / 26, this.length);
|
||
var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
|
||
var maskedWords = extended;
|
||
|
||
h -= s;
|
||
h = Math.max(0, h);
|
||
|
||
// Extended mode, copy masked part
|
||
if (maskedWords) {
|
||
for (var i = 0; i < s; i++) {
|
||
maskedWords.words[i] = this.words[i];
|
||
}
|
||
maskedWords.length = s;
|
||
}
|
||
|
||
if (s === 0) ; else if (this.length > s) {
|
||
this.length -= s;
|
||
for (i = 0; i < this.length; i++) {
|
||
this.words[i] = this.words[i + s];
|
||
}
|
||
} else {
|
||
this.words[0] = 0;
|
||
this.length = 1;
|
||
}
|
||
|
||
var carry = 0;
|
||
for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {
|
||
var word = this.words[i] | 0;
|
||
this.words[i] = (carry << (26 - r)) | (word >>> r);
|
||
carry = word & mask;
|
||
}
|
||
|
||
// Push carried bits as a mask
|
||
if (maskedWords && carry !== 0) {
|
||
maskedWords.words[maskedWords.length++] = carry;
|
||
}
|
||
|
||
if (this.length === 0) {
|
||
this.words[0] = 0;
|
||
this.length = 1;
|
||
}
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype.ishrn = function ishrn (bits, hint, extended) {
|
||
// TODO(indutny): implement me
|
||
assert(this.negative === 0);
|
||
return this.iushrn(bits, hint, extended);
|
||
};
|
||
|
||
// Shift-left
|
||
BN.prototype.shln = function shln (bits) {
|
||
return this.clone().ishln(bits);
|
||
};
|
||
|
||
BN.prototype.ushln = function ushln (bits) {
|
||
return this.clone().iushln(bits);
|
||
};
|
||
|
||
// Shift-right
|
||
BN.prototype.shrn = function shrn (bits) {
|
||
return this.clone().ishrn(bits);
|
||
};
|
||
|
||
BN.prototype.ushrn = function ushrn (bits) {
|
||
return this.clone().iushrn(bits);
|
||
};
|
||
|
||
// Test if n bit is set
|
||
BN.prototype.testn = function testn (bit) {
|
||
assert(typeof bit === 'number' && bit >= 0);
|
||
var r = bit % 26;
|
||
var s = (bit - r) / 26;
|
||
var q = 1 << r;
|
||
|
||
// Fast case: bit is much higher than all existing words
|
||
if (this.length <= s) return false;
|
||
|
||
// Check bit and return
|
||
var w = this.words[s];
|
||
|
||
return !!(w & q);
|
||
};
|
||
|
||
// Return only lowers bits of number (in-place)
|
||
BN.prototype.imaskn = function imaskn (bits) {
|
||
assert(typeof bits === 'number' && bits >= 0);
|
||
var r = bits % 26;
|
||
var s = (bits - r) / 26;
|
||
|
||
assert(this.negative === 0, 'imaskn works only with positive numbers');
|
||
|
||
if (this.length <= s) {
|
||
return this;
|
||
}
|
||
|
||
if (r !== 0) {
|
||
s++;
|
||
}
|
||
this.length = Math.min(s, this.length);
|
||
|
||
if (r !== 0) {
|
||
var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
|
||
this.words[this.length - 1] &= mask;
|
||
}
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
// Return only lowers bits of number
|
||
BN.prototype.maskn = function maskn (bits) {
|
||
return this.clone().imaskn(bits);
|
||
};
|
||
|
||
// Add plain number `num` to `this`
|
||
BN.prototype.iaddn = function iaddn (num) {
|
||
assert(typeof num === 'number');
|
||
assert(num < 0x4000000);
|
||
if (num < 0) return this.isubn(-num);
|
||
|
||
// Possible sign change
|
||
if (this.negative !== 0) {
|
||
if (this.length === 1 && (this.words[0] | 0) <= num) {
|
||
this.words[0] = num - (this.words[0] | 0);
|
||
this.negative = 0;
|
||
return this;
|
||
}
|
||
|
||
this.negative = 0;
|
||
this.isubn(num);
|
||
this.negative = 1;
|
||
return this;
|
||
}
|
||
|
||
// Add without checks
|
||
return this._iaddn(num);
|
||
};
|
||
|
||
BN.prototype._iaddn = function _iaddn (num) {
|
||
this.words[0] += num;
|
||
|
||
// Carry
|
||
for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {
|
||
this.words[i] -= 0x4000000;
|
||
if (i === this.length - 1) {
|
||
this.words[i + 1] = 1;
|
||
} else {
|
||
this.words[i + 1]++;
|
||
}
|
||
}
|
||
this.length = Math.max(this.length, i + 1);
|
||
|
||
return this;
|
||
};
|
||
|
||
// Subtract plain number `num` from `this`
|
||
BN.prototype.isubn = function isubn (num) {
|
||
assert(typeof num === 'number');
|
||
assert(num < 0x4000000);
|
||
if (num < 0) return this.iaddn(-num);
|
||
|
||
if (this.negative !== 0) {
|
||
this.negative = 0;
|
||
this.iaddn(num);
|
||
this.negative = 1;
|
||
return this;
|
||
}
|
||
|
||
this.words[0] -= num;
|
||
|
||
if (this.length === 1 && this.words[0] < 0) {
|
||
this.words[0] = -this.words[0];
|
||
this.negative = 1;
|
||
} else {
|
||
// Carry
|
||
for (var i = 0; i < this.length && this.words[i] < 0; i++) {
|
||
this.words[i] += 0x4000000;
|
||
this.words[i + 1] -= 1;
|
||
}
|
||
}
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype.addn = function addn (num) {
|
||
return this.clone().iaddn(num);
|
||
};
|
||
|
||
BN.prototype.subn = function subn (num) {
|
||
return this.clone().isubn(num);
|
||
};
|
||
|
||
BN.prototype.iabs = function iabs () {
|
||
this.negative = 0;
|
||
|
||
return this;
|
||
};
|
||
|
||
BN.prototype.abs = function abs () {
|
||
return this.clone().iabs();
|
||
};
|
||
|
||
BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {
|
||
var len = num.length + shift;
|
||
var i;
|
||
|
||
this._expand(len);
|
||
|
||
var w;
|
||
var carry = 0;
|
||
for (i = 0; i < num.length; i++) {
|
||
w = (this.words[i + shift] | 0) + carry;
|
||
var right = (num.words[i] | 0) * mul;
|
||
w -= right & 0x3ffffff;
|
||
carry = (w >> 26) - ((right / 0x4000000) | 0);
|
||
this.words[i + shift] = w & 0x3ffffff;
|
||
}
|
||
for (; i < this.length - shift; i++) {
|
||
w = (this.words[i + shift] | 0) + carry;
|
||
carry = w >> 26;
|
||
this.words[i + shift] = w & 0x3ffffff;
|
||
}
|
||
|
||
if (carry === 0) return this._strip();
|
||
|
||
// Subtraction overflow
|
||
assert(carry === -1);
|
||
carry = 0;
|
||
for (i = 0; i < this.length; i++) {
|
||
w = -(this.words[i] | 0) + carry;
|
||
carry = w >> 26;
|
||
this.words[i] = w & 0x3ffffff;
|
||
}
|
||
this.negative = 1;
|
||
|
||
return this._strip();
|
||
};
|
||
|
||
BN.prototype._wordDiv = function _wordDiv (num, mode) {
|
||
var shift = this.length - num.length;
|
||
|
||
var a = this.clone();
|
||
var b = num;
|
||
|
||
// Normalize
|
||
var bhi = b.words[b.length - 1] | 0;
|
||
var bhiBits = this._countBits(bhi);
|
||
shift = 26 - bhiBits;
|
||
if (shift !== 0) {
|
||
b = b.ushln(shift);
|
||
a.iushln(shift);
|
||
bhi = b.words[b.length - 1] | 0;
|
||
}
|
||
|
||
// Initialize quotient
|
||
var m = a.length - b.length;
|
||
var q;
|
||
|
||
if (mode !== 'mod') {
|
||
q = new BN(null);
|
||
q.length = m + 1;
|
||
q.words = new Array(q.length);
|
||
for (var i = 0; i < q.length; i++) {
|
||
q.words[i] = 0;
|
||
}
|
||
}
|
||
|
||
var diff = a.clone()._ishlnsubmul(b, 1, m);
|
||
if (diff.negative === 0) {
|
||
a = diff;
|
||
if (q) {
|
||
q.words[m] = 1;
|
||
}
|
||
}
|
||
|
||
for (var j = m - 1; j >= 0; j--) {
|
||
var qj = (a.words[b.length + j] | 0) * 0x4000000 +
|
||
(a.words[b.length + j - 1] | 0);
|
||
|
||
// NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max
|
||
// (0x7ffffff)
|
||
qj = Math.min((qj / bhi) | 0, 0x3ffffff);
|
||
|
||
a._ishlnsubmul(b, qj, j);
|
||
while (a.negative !== 0) {
|
||
qj--;
|
||
a.negative = 0;
|
||
a._ishlnsubmul(b, 1, j);
|
||
if (!a.isZero()) {
|
||
a.negative ^= 1;
|
||
}
|
||
}
|
||
if (q) {
|
||
q.words[j] = qj;
|
||
}
|
||
}
|
||
if (q) {
|
||
q._strip();
|
||
}
|
||
a._strip();
|
||
|
||
// Denormalize
|
||
if (mode !== 'div' && shift !== 0) {
|
||
a.iushrn(shift);
|
||
}
|
||
|
||
return {
|
||
div: q || null,
|
||
mod: a
|
||
};
|
||
};
|
||
|
||
// NOTE: 1) `mode` can be set to `mod` to request mod only,
|
||
// to `div` to request div only, or be absent to
|
||
// request both div & mod
|
||
// 2) `positive` is true if unsigned mod is requested
|
||
BN.prototype.divmod = function divmod (num, mode, positive) {
|
||
assert(!num.isZero());
|
||
|
||
if (this.isZero()) {
|
||
return {
|
||
div: new BN(0),
|
||
mod: new BN(0)
|
||
};
|
||
}
|
||
|
||
var div, mod, res;
|
||
if (this.negative !== 0 && num.negative === 0) {
|
||
res = this.neg().divmod(num, mode);
|
||
|
||
if (mode !== 'mod') {
|
||
div = res.div.neg();
|
||
}
|
||
|
||
if (mode !== 'div') {
|
||
mod = res.mod.neg();
|
||
if (positive && mod.negative !== 0) {
|
||
mod.iadd(num);
|
||
}
|
||
}
|
||
|
||
return {
|
||
div: div,
|
||
mod: mod
|
||
};
|
||
}
|
||
|
||
if (this.negative === 0 && num.negative !== 0) {
|
||
res = this.divmod(num.neg(), mode);
|
||
|
||
if (mode !== 'mod') {
|
||
div = res.div.neg();
|
||
}
|
||
|
||
return {
|
||
div: div,
|
||
mod: res.mod
|
||
};
|
||
}
|
||
|
||
if ((this.negative & num.negative) !== 0) {
|
||
res = this.neg().divmod(num.neg(), mode);
|
||
|
||
if (mode !== 'div') {
|
||
mod = res.mod.neg();
|
||
if (positive && mod.negative !== 0) {
|
||
mod.isub(num);
|
||
}
|
||
}
|
||
|
||
return {
|
||
div: res.div,
|
||
mod: mod
|
||
};
|
||
}
|
||
|
||
// Both numbers are positive at this point
|
||
|
||
// Strip both numbers to approximate shift value
|
||
if (num.length > this.length || this.cmp(num) < 0) {
|
||
return {
|
||
div: new BN(0),
|
||
mod: this
|
||
};
|
||
}
|
||
|
||
// Very short reduction
|
||
if (num.length === 1) {
|
||
if (mode === 'div') {
|
||
return {
|
||
div: this.divn(num.words[0]),
|
||
mod: null
|
||
};
|
||
}
|
||
|
||
if (mode === 'mod') {
|
||
return {
|
||
div: null,
|
||
mod: new BN(this.modrn(num.words[0]))
|
||
};
|
||
}
|
||
|
||
return {
|
||
div: this.divn(num.words[0]),
|
||
mod: new BN(this.modrn(num.words[0]))
|
||
};
|
||
}
|
||
|
||
return this._wordDiv(num, mode);
|
||
};
|
||
|
||
// Find `this` / `num`
|
||
BN.prototype.div = function div (num) {
|
||
return this.divmod(num, 'div', false).div;
|
||
};
|
||
|
||
// Find `this` % `num`
|
||
BN.prototype.mod = function mod (num) {
|
||
return this.divmod(num, 'mod', false).mod;
|
||
};
|
||
|
||
BN.prototype.umod = function umod (num) {
|
||
return this.divmod(num, 'mod', true).mod;
|
||
};
|
||
|
||
// Find Round(`this` / `num`)
|
||
BN.prototype.divRound = function divRound (num) {
|
||
var dm = this.divmod(num);
|
||
|
||
// Fast case - exact division
|
||
if (dm.mod.isZero()) return dm.div;
|
||
|
||
var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;
|
||
|
||
var half = num.ushrn(1);
|
||
var r2 = num.andln(1);
|
||
var cmp = mod.cmp(half);
|
||
|
||
// Round down
|
||
if (cmp < 0 || (r2 === 1 && cmp === 0)) return dm.div;
|
||
|
||
// Round up
|
||
return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);
|
||
};
|
||
|
||
BN.prototype.modrn = function modrn (num) {
|
||
var isNegNum = num < 0;
|
||
if (isNegNum) num = -num;
|
||
|
||
assert(num <= 0x3ffffff);
|
||
var p = (1 << 26) % num;
|
||
|
||
var acc = 0;
|
||
for (var i = this.length - 1; i >= 0; i--) {
|
||
acc = (p * acc + (this.words[i] | 0)) % num;
|
||
}
|
||
|
||
return isNegNum ? -acc : acc;
|
||
};
|
||
|
||
// WARNING: DEPRECATED
|
||
BN.prototype.modn = function modn (num) {
|
||
return this.modrn(num);
|
||
};
|
||
|
||
// In-place division by number
|
||
BN.prototype.idivn = function idivn (num) {
|
||
var isNegNum = num < 0;
|
||
if (isNegNum) num = -num;
|
||
|
||
assert(num <= 0x3ffffff);
|
||
|
||
var carry = 0;
|
||
for (var i = this.length - 1; i >= 0; i--) {
|
||
var w = (this.words[i] | 0) + carry * 0x4000000;
|
||
this.words[i] = (w / num) | 0;
|
||
carry = w % num;
|
||
}
|
||
|
||
this._strip();
|
||
return isNegNum ? this.ineg() : this;
|
||
};
|
||
|
||
BN.prototype.divn = function divn (num) {
|
||
return this.clone().idivn(num);
|
||
};
|
||
|
||
BN.prototype.egcd = function egcd (p) {
|
||
assert(p.negative === 0);
|
||
assert(!p.isZero());
|
||
|
||
var x = this;
|
||
var y = p.clone();
|
||
|
||
if (x.negative !== 0) {
|
||
x = x.umod(p);
|
||
} else {
|
||
x = x.clone();
|
||
}
|
||
|
||
// A * x + B * y = x
|
||
var A = new BN(1);
|
||
var B = new BN(0);
|
||
|
||
// C * x + D * y = y
|
||
var C = new BN(0);
|
||
var D = new BN(1);
|
||
|
||
var g = 0;
|
||
|
||
while (x.isEven() && y.isEven()) {
|
||
x.iushrn(1);
|
||
y.iushrn(1);
|
||
++g;
|
||
}
|
||
|
||
var yp = y.clone();
|
||
var xp = x.clone();
|
||
|
||
while (!x.isZero()) {
|
||
for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
|
||
if (i > 0) {
|
||
x.iushrn(i);
|
||
while (i-- > 0) {
|
||
if (A.isOdd() || B.isOdd()) {
|
||
A.iadd(yp);
|
||
B.isub(xp);
|
||
}
|
||
|
||
A.iushrn(1);
|
||
B.iushrn(1);
|
||
}
|
||
}
|
||
|
||
for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
|
||
if (j > 0) {
|
||
y.iushrn(j);
|
||
while (j-- > 0) {
|
||
if (C.isOdd() || D.isOdd()) {
|
||
C.iadd(yp);
|
||
D.isub(xp);
|
||
}
|
||
|
||
C.iushrn(1);
|
||
D.iushrn(1);
|
||
}
|
||
}
|
||
|
||
if (x.cmp(y) >= 0) {
|
||
x.isub(y);
|
||
A.isub(C);
|
||
B.isub(D);
|
||
} else {
|
||
y.isub(x);
|
||
C.isub(A);
|
||
D.isub(B);
|
||
}
|
||
}
|
||
|
||
return {
|
||
a: C,
|
||
b: D,
|
||
gcd: y.iushln(g)
|
||
};
|
||
};
|
||
|
||
// This is reduced incarnation of the binary EEA
|
||
// above, designated to invert members of the
|
||
// _prime_ fields F(p) at a maximal speed
|
||
BN.prototype._invmp = function _invmp (p) {
|
||
assert(p.negative === 0);
|
||
assert(!p.isZero());
|
||
|
||
var a = this;
|
||
var b = p.clone();
|
||
|
||
if (a.negative !== 0) {
|
||
a = a.umod(p);
|
||
} else {
|
||
a = a.clone();
|
||
}
|
||
|
||
var x1 = new BN(1);
|
||
var x2 = new BN(0);
|
||
|
||
var delta = b.clone();
|
||
|
||
while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {
|
||
for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
|
||
if (i > 0) {
|
||
a.iushrn(i);
|
||
while (i-- > 0) {
|
||
if (x1.isOdd()) {
|
||
x1.iadd(delta);
|
||
}
|
||
|
||
x1.iushrn(1);
|
||
}
|
||
}
|
||
|
||
for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
|
||
if (j > 0) {
|
||
b.iushrn(j);
|
||
while (j-- > 0) {
|
||
if (x2.isOdd()) {
|
||
x2.iadd(delta);
|
||
}
|
||
|
||
x2.iushrn(1);
|
||
}
|
||
}
|
||
|
||
if (a.cmp(b) >= 0) {
|
||
a.isub(b);
|
||
x1.isub(x2);
|
||
} else {
|
||
b.isub(a);
|
||
x2.isub(x1);
|
||
}
|
||
}
|
||
|
||
var res;
|
||
if (a.cmpn(1) === 0) {
|
||
res = x1;
|
||
} else {
|
||
res = x2;
|
||
}
|
||
|
||
if (res.cmpn(0) < 0) {
|
||
res.iadd(p);
|
||
}
|
||
|
||
return res;
|
||
};
|
||
|
||
BN.prototype.gcd = function gcd (num) {
|
||
if (this.isZero()) return num.abs();
|
||
if (num.isZero()) return this.abs();
|
||
|
||
var a = this.clone();
|
||
var b = num.clone();
|
||
a.negative = 0;
|
||
b.negative = 0;
|
||
|
||
// Remove common factor of two
|
||
for (var shift = 0; a.isEven() && b.isEven(); shift++) {
|
||
a.iushrn(1);
|
||
b.iushrn(1);
|
||
}
|
||
|
||
do {
|
||
while (a.isEven()) {
|
||
a.iushrn(1);
|
||
}
|
||
while (b.isEven()) {
|
||
b.iushrn(1);
|
||
}
|
||
|
||
var r = a.cmp(b);
|
||
if (r < 0) {
|
||
// Swap `a` and `b` to make `a` always bigger than `b`
|
||
var t = a;
|
||
a = b;
|
||
b = t;
|
||
} else if (r === 0 || b.cmpn(1) === 0) {
|
||
break;
|
||
}
|
||
|
||
a.isub(b);
|
||
} while (true);
|
||
|
||
return b.iushln(shift);
|
||
};
|
||
|
||
// Invert number in the field F(num)
|
||
BN.prototype.invm = function invm (num) {
|
||
return this.egcd(num).a.umod(num);
|
||
};
|
||
|
||
BN.prototype.isEven = function isEven () {
|
||
return (this.words[0] & 1) === 0;
|
||
};
|
||
|
||
BN.prototype.isOdd = function isOdd () {
|
||
return (this.words[0] & 1) === 1;
|
||
};
|
||
|
||
// And first word and num
|
||
BN.prototype.andln = function andln (num) {
|
||
return this.words[0] & num;
|
||
};
|
||
|
||
// Increment at the bit position in-line
|
||
BN.prototype.bincn = function bincn (bit) {
|
||
assert(typeof bit === 'number');
|
||
var r = bit % 26;
|
||
var s = (bit - r) / 26;
|
||
var q = 1 << r;
|
||
|
||
// Fast case: bit is much higher than all existing words
|
||
if (this.length <= s) {
|
||
this._expand(s + 1);
|
||
this.words[s] |= q;
|
||
return this;
|
||
}
|
||
|
||
// Add bit and propagate, if needed
|
||
var carry = q;
|
||
for (var i = s; carry !== 0 && i < this.length; i++) {
|
||
var w = this.words[i] | 0;
|
||
w += carry;
|
||
carry = w >>> 26;
|
||
w &= 0x3ffffff;
|
||
this.words[i] = w;
|
||
}
|
||
if (carry !== 0) {
|
||
this.words[i] = carry;
|
||
this.length++;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
BN.prototype.isZero = function isZero () {
|
||
return this.length === 1 && this.words[0] === 0;
|
||
};
|
||
|
||
BN.prototype.cmpn = function cmpn (num) {
|
||
var negative = num < 0;
|
||
|
||
if (this.negative !== 0 && !negative) return -1;
|
||
if (this.negative === 0 && negative) return 1;
|
||
|
||
this._strip();
|
||
|
||
var res;
|
||
if (this.length > 1) {
|
||
res = 1;
|
||
} else {
|
||
if (negative) {
|
||
num = -num;
|
||
}
|
||
|
||
assert(num <= 0x3ffffff, 'Number is too big');
|
||
|
||
var w = this.words[0] | 0;
|
||
res = w === num ? 0 : w < num ? -1 : 1;
|
||
}
|
||
if (this.negative !== 0) return -res | 0;
|
||
return res;
|
||
};
|
||
|
||
// Compare two numbers and return:
|
||
// 1 - if `this` > `num`
|
||
// 0 - if `this` == `num`
|
||
// -1 - if `this` < `num`
|
||
BN.prototype.cmp = function cmp (num) {
|
||
if (this.negative !== 0 && num.negative === 0) return -1;
|
||
if (this.negative === 0 && num.negative !== 0) return 1;
|
||
|
||
var res = this.ucmp(num);
|
||
if (this.negative !== 0) return -res | 0;
|
||
return res;
|
||
};
|
||
|
||
// Unsigned comparison
|
||
BN.prototype.ucmp = function ucmp (num) {
|
||
// At this point both numbers have the same sign
|
||
if (this.length > num.length) return 1;
|
||
if (this.length < num.length) return -1;
|
||
|
||
var res = 0;
|
||
for (var i = this.length - 1; i >= 0; i--) {
|
||
var a = this.words[i] | 0;
|
||
var b = num.words[i] | 0;
|
||
|
||
if (a === b) continue;
|
||
if (a < b) {
|
||
res = -1;
|
||
} else if (a > b) {
|
||
res = 1;
|
||
}
|
||
break;
|
||
}
|
||
return res;
|
||
};
|
||
|
||
BN.prototype.gtn = function gtn (num) {
|
||
return this.cmpn(num) === 1;
|
||
};
|
||
|
||
BN.prototype.gt = function gt (num) {
|
||
return this.cmp(num) === 1;
|
||
};
|
||
|
||
BN.prototype.gten = function gten (num) {
|
||
return this.cmpn(num) >= 0;
|
||
};
|
||
|
||
BN.prototype.gte = function gte (num) {
|
||
return this.cmp(num) >= 0;
|
||
};
|
||
|
||
BN.prototype.ltn = function ltn (num) {
|
||
return this.cmpn(num) === -1;
|
||
};
|
||
|
||
BN.prototype.lt = function lt (num) {
|
||
return this.cmp(num) === -1;
|
||
};
|
||
|
||
BN.prototype.lten = function lten (num) {
|
||
return this.cmpn(num) <= 0;
|
||
};
|
||
|
||
BN.prototype.lte = function lte (num) {
|
||
return this.cmp(num) <= 0;
|
||
};
|
||
|
||
BN.prototype.eqn = function eqn (num) {
|
||
return this.cmpn(num) === 0;
|
||
};
|
||
|
||
BN.prototype.eq = function eq (num) {
|
||
return this.cmp(num) === 0;
|
||
};
|
||
|
||
//
|
||
// A reduce context, could be using montgomery or something better, depending
|
||
// on the `m` itself.
|
||
//
|
||
BN.red = function red (num) {
|
||
return new Red(num);
|
||
};
|
||
|
||
BN.prototype.toRed = function toRed (ctx) {
|
||
assert(!this.red, 'Already a number in reduction context');
|
||
assert(this.negative === 0, 'red works only with positives');
|
||
return ctx.convertTo(this)._forceRed(ctx);
|
||
};
|
||
|
||
BN.prototype.fromRed = function fromRed () {
|
||
assert(this.red, 'fromRed works only with numbers in reduction context');
|
||
return this.red.convertFrom(this);
|
||
};
|
||
|
||
BN.prototype._forceRed = function _forceRed (ctx) {
|
||
this.red = ctx;
|
||
return this;
|
||
};
|
||
|
||
BN.prototype.forceRed = function forceRed (ctx) {
|
||
assert(!this.red, 'Already a number in reduction context');
|
||
return this._forceRed(ctx);
|
||
};
|
||
|
||
BN.prototype.redAdd = function redAdd (num) {
|
||
assert(this.red, 'redAdd works only with red numbers');
|
||
return this.red.add(this, num);
|
||
};
|
||
|
||
BN.prototype.redIAdd = function redIAdd (num) {
|
||
assert(this.red, 'redIAdd works only with red numbers');
|
||
return this.red.iadd(this, num);
|
||
};
|
||
|
||
BN.prototype.redSub = function redSub (num) {
|
||
assert(this.red, 'redSub works only with red numbers');
|
||
return this.red.sub(this, num);
|
||
};
|
||
|
||
BN.prototype.redISub = function redISub (num) {
|
||
assert(this.red, 'redISub works only with red numbers');
|
||
return this.red.isub(this, num);
|
||
};
|
||
|
||
BN.prototype.redShl = function redShl (num) {
|
||
assert(this.red, 'redShl works only with red numbers');
|
||
return this.red.shl(this, num);
|
||
};
|
||
|
||
BN.prototype.redMul = function redMul (num) {
|
||
assert(this.red, 'redMul works only with red numbers');
|
||
this.red._verify2(this, num);
|
||
return this.red.mul(this, num);
|
||
};
|
||
|
||
BN.prototype.redIMul = function redIMul (num) {
|
||
assert(this.red, 'redMul works only with red numbers');
|
||
this.red._verify2(this, num);
|
||
return this.red.imul(this, num);
|
||
};
|
||
|
||
BN.prototype.redSqr = function redSqr () {
|
||
assert(this.red, 'redSqr works only with red numbers');
|
||
this.red._verify1(this);
|
||
return this.red.sqr(this);
|
||
};
|
||
|
||
BN.prototype.redISqr = function redISqr () {
|
||
assert(this.red, 'redISqr works only with red numbers');
|
||
this.red._verify1(this);
|
||
return this.red.isqr(this);
|
||
};
|
||
|
||
// Square root over p
|
||
BN.prototype.redSqrt = function redSqrt () {
|
||
assert(this.red, 'redSqrt works only with red numbers');
|
||
this.red._verify1(this);
|
||
return this.red.sqrt(this);
|
||
};
|
||
|
||
BN.prototype.redInvm = function redInvm () {
|
||
assert(this.red, 'redInvm works only with red numbers');
|
||
this.red._verify1(this);
|
||
return this.red.invm(this);
|
||
};
|
||
|
||
// Return negative clone of `this` % `red modulo`
|
||
BN.prototype.redNeg = function redNeg () {
|
||
assert(this.red, 'redNeg works only with red numbers');
|
||
this.red._verify1(this);
|
||
return this.red.neg(this);
|
||
};
|
||
|
||
BN.prototype.redPow = function redPow (num) {
|
||
assert(this.red && !num.red, 'redPow(normalNum)');
|
||
this.red._verify1(this);
|
||
return this.red.pow(this, num);
|
||
};
|
||
|
||
// Prime numbers with efficient reduction
|
||
var primes = {
|
||
k256: null,
|
||
p224: null,
|
||
p192: null,
|
||
p25519: null
|
||
};
|
||
|
||
// Pseudo-Mersenne prime
|
||
function MPrime (name, p) {
|
||
// P = 2 ^ N - K
|
||
this.name = name;
|
||
this.p = new BN(p, 16);
|
||
this.n = this.p.bitLength();
|
||
this.k = new BN(1).iushln(this.n).isub(this.p);
|
||
|
||
this.tmp = this._tmp();
|
||
}
|
||
|
||
MPrime.prototype._tmp = function _tmp () {
|
||
var tmp = new BN(null);
|
||
tmp.words = new Array(Math.ceil(this.n / 13));
|
||
return tmp;
|
||
};
|
||
|
||
MPrime.prototype.ireduce = function ireduce (num) {
|
||
// Assumes that `num` is less than `P^2`
|
||
// num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)
|
||
var r = num;
|
||
var rlen;
|
||
|
||
do {
|
||
this.split(r, this.tmp);
|
||
r = this.imulK(r);
|
||
r = r.iadd(this.tmp);
|
||
rlen = r.bitLength();
|
||
} while (rlen > this.n);
|
||
|
||
var cmp = rlen < this.n ? -1 : r.ucmp(this.p);
|
||
if (cmp === 0) {
|
||
r.words[0] = 0;
|
||
r.length = 1;
|
||
} else if (cmp > 0) {
|
||
r.isub(this.p);
|
||
} else {
|
||
if (r.strip !== undefined) {
|
||
// r is a BN v4 instance
|
||
r.strip();
|
||
} else {
|
||
// r is a BN v5 instance
|
||
r._strip();
|
||
}
|
||
}
|
||
|
||
return r;
|
||
};
|
||
|
||
MPrime.prototype.split = function split (input, out) {
|
||
input.iushrn(this.n, 0, out);
|
||
};
|
||
|
||
MPrime.prototype.imulK = function imulK (num) {
|
||
return num.imul(this.k);
|
||
};
|
||
|
||
function K256 () {
|
||
MPrime.call(
|
||
this,
|
||
'k256',
|
||
'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');
|
||
}
|
||
inherits(K256, MPrime);
|
||
|
||
K256.prototype.split = function split (input, output) {
|
||
// 256 = 9 * 26 + 22
|
||
var mask = 0x3fffff;
|
||
|
||
var outLen = Math.min(input.length, 9);
|
||
for (var i = 0; i < outLen; i++) {
|
||
output.words[i] = input.words[i];
|
||
}
|
||
output.length = outLen;
|
||
|
||
if (input.length <= 9) {
|
||
input.words[0] = 0;
|
||
input.length = 1;
|
||
return;
|
||
}
|
||
|
||
// Shift by 9 limbs
|
||
var prev = input.words[9];
|
||
output.words[output.length++] = prev & mask;
|
||
|
||
for (i = 10; i < input.length; i++) {
|
||
var next = input.words[i] | 0;
|
||
input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);
|
||
prev = next;
|
||
}
|
||
prev >>>= 22;
|
||
input.words[i - 10] = prev;
|
||
if (prev === 0 && input.length > 10) {
|
||
input.length -= 10;
|
||
} else {
|
||
input.length -= 9;
|
||
}
|
||
};
|
||
|
||
K256.prototype.imulK = function imulK (num) {
|
||
// K = 0x1000003d1 = [ 0x40, 0x3d1 ]
|
||
num.words[num.length] = 0;
|
||
num.words[num.length + 1] = 0;
|
||
num.length += 2;
|
||
|
||
// bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390
|
||
var lo = 0;
|
||
for (var i = 0; i < num.length; i++) {
|
||
var w = num.words[i] | 0;
|
||
lo += w * 0x3d1;
|
||
num.words[i] = lo & 0x3ffffff;
|
||
lo = w * 0x40 + ((lo / 0x4000000) | 0);
|
||
}
|
||
|
||
// Fast length reduction
|
||
if (num.words[num.length - 1] === 0) {
|
||
num.length--;
|
||
if (num.words[num.length - 1] === 0) {
|
||
num.length--;
|
||
}
|
||
}
|
||
return num;
|
||
};
|
||
|
||
function P224 () {
|
||
MPrime.call(
|
||
this,
|
||
'p224',
|
||
'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');
|
||
}
|
||
inherits(P224, MPrime);
|
||
|
||
function P192 () {
|
||
MPrime.call(
|
||
this,
|
||
'p192',
|
||
'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');
|
||
}
|
||
inherits(P192, MPrime);
|
||
|
||
function P25519 () {
|
||
// 2 ^ 255 - 19
|
||
MPrime.call(
|
||
this,
|
||
'25519',
|
||
'7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');
|
||
}
|
||
inherits(P25519, MPrime);
|
||
|
||
P25519.prototype.imulK = function imulK (num) {
|
||
// K = 0x13
|
||
var carry = 0;
|
||
for (var i = 0; i < num.length; i++) {
|
||
var hi = (num.words[i] | 0) * 0x13 + carry;
|
||
var lo = hi & 0x3ffffff;
|
||
hi >>>= 26;
|
||
|
||
num.words[i] = lo;
|
||
carry = hi;
|
||
}
|
||
if (carry !== 0) {
|
||
num.words[num.length++] = carry;
|
||
}
|
||
return num;
|
||
};
|
||
|
||
// Exported mostly for testing purposes, use plain name instead
|
||
BN._prime = function prime (name) {
|
||
// Cached version of prime
|
||
if (primes[name]) return primes[name];
|
||
|
||
var prime;
|
||
if (name === 'k256') {
|
||
prime = new K256();
|
||
} else if (name === 'p224') {
|
||
prime = new P224();
|
||
} else if (name === 'p192') {
|
||
prime = new P192();
|
||
} else if (name === 'p25519') {
|
||
prime = new P25519();
|
||
} else {
|
||
throw new Error('Unknown prime ' + name);
|
||
}
|
||
primes[name] = prime;
|
||
|
||
return prime;
|
||
};
|
||
|
||
//
|
||
// Base reduction engine
|
||
//
|
||
function Red (m) {
|
||
if (typeof m === 'string') {
|
||
var prime = BN._prime(m);
|
||
this.m = prime.p;
|
||
this.prime = prime;
|
||
} else {
|
||
assert(m.gtn(1), 'modulus must be greater than 1');
|
||
this.m = m;
|
||
this.prime = null;
|
||
}
|
||
}
|
||
|
||
Red.prototype._verify1 = function _verify1 (a) {
|
||
assert(a.negative === 0, 'red works only with positives');
|
||
assert(a.red, 'red works only with red numbers');
|
||
};
|
||
|
||
Red.prototype._verify2 = function _verify2 (a, b) {
|
||
assert((a.negative | b.negative) === 0, 'red works only with positives');
|
||
assert(a.red && a.red === b.red,
|
||
'red works only with red numbers');
|
||
};
|
||
|
||
Red.prototype.imod = function imod (a) {
|
||
if (this.prime) return this.prime.ireduce(a)._forceRed(this);
|
||
|
||
move(a, a.umod(this.m)._forceRed(this));
|
||
return a;
|
||
};
|
||
|
||
Red.prototype.neg = function neg (a) {
|
||
if (a.isZero()) {
|
||
return a.clone();
|
||
}
|
||
|
||
return this.m.sub(a)._forceRed(this);
|
||
};
|
||
|
||
Red.prototype.add = function add (a, b) {
|
||
this._verify2(a, b);
|
||
|
||
var res = a.add(b);
|
||
if (res.cmp(this.m) >= 0) {
|
||
res.isub(this.m);
|
||
}
|
||
return res._forceRed(this);
|
||
};
|
||
|
||
Red.prototype.iadd = function iadd (a, b) {
|
||
this._verify2(a, b);
|
||
|
||
var res = a.iadd(b);
|
||
if (res.cmp(this.m) >= 0) {
|
||
res.isub(this.m);
|
||
}
|
||
return res;
|
||
};
|
||
|
||
Red.prototype.sub = function sub (a, b) {
|
||
this._verify2(a, b);
|
||
|
||
var res = a.sub(b);
|
||
if (res.cmpn(0) < 0) {
|
||
res.iadd(this.m);
|
||
}
|
||
return res._forceRed(this);
|
||
};
|
||
|
||
Red.prototype.isub = function isub (a, b) {
|
||
this._verify2(a, b);
|
||
|
||
var res = a.isub(b);
|
||
if (res.cmpn(0) < 0) {
|
||
res.iadd(this.m);
|
||
}
|
||
return res;
|
||
};
|
||
|
||
Red.prototype.shl = function shl (a, num) {
|
||
this._verify1(a);
|
||
return this.imod(a.ushln(num));
|
||
};
|
||
|
||
Red.prototype.imul = function imul (a, b) {
|
||
this._verify2(a, b);
|
||
return this.imod(a.imul(b));
|
||
};
|
||
|
||
Red.prototype.mul = function mul (a, b) {
|
||
this._verify2(a, b);
|
||
return this.imod(a.mul(b));
|
||
};
|
||
|
||
Red.prototype.isqr = function isqr (a) {
|
||
return this.imul(a, a.clone());
|
||
};
|
||
|
||
Red.prototype.sqr = function sqr (a) {
|
||
return this.mul(a, a);
|
||
};
|
||
|
||
Red.prototype.sqrt = function sqrt (a) {
|
||
if (a.isZero()) return a.clone();
|
||
|
||
var mod3 = this.m.andln(3);
|
||
assert(mod3 % 2 === 1);
|
||
|
||
// Fast case
|
||
if (mod3 === 3) {
|
||
var pow = this.m.add(new BN(1)).iushrn(2);
|
||
return this.pow(a, pow);
|
||
}
|
||
|
||
// Tonelli-Shanks algorithm (Totally unoptimized and slow)
|
||
//
|
||
// Find Q and S, that Q * 2 ^ S = (P - 1)
|
||
var q = this.m.subn(1);
|
||
var s = 0;
|
||
while (!q.isZero() && q.andln(1) === 0) {
|
||
s++;
|
||
q.iushrn(1);
|
||
}
|
||
assert(!q.isZero());
|
||
|
||
var one = new BN(1).toRed(this);
|
||
var nOne = one.redNeg();
|
||
|
||
// Find quadratic non-residue
|
||
// NOTE: Max is such because of generalized Riemann hypothesis.
|
||
var lpow = this.m.subn(1).iushrn(1);
|
||
var z = this.m.bitLength();
|
||
z = new BN(2 * z * z).toRed(this);
|
||
|
||
while (this.pow(z, lpow).cmp(nOne) !== 0) {
|
||
z.redIAdd(nOne);
|
||
}
|
||
|
||
var c = this.pow(z, q);
|
||
var r = this.pow(a, q.addn(1).iushrn(1));
|
||
var t = this.pow(a, q);
|
||
var m = s;
|
||
while (t.cmp(one) !== 0) {
|
||
var tmp = t;
|
||
for (var i = 0; tmp.cmp(one) !== 0; i++) {
|
||
tmp = tmp.redSqr();
|
||
}
|
||
assert(i < m);
|
||
var b = this.pow(c, new BN(1).iushln(m - i - 1));
|
||
|
||
r = r.redMul(b);
|
||
c = b.redSqr();
|
||
t = t.redMul(c);
|
||
m = i;
|
||
}
|
||
|
||
return r;
|
||
};
|
||
|
||
Red.prototype.invm = function invm (a) {
|
||
var inv = a._invmp(this.m);
|
||
if (inv.negative !== 0) {
|
||
inv.negative = 0;
|
||
return this.imod(inv).redNeg();
|
||
} else {
|
||
return this.imod(inv);
|
||
}
|
||
};
|
||
|
||
Red.prototype.pow = function pow (a, num) {
|
||
if (num.isZero()) return new BN(1).toRed(this);
|
||
if (num.cmpn(1) === 0) return a.clone();
|
||
|
||
var windowSize = 4;
|
||
var wnd = new Array(1 << windowSize);
|
||
wnd[0] = new BN(1).toRed(this);
|
||
wnd[1] = a;
|
||
for (var i = 2; i < wnd.length; i++) {
|
||
wnd[i] = this.mul(wnd[i - 1], a);
|
||
}
|
||
|
||
var res = wnd[0];
|
||
var current = 0;
|
||
var currentLen = 0;
|
||
var start = num.bitLength() % 26;
|
||
if (start === 0) {
|
||
start = 26;
|
||
}
|
||
|
||
for (i = num.length - 1; i >= 0; i--) {
|
||
var word = num.words[i];
|
||
for (var j = start - 1; j >= 0; j--) {
|
||
var bit = (word >> j) & 1;
|
||
if (res !== wnd[0]) {
|
||
res = this.sqr(res);
|
||
}
|
||
|
||
if (bit === 0 && current === 0) {
|
||
currentLen = 0;
|
||
continue;
|
||
}
|
||
|
||
current <<= 1;
|
||
current |= bit;
|
||
currentLen++;
|
||
if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;
|
||
|
||
res = this.mul(res, wnd[current]);
|
||
currentLen = 0;
|
||
current = 0;
|
||
}
|
||
start = 26;
|
||
}
|
||
|
||
return res;
|
||
};
|
||
|
||
Red.prototype.convertTo = function convertTo (num) {
|
||
var r = num.umod(this.m);
|
||
|
||
return r === num ? r.clone() : r;
|
||
};
|
||
|
||
Red.prototype.convertFrom = function convertFrom (num) {
|
||
var res = num.clone();
|
||
res.red = null;
|
||
return res;
|
||
};
|
||
|
||
//
|
||
// Montgomery method engine
|
||
//
|
||
|
||
BN.mont = function mont (num) {
|
||
return new Mont(num);
|
||
};
|
||
|
||
function Mont (m) {
|
||
Red.call(this, m);
|
||
|
||
this.shift = this.m.bitLength();
|
||
if (this.shift % 26 !== 0) {
|
||
this.shift += 26 - (this.shift % 26);
|
||
}
|
||
|
||
this.r = new BN(1).iushln(this.shift);
|
||
this.r2 = this.imod(this.r.sqr());
|
||
this.rinv = this.r._invmp(this.m);
|
||
|
||
this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);
|
||
this.minv = this.minv.umod(this.r);
|
||
this.minv = this.r.sub(this.minv);
|
||
}
|
||
inherits(Mont, Red);
|
||
|
||
Mont.prototype.convertTo = function convertTo (num) {
|
||
return this.imod(num.ushln(this.shift));
|
||
};
|
||
|
||
Mont.prototype.convertFrom = function convertFrom (num) {
|
||
var r = this.imod(num.mul(this.rinv));
|
||
r.red = null;
|
||
return r;
|
||
};
|
||
|
||
Mont.prototype.imul = function imul (a, b) {
|
||
if (a.isZero() || b.isZero()) {
|
||
a.words[0] = 0;
|
||
a.length = 1;
|
||
return a;
|
||
}
|
||
|
||
var t = a.imul(b);
|
||
var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
|
||
var u = t.isub(c).iushrn(this.shift);
|
||
var res = u;
|
||
|
||
if (u.cmp(this.m) >= 0) {
|
||
res = u.isub(this.m);
|
||
} else if (u.cmpn(0) < 0) {
|
||
res = u.iadd(this.m);
|
||
}
|
||
|
||
return res._forceRed(this);
|
||
};
|
||
|
||
Mont.prototype.mul = function mul (a, b) {
|
||
if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);
|
||
|
||
var t = a.mul(b);
|
||
var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
|
||
var u = t.isub(c).iushrn(this.shift);
|
||
var res = u;
|
||
if (u.cmp(this.m) >= 0) {
|
||
res = u.isub(this.m);
|
||
} else if (u.cmpn(0) < 0) {
|
||
res = u.iadd(this.m);
|
||
}
|
||
|
||
return res._forceRed(this);
|
||
};
|
||
|
||
Mont.prototype.invm = function invm (a) {
|
||
// (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R
|
||
var res = this.imod(a._invmp(this.m).mul(this.r2));
|
||
return res._forceRed(this);
|
||
};
|
||
})(module, commonjsGlobal);
|
||
} (bn));
|
||
|
||
var bnExports = bn.exports;
|
||
var BN = /*@__PURE__*/getDefaultExportFromCjs(bnExports);
|
||
|
||
var safeBuffer = {exports: {}};
|
||
|
||
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||
|
||
(function (module, exports) {
|
||
/* eslint-disable node/no-deprecated-api */
|
||
var buffer$1 = buffer;
|
||
var Buffer = buffer$1.Buffer;
|
||
|
||
// alternative to using Object.keys for old browsers
|
||
function copyProps (src, dst) {
|
||
for (var key in src) {
|
||
dst[key] = src[key];
|
||
}
|
||
}
|
||
if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
|
||
module.exports = buffer$1;
|
||
} else {
|
||
// Copy properties from require('buffer')
|
||
copyProps(buffer$1, exports);
|
||
exports.Buffer = SafeBuffer;
|
||
}
|
||
|
||
function SafeBuffer (arg, encodingOrOffset, length) {
|
||
return Buffer(arg, encodingOrOffset, length)
|
||
}
|
||
|
||
SafeBuffer.prototype = Object.create(Buffer.prototype);
|
||
|
||
// Copy static methods from Buffer
|
||
copyProps(Buffer, SafeBuffer);
|
||
|
||
SafeBuffer.from = function (arg, encodingOrOffset, length) {
|
||
if (typeof arg === 'number') {
|
||
throw new TypeError('Argument must not be a number')
|
||
}
|
||
return Buffer(arg, encodingOrOffset, length)
|
||
};
|
||
|
||
SafeBuffer.alloc = function (size, fill, encoding) {
|
||
if (typeof size !== 'number') {
|
||
throw new TypeError('Argument must be a number')
|
||
}
|
||
var buf = Buffer(size);
|
||
if (fill !== undefined) {
|
||
if (typeof encoding === 'string') {
|
||
buf.fill(fill, encoding);
|
||
} else {
|
||
buf.fill(fill);
|
||
}
|
||
} else {
|
||
buf.fill(0);
|
||
}
|
||
return buf
|
||
};
|
||
|
||
SafeBuffer.allocUnsafe = function (size) {
|
||
if (typeof size !== 'number') {
|
||
throw new TypeError('Argument must be a number')
|
||
}
|
||
return Buffer(size)
|
||
};
|
||
|
||
SafeBuffer.allocUnsafeSlow = function (size) {
|
||
if (typeof size !== 'number') {
|
||
throw new TypeError('Argument must be a number')
|
||
}
|
||
return buffer$1.SlowBuffer(size)
|
||
};
|
||
} (safeBuffer, safeBuffer.exports));
|
||
|
||
var safeBufferExports = safeBuffer.exports;
|
||
|
||
// base-x encoding / decoding
|
||
// Copyright (c) 2018 base-x contributors
|
||
// Copyright (c) 2014-2018 The Bitcoin Core developers (base58.cpp)
|
||
// Distributed under the MIT software license, see the accompanying
|
||
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||
// @ts-ignore
|
||
var _Buffer = safeBufferExports.Buffer;
|
||
function base (ALPHABET) {
|
||
if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }
|
||
var BASE_MAP = new Uint8Array(256);
|
||
for (var j = 0; j < BASE_MAP.length; j++) {
|
||
BASE_MAP[j] = 255;
|
||
}
|
||
for (var i = 0; i < ALPHABET.length; i++) {
|
||
var x = ALPHABET.charAt(i);
|
||
var xc = x.charCodeAt(0);
|
||
if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }
|
||
BASE_MAP[xc] = i;
|
||
}
|
||
var BASE = ALPHABET.length;
|
||
var LEADER = ALPHABET.charAt(0);
|
||
var FACTOR = Math.log(BASE) / Math.log(256); // log(BASE) / log(256), rounded up
|
||
var iFACTOR = Math.log(256) / Math.log(BASE); // log(256) / log(BASE), rounded up
|
||
function encode (source) {
|
||
if (Array.isArray(source) || source instanceof Uint8Array) { source = _Buffer.from(source); }
|
||
if (!_Buffer.isBuffer(source)) { throw new TypeError('Expected Buffer') }
|
||
if (source.length === 0) { return '' }
|
||
// Skip & count leading zeroes.
|
||
var zeroes = 0;
|
||
var length = 0;
|
||
var pbegin = 0;
|
||
var pend = source.length;
|
||
while (pbegin !== pend && source[pbegin] === 0) {
|
||
pbegin++;
|
||
zeroes++;
|
||
}
|
||
// Allocate enough space in big-endian base58 representation.
|
||
var size = ((pend - pbegin) * iFACTOR + 1) >>> 0;
|
||
var b58 = new Uint8Array(size);
|
||
// Process the bytes.
|
||
while (pbegin !== pend) {
|
||
var carry = source[pbegin];
|
||
// Apply "b58 = b58 * 256 + ch".
|
||
var i = 0;
|
||
for (var it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {
|
||
carry += (256 * b58[it1]) >>> 0;
|
||
b58[it1] = (carry % BASE) >>> 0;
|
||
carry = (carry / BASE) >>> 0;
|
||
}
|
||
if (carry !== 0) { throw new Error('Non-zero carry') }
|
||
length = i;
|
||
pbegin++;
|
||
}
|
||
// Skip leading zeroes in base58 result.
|
||
var it2 = size - length;
|
||
while (it2 !== size && b58[it2] === 0) {
|
||
it2++;
|
||
}
|
||
// Translate the result into a string.
|
||
var str = LEADER.repeat(zeroes);
|
||
for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]); }
|
||
return str
|
||
}
|
||
function decodeUnsafe (source) {
|
||
if (typeof source !== 'string') { throw new TypeError('Expected String') }
|
||
if (source.length === 0) { return _Buffer.alloc(0) }
|
||
var psz = 0;
|
||
// Skip and count leading '1's.
|
||
var zeroes = 0;
|
||
var length = 0;
|
||
while (source[psz] === LEADER) {
|
||
zeroes++;
|
||
psz++;
|
||
}
|
||
// Allocate enough space in big-endian base256 representation.
|
||
var size = (((source.length - psz) * FACTOR) + 1) >>> 0; // log(58) / log(256), rounded up.
|
||
var b256 = new Uint8Array(size);
|
||
// Process the characters.
|
||
while (source[psz]) {
|
||
// Decode character
|
||
var carry = BASE_MAP[source.charCodeAt(psz)];
|
||
// Invalid character
|
||
if (carry === 255) { return }
|
||
var i = 0;
|
||
for (var it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {
|
||
carry += (BASE * b256[it3]) >>> 0;
|
||
b256[it3] = (carry % 256) >>> 0;
|
||
carry = (carry / 256) >>> 0;
|
||
}
|
||
if (carry !== 0) { throw new Error('Non-zero carry') }
|
||
length = i;
|
||
psz++;
|
||
}
|
||
// Skip leading zeroes in b256.
|
||
var it4 = size - length;
|
||
while (it4 !== size && b256[it4] === 0) {
|
||
it4++;
|
||
}
|
||
var vch = _Buffer.allocUnsafe(zeroes + (size - it4));
|
||
vch.fill(0x00, 0, zeroes);
|
||
var j = zeroes;
|
||
while (it4 !== size) {
|
||
vch[j++] = b256[it4++];
|
||
}
|
||
return vch
|
||
}
|
||
function decode (string) {
|
||
var buffer = decodeUnsafe(string);
|
||
if (buffer) { return buffer }
|
||
throw new Error('Non-base' + BASE + ' character')
|
||
}
|
||
return {
|
||
encode: encode,
|
||
decodeUnsafe: decodeUnsafe,
|
||
decode: decode
|
||
}
|
||
}
|
||
var src = base;
|
||
|
||
var basex = src;
|
||
var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||
|
||
var bs58 = basex(ALPHABET);
|
||
|
||
var bs58$1 = /*@__PURE__*/getDefaultExportFromCjs(bs58);
|
||
|
||
function number$1(n) {
|
||
if (!Number.isSafeInteger(n) || n < 0)
|
||
throw new Error(`Wrong positive integer: ${n}`);
|
||
}
|
||
// copied from utils
|
||
function isBytes$1(a) {
|
||
return (a instanceof Uint8Array ||
|
||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
|
||
}
|
||
function bytes(b, ...lengths) {
|
||
if (!isBytes$1(b))
|
||
throw new Error('Expected Uint8Array');
|
||
if (lengths.length > 0 && !lengths.includes(b.length))
|
||
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
|
||
}
|
||
function exists(instance, checkFinished = true) {
|
||
if (instance.destroyed)
|
||
throw new Error('Hash instance has been destroyed');
|
||
if (checkFinished && instance.finished)
|
||
throw new Error('Hash#digest() has already been called');
|
||
}
|
||
function output(out, instance) {
|
||
bytes(out);
|
||
const min = instance.outputLen;
|
||
if (out.length < min) {
|
||
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
|
||
}
|
||
}
|
||
|
||
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
|
||
// node.js versions earlier than v19 don't declare it in global scope.
|
||
// For node.js, package.json#exports field mapping rewrites import
|
||
// from `crypto` to `cryptoNode`, which imports native module.
|
||
// Makes the utils un-importable in browsers without a bundler.
|
||
// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
|
||
const u32$1 = (arr) => new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
||
function isBytes(a) {
|
||
return (a instanceof Uint8Array ||
|
||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
|
||
}
|
||
// Cast array to view
|
||
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
||
// The rotate right (circular right shift) operation for uint32
|
||
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
|
||
// big-endian hardware is rare. Just in case someone still decides to run hashes:
|
||
// early-throw an error because we don't support BE yet.
|
||
// Other libraries would silently corrupt the data instead of throwing an error,
|
||
// when they don't support it.
|
||
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
|
||
if (!isLE)
|
||
throw new Error('Non little-endian hardware is not supported');
|
||
/**
|
||
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
||
*/
|
||
function utf8ToBytes(str) {
|
||
if (typeof str !== 'string')
|
||
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
||
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
|
||
}
|
||
/**
|
||
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
|
||
* Warning: when Uint8Array is passed, it would NOT get copied.
|
||
* Keep in mind for future mutable operations.
|
||
*/
|
||
function toBytes(data) {
|
||
if (typeof data === 'string')
|
||
data = utf8ToBytes(data);
|
||
if (!isBytes(data))
|
||
throw new Error(`expected Uint8Array, got ${typeof data}`);
|
||
return data;
|
||
}
|
||
// For runtime check if class implements interface
|
||
class Hash {
|
||
// Safe version that clones internal state
|
||
clone() {
|
||
return this._cloneInto();
|
||
}
|
||
}
|
||
function wrapConstructor(hashCons) {
|
||
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
||
const tmp = hashCons();
|
||
hashC.outputLen = tmp.outputLen;
|
||
hashC.blockLen = tmp.blockLen;
|
||
hashC.create = () => hashCons();
|
||
return hashC;
|
||
}
|
||
|
||
// Polyfill for Safari 14
|
||
function setBigUint64(view, byteOffset, value, isLE) {
|
||
if (typeof view.setBigUint64 === 'function')
|
||
return view.setBigUint64(byteOffset, value, isLE);
|
||
const _32n = BigInt(32);
|
||
const _u32_max = BigInt(0xffffffff);
|
||
const wh = Number((value >> _32n) & _u32_max);
|
||
const wl = Number(value & _u32_max);
|
||
const h = isLE ? 4 : 0;
|
||
const l = isLE ? 0 : 4;
|
||
view.setUint32(byteOffset + h, wh, isLE);
|
||
view.setUint32(byteOffset + l, wl, isLE);
|
||
}
|
||
// Base SHA2 class (RFC 6234)
|
||
class SHA2 extends Hash {
|
||
constructor(blockLen, outputLen, padOffset, isLE) {
|
||
super();
|
||
this.blockLen = blockLen;
|
||
this.outputLen = outputLen;
|
||
this.padOffset = padOffset;
|
||
this.isLE = isLE;
|
||
this.finished = false;
|
||
this.length = 0;
|
||
this.pos = 0;
|
||
this.destroyed = false;
|
||
this.buffer = new Uint8Array(blockLen);
|
||
this.view = createView(this.buffer);
|
||
}
|
||
update(data) {
|
||
exists(this);
|
||
const { view, buffer, blockLen } = this;
|
||
data = toBytes(data);
|
||
const len = data.length;
|
||
for (let pos = 0; pos < len;) {
|
||
const take = Math.min(blockLen - this.pos, len - pos);
|
||
// Fast path: we have at least one block in input, cast it to view and process
|
||
if (take === blockLen) {
|
||
const dataView = createView(data);
|
||
for (; blockLen <= len - pos; pos += blockLen)
|
||
this.process(dataView, pos);
|
||
continue;
|
||
}
|
||
buffer.set(data.subarray(pos, pos + take), this.pos);
|
||
this.pos += take;
|
||
pos += take;
|
||
if (this.pos === blockLen) {
|
||
this.process(view, 0);
|
||
this.pos = 0;
|
||
}
|
||
}
|
||
this.length += data.length;
|
||
this.roundClean();
|
||
return this;
|
||
}
|
||
digestInto(out) {
|
||
exists(this);
|
||
output(out, this);
|
||
this.finished = true;
|
||
// Padding
|
||
// We can avoid allocation of buffer for padding completely if it
|
||
// was previously not allocated here. But it won't change performance.
|
||
const { buffer, view, blockLen, isLE } = this;
|
||
let { pos } = this;
|
||
// append the bit '1' to the message
|
||
buffer[pos++] = 0b10000000;
|
||
this.buffer.subarray(pos).fill(0);
|
||
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
|
||
if (this.padOffset > blockLen - pos) {
|
||
this.process(view, 0);
|
||
pos = 0;
|
||
}
|
||
// Pad until full block byte with zeros
|
||
for (let i = pos; i < blockLen; i++)
|
||
buffer[i] = 0;
|
||
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
|
||
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
|
||
// So we just write lowest 64 bits of that value.
|
||
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
|
||
this.process(view, 0);
|
||
const oview = createView(out);
|
||
const len = this.outputLen;
|
||
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
|
||
if (len % 4)
|
||
throw new Error('_sha2: outputLen should be aligned to 32bit');
|
||
const outLen = len / 4;
|
||
const state = this.get();
|
||
if (outLen > state.length)
|
||
throw new Error('_sha2: outputLen bigger than state');
|
||
for (let i = 0; i < outLen; i++)
|
||
oview.setUint32(4 * i, state[i], isLE);
|
||
}
|
||
digest() {
|
||
const { buffer, outputLen } = this;
|
||
this.digestInto(buffer);
|
||
const res = buffer.slice(0, outputLen);
|
||
this.destroy();
|
||
return res;
|
||
}
|
||
_cloneInto(to) {
|
||
to || (to = new this.constructor());
|
||
to.set(...this.get());
|
||
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
||
to.length = length;
|
||
to.pos = pos;
|
||
to.finished = finished;
|
||
to.destroyed = destroyed;
|
||
if (length % blockLen)
|
||
to.buffer.set(buffer);
|
||
return to;
|
||
}
|
||
}
|
||
|
||
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
|
||
// BTC network is doing 2^67 hashes/sec as per early 2023.
|
||
// Choice: a ? b : c
|
||
const Chi = (a, b, c) => (a & b) ^ (~a & c);
|
||
// Majority function, true if any two inpust is true
|
||
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
|
||
// Round constants:
|
||
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
|
||
// prettier-ignore
|
||
const SHA256_K$1 = /* @__PURE__ */ new Uint32Array([
|
||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||
]);
|
||
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
|
||
// prettier-ignore
|
||
const IV = /* @__PURE__ */ new Uint32Array([
|
||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||
]);
|
||
// Temporary buffer, not used to store anything between runs
|
||
// Named this way because it matches specification.
|
||
const SHA256_W$1 = /* @__PURE__ */ new Uint32Array(64);
|
||
let SHA256$1 = class SHA256 extends SHA2 {
|
||
constructor() {
|
||
super(64, 32, 8, false);
|
||
// We cannot use array here since array allows indexing by variable
|
||
// which means optimizer/compiler cannot use registers.
|
||
this.A = IV[0] | 0;
|
||
this.B = IV[1] | 0;
|
||
this.C = IV[2] | 0;
|
||
this.D = IV[3] | 0;
|
||
this.E = IV[4] | 0;
|
||
this.F = IV[5] | 0;
|
||
this.G = IV[6] | 0;
|
||
this.H = IV[7] | 0;
|
||
}
|
||
get() {
|
||
const { A, B, C, D, E, F, G, H } = this;
|
||
return [A, B, C, D, E, F, G, H];
|
||
}
|
||
// prettier-ignore
|
||
set(A, B, C, D, E, F, G, H) {
|
||
this.A = A | 0;
|
||
this.B = B | 0;
|
||
this.C = C | 0;
|
||
this.D = D | 0;
|
||
this.E = E | 0;
|
||
this.F = F | 0;
|
||
this.G = G | 0;
|
||
this.H = H | 0;
|
||
}
|
||
process(view, offset) {
|
||
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
|
||
for (let i = 0; i < 16; i++, offset += 4)
|
||
SHA256_W$1[i] = view.getUint32(offset, false);
|
||
for (let i = 16; i < 64; i++) {
|
||
const W15 = SHA256_W$1[i - 15];
|
||
const W2 = SHA256_W$1[i - 2];
|
||
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
|
||
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
|
||
SHA256_W$1[i] = (s1 + SHA256_W$1[i - 7] + s0 + SHA256_W$1[i - 16]) | 0;
|
||
}
|
||
// Compression function main loop, 64 rounds
|
||
let { A, B, C, D, E, F, G, H } = this;
|
||
for (let i = 0; i < 64; i++) {
|
||
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
||
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K$1[i] + SHA256_W$1[i]) | 0;
|
||
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
||
const T2 = (sigma0 + Maj(A, B, C)) | 0;
|
||
H = G;
|
||
G = F;
|
||
F = E;
|
||
E = (D + T1) | 0;
|
||
D = C;
|
||
C = B;
|
||
B = A;
|
||
A = (T1 + T2) | 0;
|
||
}
|
||
// Add the compressed chunk to the current hash value
|
||
A = (A + this.A) | 0;
|
||
B = (B + this.B) | 0;
|
||
C = (C + this.C) | 0;
|
||
D = (D + this.D) | 0;
|
||
E = (E + this.E) | 0;
|
||
F = (F + this.F) | 0;
|
||
G = (G + this.G) | 0;
|
||
H = (H + this.H) | 0;
|
||
this.set(A, B, C, D, E, F, G, H);
|
||
}
|
||
roundClean() {
|
||
SHA256_W$1.fill(0);
|
||
}
|
||
destroy() {
|
||
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
||
this.buffer.fill(0);
|
||
}
|
||
};
|
||
/**
|
||
* SHA2-256 hash function
|
||
* @param message - data that would be hashed
|
||
*/
|
||
const sha256$1 = /* @__PURE__ */ wrapConstructor(() => new SHA256$1());
|
||
|
||
var lib = {};
|
||
|
||
var encoding_lib = {};
|
||
|
||
// This is free and unencumbered software released into the public domain.
|
||
// See LICENSE.md for more information.
|
||
|
||
//
|
||
// Utilities
|
||
//
|
||
|
||
/**
|
||
* @param {number} a The number to test.
|
||
* @param {number} min The minimum value in the range, inclusive.
|
||
* @param {number} max The maximum value in the range, inclusive.
|
||
* @return {boolean} True if a >= min and a <= max.
|
||
*/
|
||
function inRange(a, min, max) {
|
||
return min <= a && a <= max;
|
||
}
|
||
|
||
/**
|
||
* @param {*} o
|
||
* @return {Object}
|
||
*/
|
||
function ToDictionary(o) {
|
||
if (o === undefined) return {};
|
||
if (o === Object(o)) return o;
|
||
throw TypeError('Could not convert argument to dictionary');
|
||
}
|
||
|
||
/**
|
||
* @param {string} string Input string of UTF-16 code units.
|
||
* @return {!Array.<number>} Code points.
|
||
*/
|
||
function stringToCodePoints(string) {
|
||
// https://heycam.github.io/webidl/#dfn-obtain-unicode
|
||
|
||
// 1. Let S be the DOMString value.
|
||
var s = String(string);
|
||
|
||
// 2. Let n be the length of S.
|
||
var n = s.length;
|
||
|
||
// 3. Initialize i to 0.
|
||
var i = 0;
|
||
|
||
// 4. Initialize U to be an empty sequence of Unicode characters.
|
||
var u = [];
|
||
|
||
// 5. While i < n:
|
||
while (i < n) {
|
||
|
||
// 1. Let c be the code unit in S at index i.
|
||
var c = s.charCodeAt(i);
|
||
|
||
// 2. Depending on the value of c:
|
||
|
||
// c < 0xD800 or c > 0xDFFF
|
||
if (c < 0xD800 || c > 0xDFFF) {
|
||
// Append to U the Unicode character with code point c.
|
||
u.push(c);
|
||
}
|
||
|
||
// 0xDC00 ≤ c ≤ 0xDFFF
|
||
else if (0xDC00 <= c && c <= 0xDFFF) {
|
||
// Append to U a U+FFFD REPLACEMENT CHARACTER.
|
||
u.push(0xFFFD);
|
||
}
|
||
|
||
// 0xD800 ≤ c ≤ 0xDBFF
|
||
else if (0xD800 <= c && c <= 0xDBFF) {
|
||
// 1. If i = n−1, then append to U a U+FFFD REPLACEMENT
|
||
// CHARACTER.
|
||
if (i === n - 1) {
|
||
u.push(0xFFFD);
|
||
}
|
||
// 2. Otherwise, i < n−1:
|
||
else {
|
||
// 1. Let d be the code unit in S at index i+1.
|
||
var d = string.charCodeAt(i + 1);
|
||
|
||
// 2. If 0xDC00 ≤ d ≤ 0xDFFF, then:
|
||
if (0xDC00 <= d && d <= 0xDFFF) {
|
||
// 1. Let a be c & 0x3FF.
|
||
var a = c & 0x3FF;
|
||
|
||
// 2. Let b be d & 0x3FF.
|
||
var b = d & 0x3FF;
|
||
|
||
// 3. Append to U the Unicode character with code point
|
||
// 2^16+2^10*a+b.
|
||
u.push(0x10000 + (a << 10) + b);
|
||
|
||
// 4. Set i to i+1.
|
||
i += 1;
|
||
}
|
||
|
||
// 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a
|
||
// U+FFFD REPLACEMENT CHARACTER.
|
||
else {
|
||
u.push(0xFFFD);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 3. Set i to i+1.
|
||
i += 1;
|
||
}
|
||
|
||
// 6. Return U.
|
||
return u;
|
||
}
|
||
|
||
/**
|
||
* @param {!Array.<number>} code_points Array of code points.
|
||
* @return {string} string String of UTF-16 code units.
|
||
*/
|
||
function codePointsToString(code_points) {
|
||
var s = '';
|
||
for (var i = 0; i < code_points.length; ++i) {
|
||
var cp = code_points[i];
|
||
if (cp <= 0xFFFF) {
|
||
s += String.fromCharCode(cp);
|
||
} else {
|
||
cp -= 0x10000;
|
||
s += String.fromCharCode((cp >> 10) + 0xD800,
|
||
(cp & 0x3FF) + 0xDC00);
|
||
}
|
||
}
|
||
return s;
|
||
}
|
||
|
||
|
||
//
|
||
// Implementation of Encoding specification
|
||
// https://encoding.spec.whatwg.org/
|
||
//
|
||
|
||
//
|
||
// 3. Terminology
|
||
//
|
||
|
||
/**
|
||
* End-of-stream is a special token that signifies no more tokens
|
||
* are in the stream.
|
||
* @const
|
||
*/ var end_of_stream = -1;
|
||
|
||
/**
|
||
* A stream represents an ordered sequence of tokens.
|
||
*
|
||
* @constructor
|
||
* @param {!(Array.<number>|Uint8Array)} tokens Array of tokens that provide the
|
||
* stream.
|
||
*/
|
||
function Stream(tokens) {
|
||
/** @type {!Array.<number>} */
|
||
this.tokens = [].slice.call(tokens);
|
||
}
|
||
|
||
Stream.prototype = {
|
||
/**
|
||
* @return {boolean} True if end-of-stream has been hit.
|
||
*/
|
||
endOfStream: function() {
|
||
return !this.tokens.length;
|
||
},
|
||
|
||
/**
|
||
* When a token is read from a stream, the first token in the
|
||
* stream must be returned and subsequently removed, and
|
||
* end-of-stream must be returned otherwise.
|
||
*
|
||
* @return {number} Get the next token from the stream, or
|
||
* end_of_stream.
|
||
*/
|
||
read: function() {
|
||
if (!this.tokens.length)
|
||
return end_of_stream;
|
||
return this.tokens.shift();
|
||
},
|
||
|
||
/**
|
||
* When one or more tokens are prepended to a stream, those tokens
|
||
* must be inserted, in given order, before the first token in the
|
||
* stream.
|
||
*
|
||
* @param {(number|!Array.<number>)} token The token(s) to prepend to the stream.
|
||
*/
|
||
prepend: function(token) {
|
||
if (Array.isArray(token)) {
|
||
var tokens = /**@type {!Array.<number>}*/(token);
|
||
while (tokens.length)
|
||
this.tokens.unshift(tokens.pop());
|
||
} else {
|
||
this.tokens.unshift(token);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* When one or more tokens are pushed to a stream, those tokens
|
||
* must be inserted, in given order, after the last token in the
|
||
* stream.
|
||
*
|
||
* @param {(number|!Array.<number>)} token The tokens(s) to prepend to the stream.
|
||
*/
|
||
push: function(token) {
|
||
if (Array.isArray(token)) {
|
||
var tokens = /**@type {!Array.<number>}*/(token);
|
||
while (tokens.length)
|
||
this.tokens.push(tokens.shift());
|
||
} else {
|
||
this.tokens.push(token);
|
||
}
|
||
}
|
||
};
|
||
|
||
//
|
||
// 4. Encodings
|
||
//
|
||
|
||
// 4.1 Encoders and decoders
|
||
|
||
/** @const */
|
||
var finished = -1;
|
||
|
||
/**
|
||
* @param {boolean} fatal If true, decoding errors raise an exception.
|
||
* @param {number=} opt_code_point Override the standard fallback code point.
|
||
* @return {number} The code point to insert on a decoding error.
|
||
*/
|
||
function decoderError(fatal, opt_code_point) {
|
||
if (fatal)
|
||
throw TypeError('Decoder error');
|
||
return opt_code_point || 0xFFFD;
|
||
}
|
||
|
||
//
|
||
// 7. API
|
||
//
|
||
|
||
/** @const */ var DEFAULT_ENCODING = 'utf-8';
|
||
|
||
// 7.1 Interface TextDecoder
|
||
|
||
/**
|
||
* @constructor
|
||
* @param {string=} encoding The label of the encoding;
|
||
* defaults to 'utf-8'.
|
||
* @param {Object=} options
|
||
*/
|
||
function TextDecoder$1(encoding, options) {
|
||
if (!(this instanceof TextDecoder$1)) {
|
||
return new TextDecoder$1(encoding, options);
|
||
}
|
||
encoding = encoding !== undefined ? String(encoding).toLowerCase() : DEFAULT_ENCODING;
|
||
if (encoding !== DEFAULT_ENCODING) {
|
||
throw new Error('Encoding not supported. Only utf-8 is supported');
|
||
}
|
||
options = ToDictionary(options);
|
||
|
||
/** @private @type {boolean} */
|
||
this._streaming = false;
|
||
/** @private @type {boolean} */
|
||
this._BOMseen = false;
|
||
/** @private @type {?Decoder} */
|
||
this._decoder = null;
|
||
/** @private @type {boolean} */
|
||
this._fatal = Boolean(options['fatal']);
|
||
/** @private @type {boolean} */
|
||
this._ignoreBOM = Boolean(options['ignoreBOM']);
|
||
|
||
Object.defineProperty(this, 'encoding', {value: 'utf-8'});
|
||
Object.defineProperty(this, 'fatal', {value: this._fatal});
|
||
Object.defineProperty(this, 'ignoreBOM', {value: this._ignoreBOM});
|
||
}
|
||
|
||
TextDecoder$1.prototype = {
|
||
/**
|
||
* @param {ArrayBufferView=} input The buffer of bytes to decode.
|
||
* @param {Object=} options
|
||
* @return {string} The decoded string.
|
||
*/
|
||
decode: function decode(input, options) {
|
||
var bytes;
|
||
if (typeof input === 'object' && input instanceof ArrayBuffer) {
|
||
bytes = new Uint8Array(input);
|
||
} else if (typeof input === 'object' && 'buffer' in input &&
|
||
input.buffer instanceof ArrayBuffer) {
|
||
bytes = new Uint8Array(input.buffer,
|
||
input.byteOffset,
|
||
input.byteLength);
|
||
} else {
|
||
bytes = new Uint8Array(0);
|
||
}
|
||
|
||
options = ToDictionary(options);
|
||
|
||
if (!this._streaming) {
|
||
this._decoder = new UTF8Decoder({fatal: this._fatal});
|
||
this._BOMseen = false;
|
||
}
|
||
this._streaming = Boolean(options['stream']);
|
||
|
||
var input_stream = new Stream(bytes);
|
||
|
||
var code_points = [];
|
||
|
||
/** @type {?(number|!Array.<number>)} */
|
||
var result;
|
||
|
||
while (!input_stream.endOfStream()) {
|
||
result = this._decoder.handler(input_stream, input_stream.read());
|
||
if (result === finished)
|
||
break;
|
||
if (result === null)
|
||
continue;
|
||
if (Array.isArray(result))
|
||
code_points.push.apply(code_points, /**@type {!Array.<number>}*/(result));
|
||
else
|
||
code_points.push(result);
|
||
}
|
||
if (!this._streaming) {
|
||
do {
|
||
result = this._decoder.handler(input_stream, input_stream.read());
|
||
if (result === finished)
|
||
break;
|
||
if (result === null)
|
||
continue;
|
||
if (Array.isArray(result))
|
||
code_points.push.apply(code_points, /**@type {!Array.<number>}*/(result));
|
||
else
|
||
code_points.push(result);
|
||
} while (!input_stream.endOfStream());
|
||
this._decoder = null;
|
||
}
|
||
|
||
if (code_points.length) {
|
||
// If encoding is one of utf-8, utf-16be, and utf-16le, and
|
||
// ignore BOM flag and BOM seen flag are unset, run these
|
||
// subsubsteps:
|
||
if (['utf-8'].indexOf(this.encoding) !== -1 &&
|
||
!this._ignoreBOM && !this._BOMseen) {
|
||
// If token is U+FEFF, set BOM seen flag.
|
||
if (code_points[0] === 0xFEFF) {
|
||
this._BOMseen = true;
|
||
code_points.shift();
|
||
} else {
|
||
// Otherwise, if token is not end-of-stream, set BOM seen
|
||
// flag and append token to output.
|
||
this._BOMseen = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return codePointsToString(code_points);
|
||
}
|
||
};
|
||
|
||
// 7.2 Interface TextEncoder
|
||
|
||
/**
|
||
* @constructor
|
||
* @param {string=} encoding The label of the encoding;
|
||
* defaults to 'utf-8'.
|
||
* @param {Object=} options
|
||
*/
|
||
function TextEncoder$1(encoding, options) {
|
||
if (!(this instanceof TextEncoder$1))
|
||
return new TextEncoder$1(encoding, options);
|
||
encoding = encoding !== undefined ? String(encoding).toLowerCase() : DEFAULT_ENCODING;
|
||
if (encoding !== DEFAULT_ENCODING) {
|
||
throw new Error('Encoding not supported. Only utf-8 is supported');
|
||
}
|
||
options = ToDictionary(options);
|
||
|
||
/** @private @type {boolean} */
|
||
this._streaming = false;
|
||
/** @private @type {?Encoder} */
|
||
this._encoder = null;
|
||
/** @private @type {{fatal: boolean}} */
|
||
this._options = {fatal: Boolean(options['fatal'])};
|
||
|
||
Object.defineProperty(this, 'encoding', {value: 'utf-8'});
|
||
}
|
||
|
||
TextEncoder$1.prototype = {
|
||
/**
|
||
* @param {string=} opt_string The string to encode.
|
||
* @param {Object=} options
|
||
* @return {Uint8Array} Encoded bytes, as a Uint8Array.
|
||
*/
|
||
encode: function encode(opt_string, options) {
|
||
opt_string = opt_string ? String(opt_string) : '';
|
||
options = ToDictionary(options);
|
||
|
||
// NOTE: This option is nonstandard. None of the encodings
|
||
// permitted for encoding (i.e. UTF-8, UTF-16) are stateful,
|
||
// so streaming is not necessary.
|
||
if (!this._streaming)
|
||
this._encoder = new UTF8Encoder(this._options);
|
||
this._streaming = Boolean(options['stream']);
|
||
|
||
var bytes = [];
|
||
var input_stream = new Stream(stringToCodePoints(opt_string));
|
||
/** @type {?(number|!Array.<number>)} */
|
||
var result;
|
||
while (!input_stream.endOfStream()) {
|
||
result = this._encoder.handler(input_stream, input_stream.read());
|
||
if (result === finished)
|
||
break;
|
||
if (Array.isArray(result))
|
||
bytes.push.apply(bytes, /**@type {!Array.<number>}*/(result));
|
||
else
|
||
bytes.push(result);
|
||
}
|
||
if (!this._streaming) {
|
||
while (true) {
|
||
result = this._encoder.handler(input_stream, input_stream.read());
|
||
if (result === finished)
|
||
break;
|
||
if (Array.isArray(result))
|
||
bytes.push.apply(bytes, /**@type {!Array.<number>}*/(result));
|
||
else
|
||
bytes.push(result);
|
||
}
|
||
this._encoder = null;
|
||
}
|
||
return new Uint8Array(bytes);
|
||
}
|
||
};
|
||
|
||
//
|
||
// 8. The encoding
|
||
//
|
||
|
||
// 8.1 utf-8
|
||
|
||
/**
|
||
* @constructor
|
||
* @implements {Decoder}
|
||
* @param {{fatal: boolean}} options
|
||
*/
|
||
function UTF8Decoder(options) {
|
||
var fatal = options.fatal;
|
||
|
||
// utf-8's decoder's has an associated utf-8 code point, utf-8
|
||
// bytes seen, and utf-8 bytes needed (all initially 0), a utf-8
|
||
// lower boundary (initially 0x80), and a utf-8 upper boundary
|
||
// (initially 0xBF).
|
||
var /** @type {number} */ utf8_code_point = 0,
|
||
/** @type {number} */ utf8_bytes_seen = 0,
|
||
/** @type {number} */ utf8_bytes_needed = 0,
|
||
/** @type {number} */ utf8_lower_boundary = 0x80,
|
||
/** @type {number} */ utf8_upper_boundary = 0xBF;
|
||
|
||
/**
|
||
* @param {Stream} stream The stream of bytes being decoded.
|
||
* @param {number} bite The next byte read from the stream.
|
||
* @return {?(number|!Array.<number>)} The next code point(s)
|
||
* decoded, or null if not enough data exists in the input
|
||
* stream to decode a complete code point.
|
||
*/
|
||
this.handler = function(stream, bite) {
|
||
// 1. If byte is end-of-stream and utf-8 bytes needed is not 0,
|
||
// set utf-8 bytes needed to 0 and return error.
|
||
if (bite === end_of_stream && utf8_bytes_needed !== 0) {
|
||
utf8_bytes_needed = 0;
|
||
return decoderError(fatal);
|
||
}
|
||
|
||
// 2. If byte is end-of-stream, return finished.
|
||
if (bite === end_of_stream)
|
||
return finished;
|
||
|
||
// 3. If utf-8 bytes needed is 0, based on byte:
|
||
if (utf8_bytes_needed === 0) {
|
||
|
||
// 0x00 to 0x7F
|
||
if (inRange(bite, 0x00, 0x7F)) {
|
||
// Return a code point whose value is byte.
|
||
return bite;
|
||
}
|
||
|
||
// 0xC2 to 0xDF
|
||
if (inRange(bite, 0xC2, 0xDF)) {
|
||
// Set utf-8 bytes needed to 1 and utf-8 code point to byte
|
||
// − 0xC0.
|
||
utf8_bytes_needed = 1;
|
||
utf8_code_point = bite - 0xC0;
|
||
}
|
||
|
||
// 0xE0 to 0xEF
|
||
else if (inRange(bite, 0xE0, 0xEF)) {
|
||
// 1. If byte is 0xE0, set utf-8 lower boundary to 0xA0.
|
||
if (bite === 0xE0)
|
||
utf8_lower_boundary = 0xA0;
|
||
// 2. If byte is 0xED, set utf-8 upper boundary to 0x9F.
|
||
if (bite === 0xED)
|
||
utf8_upper_boundary = 0x9F;
|
||
// 3. Set utf-8 bytes needed to 2 and utf-8 code point to
|
||
// byte − 0xE0.
|
||
utf8_bytes_needed = 2;
|
||
utf8_code_point = bite - 0xE0;
|
||
}
|
||
|
||
// 0xF0 to 0xF4
|
||
else if (inRange(bite, 0xF0, 0xF4)) {
|
||
// 1. If byte is 0xF0, set utf-8 lower boundary to 0x90.
|
||
if (bite === 0xF0)
|
||
utf8_lower_boundary = 0x90;
|
||
// 2. If byte is 0xF4, set utf-8 upper boundary to 0x8F.
|
||
if (bite === 0xF4)
|
||
utf8_upper_boundary = 0x8F;
|
||
// 3. Set utf-8 bytes needed to 3 and utf-8 code point to
|
||
// byte − 0xF0.
|
||
utf8_bytes_needed = 3;
|
||
utf8_code_point = bite - 0xF0;
|
||
}
|
||
|
||
// Otherwise
|
||
else {
|
||
// Return error.
|
||
return decoderError(fatal);
|
||
}
|
||
|
||
// Then (byte is in the range 0xC2 to 0xF4) set utf-8 code
|
||
// point to utf-8 code point << (6 × utf-8 bytes needed) and
|
||
// return continue.
|
||
utf8_code_point = utf8_code_point << (6 * utf8_bytes_needed);
|
||
return null;
|
||
}
|
||
|
||
// 4. If byte is not in the range utf-8 lower boundary to utf-8
|
||
// upper boundary, run these substeps:
|
||
if (!inRange(bite, utf8_lower_boundary, utf8_upper_boundary)) {
|
||
|
||
// 1. Set utf-8 code point, utf-8 bytes needed, and utf-8
|
||
// bytes seen to 0, set utf-8 lower boundary to 0x80, and set
|
||
// utf-8 upper boundary to 0xBF.
|
||
utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
|
||
utf8_lower_boundary = 0x80;
|
||
utf8_upper_boundary = 0xBF;
|
||
|
||
// 2. Prepend byte to stream.
|
||
stream.prepend(bite);
|
||
|
||
// 3. Return error.
|
||
return decoderError(fatal);
|
||
}
|
||
|
||
// 5. Set utf-8 lower boundary to 0x80 and utf-8 upper boundary
|
||
// to 0xBF.
|
||
utf8_lower_boundary = 0x80;
|
||
utf8_upper_boundary = 0xBF;
|
||
|
||
// 6. Increase utf-8 bytes seen by one and set utf-8 code point
|
||
// to utf-8 code point + (byte − 0x80) << (6 × (utf-8 bytes
|
||
// needed − utf-8 bytes seen)).
|
||
utf8_bytes_seen += 1;
|
||
utf8_code_point += (bite - 0x80) << (6 * (utf8_bytes_needed - utf8_bytes_seen));
|
||
|
||
// 7. If utf-8 bytes seen is not equal to utf-8 bytes needed,
|
||
// continue.
|
||
if (utf8_bytes_seen !== utf8_bytes_needed)
|
||
return null;
|
||
|
||
// 8. Let code point be utf-8 code point.
|
||
var code_point = utf8_code_point;
|
||
|
||
// 9. Set utf-8 code point, utf-8 bytes needed, and utf-8 bytes
|
||
// seen to 0.
|
||
utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
|
||
|
||
// 10. Return a code point whose value is code point.
|
||
return code_point;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @constructor
|
||
* @implements {Encoder}
|
||
* @param {{fatal: boolean}} options
|
||
*/
|
||
function UTF8Encoder(options) {
|
||
options.fatal;
|
||
/**
|
||
* @param {Stream} stream Input stream.
|
||
* @param {number} code_point Next code point read from the stream.
|
||
* @return {(number|!Array.<number>)} Byte(s) to emit.
|
||
*/
|
||
this.handler = function(stream, code_point) {
|
||
// 1. If code point is end-of-stream, return finished.
|
||
if (code_point === end_of_stream)
|
||
return finished;
|
||
|
||
// 2. If code point is in the range U+0000 to U+007F, return a
|
||
// byte whose value is code point.
|
||
if (inRange(code_point, 0x0000, 0x007f))
|
||
return code_point;
|
||
|
||
// 3. Set count and offset based on the range code point is in:
|
||
var count, offset;
|
||
// U+0080 to U+07FF: 1 and 0xC0
|
||
if (inRange(code_point, 0x0080, 0x07FF)) {
|
||
count = 1;
|
||
offset = 0xC0;
|
||
}
|
||
// U+0800 to U+FFFF: 2 and 0xE0
|
||
else if (inRange(code_point, 0x0800, 0xFFFF)) {
|
||
count = 2;
|
||
offset = 0xE0;
|
||
}
|
||
// U+10000 to U+10FFFF: 3 and 0xF0
|
||
else if (inRange(code_point, 0x10000, 0x10FFFF)) {
|
||
count = 3;
|
||
offset = 0xF0;
|
||
}
|
||
|
||
// 4.Let bytes be a byte sequence whose first byte is (code
|
||
// point >> (6 × count)) + offset.
|
||
var bytes = [(code_point >> (6 * count)) + offset];
|
||
|
||
// 5. Run these substeps while count is greater than 0:
|
||
while (count > 0) {
|
||
|
||
// 1. Set temp to code point >> (6 × (count − 1)).
|
||
var temp = code_point >> (6 * (count - 1));
|
||
|
||
// 2. Append to bytes 0x80 | (temp & 0x3F).
|
||
bytes.push(0x80 | (temp & 0x3F));
|
||
|
||
// 3. Decrease count by one.
|
||
count -= 1;
|
||
}
|
||
|
||
// 6. Return bytes bytes, in order.
|
||
return bytes;
|
||
};
|
||
}
|
||
|
||
encoding_lib.TextEncoder = TextEncoder$1;
|
||
encoding_lib.TextDecoder = TextDecoder$1;
|
||
|
||
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||
if (k2 === undefined) k2 = k;
|
||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||
}) : (function(o, m, k, k2) {
|
||
if (k2 === undefined) k2 = k;
|
||
o[k2] = m[k];
|
||
}));
|
||
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||
}) : function(o, v) {
|
||
o["default"] = v;
|
||
});
|
||
var __decorate = (commonjsGlobal && commonjsGlobal.__decorate) || function (decorators, target, key, desc) {
|
||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||
};
|
||
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
|
||
if (mod && mod.__esModule) return mod;
|
||
var result = {};
|
||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||
__setModuleDefault(result, mod);
|
||
return result;
|
||
};
|
||
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
|
||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||
};
|
||
Object.defineProperty(lib, "__esModule", { value: true });
|
||
var deserializeUnchecked_1 = lib.deserializeUnchecked = deserialize_1 = lib.deserialize = serialize_1 = lib.serialize = lib.BinaryReader = lib.BinaryWriter = lib.BorshError = lib.baseDecode = lib.baseEncode = void 0;
|
||
const bn_js_1 = __importDefault(bnExports);
|
||
const bs58_1 = __importDefault(bs58);
|
||
// TODO: Make sure this polyfill not included when not required
|
||
const encoding = __importStar(encoding_lib);
|
||
const ResolvedTextDecoder = typeof TextDecoder !== "function" ? encoding.TextDecoder : TextDecoder;
|
||
const textDecoder = new ResolvedTextDecoder("utf-8", { fatal: true });
|
||
function baseEncode(value) {
|
||
if (typeof value === "string") {
|
||
value = Buffer.from(value, "utf8");
|
||
}
|
||
return bs58_1.default.encode(Buffer.from(value));
|
||
}
|
||
lib.baseEncode = baseEncode;
|
||
function baseDecode(value) {
|
||
return Buffer.from(bs58_1.default.decode(value));
|
||
}
|
||
lib.baseDecode = baseDecode;
|
||
const INITIAL_LENGTH = 1024;
|
||
class BorshError extends Error {
|
||
constructor(message) {
|
||
super(message);
|
||
this.fieldPath = [];
|
||
this.originalMessage = message;
|
||
}
|
||
addToFieldPath(fieldName) {
|
||
this.fieldPath.splice(0, 0, fieldName);
|
||
// NOTE: Modifying message directly as jest doesn't use .toString()
|
||
this.message = this.originalMessage + ": " + this.fieldPath.join(".");
|
||
}
|
||
}
|
||
lib.BorshError = BorshError;
|
||
/// Binary encoder.
|
||
class BinaryWriter {
|
||
constructor() {
|
||
this.buf = Buffer.alloc(INITIAL_LENGTH);
|
||
this.length = 0;
|
||
}
|
||
maybeResize() {
|
||
if (this.buf.length < 16 + this.length) {
|
||
this.buf = Buffer.concat([this.buf, Buffer.alloc(INITIAL_LENGTH)]);
|
||
}
|
||
}
|
||
writeU8(value) {
|
||
this.maybeResize();
|
||
this.buf.writeUInt8(value, this.length);
|
||
this.length += 1;
|
||
}
|
||
writeU16(value) {
|
||
this.maybeResize();
|
||
this.buf.writeUInt16LE(value, this.length);
|
||
this.length += 2;
|
||
}
|
||
writeU32(value) {
|
||
this.maybeResize();
|
||
this.buf.writeUInt32LE(value, this.length);
|
||
this.length += 4;
|
||
}
|
||
writeU64(value) {
|
||
this.maybeResize();
|
||
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 8)));
|
||
}
|
||
writeU128(value) {
|
||
this.maybeResize();
|
||
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 16)));
|
||
}
|
||
writeU256(value) {
|
||
this.maybeResize();
|
||
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 32)));
|
||
}
|
||
writeU512(value) {
|
||
this.maybeResize();
|
||
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 64)));
|
||
}
|
||
writeBuffer(buffer) {
|
||
// Buffer.from is needed as this.buf.subarray can return plain Uint8Array in browser
|
||
this.buf = Buffer.concat([
|
||
Buffer.from(this.buf.subarray(0, this.length)),
|
||
buffer,
|
||
Buffer.alloc(INITIAL_LENGTH),
|
||
]);
|
||
this.length += buffer.length;
|
||
}
|
||
writeString(str) {
|
||
this.maybeResize();
|
||
const b = Buffer.from(str, "utf8");
|
||
this.writeU32(b.length);
|
||
this.writeBuffer(b);
|
||
}
|
||
writeFixedArray(array) {
|
||
this.writeBuffer(Buffer.from(array));
|
||
}
|
||
writeArray(array, fn) {
|
||
this.maybeResize();
|
||
this.writeU32(array.length);
|
||
for (const elem of array) {
|
||
this.maybeResize();
|
||
fn(elem);
|
||
}
|
||
}
|
||
toArray() {
|
||
return this.buf.subarray(0, this.length);
|
||
}
|
||
}
|
||
lib.BinaryWriter = BinaryWriter;
|
||
function handlingRangeError(target, propertyKey, propertyDescriptor) {
|
||
const originalMethod = propertyDescriptor.value;
|
||
propertyDescriptor.value = function (...args) {
|
||
try {
|
||
return originalMethod.apply(this, args);
|
||
}
|
||
catch (e) {
|
||
if (e instanceof RangeError) {
|
||
const code = e.code;
|
||
if (["ERR_BUFFER_OUT_OF_BOUNDS", "ERR_OUT_OF_RANGE"].indexOf(code) >= 0) {
|
||
throw new BorshError("Reached the end of buffer when deserializing");
|
||
}
|
||
}
|
||
throw e;
|
||
}
|
||
};
|
||
}
|
||
class BinaryReader {
|
||
constructor(buf) {
|
||
this.buf = buf;
|
||
this.offset = 0;
|
||
}
|
||
readU8() {
|
||
const value = this.buf.readUInt8(this.offset);
|
||
this.offset += 1;
|
||
return value;
|
||
}
|
||
readU16() {
|
||
const value = this.buf.readUInt16LE(this.offset);
|
||
this.offset += 2;
|
||
return value;
|
||
}
|
||
readU32() {
|
||
const value = this.buf.readUInt32LE(this.offset);
|
||
this.offset += 4;
|
||
return value;
|
||
}
|
||
readU64() {
|
||
const buf = this.readBuffer(8);
|
||
return new bn_js_1.default(buf, "le");
|
||
}
|
||
readU128() {
|
||
const buf = this.readBuffer(16);
|
||
return new bn_js_1.default(buf, "le");
|
||
}
|
||
readU256() {
|
||
const buf = this.readBuffer(32);
|
||
return new bn_js_1.default(buf, "le");
|
||
}
|
||
readU512() {
|
||
const buf = this.readBuffer(64);
|
||
return new bn_js_1.default(buf, "le");
|
||
}
|
||
readBuffer(len) {
|
||
if (this.offset + len > this.buf.length) {
|
||
throw new BorshError(`Expected buffer length ${len} isn't within bounds`);
|
||
}
|
||
const result = this.buf.slice(this.offset, this.offset + len);
|
||
this.offset += len;
|
||
return result;
|
||
}
|
||
readString() {
|
||
const len = this.readU32();
|
||
const buf = this.readBuffer(len);
|
||
try {
|
||
// NOTE: Using TextDecoder to fail on invalid UTF-8
|
||
return textDecoder.decode(buf);
|
||
}
|
||
catch (e) {
|
||
throw new BorshError(`Error decoding UTF-8 string: ${e}`);
|
||
}
|
||
}
|
||
readFixedArray(len) {
|
||
return new Uint8Array(this.readBuffer(len));
|
||
}
|
||
readArray(fn) {
|
||
const len = this.readU32();
|
||
const result = Array();
|
||
for (let i = 0; i < len; ++i) {
|
||
result.push(fn());
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readU8", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readU16", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readU32", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readU64", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readU128", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readU256", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readU512", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readString", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readFixedArray", null);
|
||
__decorate([
|
||
handlingRangeError
|
||
], BinaryReader.prototype, "readArray", null);
|
||
lib.BinaryReader = BinaryReader;
|
||
function capitalizeFirstLetter(string) {
|
||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||
}
|
||
function serializeField(schema, fieldName, value, fieldType, writer) {
|
||
try {
|
||
// TODO: Handle missing values properly (make sure they never result in just skipped write)
|
||
if (typeof fieldType === "string") {
|
||
writer[`write${capitalizeFirstLetter(fieldType)}`](value);
|
||
}
|
||
else if (fieldType instanceof Array) {
|
||
if (typeof fieldType[0] === "number") {
|
||
if (value.length !== fieldType[0]) {
|
||
throw new BorshError(`Expecting byte array of length ${fieldType[0]}, but got ${value.length} bytes`);
|
||
}
|
||
writer.writeFixedArray(value);
|
||
}
|
||
else if (fieldType.length === 2 && typeof fieldType[1] === "number") {
|
||
if (value.length !== fieldType[1]) {
|
||
throw new BorshError(`Expecting byte array of length ${fieldType[1]}, but got ${value.length} bytes`);
|
||
}
|
||
for (let i = 0; i < fieldType[1]; i++) {
|
||
serializeField(schema, null, value[i], fieldType[0], writer);
|
||
}
|
||
}
|
||
else {
|
||
writer.writeArray(value, (item) => {
|
||
serializeField(schema, fieldName, item, fieldType[0], writer);
|
||
});
|
||
}
|
||
}
|
||
else if (fieldType.kind !== undefined) {
|
||
switch (fieldType.kind) {
|
||
case "option": {
|
||
if (value === null || value === undefined) {
|
||
writer.writeU8(0);
|
||
}
|
||
else {
|
||
writer.writeU8(1);
|
||
serializeField(schema, fieldName, value, fieldType.type, writer);
|
||
}
|
||
break;
|
||
}
|
||
case "map": {
|
||
writer.writeU32(value.size);
|
||
value.forEach((val, key) => {
|
||
serializeField(schema, fieldName, key, fieldType.key, writer);
|
||
serializeField(schema, fieldName, val, fieldType.value, writer);
|
||
});
|
||
break;
|
||
}
|
||
default:
|
||
throw new BorshError(`FieldType ${fieldType} unrecognized`);
|
||
}
|
||
}
|
||
else {
|
||
serializeStruct(schema, value, writer);
|
||
}
|
||
}
|
||
catch (error) {
|
||
if (error instanceof BorshError) {
|
||
error.addToFieldPath(fieldName);
|
||
}
|
||
throw error;
|
||
}
|
||
}
|
||
function serializeStruct(schema, obj, writer) {
|
||
if (typeof obj.borshSerialize === "function") {
|
||
obj.borshSerialize(writer);
|
||
return;
|
||
}
|
||
const structSchema = schema.get(obj.constructor);
|
||
if (!structSchema) {
|
||
throw new BorshError(`Class ${obj.constructor.name} is missing in schema`);
|
||
}
|
||
if (structSchema.kind === "struct") {
|
||
structSchema.fields.map(([fieldName, fieldType]) => {
|
||
serializeField(schema, fieldName, obj[fieldName], fieldType, writer);
|
||
});
|
||
}
|
||
else if (structSchema.kind === "enum") {
|
||
const name = obj[structSchema.field];
|
||
for (let idx = 0; idx < structSchema.values.length; ++idx) {
|
||
const [fieldName, fieldType] = structSchema.values[idx];
|
||
if (fieldName === name) {
|
||
writer.writeU8(idx);
|
||
serializeField(schema, fieldName, obj[fieldName], fieldType, writer);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
throw new BorshError(`Unexpected schema kind: ${structSchema.kind} for ${obj.constructor.name}`);
|
||
}
|
||
}
|
||
/// Serialize given object using schema of the form:
|
||
/// { class_name -> [ [field_name, field_type], .. ], .. }
|
||
function serialize(schema, obj, Writer = BinaryWriter) {
|
||
const writer = new Writer();
|
||
serializeStruct(schema, obj, writer);
|
||
return writer.toArray();
|
||
}
|
||
var serialize_1 = lib.serialize = serialize;
|
||
function deserializeField(schema, fieldName, fieldType, reader) {
|
||
try {
|
||
if (typeof fieldType === "string") {
|
||
return reader[`read${capitalizeFirstLetter(fieldType)}`]();
|
||
}
|
||
if (fieldType instanceof Array) {
|
||
if (typeof fieldType[0] === "number") {
|
||
return reader.readFixedArray(fieldType[0]);
|
||
}
|
||
else if (typeof fieldType[1] === "number") {
|
||
const arr = [];
|
||
for (let i = 0; i < fieldType[1]; i++) {
|
||
arr.push(deserializeField(schema, null, fieldType[0], reader));
|
||
}
|
||
return arr;
|
||
}
|
||
else {
|
||
return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader));
|
||
}
|
||
}
|
||
if (fieldType.kind === "option") {
|
||
const option = reader.readU8();
|
||
if (option) {
|
||
return deserializeField(schema, fieldName, fieldType.type, reader);
|
||
}
|
||
return undefined;
|
||
}
|
||
if (fieldType.kind === "map") {
|
||
let map = new Map();
|
||
const length = reader.readU32();
|
||
for (let i = 0; i < length; i++) {
|
||
const key = deserializeField(schema, fieldName, fieldType.key, reader);
|
||
const val = deserializeField(schema, fieldName, fieldType.value, reader);
|
||
map.set(key, val);
|
||
}
|
||
return map;
|
||
}
|
||
return deserializeStruct(schema, fieldType, reader);
|
||
}
|
||
catch (error) {
|
||
if (error instanceof BorshError) {
|
||
error.addToFieldPath(fieldName);
|
||
}
|
||
throw error;
|
||
}
|
||
}
|
||
function deserializeStruct(schema, classType, reader) {
|
||
if (typeof classType.borshDeserialize === "function") {
|
||
return classType.borshDeserialize(reader);
|
||
}
|
||
const structSchema = schema.get(classType);
|
||
if (!structSchema) {
|
||
throw new BorshError(`Class ${classType.name} is missing in schema`);
|
||
}
|
||
if (structSchema.kind === "struct") {
|
||
const result = {};
|
||
for (const [fieldName, fieldType] of schema.get(classType).fields) {
|
||
result[fieldName] = deserializeField(schema, fieldName, fieldType, reader);
|
||
}
|
||
return new classType(result);
|
||
}
|
||
if (structSchema.kind === "enum") {
|
||
const idx = reader.readU8();
|
||
if (idx >= structSchema.values.length) {
|
||
throw new BorshError(`Enum index: ${idx} is out of range`);
|
||
}
|
||
const [fieldName, fieldType] = structSchema.values[idx];
|
||
const fieldValue = deserializeField(schema, fieldName, fieldType, reader);
|
||
return new classType({ [fieldName]: fieldValue });
|
||
}
|
||
throw new BorshError(`Unexpected schema kind: ${structSchema.kind} for ${classType.constructor.name}`);
|
||
}
|
||
/// Deserializes object from bytes using schema.
|
||
function deserialize(schema, classType, buffer, Reader = BinaryReader) {
|
||
const reader = new Reader(buffer);
|
||
const result = deserializeStruct(schema, classType, reader);
|
||
if (reader.offset < buffer.length) {
|
||
throw new BorshError(`Unexpected ${buffer.length - reader.offset} bytes after deserialized data`);
|
||
}
|
||
return result;
|
||
}
|
||
var deserialize_1 = lib.deserialize = deserialize;
|
||
/// Deserializes object from bytes using schema, without checking the length read
|
||
function deserializeUnchecked(schema, classType, buffer, Reader = BinaryReader) {
|
||
const reader = new Reader(buffer);
|
||
return deserializeStruct(schema, classType, reader);
|
||
}
|
||
deserializeUnchecked_1 = lib.deserializeUnchecked = deserializeUnchecked;
|
||
|
||
// Class wrapping a plain object
|
||
let Struct$1 = class Struct {
|
||
constructor(properties) {
|
||
Object.assign(this, properties);
|
||
}
|
||
encode() {
|
||
return buffer.Buffer.from(serialize_1(SOLANA_SCHEMA, this));
|
||
}
|
||
static decode(data) {
|
||
return deserialize_1(SOLANA_SCHEMA, this, data);
|
||
}
|
||
static decodeUnchecked(data) {
|
||
return deserializeUnchecked_1(SOLANA_SCHEMA, this, data);
|
||
}
|
||
};
|
||
|
||
// Class representing a Rust-compatible enum, since enums are only strings or
|
||
// numbers in pure JS
|
||
class Enum extends Struct$1 {
|
||
constructor(properties) {
|
||
super(properties);
|
||
this.enum = '';
|
||
if (Object.keys(properties).length !== 1) {
|
||
throw new Error('Enum can only take single value');
|
||
}
|
||
Object.keys(properties).map(key => {
|
||
this.enum = key;
|
||
});
|
||
}
|
||
}
|
||
const SOLANA_SCHEMA = new Map();
|
||
|
||
var _class;
|
||
let _Symbol$toStringTag;
|
||
|
||
/**
|
||
* Maximum length of derived pubkey seed
|
||
*/
|
||
const MAX_SEED_LENGTH = 32;
|
||
|
||
/**
|
||
* Size of public key in bytes
|
||
*/
|
||
const PUBLIC_KEY_LENGTH = 32;
|
||
|
||
/**
|
||
* Value to be converted into public key
|
||
*/
|
||
|
||
/**
|
||
* JSON object representation of PublicKey class
|
||
*/
|
||
|
||
function isPublicKeyData(value) {
|
||
return value._bn !== undefined;
|
||
}
|
||
|
||
// local counter used by PublicKey.unique()
|
||
let uniquePublicKeyCounter = 1;
|
||
|
||
/**
|
||
* A public key
|
||
*/
|
||
_Symbol$toStringTag = Symbol.toStringTag;
|
||
class PublicKey extends Struct$1 {
|
||
/**
|
||
* Create a new PublicKey object
|
||
* @param value ed25519 public key as buffer or base-58 encoded string
|
||
*/
|
||
constructor(value) {
|
||
super({});
|
||
/** @internal */
|
||
this._bn = void 0;
|
||
if (isPublicKeyData(value)) {
|
||
this._bn = value._bn;
|
||
} else {
|
||
if (typeof value === 'string') {
|
||
// assume base 58 encoding by default
|
||
const decoded = bs58$1.decode(value);
|
||
if (decoded.length != PUBLIC_KEY_LENGTH) {
|
||
throw new Error(`Invalid public key input`);
|
||
}
|
||
this._bn = new BN(decoded);
|
||
} else {
|
||
this._bn = new BN(value);
|
||
}
|
||
if (this._bn.byteLength() > PUBLIC_KEY_LENGTH) {
|
||
throw new Error(`Invalid public key input`);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a unique PublicKey for tests and benchmarks using a counter
|
||
*/
|
||
static unique() {
|
||
const key = new PublicKey(uniquePublicKeyCounter);
|
||
uniquePublicKeyCounter += 1;
|
||
return new PublicKey(key.toBuffer());
|
||
}
|
||
|
||
/**
|
||
* Default public key value. The base58-encoded string representation is all ones (as seen below)
|
||
* The underlying BN number is 32 bytes that are all zeros
|
||
*/
|
||
|
||
/**
|
||
* Checks if two publicKeys are equal
|
||
*/
|
||
equals(publicKey) {
|
||
return this._bn.eq(publicKey._bn);
|
||
}
|
||
|
||
/**
|
||
* Return the base-58 representation of the public key
|
||
*/
|
||
toBase58() {
|
||
return bs58$1.encode(this.toBytes());
|
||
}
|
||
toJSON() {
|
||
return this.toBase58();
|
||
}
|
||
|
||
/**
|
||
* Return the byte array representation of the public key in big endian
|
||
*/
|
||
toBytes() {
|
||
const buf = this.toBuffer();
|
||
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
||
}
|
||
|
||
/**
|
||
* Return the Buffer representation of the public key in big endian
|
||
*/
|
||
toBuffer() {
|
||
const b = this._bn.toArrayLike(buffer.Buffer);
|
||
if (b.length === PUBLIC_KEY_LENGTH) {
|
||
return b;
|
||
}
|
||
const zeroPad = buffer.Buffer.alloc(32);
|
||
b.copy(zeroPad, 32 - b.length);
|
||
return zeroPad;
|
||
}
|
||
get [_Symbol$toStringTag]() {
|
||
return `PublicKey(${this.toString()})`;
|
||
}
|
||
|
||
/**
|
||
* Return the base-58 representation of the public key
|
||
*/
|
||
toString() {
|
||
return this.toBase58();
|
||
}
|
||
|
||
/**
|
||
* Derive a public key from another key, a seed, and a program ID.
|
||
* The program ID will also serve as the owner of the public key, giving
|
||
* it permission to write data to the account.
|
||
*/
|
||
/* eslint-disable require-await */
|
||
static async createWithSeed(fromPublicKey, seed, programId) {
|
||
const buffer$1 = buffer.Buffer.concat([fromPublicKey.toBuffer(), buffer.Buffer.from(seed), programId.toBuffer()]);
|
||
const publicKeyBytes = sha256$1(buffer$1);
|
||
return new PublicKey(publicKeyBytes);
|
||
}
|
||
|
||
/**
|
||
* Derive a program address from seeds and a program ID.
|
||
*/
|
||
/* eslint-disable require-await */
|
||
static createProgramAddressSync(seeds, programId) {
|
||
let buffer$1 = buffer.Buffer.alloc(0);
|
||
seeds.forEach(function (seed) {
|
||
if (seed.length > MAX_SEED_LENGTH) {
|
||
throw new TypeError(`Max seed length exceeded`);
|
||
}
|
||
buffer$1 = buffer.Buffer.concat([buffer$1, toBuffer(seed)]);
|
||
});
|
||
buffer$1 = buffer.Buffer.concat([buffer$1, programId.toBuffer(), buffer.Buffer.from('ProgramDerivedAddress')]);
|
||
const publicKeyBytes = sha256$1(buffer$1);
|
||
if (isOnCurve(publicKeyBytes)) {
|
||
throw new Error(`Invalid seeds, address must fall off the curve`);
|
||
}
|
||
return new PublicKey(publicKeyBytes);
|
||
}
|
||
|
||
/**
|
||
* Async version of createProgramAddressSync
|
||
* For backwards compatibility
|
||
*
|
||
* @deprecated Use {@link createProgramAddressSync} instead
|
||
*/
|
||
/* eslint-disable require-await */
|
||
static async createProgramAddress(seeds, programId) {
|
||
return this.createProgramAddressSync(seeds, programId);
|
||
}
|
||
|
||
/**
|
||
* Find a valid program address
|
||
*
|
||
* Valid program addresses must fall off the ed25519 curve. This function
|
||
* iterates a nonce until it finds one that when combined with the seeds
|
||
* results in a valid program address.
|
||
*/
|
||
static findProgramAddressSync(seeds, programId) {
|
||
let nonce = 255;
|
||
let address;
|
||
while (nonce != 0) {
|
||
try {
|
||
const seedsWithNonce = seeds.concat(buffer.Buffer.from([nonce]));
|
||
address = this.createProgramAddressSync(seedsWithNonce, programId);
|
||
} catch (err) {
|
||
if (err instanceof TypeError) {
|
||
throw err;
|
||
}
|
||
nonce--;
|
||
continue;
|
||
}
|
||
return [address, nonce];
|
||
}
|
||
throw new Error(`Unable to find a viable program address nonce`);
|
||
}
|
||
|
||
/**
|
||
* Async version of findProgramAddressSync
|
||
* For backwards compatibility
|
||
*
|
||
* @deprecated Use {@link findProgramAddressSync} instead
|
||
*/
|
||
static async findProgramAddress(seeds, programId) {
|
||
return this.findProgramAddressSync(seeds, programId);
|
||
}
|
||
|
||
/**
|
||
* Check that a pubkey is on the ed25519 curve.
|
||
*/
|
||
static isOnCurve(pubkeyData) {
|
||
const pubkey = new PublicKey(pubkeyData);
|
||
return isOnCurve(pubkey.toBytes());
|
||
}
|
||
}
|
||
_class = PublicKey;
|
||
PublicKey.default = new _class('11111111111111111111111111111111');
|
||
SOLANA_SCHEMA.set(PublicKey, {
|
||
kind: 'struct',
|
||
fields: [['_bn', 'u256']]
|
||
});
|
||
|
||
/**
|
||
* An account key pair (public and secret keys).
|
||
*
|
||
* @deprecated since v1.10.0, please use {@link Keypair} instead.
|
||
*/
|
||
class Account {
|
||
/**
|
||
* Create a new Account object
|
||
*
|
||
* If the secretKey parameter is not provided a new key pair is randomly
|
||
* created for the account
|
||
*
|
||
* @param secretKey Secret key for the account
|
||
*/
|
||
constructor(secretKey) {
|
||
/** @internal */
|
||
this._publicKey = void 0;
|
||
/** @internal */
|
||
this._secretKey = void 0;
|
||
if (secretKey) {
|
||
const secretKeyBuffer = toBuffer(secretKey);
|
||
if (secretKey.length !== 64) {
|
||
throw new Error('bad secret key size');
|
||
}
|
||
this._publicKey = secretKeyBuffer.slice(32, 64);
|
||
this._secretKey = secretKeyBuffer.slice(0, 32);
|
||
} else {
|
||
this._secretKey = toBuffer(generatePrivateKey());
|
||
this._publicKey = toBuffer(getPublicKey(this._secretKey));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* The public key for this account
|
||
*/
|
||
get publicKey() {
|
||
return new PublicKey(this._publicKey);
|
||
}
|
||
|
||
/**
|
||
* The **unencrypted** secret key for this account. The first 32 bytes
|
||
* is the private scalar and the last 32 bytes is the public key.
|
||
* Read more: https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/
|
||
*/
|
||
get secretKey() {
|
||
return buffer.Buffer.concat([this._secretKey, this._publicKey], 64);
|
||
}
|
||
}
|
||
|
||
const BPF_LOADER_DEPRECATED_PROGRAM_ID = new PublicKey('BPFLoader1111111111111111111111111111111111');
|
||
|
||
var Layout$1 = {};
|
||
|
||
/* The MIT License (MIT)
|
||
*
|
||
* Copyright 2015-2018 Peter A. Bigot
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
* of this software and associated documentation files (the "Software"), to deal
|
||
* in the Software without restriction, including without limitation the rights
|
||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
* copies of the Software, and to permit persons to whom the Software is
|
||
* furnished to do so, subject to the following conditions:
|
||
*
|
||
* The above copyright notice and this permission notice shall be included in
|
||
* all copies or substantial portions of the Software.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
* THE SOFTWARE.
|
||
*/
|
||
Object.defineProperty(Layout$1, "__esModule", { value: true });
|
||
Layout$1.s16 = Layout$1.s8 = Layout$1.nu64be = Layout$1.u48be = Layout$1.u40be = Layout$1.u32be = Layout$1.u24be = Layout$1.u16be = nu64 = Layout$1.nu64 = Layout$1.u48 = Layout$1.u40 = u32 = Layout$1.u32 = Layout$1.u24 = u16 = Layout$1.u16 = u8 = Layout$1.u8 = offset = Layout$1.offset = Layout$1.greedy = Layout$1.Constant = Layout$1.UTF8 = Layout$1.CString = Layout$1.Blob = Layout$1.Boolean = Layout$1.BitField = Layout$1.BitStructure = Layout$1.VariantLayout = Layout$1.Union = Layout$1.UnionLayoutDiscriminator = Layout$1.UnionDiscriminator = Layout$1.Structure = Layout$1.Sequence = Layout$1.DoubleBE = Layout$1.Double = Layout$1.FloatBE = Layout$1.Float = Layout$1.NearInt64BE = Layout$1.NearInt64 = Layout$1.NearUInt64BE = Layout$1.NearUInt64 = Layout$1.IntBE = Layout$1.Int = Layout$1.UIntBE = Layout$1.UInt = Layout$1.OffsetLayout = Layout$1.GreedyCount = Layout$1.ExternalLayout = Layout$1.bindConstructorLayout = Layout$1.nameWithProperty = Layout$1.Layout = Layout$1.uint8ArrayToBuffer = Layout$1.checkUint8Array = void 0;
|
||
Layout$1.constant = Layout$1.utf8 = Layout$1.cstr = blob = Layout$1.blob = Layout$1.unionLayoutDiscriminator = Layout$1.union = seq = Layout$1.seq = Layout$1.bits = struct = Layout$1.struct = Layout$1.f64be = Layout$1.f64 = Layout$1.f32be = Layout$1.f32 = Layout$1.ns64be = Layout$1.s48be = Layout$1.s40be = Layout$1.s32be = Layout$1.s24be = Layout$1.s16be = ns64 = Layout$1.ns64 = Layout$1.s48 = Layout$1.s40 = Layout$1.s32 = Layout$1.s24 = void 0;
|
||
const buffer_1 = buffer;
|
||
/* Check if a value is a Uint8Array.
|
||
*
|
||
* @ignore */
|
||
function checkUint8Array(b) {
|
||
if (!(b instanceof Uint8Array)) {
|
||
throw new TypeError('b must be a Uint8Array');
|
||
}
|
||
}
|
||
Layout$1.checkUint8Array = checkUint8Array;
|
||
/* Create a Buffer instance from a Uint8Array.
|
||
*
|
||
* @ignore */
|
||
function uint8ArrayToBuffer(b) {
|
||
checkUint8Array(b);
|
||
return buffer_1.Buffer.from(b.buffer, b.byteOffset, b.length);
|
||
}
|
||
Layout$1.uint8ArrayToBuffer = uint8ArrayToBuffer;
|
||
/**
|
||
* Base class for layout objects.
|
||
*
|
||
* **NOTE** This is an abstract base class; you can create instances
|
||
* if it amuses you, but they won't support the {@link
|
||
* Layout#encode|encode} or {@link Layout#decode|decode} functions.
|
||
*
|
||
* @param {Number} span - Initializer for {@link Layout#span|span}. The
|
||
* parameter must be an integer; a negative value signifies that the
|
||
* span is {@link Layout#getSpan|value-specific}.
|
||
*
|
||
* @param {string} [property] - Initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @abstract
|
||
*/
|
||
class Layout {
|
||
constructor(span, property) {
|
||
if (!Number.isInteger(span)) {
|
||
throw new TypeError('span must be an integer');
|
||
}
|
||
/** The span of the layout in bytes.
|
||
*
|
||
* Positive values are generally expected.
|
||
*
|
||
* Zero will only appear in {@link Constant}s and in {@link
|
||
* Sequence}s where the {@link Sequence#count|count} is zero.
|
||
*
|
||
* A negative value indicates that the span is value-specific, and
|
||
* must be obtained using {@link Layout#getSpan|getSpan}. */
|
||
this.span = span;
|
||
/** The property name used when this layout is represented in an
|
||
* Object.
|
||
*
|
||
* Used only for layouts that {@link Layout#decode|decode} to Object
|
||
* instances. If left undefined the span of the unnamed layout will
|
||
* be treated as padding: it will not be mutated by {@link
|
||
* Layout#encode|encode} nor represented as a property in the
|
||
* decoded Object. */
|
||
this.property = property;
|
||
}
|
||
/** Function to create an Object into which decoded properties will
|
||
* be written.
|
||
*
|
||
* Used only for layouts that {@link Layout#decode|decode} to Object
|
||
* instances, which means:
|
||
* * {@link Structure}
|
||
* * {@link Union}
|
||
* * {@link VariantLayout}
|
||
* * {@link BitStructure}
|
||
*
|
||
* If left undefined the JavaScript representation of these layouts
|
||
* will be Object instances.
|
||
*
|
||
* See {@link bindConstructorLayout}.
|
||
*/
|
||
makeDestinationObject() {
|
||
return {};
|
||
}
|
||
/**
|
||
* Calculate the span of a specific instance of a layout.
|
||
*
|
||
* @param {Uint8Array} b - the buffer that contains an encoded instance.
|
||
*
|
||
* @param {Number} [offset] - the offset at which the encoded instance
|
||
* starts. If absent a zero offset is inferred.
|
||
*
|
||
* @return {Number} - the number of bytes covered by the layout
|
||
* instance. If this method is not overridden in a subclass the
|
||
* definition-time constant {@link Layout#span|span} will be
|
||
* returned.
|
||
*
|
||
* @throws {RangeError} - if the length of the value cannot be
|
||
* determined.
|
||
*/
|
||
getSpan(b, offset) {
|
||
if (0 > this.span) {
|
||
throw new RangeError('indeterminate span');
|
||
}
|
||
return this.span;
|
||
}
|
||
/**
|
||
* Replicate the layout using a new property.
|
||
*
|
||
* This function must be used to get a structurally-equivalent layout
|
||
* with a different name since all {@link Layout} instances are
|
||
* immutable.
|
||
*
|
||
* **NOTE** This is a shallow copy. All fields except {@link
|
||
* Layout#property|property} are strictly equal to the origin layout.
|
||
*
|
||
* @param {String} property - the value for {@link
|
||
* Layout#property|property} in the replica.
|
||
*
|
||
* @returns {Layout} - the copy with {@link Layout#property|property}
|
||
* set to `property`.
|
||
*/
|
||
replicate(property) {
|
||
const rv = Object.create(this.constructor.prototype);
|
||
Object.assign(rv, this);
|
||
rv.property = property;
|
||
return rv;
|
||
}
|
||
/**
|
||
* Create an object from layout properties and an array of values.
|
||
*
|
||
* **NOTE** This function returns `undefined` if invoked on a layout
|
||
* that does not return its value as an Object. Objects are
|
||
* returned for things that are a {@link Structure}, which includes
|
||
* {@link VariantLayout|variant layouts} if they are structures, and
|
||
* excludes {@link Union}s. If you want this feature for a union
|
||
* you must use {@link Union.getVariant|getVariant} to select the
|
||
* desired layout.
|
||
*
|
||
* @param {Array} values - an array of values that correspond to the
|
||
* default order for properties. As with {@link Layout#decode|decode}
|
||
* layout elements that have no property name are skipped when
|
||
* iterating over the array values. Only the top-level properties are
|
||
* assigned; arguments are not assigned to properties of contained
|
||
* layouts. Any unused values are ignored.
|
||
*
|
||
* @return {(Object|undefined)}
|
||
*/
|
||
fromArray(values) {
|
||
return undefined;
|
||
}
|
||
}
|
||
Layout$1.Layout = Layout;
|
||
/* Provide text that carries a name (such as for a function that will
|
||
* be throwing an error) annotated with the property of a given layout
|
||
* (such as one for which the value was unacceptable).
|
||
*
|
||
* @ignore */
|
||
function nameWithProperty(name, lo) {
|
||
if (lo.property) {
|
||
return name + '[' + lo.property + ']';
|
||
}
|
||
return name;
|
||
}
|
||
Layout$1.nameWithProperty = nameWithProperty;
|
||
/**
|
||
* Augment a class so that instances can be encoded/decoded using a
|
||
* given layout.
|
||
*
|
||
* Calling this function couples `Class` with `layout` in several ways:
|
||
*
|
||
* * `Class.layout_` becomes a static member property equal to `layout`;
|
||
* * `layout.boundConstructor_` becomes a static member property equal
|
||
* to `Class`;
|
||
* * The {@link Layout#makeDestinationObject|makeDestinationObject()}
|
||
* property of `layout` is set to a function that returns a `new
|
||
* Class()`;
|
||
* * `Class.decode(b, offset)` becomes a static member function that
|
||
* delegates to {@link Layout#decode|layout.decode}. The
|
||
* synthesized function may be captured and extended.
|
||
* * `Class.prototype.encode(b, offset)` provides an instance member
|
||
* function that delegates to {@link Layout#encode|layout.encode}
|
||
* with `src` set to `this`. The synthesized function may be
|
||
* captured and extended, but when the extension is invoked `this`
|
||
* must be explicitly bound to the instance.
|
||
*
|
||
* @param {class} Class - a JavaScript class with a nullary
|
||
* constructor.
|
||
*
|
||
* @param {Layout} layout - the {@link Layout} instance used to encode
|
||
* instances of `Class`.
|
||
*/
|
||
// `Class` must be a constructor Function, but the assignment of a `layout_` property to it makes it difficult to type
|
||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||
function bindConstructorLayout(Class, layout) {
|
||
if ('function' !== typeof Class) {
|
||
throw new TypeError('Class must be constructor');
|
||
}
|
||
if (Object.prototype.hasOwnProperty.call(Class, 'layout_')) {
|
||
throw new Error('Class is already bound to a layout');
|
||
}
|
||
if (!(layout && (layout instanceof Layout))) {
|
||
throw new TypeError('layout must be a Layout');
|
||
}
|
||
if (Object.prototype.hasOwnProperty.call(layout, 'boundConstructor_')) {
|
||
throw new Error('layout is already bound to a constructor');
|
||
}
|
||
Class.layout_ = layout;
|
||
layout.boundConstructor_ = Class;
|
||
layout.makeDestinationObject = (() => new Class());
|
||
Object.defineProperty(Class.prototype, 'encode', {
|
||
value(b, offset) {
|
||
return layout.encode(this, b, offset);
|
||
},
|
||
writable: true,
|
||
});
|
||
Object.defineProperty(Class, 'decode', {
|
||
value(b, offset) {
|
||
return layout.decode(b, offset);
|
||
},
|
||
writable: true,
|
||
});
|
||
}
|
||
Layout$1.bindConstructorLayout = bindConstructorLayout;
|
||
/**
|
||
* An object that behaves like a layout but does not consume space
|
||
* within its containing layout.
|
||
*
|
||
* This is primarily used to obtain metadata about a member, such as a
|
||
* {@link OffsetLayout} that can provide data about a {@link
|
||
* Layout#getSpan|value-specific span}.
|
||
*
|
||
* **NOTE** This is an abstract base class; you can create instances
|
||
* if it amuses you, but they won't support {@link
|
||
* ExternalLayout#isCount|isCount} or other {@link Layout} functions.
|
||
*
|
||
* @param {Number} span - initializer for {@link Layout#span|span}.
|
||
* The parameter can range from 1 through 6.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @abstract
|
||
* @augments {Layout}
|
||
*/
|
||
class ExternalLayout extends Layout {
|
||
/**
|
||
* Return `true` iff the external layout decodes to an unsigned
|
||
* integer layout.
|
||
*
|
||
* In that case it can be used as the source of {@link
|
||
* Sequence#count|Sequence counts}, {@link Blob#length|Blob lengths},
|
||
* or as {@link UnionLayoutDiscriminator#layout|external union
|
||
* discriminators}.
|
||
*
|
||
* @abstract
|
||
*/
|
||
isCount() {
|
||
throw new Error('ExternalLayout is abstract');
|
||
}
|
||
}
|
||
Layout$1.ExternalLayout = ExternalLayout;
|
||
/**
|
||
* An {@link ExternalLayout} that determines its {@link
|
||
* Layout#decode|value} based on offset into and length of the buffer
|
||
* on which it is invoked.
|
||
*
|
||
* *Factory*: {@link module:Layout.greedy|greedy}
|
||
*
|
||
* @param {Number} [elementSpan] - initializer for {@link
|
||
* GreedyCount#elementSpan|elementSpan}.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {ExternalLayout}
|
||
*/
|
||
class GreedyCount extends ExternalLayout {
|
||
constructor(elementSpan = 1, property) {
|
||
if ((!Number.isInteger(elementSpan)) || (0 >= elementSpan)) {
|
||
throw new TypeError('elementSpan must be a (positive) integer');
|
||
}
|
||
super(-1, property);
|
||
/** The layout for individual elements of the sequence. The value
|
||
* must be a positive integer. If not provided, the value will be
|
||
* 1. */
|
||
this.elementSpan = elementSpan;
|
||
}
|
||
/** @override */
|
||
isCount() {
|
||
return true;
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
checkUint8Array(b);
|
||
const rem = b.length - offset;
|
||
return Math.floor(rem / this.elementSpan);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset) {
|
||
return 0;
|
||
}
|
||
}
|
||
Layout$1.GreedyCount = GreedyCount;
|
||
/**
|
||
* An {@link ExternalLayout} that supports accessing a {@link Layout}
|
||
* at a fixed offset from the start of another Layout. The offset may
|
||
* be before, within, or after the base layout.
|
||
*
|
||
* *Factory*: {@link module:Layout.offset|offset}
|
||
*
|
||
* @param {Layout} layout - initializer for {@link
|
||
* OffsetLayout#layout|layout}, modulo `property`.
|
||
*
|
||
* @param {Number} [offset] - Initializes {@link
|
||
* OffsetLayout#offset|offset}. Defaults to zero.
|
||
*
|
||
* @param {string} [property] - Optional new property name for a
|
||
* {@link Layout#replicate| replica} of `layout` to be used as {@link
|
||
* OffsetLayout#layout|layout}. If not provided the `layout` is used
|
||
* unchanged.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class OffsetLayout extends ExternalLayout {
|
||
constructor(layout, offset = 0, property) {
|
||
if (!(layout instanceof Layout)) {
|
||
throw new TypeError('layout must be a Layout');
|
||
}
|
||
if (!Number.isInteger(offset)) {
|
||
throw new TypeError('offset must be integer or undefined');
|
||
}
|
||
super(layout.span, property || layout.property);
|
||
/** The subordinated layout. */
|
||
this.layout = layout;
|
||
/** The location of {@link OffsetLayout#layout} relative to the
|
||
* start of another layout.
|
||
*
|
||
* The value may be positive or negative, but an error will thrown
|
||
* if at the point of use it goes outside the span of the Uint8Array
|
||
* being accessed. */
|
||
this.offset = offset;
|
||
}
|
||
/** @override */
|
||
isCount() {
|
||
return ((this.layout instanceof UInt)
|
||
|| (this.layout instanceof UIntBE));
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return this.layout.decode(b, offset + this.offset);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
return this.layout.encode(src, b, offset + this.offset);
|
||
}
|
||
}
|
||
Layout$1.OffsetLayout = OffsetLayout;
|
||
/**
|
||
* Represent an unsigned integer in little-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.u8|u8}, {@link
|
||
* module:Layout.u16|u16}, {@link module:Layout.u24|u24}, {@link
|
||
* module:Layout.u32|u32}, {@link module:Layout.u40|u40}, {@link
|
||
* module:Layout.u48|u48}
|
||
*
|
||
* @param {Number} span - initializer for {@link Layout#span|span}.
|
||
* The parameter can range from 1 through 6.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class UInt extends Layout {
|
||
constructor(span, property) {
|
||
super(span, property);
|
||
if (6 < this.span) {
|
||
throw new RangeError('span must not exceed 6 bytes');
|
||
}
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readUIntLE(offset, this.span);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeUIntLE(src, offset, this.span);
|
||
return this.span;
|
||
}
|
||
}
|
||
Layout$1.UInt = UInt;
|
||
/**
|
||
* Represent an unsigned integer in big-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.u8be|u8be}, {@link
|
||
* module:Layout.u16be|u16be}, {@link module:Layout.u24be|u24be},
|
||
* {@link module:Layout.u32be|u32be}, {@link
|
||
* module:Layout.u40be|u40be}, {@link module:Layout.u48be|u48be}
|
||
*
|
||
* @param {Number} span - initializer for {@link Layout#span|span}.
|
||
* The parameter can range from 1 through 6.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class UIntBE extends Layout {
|
||
constructor(span, property) {
|
||
super(span, property);
|
||
if (6 < this.span) {
|
||
throw new RangeError('span must not exceed 6 bytes');
|
||
}
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readUIntBE(offset, this.span);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeUIntBE(src, offset, this.span);
|
||
return this.span;
|
||
}
|
||
}
|
||
Layout$1.UIntBE = UIntBE;
|
||
/**
|
||
* Represent a signed integer in little-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.s8|s8}, {@link
|
||
* module:Layout.s16|s16}, {@link module:Layout.s24|s24}, {@link
|
||
* module:Layout.s32|s32}, {@link module:Layout.s40|s40}, {@link
|
||
* module:Layout.s48|s48}
|
||
*
|
||
* @param {Number} span - initializer for {@link Layout#span|span}.
|
||
* The parameter can range from 1 through 6.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Int extends Layout {
|
||
constructor(span, property) {
|
||
super(span, property);
|
||
if (6 < this.span) {
|
||
throw new RangeError('span must not exceed 6 bytes');
|
||
}
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readIntLE(offset, this.span);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeIntLE(src, offset, this.span);
|
||
return this.span;
|
||
}
|
||
}
|
||
Layout$1.Int = Int;
|
||
/**
|
||
* Represent a signed integer in big-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.s8be|s8be}, {@link
|
||
* module:Layout.s16be|s16be}, {@link module:Layout.s24be|s24be},
|
||
* {@link module:Layout.s32be|s32be}, {@link
|
||
* module:Layout.s40be|s40be}, {@link module:Layout.s48be|s48be}
|
||
*
|
||
* @param {Number} span - initializer for {@link Layout#span|span}.
|
||
* The parameter can range from 1 through 6.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class IntBE extends Layout {
|
||
constructor(span, property) {
|
||
super(span, property);
|
||
if (6 < this.span) {
|
||
throw new RangeError('span must not exceed 6 bytes');
|
||
}
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readIntBE(offset, this.span);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeIntBE(src, offset, this.span);
|
||
return this.span;
|
||
}
|
||
}
|
||
Layout$1.IntBE = IntBE;
|
||
const V2E32 = Math.pow(2, 32);
|
||
/* True modulus high and low 32-bit words, where low word is always
|
||
* non-negative. */
|
||
function divmodInt64(src) {
|
||
const hi32 = Math.floor(src / V2E32);
|
||
const lo32 = src - (hi32 * V2E32);
|
||
return { hi32, lo32 };
|
||
}
|
||
/* Reconstruct Number from quotient and non-negative remainder */
|
||
function roundedInt64(hi32, lo32) {
|
||
return hi32 * V2E32 + lo32;
|
||
}
|
||
/**
|
||
* Represent an unsigned 64-bit integer in little-endian format when
|
||
* encoded and as a near integral JavaScript Number when decoded.
|
||
*
|
||
* *Factory*: {@link module:Layout.nu64|nu64}
|
||
*
|
||
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
||
* the exact value of the encoded representation.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class NearUInt64 extends Layout {
|
||
constructor(property) {
|
||
super(8, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
const lo32 = buffer.readUInt32LE(offset);
|
||
const hi32 = buffer.readUInt32LE(offset + 4);
|
||
return roundedInt64(hi32, lo32);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
const split = divmodInt64(src);
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
buffer.writeUInt32LE(split.lo32, offset);
|
||
buffer.writeUInt32LE(split.hi32, offset + 4);
|
||
return 8;
|
||
}
|
||
}
|
||
Layout$1.NearUInt64 = NearUInt64;
|
||
/**
|
||
* Represent an unsigned 64-bit integer in big-endian format when
|
||
* encoded and as a near integral JavaScript Number when decoded.
|
||
*
|
||
* *Factory*: {@link module:Layout.nu64be|nu64be}
|
||
*
|
||
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
||
* the exact value of the encoded representation.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class NearUInt64BE extends Layout {
|
||
constructor(property) {
|
||
super(8, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
const hi32 = buffer.readUInt32BE(offset);
|
||
const lo32 = buffer.readUInt32BE(offset + 4);
|
||
return roundedInt64(hi32, lo32);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
const split = divmodInt64(src);
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
buffer.writeUInt32BE(split.hi32, offset);
|
||
buffer.writeUInt32BE(split.lo32, offset + 4);
|
||
return 8;
|
||
}
|
||
}
|
||
Layout$1.NearUInt64BE = NearUInt64BE;
|
||
/**
|
||
* Represent a signed 64-bit integer in little-endian format when
|
||
* encoded and as a near integral JavaScript Number when decoded.
|
||
*
|
||
* *Factory*: {@link module:Layout.ns64|ns64}
|
||
*
|
||
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
||
* the exact value of the encoded representation.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class NearInt64 extends Layout {
|
||
constructor(property) {
|
||
super(8, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
const lo32 = buffer.readUInt32LE(offset);
|
||
const hi32 = buffer.readInt32LE(offset + 4);
|
||
return roundedInt64(hi32, lo32);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
const split = divmodInt64(src);
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
buffer.writeUInt32LE(split.lo32, offset);
|
||
buffer.writeInt32LE(split.hi32, offset + 4);
|
||
return 8;
|
||
}
|
||
}
|
||
Layout$1.NearInt64 = NearInt64;
|
||
/**
|
||
* Represent a signed 64-bit integer in big-endian format when
|
||
* encoded and as a near integral JavaScript Number when decoded.
|
||
*
|
||
* *Factory*: {@link module:Layout.ns64be|ns64be}
|
||
*
|
||
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
||
* the exact value of the encoded representation.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class NearInt64BE extends Layout {
|
||
constructor(property) {
|
||
super(8, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
const hi32 = buffer.readInt32BE(offset);
|
||
const lo32 = buffer.readUInt32BE(offset + 4);
|
||
return roundedInt64(hi32, lo32);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
const split = divmodInt64(src);
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
buffer.writeInt32BE(split.hi32, offset);
|
||
buffer.writeUInt32BE(split.lo32, offset + 4);
|
||
return 8;
|
||
}
|
||
}
|
||
Layout$1.NearInt64BE = NearInt64BE;
|
||
/**
|
||
* Represent a 32-bit floating point number in little-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.f32|f32}
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Float extends Layout {
|
||
constructor(property) {
|
||
super(4, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readFloatLE(offset);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeFloatLE(src, offset);
|
||
return 4;
|
||
}
|
||
}
|
||
Layout$1.Float = Float;
|
||
/**
|
||
* Represent a 32-bit floating point number in big-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.f32be|f32be}
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class FloatBE extends Layout {
|
||
constructor(property) {
|
||
super(4, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readFloatBE(offset);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeFloatBE(src, offset);
|
||
return 4;
|
||
}
|
||
}
|
||
Layout$1.FloatBE = FloatBE;
|
||
/**
|
||
* Represent a 64-bit floating point number in little-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.f64|f64}
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Double extends Layout {
|
||
constructor(property) {
|
||
super(8, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readDoubleLE(offset);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeDoubleLE(src, offset);
|
||
return 8;
|
||
}
|
||
}
|
||
Layout$1.Double = Double;
|
||
/**
|
||
* Represent a 64-bit floating point number in big-endian format.
|
||
*
|
||
* *Factory*: {@link module:Layout.f64be|f64be}
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class DoubleBE extends Layout {
|
||
constructor(property) {
|
||
super(8, property);
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
return uint8ArrayToBuffer(b).readDoubleBE(offset);
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
uint8ArrayToBuffer(b).writeDoubleBE(src, offset);
|
||
return 8;
|
||
}
|
||
}
|
||
Layout$1.DoubleBE = DoubleBE;
|
||
/**
|
||
* Represent a contiguous sequence of a specific layout as an Array.
|
||
*
|
||
* *Factory*: {@link module:Layout.seq|seq}
|
||
*
|
||
* @param {Layout} elementLayout - initializer for {@link
|
||
* Sequence#elementLayout|elementLayout}.
|
||
*
|
||
* @param {(Number|ExternalLayout)} count - initializer for {@link
|
||
* Sequence#count|count}. The parameter must be either a positive
|
||
* integer or an instance of {@link ExternalLayout}.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Sequence extends Layout {
|
||
constructor(elementLayout, count, property) {
|
||
if (!(elementLayout instanceof Layout)) {
|
||
throw new TypeError('elementLayout must be a Layout');
|
||
}
|
||
if (!(((count instanceof ExternalLayout) && count.isCount())
|
||
|| (Number.isInteger(count) && (0 <= count)))) {
|
||
throw new TypeError('count must be non-negative integer '
|
||
+ 'or an unsigned integer ExternalLayout');
|
||
}
|
||
let span = -1;
|
||
if ((!(count instanceof ExternalLayout))
|
||
&& (0 < elementLayout.span)) {
|
||
span = count * elementLayout.span;
|
||
}
|
||
super(span, property);
|
||
/** The layout for individual elements of the sequence. */
|
||
this.elementLayout = elementLayout;
|
||
/** The number of elements in the sequence.
|
||
*
|
||
* This will be either a non-negative integer or an instance of
|
||
* {@link ExternalLayout} for which {@link
|
||
* ExternalLayout#isCount|isCount()} is `true`. */
|
||
this.count = count;
|
||
}
|
||
/** @override */
|
||
getSpan(b, offset = 0) {
|
||
if (0 <= this.span) {
|
||
return this.span;
|
||
}
|
||
let span = 0;
|
||
let count = this.count;
|
||
if (count instanceof ExternalLayout) {
|
||
count = count.decode(b, offset);
|
||
}
|
||
if (0 < this.elementLayout.span) {
|
||
span = count * this.elementLayout.span;
|
||
}
|
||
else {
|
||
let idx = 0;
|
||
while (idx < count) {
|
||
span += this.elementLayout.getSpan(b, offset + span);
|
||
++idx;
|
||
}
|
||
}
|
||
return span;
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const rv = [];
|
||
let i = 0;
|
||
let count = this.count;
|
||
if (count instanceof ExternalLayout) {
|
||
count = count.decode(b, offset);
|
||
}
|
||
while (i < count) {
|
||
rv.push(this.elementLayout.decode(b, offset));
|
||
offset += this.elementLayout.getSpan(b, offset);
|
||
i += 1;
|
||
}
|
||
return rv;
|
||
}
|
||
/** Implement {@link Layout#encode|encode} for {@link Sequence}.
|
||
*
|
||
* **NOTE** If `src` is shorter than {@link Sequence#count|count} then
|
||
* the unused space in the buffer is left unchanged. If `src` is
|
||
* longer than {@link Sequence#count|count} the unneeded elements are
|
||
* ignored.
|
||
*
|
||
* **NOTE** If {@link Layout#count|count} is an instance of {@link
|
||
* ExternalLayout} then the length of `src` will be encoded as the
|
||
* count after `src` is encoded. */
|
||
encode(src, b, offset = 0) {
|
||
const elo = this.elementLayout;
|
||
const span = src.reduce((span, v) => {
|
||
return span + elo.encode(v, b, offset + span);
|
||
}, 0);
|
||
if (this.count instanceof ExternalLayout) {
|
||
this.count.encode(src.length, b, offset);
|
||
}
|
||
return span;
|
||
}
|
||
}
|
||
Layout$1.Sequence = Sequence;
|
||
/**
|
||
* Represent a contiguous sequence of arbitrary layout elements as an
|
||
* Object.
|
||
*
|
||
* *Factory*: {@link module:Layout.struct|struct}
|
||
*
|
||
* **NOTE** The {@link Layout#span|span} of the structure is variable
|
||
* if any layout in {@link Structure#fields|fields} has a variable
|
||
* span. When {@link Layout#encode|encoding} we must have a value for
|
||
* all variable-length fields, or we wouldn't be able to figure out
|
||
* how much space to use for storage. We can only identify the value
|
||
* for a field when it has a {@link Layout#property|property}. As
|
||
* such, although a structure may contain both unnamed fields and
|
||
* variable-length fields, it cannot contain an unnamed
|
||
* variable-length field.
|
||
*
|
||
* @param {Layout[]} fields - initializer for {@link
|
||
* Structure#fields|fields}. An error is raised if this contains a
|
||
* variable-length field for which a {@link Layout#property|property}
|
||
* is not defined.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @param {Boolean} [decodePrefixes] - initializer for {@link
|
||
* Structure#decodePrefixes|property}.
|
||
*
|
||
* @throws {Error} - if `fields` contains an unnamed variable-length
|
||
* layout.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Structure extends Layout {
|
||
constructor(fields, property, decodePrefixes) {
|
||
if (!(Array.isArray(fields)
|
||
&& fields.reduce((acc, v) => acc && (v instanceof Layout), true))) {
|
||
throw new TypeError('fields must be array of Layout instances');
|
||
}
|
||
if (('boolean' === typeof property)
|
||
&& (undefined === decodePrefixes)) {
|
||
decodePrefixes = property;
|
||
property = undefined;
|
||
}
|
||
/* Verify absence of unnamed variable-length fields. */
|
||
for (const fd of fields) {
|
||
if ((0 > fd.span)
|
||
&& (undefined === fd.property)) {
|
||
throw new Error('fields cannot contain unnamed variable-length layout');
|
||
}
|
||
}
|
||
let span = -1;
|
||
try {
|
||
span = fields.reduce((span, fd) => span + fd.getSpan(), 0);
|
||
}
|
||
catch (e) {
|
||
// ignore error
|
||
}
|
||
super(span, property);
|
||
/** The sequence of {@link Layout} values that comprise the
|
||
* structure.
|
||
*
|
||
* The individual elements need not be the same type, and may be
|
||
* either scalar or aggregate layouts. If a member layout leaves
|
||
* its {@link Layout#property|property} undefined the
|
||
* corresponding region of the buffer associated with the element
|
||
* will not be mutated.
|
||
*
|
||
* @type {Layout[]} */
|
||
this.fields = fields;
|
||
/** Control behavior of {@link Layout#decode|decode()} given short
|
||
* buffers.
|
||
*
|
||
* In some situations a structure many be extended with additional
|
||
* fields over time, with older installations providing only a
|
||
* prefix of the full structure. If this property is `true`
|
||
* decoding will accept those buffers and leave subsequent fields
|
||
* undefined, as long as the buffer ends at a field boundary.
|
||
* Defaults to `false`. */
|
||
this.decodePrefixes = !!decodePrefixes;
|
||
}
|
||
/** @override */
|
||
getSpan(b, offset = 0) {
|
||
if (0 <= this.span) {
|
||
return this.span;
|
||
}
|
||
let span = 0;
|
||
try {
|
||
span = this.fields.reduce((span, fd) => {
|
||
const fsp = fd.getSpan(b, offset);
|
||
offset += fsp;
|
||
return span + fsp;
|
||
}, 0);
|
||
}
|
||
catch (e) {
|
||
throw new RangeError('indeterminate span');
|
||
}
|
||
return span;
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
checkUint8Array(b);
|
||
const dest = this.makeDestinationObject();
|
||
for (const fd of this.fields) {
|
||
if (undefined !== fd.property) {
|
||
dest[fd.property] = fd.decode(b, offset);
|
||
}
|
||
offset += fd.getSpan(b, offset);
|
||
if (this.decodePrefixes
|
||
&& (b.length === offset)) {
|
||
break;
|
||
}
|
||
}
|
||
return dest;
|
||
}
|
||
/** Implement {@link Layout#encode|encode} for {@link Structure}.
|
||
*
|
||
* If `src` is missing a property for a member with a defined {@link
|
||
* Layout#property|property} the corresponding region of the buffer is
|
||
* left unmodified. */
|
||
encode(src, b, offset = 0) {
|
||
const firstOffset = offset;
|
||
let lastOffset = 0;
|
||
let lastWrote = 0;
|
||
for (const fd of this.fields) {
|
||
let span = fd.span;
|
||
lastWrote = (0 < span) ? span : 0;
|
||
if (undefined !== fd.property) {
|
||
const fv = src[fd.property];
|
||
if (undefined !== fv) {
|
||
lastWrote = fd.encode(fv, b, offset);
|
||
if (0 > span) {
|
||
/* Read the as-encoded span, which is not necessarily the
|
||
* same as what we wrote. */
|
||
span = fd.getSpan(b, offset);
|
||
}
|
||
}
|
||
}
|
||
lastOffset = offset;
|
||
offset += span;
|
||
}
|
||
/* Use (lastOffset + lastWrote) instead of offset because the last
|
||
* item may have had a dynamic length and we don't want to include
|
||
* the padding between it and the end of the space reserved for
|
||
* it. */
|
||
return (lastOffset + lastWrote) - firstOffset;
|
||
}
|
||
/** @override */
|
||
fromArray(values) {
|
||
const dest = this.makeDestinationObject();
|
||
for (const fd of this.fields) {
|
||
if ((undefined !== fd.property)
|
||
&& (0 < values.length)) {
|
||
dest[fd.property] = values.shift();
|
||
}
|
||
}
|
||
return dest;
|
||
}
|
||
/**
|
||
* Get access to the layout of a given property.
|
||
*
|
||
* @param {String} property - the structure member of interest.
|
||
*
|
||
* @return {Layout} - the layout associated with `property`, or
|
||
* undefined if there is no such property.
|
||
*/
|
||
layoutFor(property) {
|
||
if ('string' !== typeof property) {
|
||
throw new TypeError('property must be string');
|
||
}
|
||
for (const fd of this.fields) {
|
||
if (fd.property === property) {
|
||
return fd;
|
||
}
|
||
}
|
||
return undefined;
|
||
}
|
||
/**
|
||
* Get the offset of a structure member.
|
||
*
|
||
* @param {String} property - the structure member of interest.
|
||
*
|
||
* @return {Number} - the offset in bytes to the start of `property`
|
||
* within the structure, or undefined if `property` is not a field
|
||
* within the structure. If the property is a member but follows a
|
||
* variable-length structure member a negative number will be
|
||
* returned.
|
||
*/
|
||
offsetOf(property) {
|
||
if ('string' !== typeof property) {
|
||
throw new TypeError('property must be string');
|
||
}
|
||
let offset = 0;
|
||
for (const fd of this.fields) {
|
||
if (fd.property === property) {
|
||
return offset;
|
||
}
|
||
if (0 > fd.span) {
|
||
offset = -1;
|
||
}
|
||
else if (0 <= offset) {
|
||
offset += fd.span;
|
||
}
|
||
}
|
||
return undefined;
|
||
}
|
||
}
|
||
Layout$1.Structure = Structure;
|
||
/**
|
||
* An object that can provide a {@link
|
||
* Union#discriminator|discriminator} API for {@link Union}.
|
||
*
|
||
* **NOTE** This is an abstract base class; you can create instances
|
||
* if it amuses you, but they won't support the {@link
|
||
* UnionDiscriminator#encode|encode} or {@link
|
||
* UnionDiscriminator#decode|decode} functions.
|
||
*
|
||
* @param {string} [property] - Default for {@link
|
||
* UnionDiscriminator#property|property}.
|
||
*
|
||
* @abstract
|
||
*/
|
||
class UnionDiscriminator {
|
||
constructor(property) {
|
||
/** The {@link Layout#property|property} to be used when the
|
||
* discriminator is referenced in isolation (generally when {@link
|
||
* Union#decode|Union decode} cannot delegate to a specific
|
||
* variant). */
|
||
this.property = property;
|
||
}
|
||
/** Analog to {@link Layout#decode|Layout decode} for union discriminators.
|
||
*
|
||
* The implementation of this method need not reference the buffer if
|
||
* variant information is available through other means. */
|
||
decode(b, offset) {
|
||
throw new Error('UnionDiscriminator is abstract');
|
||
}
|
||
/** Analog to {@link Layout#decode|Layout encode} for union discriminators.
|
||
*
|
||
* The implementation of this method need not store the value if
|
||
* variant information is maintained through other means. */
|
||
encode(src, b, offset) {
|
||
throw new Error('UnionDiscriminator is abstract');
|
||
}
|
||
}
|
||
Layout$1.UnionDiscriminator = UnionDiscriminator;
|
||
/**
|
||
* An object that can provide a {@link
|
||
* UnionDiscriminator|discriminator API} for {@link Union} using an
|
||
* unsigned integral {@link Layout} instance located either inside or
|
||
* outside the union.
|
||
*
|
||
* @param {ExternalLayout} layout - initializes {@link
|
||
* UnionLayoutDiscriminator#layout|layout}. Must satisfy {@link
|
||
* ExternalLayout#isCount|isCount()}.
|
||
*
|
||
* @param {string} [property] - Default for {@link
|
||
* UnionDiscriminator#property|property}, superseding the property
|
||
* from `layout`, but defaulting to `variant` if neither `property`
|
||
* nor layout provide a property name.
|
||
*
|
||
* @augments {UnionDiscriminator}
|
||
*/
|
||
class UnionLayoutDiscriminator extends UnionDiscriminator {
|
||
constructor(layout, property) {
|
||
if (!((layout instanceof ExternalLayout)
|
||
&& layout.isCount())) {
|
||
throw new TypeError('layout must be an unsigned integer ExternalLayout');
|
||
}
|
||
super(property || layout.property || 'variant');
|
||
/** The {@link ExternalLayout} used to access the discriminator
|
||
* value. */
|
||
this.layout = layout;
|
||
}
|
||
/** Delegate decoding to {@link UnionLayoutDiscriminator#layout|layout}. */
|
||
decode(b, offset) {
|
||
return this.layout.decode(b, offset);
|
||
}
|
||
/** Delegate encoding to {@link UnionLayoutDiscriminator#layout|layout}. */
|
||
encode(src, b, offset) {
|
||
return this.layout.encode(src, b, offset);
|
||
}
|
||
}
|
||
Layout$1.UnionLayoutDiscriminator = UnionLayoutDiscriminator;
|
||
/**
|
||
* Represent any number of span-compatible layouts.
|
||
*
|
||
* *Factory*: {@link module:Layout.union|union}
|
||
*
|
||
* If the union has a {@link Union#defaultLayout|default layout} that
|
||
* layout must have a non-negative {@link Layout#span|span}. The span
|
||
* of a fixed-span union includes its {@link
|
||
* Union#discriminator|discriminator} if the variant is a {@link
|
||
* Union#usesPrefixDiscriminator|prefix of the union}, plus the span
|
||
* of its {@link Union#defaultLayout|default layout}.
|
||
*
|
||
* If the union does not have a default layout then the encoded span
|
||
* of the union depends on the encoded span of its variant (which may
|
||
* be fixed or variable).
|
||
*
|
||
* {@link VariantLayout#layout|Variant layout}s are added through
|
||
* {@link Union#addVariant|addVariant}. If the union has a default
|
||
* layout, the span of the {@link VariantLayout#layout|layout
|
||
* contained by the variant} must not exceed the span of the {@link
|
||
* Union#defaultLayout|default layout} (minus the span of a {@link
|
||
* Union#usesPrefixDiscriminator|prefix disriminator}, if used). The
|
||
* span of the variant will equal the span of the union itself.
|
||
*
|
||
* The variant for a buffer can only be identified from the {@link
|
||
* Union#discriminator|discriminator} {@link
|
||
* UnionDiscriminator#property|property} (in the case of the {@link
|
||
* Union#defaultLayout|default layout}), or by using {@link
|
||
* Union#getVariant|getVariant} and examining the resulting {@link
|
||
* VariantLayout} instance.
|
||
*
|
||
* A variant compatible with a JavaScript object can be identified
|
||
* using {@link Union#getSourceVariant|getSourceVariant}.
|
||
*
|
||
* @param {(UnionDiscriminator|ExternalLayout|Layout)} discr - How to
|
||
* identify the layout used to interpret the union contents. The
|
||
* parameter must be an instance of {@link UnionDiscriminator}, an
|
||
* {@link ExternalLayout} that satisfies {@link
|
||
* ExternalLayout#isCount|isCount()}, or {@link UInt} (or {@link
|
||
* UIntBE}). When a non-external layout element is passed the layout
|
||
* appears at the start of the union. In all cases the (synthesized)
|
||
* {@link UnionDiscriminator} instance is recorded as {@link
|
||
* Union#discriminator|discriminator}.
|
||
*
|
||
* @param {(Layout|null)} defaultLayout - initializer for {@link
|
||
* Union#defaultLayout|defaultLayout}. If absent defaults to `null`.
|
||
* If `null` there is no default layout: the union has data-dependent
|
||
* length and attempts to decode or encode unrecognized variants will
|
||
* throw an exception. A {@link Layout} instance must have a
|
||
* non-negative {@link Layout#span|span}, and if it lacks a {@link
|
||
* Layout#property|property} the {@link
|
||
* Union#defaultLayout|defaultLayout} will be a {@link
|
||
* Layout#replicate|replica} with property `content`.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Union extends Layout {
|
||
constructor(discr, defaultLayout, property) {
|
||
let discriminator;
|
||
if ((discr instanceof UInt)
|
||
|| (discr instanceof UIntBE)) {
|
||
discriminator = new UnionLayoutDiscriminator(new OffsetLayout(discr));
|
||
}
|
||
else if ((discr instanceof ExternalLayout)
|
||
&& discr.isCount()) {
|
||
discriminator = new UnionLayoutDiscriminator(discr);
|
||
}
|
||
else if (!(discr instanceof UnionDiscriminator)) {
|
||
throw new TypeError('discr must be a UnionDiscriminator '
|
||
+ 'or an unsigned integer layout');
|
||
}
|
||
else {
|
||
discriminator = discr;
|
||
}
|
||
if (undefined === defaultLayout) {
|
||
defaultLayout = null;
|
||
}
|
||
if (!((null === defaultLayout)
|
||
|| (defaultLayout instanceof Layout))) {
|
||
throw new TypeError('defaultLayout must be null or a Layout');
|
||
}
|
||
if (null !== defaultLayout) {
|
||
if (0 > defaultLayout.span) {
|
||
throw new Error('defaultLayout must have constant span');
|
||
}
|
||
if (undefined === defaultLayout.property) {
|
||
defaultLayout = defaultLayout.replicate('content');
|
||
}
|
||
}
|
||
/* The union span can be estimated only if there's a default
|
||
* layout. The union spans its default layout, plus any prefix
|
||
* variant layout. By construction both layouts, if present, have
|
||
* non-negative span. */
|
||
let span = -1;
|
||
if (defaultLayout) {
|
||
span = defaultLayout.span;
|
||
if ((0 <= span) && ((discr instanceof UInt)
|
||
|| (discr instanceof UIntBE))) {
|
||
span += discriminator.layout.span;
|
||
}
|
||
}
|
||
super(span, property);
|
||
/** The interface for the discriminator value in isolation.
|
||
*
|
||
* This a {@link UnionDiscriminator} either passed to the
|
||
* constructor or synthesized from the `discr` constructor
|
||
* argument. {@link
|
||
* Union#usesPrefixDiscriminator|usesPrefixDiscriminator} will be
|
||
* `true` iff the `discr` parameter was a non-offset {@link
|
||
* Layout} instance. */
|
||
this.discriminator = discriminator;
|
||
/** `true` if the {@link Union#discriminator|discriminator} is the
|
||
* first field in the union.
|
||
*
|
||
* If `false` the discriminator is obtained from somewhere
|
||
* else. */
|
||
this.usesPrefixDiscriminator = (discr instanceof UInt)
|
||
|| (discr instanceof UIntBE);
|
||
/** The layout for non-discriminator content when the value of the
|
||
* discriminator is not recognized.
|
||
*
|
||
* This is the value passed to the constructor. It is
|
||
* structurally equivalent to the second component of {@link
|
||
* Union#layout|layout} but may have a different property
|
||
* name. */
|
||
this.defaultLayout = defaultLayout;
|
||
/** A registry of allowed variants.
|
||
*
|
||
* The keys are unsigned integers which should be compatible with
|
||
* {@link Union.discriminator|discriminator}. The property value
|
||
* is the corresponding {@link VariantLayout} instances assigned
|
||
* to this union by {@link Union#addVariant|addVariant}.
|
||
*
|
||
* **NOTE** The registry remains mutable so that variants can be
|
||
* {@link Union#addVariant|added} at any time. Users should not
|
||
* manipulate the content of this property. */
|
||
this.registry = {};
|
||
/* Private variable used when invoking getSourceVariant */
|
||
let boundGetSourceVariant = this.defaultGetSourceVariant.bind(this);
|
||
/** Function to infer the variant selected by a source object.
|
||
*
|
||
* Defaults to {@link
|
||
* Union#defaultGetSourceVariant|defaultGetSourceVariant} but may
|
||
* be overridden using {@link
|
||
* Union#configGetSourceVariant|configGetSourceVariant}.
|
||
*
|
||
* @param {Object} src - as with {@link
|
||
* Union#defaultGetSourceVariant|defaultGetSourceVariant}.
|
||
*
|
||
* @returns {(undefined|VariantLayout)} The default variant
|
||
* (`undefined`) or first registered variant that uses a property
|
||
* available in `src`. */
|
||
this.getSourceVariant = function (src) {
|
||
return boundGetSourceVariant(src);
|
||
};
|
||
/** Function to override the implementation of {@link
|
||
* Union#getSourceVariant|getSourceVariant}.
|
||
*
|
||
* Use this if the desired variant cannot be identified using the
|
||
* algorithm of {@link
|
||
* Union#defaultGetSourceVariant|defaultGetSourceVariant}.
|
||
*
|
||
* **NOTE** The provided function will be invoked bound to this
|
||
* Union instance, providing local access to {@link
|
||
* Union#registry|registry}.
|
||
*
|
||
* @param {Function} gsv - a function that follows the API of
|
||
* {@link Union#defaultGetSourceVariant|defaultGetSourceVariant}. */
|
||
this.configGetSourceVariant = function (gsv) {
|
||
boundGetSourceVariant = gsv.bind(this);
|
||
};
|
||
}
|
||
/** @override */
|
||
getSpan(b, offset = 0) {
|
||
if (0 <= this.span) {
|
||
return this.span;
|
||
}
|
||
/* Default layouts always have non-negative span, so we don't have
|
||
* one and we have to recognize the variant which will in turn
|
||
* determine the span. */
|
||
const vlo = this.getVariant(b, offset);
|
||
if (!vlo) {
|
||
throw new Error('unable to determine span for unrecognized variant');
|
||
}
|
||
return vlo.getSpan(b, offset);
|
||
}
|
||
/**
|
||
* Method to infer a registered Union variant compatible with `src`.
|
||
*
|
||
* The first satisfied rule in the following sequence defines the
|
||
* return value:
|
||
* * If `src` has properties matching the Union discriminator and
|
||
* the default layout, `undefined` is returned regardless of the
|
||
* value of the discriminator property (this ensures the default
|
||
* layout will be used);
|
||
* * If `src` has a property matching the Union discriminator, the
|
||
* value of the discriminator identifies a registered variant, and
|
||
* either (a) the variant has no layout, or (b) `src` has the
|
||
* variant's property, then the variant is returned (because the
|
||
* source satisfies the constraints of the variant it identifies);
|
||
* * If `src` does not have a property matching the Union
|
||
* discriminator, but does have a property matching a registered
|
||
* variant, then the variant is returned (because the source
|
||
* matches a variant without an explicit conflict);
|
||
* * An error is thrown (because we either can't identify a variant,
|
||
* or we were explicitly told the variant but can't satisfy it).
|
||
*
|
||
* @param {Object} src - an object presumed to be compatible with
|
||
* the content of the Union.
|
||
*
|
||
* @return {(undefined|VariantLayout)} - as described above.
|
||
*
|
||
* @throws {Error} - if `src` cannot be associated with a default or
|
||
* registered variant.
|
||
*/
|
||
defaultGetSourceVariant(src) {
|
||
if (Object.prototype.hasOwnProperty.call(src, this.discriminator.property)) {
|
||
if (this.defaultLayout && this.defaultLayout.property
|
||
&& Object.prototype.hasOwnProperty.call(src, this.defaultLayout.property)) {
|
||
return undefined;
|
||
}
|
||
const vlo = this.registry[src[this.discriminator.property]];
|
||
if (vlo
|
||
&& ((!vlo.layout)
|
||
|| (vlo.property && Object.prototype.hasOwnProperty.call(src, vlo.property)))) {
|
||
return vlo;
|
||
}
|
||
}
|
||
else {
|
||
for (const tag in this.registry) {
|
||
const vlo = this.registry[tag];
|
||
if (vlo.property && Object.prototype.hasOwnProperty.call(src, vlo.property)) {
|
||
return vlo;
|
||
}
|
||
}
|
||
}
|
||
throw new Error('unable to infer src variant');
|
||
}
|
||
/** Implement {@link Layout#decode|decode} for {@link Union}.
|
||
*
|
||
* If the variant is {@link Union#addVariant|registered} the return
|
||
* value is an instance of that variant, with no explicit
|
||
* discriminator. Otherwise the {@link Union#defaultLayout|default
|
||
* layout} is used to decode the content. */
|
||
decode(b, offset = 0) {
|
||
let dest;
|
||
const dlo = this.discriminator;
|
||
const discr = dlo.decode(b, offset);
|
||
const clo = this.registry[discr];
|
||
if (undefined === clo) {
|
||
const defaultLayout = this.defaultLayout;
|
||
let contentOffset = 0;
|
||
if (this.usesPrefixDiscriminator) {
|
||
contentOffset = dlo.layout.span;
|
||
}
|
||
dest = this.makeDestinationObject();
|
||
dest[dlo.property] = discr;
|
||
// defaultLayout.property can be undefined, but this is allowed by buffer-layout
|
||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||
dest[defaultLayout.property] = defaultLayout.decode(b, offset + contentOffset);
|
||
}
|
||
else {
|
||
dest = clo.decode(b, offset);
|
||
}
|
||
return dest;
|
||
}
|
||
/** Implement {@link Layout#encode|encode} for {@link Union}.
|
||
*
|
||
* This API assumes the `src` object is consistent with the union's
|
||
* {@link Union#defaultLayout|default layout}. To encode variants
|
||
* use the appropriate variant-specific {@link VariantLayout#encode}
|
||
* method. */
|
||
encode(src, b, offset = 0) {
|
||
const vlo = this.getSourceVariant(src);
|
||
if (undefined === vlo) {
|
||
const dlo = this.discriminator;
|
||
// this.defaultLayout is not undefined when vlo is undefined
|
||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||
const clo = this.defaultLayout;
|
||
let contentOffset = 0;
|
||
if (this.usesPrefixDiscriminator) {
|
||
contentOffset = dlo.layout.span;
|
||
}
|
||
dlo.encode(src[dlo.property], b, offset);
|
||
// clo.property is not undefined when vlo is undefined
|
||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||
return contentOffset + clo.encode(src[clo.property], b, offset + contentOffset);
|
||
}
|
||
return vlo.encode(src, b, offset);
|
||
}
|
||
/** Register a new variant structure within a union. The newly
|
||
* created variant is returned.
|
||
*
|
||
* @param {Number} variant - initializer for {@link
|
||
* VariantLayout#variant|variant}.
|
||
*
|
||
* @param {Layout} layout - initializer for {@link
|
||
* VariantLayout#layout|layout}.
|
||
*
|
||
* @param {String} property - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @return {VariantLayout} */
|
||
addVariant(variant, layout, property) {
|
||
const rv = new VariantLayout(this, variant, layout, property);
|
||
this.registry[variant] = rv;
|
||
return rv;
|
||
}
|
||
/**
|
||
* Get the layout associated with a registered variant.
|
||
*
|
||
* If `vb` does not produce a registered variant the function returns
|
||
* `undefined`.
|
||
*
|
||
* @param {(Number|Uint8Array)} vb - either the variant number, or a
|
||
* buffer from which the discriminator is to be read.
|
||
*
|
||
* @param {Number} offset - offset into `vb` for the start of the
|
||
* union. Used only when `vb` is an instance of {Uint8Array}.
|
||
*
|
||
* @return {({VariantLayout}|undefined)}
|
||
*/
|
||
getVariant(vb, offset = 0) {
|
||
let variant;
|
||
if (vb instanceof Uint8Array) {
|
||
variant = this.discriminator.decode(vb, offset);
|
||
}
|
||
else {
|
||
variant = vb;
|
||
}
|
||
return this.registry[variant];
|
||
}
|
||
}
|
||
Layout$1.Union = Union;
|
||
/**
|
||
* Represent a specific variant within a containing union.
|
||
*
|
||
* **NOTE** The {@link Layout#span|span} of the variant may include
|
||
* the span of the {@link Union#discriminator|discriminator} used to
|
||
* identify it, but values read and written using the variant strictly
|
||
* conform to the content of {@link VariantLayout#layout|layout}.
|
||
*
|
||
* **NOTE** User code should not invoke this constructor directly. Use
|
||
* the union {@link Union#addVariant|addVariant} helper method.
|
||
*
|
||
* @param {Union} union - initializer for {@link
|
||
* VariantLayout#union|union}.
|
||
*
|
||
* @param {Number} variant - initializer for {@link
|
||
* VariantLayout#variant|variant}.
|
||
*
|
||
* @param {Layout} [layout] - initializer for {@link
|
||
* VariantLayout#layout|layout}. If absent the variant carries no
|
||
* data.
|
||
*
|
||
* @param {String} [property] - initializer for {@link
|
||
* Layout#property|property}. Unlike many other layouts, variant
|
||
* layouts normally include a property name so they can be identified
|
||
* within their containing {@link Union}. The property identifier may
|
||
* be absent only if `layout` is is absent.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class VariantLayout extends Layout {
|
||
constructor(union, variant, layout, property) {
|
||
if (!(union instanceof Union)) {
|
||
throw new TypeError('union must be a Union');
|
||
}
|
||
if ((!Number.isInteger(variant)) || (0 > variant)) {
|
||
throw new TypeError('variant must be a (non-negative) integer');
|
||
}
|
||
if (('string' === typeof layout)
|
||
&& (undefined === property)) {
|
||
property = layout;
|
||
layout = null;
|
||
}
|
||
if (layout) {
|
||
if (!(layout instanceof Layout)) {
|
||
throw new TypeError('layout must be a Layout');
|
||
}
|
||
if ((null !== union.defaultLayout)
|
||
&& (0 <= layout.span)
|
||
&& (layout.span > union.defaultLayout.span)) {
|
||
throw new Error('variant span exceeds span of containing union');
|
||
}
|
||
if ('string' !== typeof property) {
|
||
throw new TypeError('variant must have a String property');
|
||
}
|
||
}
|
||
let span = union.span;
|
||
if (0 > union.span) {
|
||
span = layout ? layout.span : 0;
|
||
if ((0 <= span) && union.usesPrefixDiscriminator) {
|
||
span += union.discriminator.layout.span;
|
||
}
|
||
}
|
||
super(span, property);
|
||
/** The {@link Union} to which this variant belongs. */
|
||
this.union = union;
|
||
/** The unsigned integral value identifying this variant within
|
||
* the {@link Union#discriminator|discriminator} of the containing
|
||
* union. */
|
||
this.variant = variant;
|
||
/** The {@link Layout} to be used when reading/writing the
|
||
* non-discriminator part of the {@link
|
||
* VariantLayout#union|union}. If `null` the variant carries no
|
||
* data. */
|
||
this.layout = layout || null;
|
||
}
|
||
/** @override */
|
||
getSpan(b, offset = 0) {
|
||
if (0 <= this.span) {
|
||
/* Will be equal to the containing union span if that is not
|
||
* variable. */
|
||
return this.span;
|
||
}
|
||
let contentOffset = 0;
|
||
if (this.union.usesPrefixDiscriminator) {
|
||
contentOffset = this.union.discriminator.layout.span;
|
||
}
|
||
/* Span is defined solely by the variant (and prefix discriminator) */
|
||
let span = 0;
|
||
if (this.layout) {
|
||
span = this.layout.getSpan(b, offset + contentOffset);
|
||
}
|
||
return contentOffset + span;
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const dest = this.makeDestinationObject();
|
||
if (this !== this.union.getVariant(b, offset)) {
|
||
throw new Error('variant mismatch');
|
||
}
|
||
let contentOffset = 0;
|
||
if (this.union.usesPrefixDiscriminator) {
|
||
contentOffset = this.union.discriminator.layout.span;
|
||
}
|
||
if (this.layout) {
|
||
dest[this.property] = this.layout.decode(b, offset + contentOffset);
|
||
}
|
||
else if (this.property) {
|
||
dest[this.property] = true;
|
||
}
|
||
else if (this.union.usesPrefixDiscriminator) {
|
||
dest[this.union.discriminator.property] = this.variant;
|
||
}
|
||
return dest;
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
let contentOffset = 0;
|
||
if (this.union.usesPrefixDiscriminator) {
|
||
contentOffset = this.union.discriminator.layout.span;
|
||
}
|
||
if (this.layout
|
||
&& (!Object.prototype.hasOwnProperty.call(src, this.property))) {
|
||
throw new TypeError('variant lacks property ' + this.property);
|
||
}
|
||
this.union.discriminator.encode(this.variant, b, offset);
|
||
let span = contentOffset;
|
||
if (this.layout) {
|
||
this.layout.encode(src[this.property], b, offset + contentOffset);
|
||
span += this.layout.getSpan(b, offset + contentOffset);
|
||
if ((0 <= this.union.span)
|
||
&& (span > this.union.span)) {
|
||
throw new Error('encoded variant overruns containing union');
|
||
}
|
||
}
|
||
return span;
|
||
}
|
||
/** Delegate {@link Layout#fromArray|fromArray} to {@link
|
||
* VariantLayout#layout|layout}. */
|
||
fromArray(values) {
|
||
if (this.layout) {
|
||
return this.layout.fromArray(values);
|
||
}
|
||
return undefined;
|
||
}
|
||
}
|
||
Layout$1.VariantLayout = VariantLayout;
|
||
/** JavaScript chose to define bitwise operations as operating on
|
||
* signed 32-bit values in 2's complement form, meaning any integer
|
||
* with bit 31 set is going to look negative. For right shifts that's
|
||
* not a problem, because `>>>` is a logical shift, but for every
|
||
* other bitwise operator we have to compensate for possible negative
|
||
* results. */
|
||
function fixBitwiseResult(v) {
|
||
if (0 > v) {
|
||
v += 0x100000000;
|
||
}
|
||
return v;
|
||
}
|
||
/**
|
||
* Contain a sequence of bit fields as an unsigned integer.
|
||
*
|
||
* *Factory*: {@link module:Layout.bits|bits}
|
||
*
|
||
* This is a container element; within it there are {@link BitField}
|
||
* instances that provide the extracted properties. The container
|
||
* simply defines the aggregate representation and its bit ordering.
|
||
* The representation is an object containing properties with numeric
|
||
* or {@link Boolean} values.
|
||
*
|
||
* {@link BitField}s are added with the {@link
|
||
* BitStructure#addField|addField} and {@link
|
||
* BitStructure#addBoolean|addBoolean} methods.
|
||
|
||
* @param {Layout} word - initializer for {@link
|
||
* BitStructure#word|word}. The parameter must be an instance of
|
||
* {@link UInt} (or {@link UIntBE}) that is no more than 4 bytes wide.
|
||
*
|
||
* @param {bool} [msb] - `true` if the bit numbering starts at the
|
||
* most significant bit of the containing word; `false` (default) if
|
||
* it starts at the least significant bit of the containing word. If
|
||
* the parameter at this position is a string and `property` is
|
||
* `undefined` the value of this argument will instead be used as the
|
||
* value of `property`.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class BitStructure extends Layout {
|
||
constructor(word, msb, property) {
|
||
if (!((word instanceof UInt)
|
||
|| (word instanceof UIntBE))) {
|
||
throw new TypeError('word must be a UInt or UIntBE layout');
|
||
}
|
||
if (('string' === typeof msb)
|
||
&& (undefined === property)) {
|
||
property = msb;
|
||
msb = false;
|
||
}
|
||
if (4 < word.span) {
|
||
throw new RangeError('word cannot exceed 32 bits');
|
||
}
|
||
super(word.span, property);
|
||
/** The layout used for the packed value. {@link BitField}
|
||
* instances are packed sequentially depending on {@link
|
||
* BitStructure#msb|msb}. */
|
||
this.word = word;
|
||
/** Whether the bit sequences are packed starting at the most
|
||
* significant bit growing down (`true`), or the least significant
|
||
* bit growing up (`false`).
|
||
*
|
||
* **NOTE** Regardless of this value, the least significant bit of
|
||
* any {@link BitField} value is the least significant bit of the
|
||
* corresponding section of the packed value. */
|
||
this.msb = !!msb;
|
||
/** The sequence of {@link BitField} layouts that comprise the
|
||
* packed structure.
|
||
*
|
||
* **NOTE** The array remains mutable to allow fields to be {@link
|
||
* BitStructure#addField|added} after construction. Users should
|
||
* not manipulate the content of this property.*/
|
||
this.fields = [];
|
||
/* Storage for the value. Capture a variable instead of using an
|
||
* instance property because we don't want anything to change the
|
||
* value without going through the mutator. */
|
||
let value = 0;
|
||
this._packedSetValue = function (v) {
|
||
value = fixBitwiseResult(v);
|
||
return this;
|
||
};
|
||
this._packedGetValue = function () {
|
||
return value;
|
||
};
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const dest = this.makeDestinationObject();
|
||
const value = this.word.decode(b, offset);
|
||
this._packedSetValue(value);
|
||
for (const fd of this.fields) {
|
||
if (undefined !== fd.property) {
|
||
dest[fd.property] = fd.decode(b);
|
||
}
|
||
}
|
||
return dest;
|
||
}
|
||
/** Implement {@link Layout#encode|encode} for {@link BitStructure}.
|
||
*
|
||
* If `src` is missing a property for a member with a defined {@link
|
||
* Layout#property|property} the corresponding region of the packed
|
||
* value is left unmodified. Unused bits are also left unmodified. */
|
||
encode(src, b, offset = 0) {
|
||
const value = this.word.decode(b, offset);
|
||
this._packedSetValue(value);
|
||
for (const fd of this.fields) {
|
||
if (undefined !== fd.property) {
|
||
const fv = src[fd.property];
|
||
if (undefined !== fv) {
|
||
fd.encode(fv);
|
||
}
|
||
}
|
||
}
|
||
return this.word.encode(this._packedGetValue(), b, offset);
|
||
}
|
||
/** Register a new bitfield with a containing bit structure. The
|
||
* resulting bitfield is returned.
|
||
*
|
||
* @param {Number} bits - initializer for {@link BitField#bits|bits}.
|
||
*
|
||
* @param {string} property - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @return {BitField} */
|
||
addField(bits, property) {
|
||
const bf = new BitField(this, bits, property);
|
||
this.fields.push(bf);
|
||
return bf;
|
||
}
|
||
/** As with {@link BitStructure#addField|addField} for single-bit
|
||
* fields with `boolean` value representation.
|
||
*
|
||
* @param {string} property - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @return {Boolean} */
|
||
// `Boolean` conflicts with the native primitive type
|
||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||
addBoolean(property) {
|
||
// This is my Boolean, not the Javascript one.
|
||
const bf = new Boolean$1(this, property);
|
||
this.fields.push(bf);
|
||
return bf;
|
||
}
|
||
/**
|
||
* Get access to the bit field for a given property.
|
||
*
|
||
* @param {String} property - the bit field of interest.
|
||
*
|
||
* @return {BitField} - the field associated with `property`, or
|
||
* undefined if there is no such property.
|
||
*/
|
||
fieldFor(property) {
|
||
if ('string' !== typeof property) {
|
||
throw new TypeError('property must be string');
|
||
}
|
||
for (const fd of this.fields) {
|
||
if (fd.property === property) {
|
||
return fd;
|
||
}
|
||
}
|
||
return undefined;
|
||
}
|
||
}
|
||
Layout$1.BitStructure = BitStructure;
|
||
/**
|
||
* Represent a sequence of bits within a {@link BitStructure}.
|
||
*
|
||
* All bit field values are represented as unsigned integers.
|
||
*
|
||
* **NOTE** User code should not invoke this constructor directly.
|
||
* Use the container {@link BitStructure#addField|addField} helper
|
||
* method.
|
||
*
|
||
* **NOTE** BitField instances are not instances of {@link Layout}
|
||
* since {@link Layout#span|span} measures 8-bit units.
|
||
*
|
||
* @param {BitStructure} container - initializer for {@link
|
||
* BitField#container|container}.
|
||
*
|
||
* @param {Number} bits - initializer for {@link BitField#bits|bits}.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*/
|
||
class BitField {
|
||
constructor(container, bits, property) {
|
||
if (!(container instanceof BitStructure)) {
|
||
throw new TypeError('container must be a BitStructure');
|
||
}
|
||
if ((!Number.isInteger(bits)) || (0 >= bits)) {
|
||
throw new TypeError('bits must be positive integer');
|
||
}
|
||
const totalBits = 8 * container.span;
|
||
const usedBits = container.fields.reduce((sum, fd) => sum + fd.bits, 0);
|
||
if ((bits + usedBits) > totalBits) {
|
||
throw new Error('bits too long for span remainder ('
|
||
+ (totalBits - usedBits) + ' of '
|
||
+ totalBits + ' remain)');
|
||
}
|
||
/** The {@link BitStructure} instance to which this bit field
|
||
* belongs. */
|
||
this.container = container;
|
||
/** The span of this value in bits. */
|
||
this.bits = bits;
|
||
/** A mask of {@link BitField#bits|bits} bits isolating value bits
|
||
* that fit within the field.
|
||
*
|
||
* That is, it masks a value that has not yet been shifted into
|
||
* position within its containing packed integer. */
|
||
this.valueMask = (1 << bits) - 1;
|
||
if (32 === bits) { // shifted value out of range
|
||
this.valueMask = 0xFFFFFFFF;
|
||
}
|
||
/** The offset of the value within the containing packed unsigned
|
||
* integer. The least significant bit of the packed value is at
|
||
* offset zero, regardless of bit ordering used. */
|
||
this.start = usedBits;
|
||
if (this.container.msb) {
|
||
this.start = totalBits - usedBits - bits;
|
||
}
|
||
/** A mask of {@link BitField#bits|bits} isolating the field value
|
||
* within the containing packed unsigned integer. */
|
||
this.wordMask = fixBitwiseResult(this.valueMask << this.start);
|
||
/** The property name used when this bitfield is represented in an
|
||
* Object.
|
||
*
|
||
* Intended to be functionally equivalent to {@link
|
||
* Layout#property}.
|
||
*
|
||
* If left undefined the corresponding span of bits will be
|
||
* treated as padding: it will not be mutated by {@link
|
||
* Layout#encode|encode} nor represented as a property in the
|
||
* decoded Object. */
|
||
this.property = property;
|
||
}
|
||
/** Store a value into the corresponding subsequence of the containing
|
||
* bit field. */
|
||
decode(b, offset) {
|
||
const word = this.container._packedGetValue();
|
||
const wordValue = fixBitwiseResult(word & this.wordMask);
|
||
const value = wordValue >>> this.start;
|
||
return value;
|
||
}
|
||
/** Store a value into the corresponding subsequence of the containing
|
||
* bit field.
|
||
*
|
||
* **NOTE** This is not a specialization of {@link
|
||
* Layout#encode|Layout.encode} and there is no return value. */
|
||
encode(value) {
|
||
if ('number' !== typeof value
|
||
|| !Number.isInteger(value)
|
||
|| (value !== fixBitwiseResult(value & this.valueMask))) {
|
||
throw new TypeError(nameWithProperty('BitField.encode', this)
|
||
+ ' value must be integer not exceeding ' + this.valueMask);
|
||
}
|
||
const word = this.container._packedGetValue();
|
||
const wordValue = fixBitwiseResult(value << this.start);
|
||
this.container._packedSetValue(fixBitwiseResult(word & ~this.wordMask)
|
||
| wordValue);
|
||
}
|
||
}
|
||
Layout$1.BitField = BitField;
|
||
/**
|
||
* Represent a single bit within a {@link BitStructure} as a
|
||
* JavaScript boolean.
|
||
*
|
||
* **NOTE** User code should not invoke this constructor directly.
|
||
* Use the container {@link BitStructure#addBoolean|addBoolean} helper
|
||
* method.
|
||
*
|
||
* @param {BitStructure} container - initializer for {@link
|
||
* BitField#container|container}.
|
||
*
|
||
* @param {string} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {BitField}
|
||
*/
|
||
/* eslint-disable no-extend-native */
|
||
let Boolean$1 = class Boolean extends BitField {
|
||
constructor(container, property) {
|
||
super(container, 1, property);
|
||
}
|
||
/** Override {@link BitField#decode|decode} for {@link Boolean|Boolean}.
|
||
*
|
||
* @returns {boolean} */
|
||
decode(b, offset) {
|
||
return !!super.decode(b, offset);
|
||
}
|
||
/** @override */
|
||
encode(value) {
|
||
if ('boolean' === typeof value) {
|
||
// BitField requires integer values
|
||
value = +value;
|
||
}
|
||
super.encode(value);
|
||
}
|
||
};
|
||
Layout$1.Boolean = Boolean$1;
|
||
/* eslint-enable no-extend-native */
|
||
/**
|
||
* Contain a fixed-length block of arbitrary data, represented as a
|
||
* Uint8Array.
|
||
*
|
||
* *Factory*: {@link module:Layout.blob|blob}
|
||
*
|
||
* @param {(Number|ExternalLayout)} length - initializes {@link
|
||
* Blob#length|length}.
|
||
*
|
||
* @param {String} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Blob extends Layout {
|
||
constructor(length, property) {
|
||
if (!(((length instanceof ExternalLayout) && length.isCount())
|
||
|| (Number.isInteger(length) && (0 <= length)))) {
|
||
throw new TypeError('length must be positive integer '
|
||
+ 'or an unsigned integer ExternalLayout');
|
||
}
|
||
let span = -1;
|
||
if (!(length instanceof ExternalLayout)) {
|
||
span = length;
|
||
}
|
||
super(span, property);
|
||
/** The number of bytes in the blob.
|
||
*
|
||
* This may be a non-negative integer, or an instance of {@link
|
||
* ExternalLayout} that satisfies {@link
|
||
* ExternalLayout#isCount|isCount()}. */
|
||
this.length = length;
|
||
}
|
||
/** @override */
|
||
getSpan(b, offset) {
|
||
let span = this.span;
|
||
if (0 > span) {
|
||
span = this.length.decode(b, offset);
|
||
}
|
||
return span;
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
let span = this.span;
|
||
if (0 > span) {
|
||
span = this.length.decode(b, offset);
|
||
}
|
||
return uint8ArrayToBuffer(b).slice(offset, offset + span);
|
||
}
|
||
/** Implement {@link Layout#encode|encode} for {@link Blob}.
|
||
*
|
||
* **NOTE** If {@link Layout#count|count} is an instance of {@link
|
||
* ExternalLayout} then the length of `src` will be encoded as the
|
||
* count after `src` is encoded. */
|
||
encode(src, b, offset) {
|
||
let span = this.length;
|
||
if (this.length instanceof ExternalLayout) {
|
||
span = src.length;
|
||
}
|
||
if (!(src instanceof Uint8Array && span === src.length)) {
|
||
throw new TypeError(nameWithProperty('Blob.encode', this)
|
||
+ ' requires (length ' + span + ') Uint8Array as src');
|
||
}
|
||
if ((offset + span) > b.length) {
|
||
throw new RangeError('encoding overruns Uint8Array');
|
||
}
|
||
const srcBuffer = uint8ArrayToBuffer(src);
|
||
uint8ArrayToBuffer(b).write(srcBuffer.toString('hex'), offset, span, 'hex');
|
||
if (this.length instanceof ExternalLayout) {
|
||
this.length.encode(span, b, offset);
|
||
}
|
||
return span;
|
||
}
|
||
}
|
||
Layout$1.Blob = Blob;
|
||
/**
|
||
* Contain a `NUL`-terminated UTF8 string.
|
||
*
|
||
* *Factory*: {@link module:Layout.cstr|cstr}
|
||
*
|
||
* **NOTE** Any UTF8 string that incorporates a zero-valued byte will
|
||
* not be correctly decoded by this layout.
|
||
*
|
||
* @param {String} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class CString extends Layout {
|
||
constructor(property) {
|
||
super(-1, property);
|
||
}
|
||
/** @override */
|
||
getSpan(b, offset = 0) {
|
||
checkUint8Array(b);
|
||
let idx = offset;
|
||
while ((idx < b.length) && (0 !== b[idx])) {
|
||
idx += 1;
|
||
}
|
||
return 1 + idx - offset;
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const span = this.getSpan(b, offset);
|
||
return uint8ArrayToBuffer(b).slice(offset, offset + span - 1).toString('utf-8');
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
/* Must force this to a string, lest it be a number and the
|
||
* "utf8-encoding" below actually allocate a buffer of length
|
||
* src */
|
||
if ('string' !== typeof src) {
|
||
src = String(src);
|
||
}
|
||
const srcb = buffer_1.Buffer.from(src, 'utf8');
|
||
const span = srcb.length;
|
||
if ((offset + span) > b.length) {
|
||
throw new RangeError('encoding overruns Buffer');
|
||
}
|
||
const buffer = uint8ArrayToBuffer(b);
|
||
srcb.copy(buffer, offset);
|
||
buffer[offset + span] = 0;
|
||
return span + 1;
|
||
}
|
||
}
|
||
Layout$1.CString = CString;
|
||
/**
|
||
* Contain a UTF8 string with implicit length.
|
||
*
|
||
* *Factory*: {@link module:Layout.utf8|utf8}
|
||
*
|
||
* **NOTE** Because the length is implicit in the size of the buffer
|
||
* this layout should be used only in isolation, or in a situation
|
||
* where the length can be expressed by operating on a slice of the
|
||
* containing buffer.
|
||
*
|
||
* @param {Number} [maxSpan] - the maximum length allowed for encoded
|
||
* string content. If not provided there is no bound on the allowed
|
||
* content.
|
||
*
|
||
* @param {String} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class UTF8 extends Layout {
|
||
constructor(maxSpan, property) {
|
||
if (('string' === typeof maxSpan) && (undefined === property)) {
|
||
property = maxSpan;
|
||
maxSpan = undefined;
|
||
}
|
||
if (undefined === maxSpan) {
|
||
maxSpan = -1;
|
||
}
|
||
else if (!Number.isInteger(maxSpan)) {
|
||
throw new TypeError('maxSpan must be an integer');
|
||
}
|
||
super(-1, property);
|
||
/** The maximum span of the layout in bytes.
|
||
*
|
||
* Positive values are generally expected. Zero is abnormal.
|
||
* Attempts to encode or decode a value that exceeds this length
|
||
* will throw a `RangeError`.
|
||
*
|
||
* A negative value indicates that there is no bound on the length
|
||
* of the content. */
|
||
this.maxSpan = maxSpan;
|
||
}
|
||
/** @override */
|
||
getSpan(b, offset = 0) {
|
||
checkUint8Array(b);
|
||
return b.length - offset;
|
||
}
|
||
/** @override */
|
||
decode(b, offset = 0) {
|
||
const span = this.getSpan(b, offset);
|
||
if ((0 <= this.maxSpan)
|
||
&& (this.maxSpan < span)) {
|
||
throw new RangeError('text length exceeds maxSpan');
|
||
}
|
||
return uint8ArrayToBuffer(b).slice(offset, offset + span).toString('utf-8');
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset = 0) {
|
||
/* Must force this to a string, lest it be a number and the
|
||
* "utf8-encoding" below actually allocate a buffer of length
|
||
* src */
|
||
if ('string' !== typeof src) {
|
||
src = String(src);
|
||
}
|
||
const srcb = buffer_1.Buffer.from(src, 'utf8');
|
||
const span = srcb.length;
|
||
if ((0 <= this.maxSpan)
|
||
&& (this.maxSpan < span)) {
|
||
throw new RangeError('text length exceeds maxSpan');
|
||
}
|
||
if ((offset + span) > b.length) {
|
||
throw new RangeError('encoding overruns Buffer');
|
||
}
|
||
srcb.copy(uint8ArrayToBuffer(b), offset);
|
||
return span;
|
||
}
|
||
}
|
||
Layout$1.UTF8 = UTF8;
|
||
/**
|
||
* Contain a constant value.
|
||
*
|
||
* This layout may be used in cases where a JavaScript value can be
|
||
* inferred without an expression in the binary encoding. An example
|
||
* would be a {@link VariantLayout|variant layout} where the content
|
||
* is implied by the union {@link Union#discriminator|discriminator}.
|
||
*
|
||
* @param {Object|Number|String} value - initializer for {@link
|
||
* Constant#value|value}. If the value is an object (or array) and
|
||
* the application intends the object to remain unchanged regardless
|
||
* of what is done to values decoded by this layout, the value should
|
||
* be frozen prior passing it to this constructor.
|
||
*
|
||
* @param {String} [property] - initializer for {@link
|
||
* Layout#property|property}.
|
||
*
|
||
* @augments {Layout}
|
||
*/
|
||
class Constant extends Layout {
|
||
constructor(value, property) {
|
||
super(0, property);
|
||
/** The value produced by this constant when the layout is {@link
|
||
* Constant#decode|decoded}.
|
||
*
|
||
* Any JavaScript value including `null` and `undefined` is
|
||
* permitted.
|
||
*
|
||
* **WARNING** If `value` passed in the constructor was not
|
||
* frozen, it is possible for users of decoded values to change
|
||
* the content of the value. */
|
||
this.value = value;
|
||
}
|
||
/** @override */
|
||
decode(b, offset) {
|
||
return this.value;
|
||
}
|
||
/** @override */
|
||
encode(src, b, offset) {
|
||
/* Constants take no space */
|
||
return 0;
|
||
}
|
||
}
|
||
Layout$1.Constant = Constant;
|
||
/** Factory for {@link GreedyCount}. */
|
||
Layout$1.greedy = ((elementSpan, property) => new GreedyCount(elementSpan, property));
|
||
/** Factory for {@link OffsetLayout}. */
|
||
var offset = Layout$1.offset = ((layout, offset, property) => new OffsetLayout(layout, offset, property));
|
||
/** Factory for {@link UInt|unsigned int layouts} spanning one
|
||
* byte. */
|
||
var u8 = Layout$1.u8 = ((property) => new UInt(1, property));
|
||
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
||
* spanning two bytes. */
|
||
var u16 = Layout$1.u16 = ((property) => new UInt(2, property));
|
||
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
||
* spanning three bytes. */
|
||
Layout$1.u24 = ((property) => new UInt(3, property));
|
||
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
||
* spanning four bytes. */
|
||
var u32 = Layout$1.u32 = ((property) => new UInt(4, property));
|
||
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
||
* spanning five bytes. */
|
||
Layout$1.u40 = ((property) => new UInt(5, property));
|
||
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
||
* spanning six bytes. */
|
||
Layout$1.u48 = ((property) => new UInt(6, property));
|
||
/** Factory for {@link NearUInt64|little-endian unsigned int
|
||
* layouts} interpreted as Numbers. */
|
||
var nu64 = Layout$1.nu64 = ((property) => new NearUInt64(property));
|
||
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
||
* spanning two bytes. */
|
||
Layout$1.u16be = ((property) => new UIntBE(2, property));
|
||
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
||
* spanning three bytes. */
|
||
Layout$1.u24be = ((property) => new UIntBE(3, property));
|
||
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
||
* spanning four bytes. */
|
||
Layout$1.u32be = ((property) => new UIntBE(4, property));
|
||
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
||
* spanning five bytes. */
|
||
Layout$1.u40be = ((property) => new UIntBE(5, property));
|
||
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
||
* spanning six bytes. */
|
||
Layout$1.u48be = ((property) => new UIntBE(6, property));
|
||
/** Factory for {@link NearUInt64BE|big-endian unsigned int
|
||
* layouts} interpreted as Numbers. */
|
||
Layout$1.nu64be = ((property) => new NearUInt64BE(property));
|
||
/** Factory for {@link Int|signed int layouts} spanning one
|
||
* byte. */
|
||
Layout$1.s8 = ((property) => new Int(1, property));
|
||
/** Factory for {@link Int|little-endian signed int layouts}
|
||
* spanning two bytes. */
|
||
Layout$1.s16 = ((property) => new Int(2, property));
|
||
/** Factory for {@link Int|little-endian signed int layouts}
|
||
* spanning three bytes. */
|
||
Layout$1.s24 = ((property) => new Int(3, property));
|
||
/** Factory for {@link Int|little-endian signed int layouts}
|
||
* spanning four bytes. */
|
||
Layout$1.s32 = ((property) => new Int(4, property));
|
||
/** Factory for {@link Int|little-endian signed int layouts}
|
||
* spanning five bytes. */
|
||
Layout$1.s40 = ((property) => new Int(5, property));
|
||
/** Factory for {@link Int|little-endian signed int layouts}
|
||
* spanning six bytes. */
|
||
Layout$1.s48 = ((property) => new Int(6, property));
|
||
/** Factory for {@link NearInt64|little-endian signed int layouts}
|
||
* interpreted as Numbers. */
|
||
var ns64 = Layout$1.ns64 = ((property) => new NearInt64(property));
|
||
/** Factory for {@link Int|big-endian signed int layouts}
|
||
* spanning two bytes. */
|
||
Layout$1.s16be = ((property) => new IntBE(2, property));
|
||
/** Factory for {@link Int|big-endian signed int layouts}
|
||
* spanning three bytes. */
|
||
Layout$1.s24be = ((property) => new IntBE(3, property));
|
||
/** Factory for {@link Int|big-endian signed int layouts}
|
||
* spanning four bytes. */
|
||
Layout$1.s32be = ((property) => new IntBE(4, property));
|
||
/** Factory for {@link Int|big-endian signed int layouts}
|
||
* spanning five bytes. */
|
||
Layout$1.s40be = ((property) => new IntBE(5, property));
|
||
/** Factory for {@link Int|big-endian signed int layouts}
|
||
* spanning six bytes. */
|
||
Layout$1.s48be = ((property) => new IntBE(6, property));
|
||
/** Factory for {@link NearInt64BE|big-endian signed int layouts}
|
||
* interpreted as Numbers. */
|
||
Layout$1.ns64be = ((property) => new NearInt64BE(property));
|
||
/** Factory for {@link Float|little-endian 32-bit floating point} values. */
|
||
Layout$1.f32 = ((property) => new Float(property));
|
||
/** Factory for {@link FloatBE|big-endian 32-bit floating point} values. */
|
||
Layout$1.f32be = ((property) => new FloatBE(property));
|
||
/** Factory for {@link Double|little-endian 64-bit floating point} values. */
|
||
Layout$1.f64 = ((property) => new Double(property));
|
||
/** Factory for {@link DoubleBE|big-endian 64-bit floating point} values. */
|
||
Layout$1.f64be = ((property) => new DoubleBE(property));
|
||
/** Factory for {@link Structure} values. */
|
||
var struct = Layout$1.struct = ((fields, property, decodePrefixes) => new Structure(fields, property, decodePrefixes));
|
||
/** Factory for {@link BitStructure} values. */
|
||
Layout$1.bits = ((word, msb, property) => new BitStructure(word, msb, property));
|
||
/** Factory for {@link Sequence} values. */
|
||
var seq = Layout$1.seq = ((elementLayout, count, property) => new Sequence(elementLayout, count, property));
|
||
/** Factory for {@link Union} values. */
|
||
Layout$1.union = ((discr, defaultLayout, property) => new Union(discr, defaultLayout, property));
|
||
/** Factory for {@link UnionLayoutDiscriminator} values. */
|
||
Layout$1.unionLayoutDiscriminator = ((layout, property) => new UnionLayoutDiscriminator(layout, property));
|
||
/** Factory for {@link Blob} values. */
|
||
var blob = Layout$1.blob = ((length, property) => new Blob(length, property));
|
||
/** Factory for {@link CString} values. */
|
||
Layout$1.cstr = ((property) => new CString(property));
|
||
/** Factory for {@link UTF8} values. */
|
||
Layout$1.utf8 = ((maxSpan, property) => new UTF8(maxSpan, property));
|
||
/** Factory for {@link Constant} values. */
|
||
Layout$1.constant = ((value, property) => new Constant(value, property));
|
||
|
||
/**
|
||
* Maximum over-the-wire size of a Transaction
|
||
*
|
||
* 1280 is IPv6 minimum MTU
|
||
* 40 bytes is the size of the IPv6 header
|
||
* 8 bytes is the size of the fragment header
|
||
*/
|
||
const PACKET_DATA_SIZE = 1280 - 40 - 8;
|
||
const VERSION_PREFIX_MASK = 0x7f;
|
||
const SIGNATURE_LENGTH_IN_BYTES = 64;
|
||
|
||
class TransactionExpiredBlockheightExceededError extends Error {
|
||
constructor(signature) {
|
||
super(`Signature ${signature} has expired: block height exceeded.`);
|
||
this.signature = void 0;
|
||
this.signature = signature;
|
||
}
|
||
}
|
||
Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
|
||
value: 'TransactionExpiredBlockheightExceededError'
|
||
});
|
||
class TransactionExpiredTimeoutError extends Error {
|
||
constructor(signature, timeoutSeconds) {
|
||
super(`Transaction was not confirmed in ${timeoutSeconds.toFixed(2)} seconds. It is ` + 'unknown if it succeeded or failed. Check signature ' + `${signature} using the Solana Explorer or CLI tools.`);
|
||
this.signature = void 0;
|
||
this.signature = signature;
|
||
}
|
||
}
|
||
Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
|
||
value: 'TransactionExpiredTimeoutError'
|
||
});
|
||
class TransactionExpiredNonceInvalidError extends Error {
|
||
constructor(signature) {
|
||
super(`Signature ${signature} has expired: the nonce is no longer valid.`);
|
||
this.signature = void 0;
|
||
this.signature = signature;
|
||
}
|
||
}
|
||
Object.defineProperty(TransactionExpiredNonceInvalidError.prototype, 'name', {
|
||
value: 'TransactionExpiredNonceInvalidError'
|
||
});
|
||
|
||
class MessageAccountKeys {
|
||
constructor(staticAccountKeys, accountKeysFromLookups) {
|
||
this.staticAccountKeys = void 0;
|
||
this.accountKeysFromLookups = void 0;
|
||
this.staticAccountKeys = staticAccountKeys;
|
||
this.accountKeysFromLookups = accountKeysFromLookups;
|
||
}
|
||
keySegments() {
|
||
const keySegments = [this.staticAccountKeys];
|
||
if (this.accountKeysFromLookups) {
|
||
keySegments.push(this.accountKeysFromLookups.writable);
|
||
keySegments.push(this.accountKeysFromLookups.readonly);
|
||
}
|
||
return keySegments;
|
||
}
|
||
get(index) {
|
||
for (const keySegment of this.keySegments()) {
|
||
if (index < keySegment.length) {
|
||
return keySegment[index];
|
||
} else {
|
||
index -= keySegment.length;
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
get length() {
|
||
return this.keySegments().flat().length;
|
||
}
|
||
compileInstructions(instructions) {
|
||
// Bail early if any account indexes would overflow a u8
|
||
const U8_MAX = 255;
|
||
if (this.length > U8_MAX + 1) {
|
||
throw new Error('Account index overflow encountered during compilation');
|
||
}
|
||
const keyIndexMap = new Map();
|
||
this.keySegments().flat().forEach((key, index) => {
|
||
keyIndexMap.set(key.toBase58(), index);
|
||
});
|
||
const findKeyIndex = key => {
|
||
const keyIndex = keyIndexMap.get(key.toBase58());
|
||
if (keyIndex === undefined) throw new Error('Encountered an unknown instruction account key during compilation');
|
||
return keyIndex;
|
||
};
|
||
return instructions.map(instruction => {
|
||
return {
|
||
programIdIndex: findKeyIndex(instruction.programId),
|
||
accountKeyIndexes: instruction.keys.map(meta => findKeyIndex(meta.pubkey)),
|
||
data: instruction.data
|
||
};
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Layout for a public key
|
||
*/
|
||
const publicKey = (property = 'publicKey') => {
|
||
return blob(32, property);
|
||
};
|
||
|
||
/**
|
||
* Layout for a signature
|
||
*/
|
||
const signature = (property = 'signature') => {
|
||
return blob(64, property);
|
||
};
|
||
/**
|
||
* Layout for a Rust String type
|
||
*/
|
||
const rustString = (property = 'string') => {
|
||
const rsl = struct([u32('length'), u32('lengthPadding'), blob(offset(u32(), -8), 'chars')], property);
|
||
const _decode = rsl.decode.bind(rsl);
|
||
const _encode = rsl.encode.bind(rsl);
|
||
const rslShim = rsl;
|
||
rslShim.decode = (b, offset) => {
|
||
const data = _decode(b, offset);
|
||
return data['chars'].toString();
|
||
};
|
||
rslShim.encode = (str, b, offset) => {
|
||
const data = {
|
||
chars: buffer.Buffer.from(str, 'utf8')
|
||
};
|
||
return _encode(data, b, offset);
|
||
};
|
||
rslShim.alloc = str => {
|
||
return u32().span + u32().span + buffer.Buffer.from(str, 'utf8').length;
|
||
};
|
||
return rslShim;
|
||
};
|
||
|
||
/**
|
||
* Layout for an Authorized object
|
||
*/
|
||
const authorized = (property = 'authorized') => {
|
||
return struct([publicKey('staker'), publicKey('withdrawer')], property);
|
||
};
|
||
|
||
/**
|
||
* Layout for a Lockup object
|
||
*/
|
||
const lockup = (property = 'lockup') => {
|
||
return struct([ns64('unixTimestamp'), ns64('epoch'), publicKey('custodian')], property);
|
||
};
|
||
|
||
/**
|
||
* Layout for a VoteInit object
|
||
*/
|
||
const voteInit = (property = 'voteInit') => {
|
||
return struct([publicKey('nodePubkey'), publicKey('authorizedVoter'), publicKey('authorizedWithdrawer'), u8('commission')], property);
|
||
};
|
||
|
||
/**
|
||
* Layout for a VoteAuthorizeWithSeedArgs object
|
||
*/
|
||
const voteAuthorizeWithSeedArgs = (property = 'voteAuthorizeWithSeedArgs') => {
|
||
return struct([u32('voteAuthorizationType'), publicKey('currentAuthorityDerivedKeyOwnerPubkey'), rustString('currentAuthorityDerivedKeySeed'), publicKey('newAuthorized')], property);
|
||
};
|
||
function getAlloc(type, fields) {
|
||
const getItemAlloc = item => {
|
||
if (item.span >= 0) {
|
||
return item.span;
|
||
} else if (typeof item.alloc === 'function') {
|
||
return item.alloc(fields[item.property]);
|
||
} else if ('count' in item && 'elementLayout' in item) {
|
||
const field = fields[item.property];
|
||
if (Array.isArray(field)) {
|
||
return field.length * getItemAlloc(item.elementLayout);
|
||
}
|
||
} else if ('fields' in item) {
|
||
// This is a `Structure` whose size needs to be recursively measured.
|
||
return getAlloc({
|
||
layout: item
|
||
}, fields[item.property]);
|
||
}
|
||
// Couldn't determine allocated size of layout
|
||
return 0;
|
||
};
|
||
let alloc = 0;
|
||
type.layout.fields.forEach(item => {
|
||
alloc += getItemAlloc(item);
|
||
});
|
||
return alloc;
|
||
}
|
||
|
||
function decodeLength(bytes) {
|
||
let len = 0;
|
||
let size = 0;
|
||
for (;;) {
|
||
let elem = bytes.shift();
|
||
len |= (elem & 0x7f) << size * 7;
|
||
size += 1;
|
||
if ((elem & 0x80) === 0) {
|
||
break;
|
||
}
|
||
}
|
||
return len;
|
||
}
|
||
function encodeLength(bytes, len) {
|
||
let rem_len = len;
|
||
for (;;) {
|
||
let elem = rem_len & 0x7f;
|
||
rem_len >>= 7;
|
||
if (rem_len == 0) {
|
||
bytes.push(elem);
|
||
break;
|
||
} else {
|
||
elem |= 0x80;
|
||
bytes.push(elem);
|
||
}
|
||
}
|
||
}
|
||
|
||
function assert$1 (condition, message) {
|
||
if (!condition) {
|
||
throw new Error(message || 'Assertion failed');
|
||
}
|
||
}
|
||
|
||
class CompiledKeys {
|
||
constructor(payer, keyMetaMap) {
|
||
this.payer = void 0;
|
||
this.keyMetaMap = void 0;
|
||
this.payer = payer;
|
||
this.keyMetaMap = keyMetaMap;
|
||
}
|
||
static compile(instructions, payer) {
|
||
const keyMetaMap = new Map();
|
||
const getOrInsertDefault = pubkey => {
|
||
const address = pubkey.toBase58();
|
||
let keyMeta = keyMetaMap.get(address);
|
||
if (keyMeta === undefined) {
|
||
keyMeta = {
|
||
isSigner: false,
|
||
isWritable: false,
|
||
isInvoked: false
|
||
};
|
||
keyMetaMap.set(address, keyMeta);
|
||
}
|
||
return keyMeta;
|
||
};
|
||
const payerKeyMeta = getOrInsertDefault(payer);
|
||
payerKeyMeta.isSigner = true;
|
||
payerKeyMeta.isWritable = true;
|
||
for (const ix of instructions) {
|
||
getOrInsertDefault(ix.programId).isInvoked = true;
|
||
for (const accountMeta of ix.keys) {
|
||
const keyMeta = getOrInsertDefault(accountMeta.pubkey);
|
||
keyMeta.isSigner ||= accountMeta.isSigner;
|
||
keyMeta.isWritable ||= accountMeta.isWritable;
|
||
}
|
||
}
|
||
return new CompiledKeys(payer, keyMetaMap);
|
||
}
|
||
getMessageComponents() {
|
||
const mapEntries = [...this.keyMetaMap.entries()];
|
||
assert$1(mapEntries.length <= 256, 'Max static account keys length exceeded');
|
||
const writableSigners = mapEntries.filter(([, meta]) => meta.isSigner && meta.isWritable);
|
||
const readonlySigners = mapEntries.filter(([, meta]) => meta.isSigner && !meta.isWritable);
|
||
const writableNonSigners = mapEntries.filter(([, meta]) => !meta.isSigner && meta.isWritable);
|
||
const readonlyNonSigners = mapEntries.filter(([, meta]) => !meta.isSigner && !meta.isWritable);
|
||
const header = {
|
||
numRequiredSignatures: writableSigners.length + readonlySigners.length,
|
||
numReadonlySignedAccounts: readonlySigners.length,
|
||
numReadonlyUnsignedAccounts: readonlyNonSigners.length
|
||
};
|
||
|
||
// sanity checks
|
||
{
|
||
assert$1(writableSigners.length > 0, 'Expected at least one writable signer key');
|
||
const [payerAddress] = writableSigners[0];
|
||
assert$1(payerAddress === this.payer.toBase58(), 'Expected first writable signer key to be the fee payer');
|
||
}
|
||
const staticAccountKeys = [...writableSigners.map(([address]) => new PublicKey(address)), ...readonlySigners.map(([address]) => new PublicKey(address)), ...writableNonSigners.map(([address]) => new PublicKey(address)), ...readonlyNonSigners.map(([address]) => new PublicKey(address))];
|
||
return [header, staticAccountKeys];
|
||
}
|
||
extractTableLookup(lookupTable) {
|
||
const [writableIndexes, drainedWritableKeys] = this.drainKeysFoundInLookupTable(lookupTable.state.addresses, keyMeta => !keyMeta.isSigner && !keyMeta.isInvoked && keyMeta.isWritable);
|
||
const [readonlyIndexes, drainedReadonlyKeys] = this.drainKeysFoundInLookupTable(lookupTable.state.addresses, keyMeta => !keyMeta.isSigner && !keyMeta.isInvoked && !keyMeta.isWritable);
|
||
|
||
// Don't extract lookup if no keys were found
|
||
if (writableIndexes.length === 0 && readonlyIndexes.length === 0) {
|
||
return;
|
||
}
|
||
return [{
|
||
accountKey: lookupTable.key,
|
||
writableIndexes,
|
||
readonlyIndexes
|
||
}, {
|
||
writable: drainedWritableKeys,
|
||
readonly: drainedReadonlyKeys
|
||
}];
|
||
}
|
||
|
||
/** @internal */
|
||
drainKeysFoundInLookupTable(lookupTableEntries, keyMetaFilter) {
|
||
const lookupTableIndexes = new Array();
|
||
const drainedKeys = new Array();
|
||
for (const [address, keyMeta] of this.keyMetaMap.entries()) {
|
||
if (keyMetaFilter(keyMeta)) {
|
||
const key = new PublicKey(address);
|
||
const lookupTableIndex = lookupTableEntries.findIndex(entry => entry.equals(key));
|
||
if (lookupTableIndex >= 0) {
|
||
assert$1(lookupTableIndex < 256, 'Max lookup table index exceeded');
|
||
lookupTableIndexes.push(lookupTableIndex);
|
||
drainedKeys.push(key);
|
||
this.keyMetaMap.delete(address);
|
||
}
|
||
}
|
||
}
|
||
return [lookupTableIndexes, drainedKeys];
|
||
}
|
||
}
|
||
|
||
const END_OF_BUFFER_ERROR_MESSAGE = 'Reached end of buffer unexpectedly';
|
||
|
||
/**
|
||
* Delegates to `Array#shift`, but throws if the array is zero-length.
|
||
*/
|
||
function guardedShift(byteArray) {
|
||
if (byteArray.length === 0) {
|
||
throw new Error(END_OF_BUFFER_ERROR_MESSAGE);
|
||
}
|
||
return byteArray.shift();
|
||
}
|
||
|
||
/**
|
||
* Delegates to `Array#splice`, but throws if the section being spliced out extends past the end of
|
||
* the array.
|
||
*/
|
||
function guardedSplice(byteArray, ...args) {
|
||
const [start] = args;
|
||
if (args.length === 2 // Implies that `deleteCount` was supplied
|
||
? start + (args[1] ?? 0) > byteArray.length : start >= byteArray.length) {
|
||
throw new Error(END_OF_BUFFER_ERROR_MESSAGE);
|
||
}
|
||
return byteArray.splice(...args);
|
||
}
|
||
|
||
/**
|
||
* An instruction to execute by a program
|
||
*
|
||
* @property {number} programIdIndex
|
||
* @property {number[]} accounts
|
||
* @property {string} data
|
||
*/
|
||
|
||
/**
|
||
* Message constructor arguments
|
||
*/
|
||
|
||
/**
|
||
* List of instructions to be processed atomically
|
||
*/
|
||
class Message {
|
||
constructor(args) {
|
||
this.header = void 0;
|
||
this.accountKeys = void 0;
|
||
this.recentBlockhash = void 0;
|
||
this.instructions = void 0;
|
||
this.indexToProgramIds = new Map();
|
||
this.header = args.header;
|
||
this.accountKeys = args.accountKeys.map(account => new PublicKey(account));
|
||
this.recentBlockhash = args.recentBlockhash;
|
||
this.instructions = args.instructions;
|
||
this.instructions.forEach(ix => this.indexToProgramIds.set(ix.programIdIndex, this.accountKeys[ix.programIdIndex]));
|
||
}
|
||
get version() {
|
||
return 'legacy';
|
||
}
|
||
get staticAccountKeys() {
|
||
return this.accountKeys;
|
||
}
|
||
get compiledInstructions() {
|
||
return this.instructions.map(ix => ({
|
||
programIdIndex: ix.programIdIndex,
|
||
accountKeyIndexes: ix.accounts,
|
||
data: bs58$1.decode(ix.data)
|
||
}));
|
||
}
|
||
get addressTableLookups() {
|
||
return [];
|
||
}
|
||
getAccountKeys() {
|
||
return new MessageAccountKeys(this.staticAccountKeys);
|
||
}
|
||
static compile(args) {
|
||
const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey);
|
||
const [header, staticAccountKeys] = compiledKeys.getMessageComponents();
|
||
const accountKeys = new MessageAccountKeys(staticAccountKeys);
|
||
const instructions = accountKeys.compileInstructions(args.instructions).map(ix => ({
|
||
programIdIndex: ix.programIdIndex,
|
||
accounts: ix.accountKeyIndexes,
|
||
data: bs58$1.encode(ix.data)
|
||
}));
|
||
return new Message({
|
||
header,
|
||
accountKeys: staticAccountKeys,
|
||
recentBlockhash: args.recentBlockhash,
|
||
instructions
|
||
});
|
||
}
|
||
isAccountSigner(index) {
|
||
return index < this.header.numRequiredSignatures;
|
||
}
|
||
isAccountWritable(index) {
|
||
const numSignedAccounts = this.header.numRequiredSignatures;
|
||
if (index >= this.header.numRequiredSignatures) {
|
||
const unsignedAccountIndex = index - numSignedAccounts;
|
||
const numUnsignedAccounts = this.accountKeys.length - numSignedAccounts;
|
||
const numWritableUnsignedAccounts = numUnsignedAccounts - this.header.numReadonlyUnsignedAccounts;
|
||
return unsignedAccountIndex < numWritableUnsignedAccounts;
|
||
} else {
|
||
const numWritableSignedAccounts = numSignedAccounts - this.header.numReadonlySignedAccounts;
|
||
return index < numWritableSignedAccounts;
|
||
}
|
||
}
|
||
isProgramId(index) {
|
||
return this.indexToProgramIds.has(index);
|
||
}
|
||
programIds() {
|
||
return [...this.indexToProgramIds.values()];
|
||
}
|
||
nonProgramIds() {
|
||
return this.accountKeys.filter((_, index) => !this.isProgramId(index));
|
||
}
|
||
serialize() {
|
||
const numKeys = this.accountKeys.length;
|
||
let keyCount = [];
|
||
encodeLength(keyCount, numKeys);
|
||
const instructions = this.instructions.map(instruction => {
|
||
const {
|
||
accounts,
|
||
programIdIndex
|
||
} = instruction;
|
||
const data = Array.from(bs58$1.decode(instruction.data));
|
||
let keyIndicesCount = [];
|
||
encodeLength(keyIndicesCount, accounts.length);
|
||
let dataCount = [];
|
||
encodeLength(dataCount, data.length);
|
||
return {
|
||
programIdIndex,
|
||
keyIndicesCount: buffer.Buffer.from(keyIndicesCount),
|
||
keyIndices: accounts,
|
||
dataLength: buffer.Buffer.from(dataCount),
|
||
data
|
||
};
|
||
});
|
||
let instructionCount = [];
|
||
encodeLength(instructionCount, instructions.length);
|
||
let instructionBuffer = buffer.Buffer.alloc(PACKET_DATA_SIZE);
|
||
buffer.Buffer.from(instructionCount).copy(instructionBuffer);
|
||
let instructionBufferLength = instructionCount.length;
|
||
instructions.forEach(instruction => {
|
||
const instructionLayout = struct([u8('programIdIndex'), blob(instruction.keyIndicesCount.length, 'keyIndicesCount'), seq(u8('keyIndex'), instruction.keyIndices.length, 'keyIndices'), blob(instruction.dataLength.length, 'dataLength'), seq(u8('userdatum'), instruction.data.length, 'data')]);
|
||
const length = instructionLayout.encode(instruction, instructionBuffer, instructionBufferLength);
|
||
instructionBufferLength += length;
|
||
});
|
||
instructionBuffer = instructionBuffer.slice(0, instructionBufferLength);
|
||
const signDataLayout = struct([blob(1, 'numRequiredSignatures'), blob(1, 'numReadonlySignedAccounts'), blob(1, 'numReadonlyUnsignedAccounts'), blob(keyCount.length, 'keyCount'), seq(publicKey('key'), numKeys, 'keys'), publicKey('recentBlockhash')]);
|
||
const transaction = {
|
||
numRequiredSignatures: buffer.Buffer.from([this.header.numRequiredSignatures]),
|
||
numReadonlySignedAccounts: buffer.Buffer.from([this.header.numReadonlySignedAccounts]),
|
||
numReadonlyUnsignedAccounts: buffer.Buffer.from([this.header.numReadonlyUnsignedAccounts]),
|
||
keyCount: buffer.Buffer.from(keyCount),
|
||
keys: this.accountKeys.map(key => toBuffer(key.toBytes())),
|
||
recentBlockhash: bs58$1.decode(this.recentBlockhash)
|
||
};
|
||
let signData = buffer.Buffer.alloc(2048);
|
||
const length = signDataLayout.encode(transaction, signData);
|
||
instructionBuffer.copy(signData, length);
|
||
return signData.slice(0, length + instructionBuffer.length);
|
||
}
|
||
|
||
/**
|
||
* Decode a compiled message into a Message object.
|
||
*/
|
||
static from(buffer$1) {
|
||
// Slice up wire data
|
||
let byteArray = [...buffer$1];
|
||
const numRequiredSignatures = guardedShift(byteArray);
|
||
if (numRequiredSignatures !== (numRequiredSignatures & VERSION_PREFIX_MASK)) {
|
||
throw new Error('Versioned messages must be deserialized with VersionedMessage.deserialize()');
|
||
}
|
||
const numReadonlySignedAccounts = guardedShift(byteArray);
|
||
const numReadonlyUnsignedAccounts = guardedShift(byteArray);
|
||
const accountCount = decodeLength(byteArray);
|
||
let accountKeys = [];
|
||
for (let i = 0; i < accountCount; i++) {
|
||
const account = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH);
|
||
accountKeys.push(new PublicKey(buffer.Buffer.from(account)));
|
||
}
|
||
const recentBlockhash = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH);
|
||
const instructionCount = decodeLength(byteArray);
|
||
let instructions = [];
|
||
for (let i = 0; i < instructionCount; i++) {
|
||
const programIdIndex = guardedShift(byteArray);
|
||
const accountCount = decodeLength(byteArray);
|
||
const accounts = guardedSplice(byteArray, 0, accountCount);
|
||
const dataLength = decodeLength(byteArray);
|
||
const dataSlice = guardedSplice(byteArray, 0, dataLength);
|
||
const data = bs58$1.encode(buffer.Buffer.from(dataSlice));
|
||
instructions.push({
|
||
programIdIndex,
|
||
accounts,
|
||
data
|
||
});
|
||
}
|
||
const messageArgs = {
|
||
header: {
|
||
numRequiredSignatures,
|
||
numReadonlySignedAccounts,
|
||
numReadonlyUnsignedAccounts
|
||
},
|
||
recentBlockhash: bs58$1.encode(buffer.Buffer.from(recentBlockhash)),
|
||
accountKeys,
|
||
instructions
|
||
};
|
||
return new Message(messageArgs);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Message constructor arguments
|
||
*/
|
||
|
||
class MessageV0 {
|
||
constructor(args) {
|
||
this.header = void 0;
|
||
this.staticAccountKeys = void 0;
|
||
this.recentBlockhash = void 0;
|
||
this.compiledInstructions = void 0;
|
||
this.addressTableLookups = void 0;
|
||
this.header = args.header;
|
||
this.staticAccountKeys = args.staticAccountKeys;
|
||
this.recentBlockhash = args.recentBlockhash;
|
||
this.compiledInstructions = args.compiledInstructions;
|
||
this.addressTableLookups = args.addressTableLookups;
|
||
}
|
||
get version() {
|
||
return 0;
|
||
}
|
||
get numAccountKeysFromLookups() {
|
||
let count = 0;
|
||
for (const lookup of this.addressTableLookups) {
|
||
count += lookup.readonlyIndexes.length + lookup.writableIndexes.length;
|
||
}
|
||
return count;
|
||
}
|
||
getAccountKeys(args) {
|
||
let accountKeysFromLookups;
|
||
if (args && 'accountKeysFromLookups' in args && args.accountKeysFromLookups) {
|
||
if (this.numAccountKeysFromLookups != args.accountKeysFromLookups.writable.length + args.accountKeysFromLookups.readonly.length) {
|
||
throw new Error('Failed to get account keys because of a mismatch in the number of account keys from lookups');
|
||
}
|
||
accountKeysFromLookups = args.accountKeysFromLookups;
|
||
} else if (args && 'addressLookupTableAccounts' in args && args.addressLookupTableAccounts) {
|
||
accountKeysFromLookups = this.resolveAddressTableLookups(args.addressLookupTableAccounts);
|
||
} else if (this.addressTableLookups.length > 0) {
|
||
throw new Error('Failed to get account keys because address table lookups were not resolved');
|
||
}
|
||
return new MessageAccountKeys(this.staticAccountKeys, accountKeysFromLookups);
|
||
}
|
||
isAccountSigner(index) {
|
||
return index < this.header.numRequiredSignatures;
|
||
}
|
||
isAccountWritable(index) {
|
||
const numSignedAccounts = this.header.numRequiredSignatures;
|
||
const numStaticAccountKeys = this.staticAccountKeys.length;
|
||
if (index >= numStaticAccountKeys) {
|
||
const lookupAccountKeysIndex = index - numStaticAccountKeys;
|
||
const numWritableLookupAccountKeys = this.addressTableLookups.reduce((count, lookup) => count + lookup.writableIndexes.length, 0);
|
||
return lookupAccountKeysIndex < numWritableLookupAccountKeys;
|
||
} else if (index >= this.header.numRequiredSignatures) {
|
||
const unsignedAccountIndex = index - numSignedAccounts;
|
||
const numUnsignedAccounts = numStaticAccountKeys - numSignedAccounts;
|
||
const numWritableUnsignedAccounts = numUnsignedAccounts - this.header.numReadonlyUnsignedAccounts;
|
||
return unsignedAccountIndex < numWritableUnsignedAccounts;
|
||
} else {
|
||
const numWritableSignedAccounts = numSignedAccounts - this.header.numReadonlySignedAccounts;
|
||
return index < numWritableSignedAccounts;
|
||
}
|
||
}
|
||
resolveAddressTableLookups(addressLookupTableAccounts) {
|
||
const accountKeysFromLookups = {
|
||
writable: [],
|
||
readonly: []
|
||
};
|
||
for (const tableLookup of this.addressTableLookups) {
|
||
const tableAccount = addressLookupTableAccounts.find(account => account.key.equals(tableLookup.accountKey));
|
||
if (!tableAccount) {
|
||
throw new Error(`Failed to find address lookup table account for table key ${tableLookup.accountKey.toBase58()}`);
|
||
}
|
||
for (const index of tableLookup.writableIndexes) {
|
||
if (index < tableAccount.state.addresses.length) {
|
||
accountKeysFromLookups.writable.push(tableAccount.state.addresses[index]);
|
||
} else {
|
||
throw new Error(`Failed to find address for index ${index} in address lookup table ${tableLookup.accountKey.toBase58()}`);
|
||
}
|
||
}
|
||
for (const index of tableLookup.readonlyIndexes) {
|
||
if (index < tableAccount.state.addresses.length) {
|
||
accountKeysFromLookups.readonly.push(tableAccount.state.addresses[index]);
|
||
} else {
|
||
throw new Error(`Failed to find address for index ${index} in address lookup table ${tableLookup.accountKey.toBase58()}`);
|
||
}
|
||
}
|
||
}
|
||
return accountKeysFromLookups;
|
||
}
|
||
static compile(args) {
|
||
const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey);
|
||
const addressTableLookups = new Array();
|
||
const accountKeysFromLookups = {
|
||
writable: new Array(),
|
||
readonly: new Array()
|
||
};
|
||
const lookupTableAccounts = args.addressLookupTableAccounts || [];
|
||
for (const lookupTable of lookupTableAccounts) {
|
||
const extractResult = compiledKeys.extractTableLookup(lookupTable);
|
||
if (extractResult !== undefined) {
|
||
const [addressTableLookup, {
|
||
writable,
|
||
readonly
|
||
}] = extractResult;
|
||
addressTableLookups.push(addressTableLookup);
|
||
accountKeysFromLookups.writable.push(...writable);
|
||
accountKeysFromLookups.readonly.push(...readonly);
|
||
}
|
||
}
|
||
const [header, staticAccountKeys] = compiledKeys.getMessageComponents();
|
||
const accountKeys = new MessageAccountKeys(staticAccountKeys, accountKeysFromLookups);
|
||
const compiledInstructions = accountKeys.compileInstructions(args.instructions);
|
||
return new MessageV0({
|
||
header,
|
||
staticAccountKeys,
|
||
recentBlockhash: args.recentBlockhash,
|
||
compiledInstructions,
|
||
addressTableLookups
|
||
});
|
||
}
|
||
serialize() {
|
||
const encodedStaticAccountKeysLength = Array();
|
||
encodeLength(encodedStaticAccountKeysLength, this.staticAccountKeys.length);
|
||
const serializedInstructions = this.serializeInstructions();
|
||
const encodedInstructionsLength = Array();
|
||
encodeLength(encodedInstructionsLength, this.compiledInstructions.length);
|
||
const serializedAddressTableLookups = this.serializeAddressTableLookups();
|
||
const encodedAddressTableLookupsLength = Array();
|
||
encodeLength(encodedAddressTableLookupsLength, this.addressTableLookups.length);
|
||
const messageLayout = struct([u8('prefix'), struct([u8('numRequiredSignatures'), u8('numReadonlySignedAccounts'), u8('numReadonlyUnsignedAccounts')], 'header'), blob(encodedStaticAccountKeysLength.length, 'staticAccountKeysLength'), seq(publicKey(), this.staticAccountKeys.length, 'staticAccountKeys'), publicKey('recentBlockhash'), blob(encodedInstructionsLength.length, 'instructionsLength'), blob(serializedInstructions.length, 'serializedInstructions'), blob(encodedAddressTableLookupsLength.length, 'addressTableLookupsLength'), blob(serializedAddressTableLookups.length, 'serializedAddressTableLookups')]);
|
||
const serializedMessage = new Uint8Array(PACKET_DATA_SIZE);
|
||
const MESSAGE_VERSION_0_PREFIX = 1 << 7;
|
||
const serializedMessageLength = messageLayout.encode({
|
||
prefix: MESSAGE_VERSION_0_PREFIX,
|
||
header: this.header,
|
||
staticAccountKeysLength: new Uint8Array(encodedStaticAccountKeysLength),
|
||
staticAccountKeys: this.staticAccountKeys.map(key => key.toBytes()),
|
||
recentBlockhash: bs58$1.decode(this.recentBlockhash),
|
||
instructionsLength: new Uint8Array(encodedInstructionsLength),
|
||
serializedInstructions,
|
||
addressTableLookupsLength: new Uint8Array(encodedAddressTableLookupsLength),
|
||
serializedAddressTableLookups
|
||
}, serializedMessage);
|
||
return serializedMessage.slice(0, serializedMessageLength);
|
||
}
|
||
serializeInstructions() {
|
||
let serializedLength = 0;
|
||
const serializedInstructions = new Uint8Array(PACKET_DATA_SIZE);
|
||
for (const instruction of this.compiledInstructions) {
|
||
const encodedAccountKeyIndexesLength = Array();
|
||
encodeLength(encodedAccountKeyIndexesLength, instruction.accountKeyIndexes.length);
|
||
const encodedDataLength = Array();
|
||
encodeLength(encodedDataLength, instruction.data.length);
|
||
const instructionLayout = struct([u8('programIdIndex'), blob(encodedAccountKeyIndexesLength.length, 'encodedAccountKeyIndexesLength'), seq(u8(), instruction.accountKeyIndexes.length, 'accountKeyIndexes'), blob(encodedDataLength.length, 'encodedDataLength'), blob(instruction.data.length, 'data')]);
|
||
serializedLength += instructionLayout.encode({
|
||
programIdIndex: instruction.programIdIndex,
|
||
encodedAccountKeyIndexesLength: new Uint8Array(encodedAccountKeyIndexesLength),
|
||
accountKeyIndexes: instruction.accountKeyIndexes,
|
||
encodedDataLength: new Uint8Array(encodedDataLength),
|
||
data: instruction.data
|
||
}, serializedInstructions, serializedLength);
|
||
}
|
||
return serializedInstructions.slice(0, serializedLength);
|
||
}
|
||
serializeAddressTableLookups() {
|
||
let serializedLength = 0;
|
||
const serializedAddressTableLookups = new Uint8Array(PACKET_DATA_SIZE);
|
||
for (const lookup of this.addressTableLookups) {
|
||
const encodedWritableIndexesLength = Array();
|
||
encodeLength(encodedWritableIndexesLength, lookup.writableIndexes.length);
|
||
const encodedReadonlyIndexesLength = Array();
|
||
encodeLength(encodedReadonlyIndexesLength, lookup.readonlyIndexes.length);
|
||
const addressTableLookupLayout = struct([publicKey('accountKey'), blob(encodedWritableIndexesLength.length, 'encodedWritableIndexesLength'), seq(u8(), lookup.writableIndexes.length, 'writableIndexes'), blob(encodedReadonlyIndexesLength.length, 'encodedReadonlyIndexesLength'), seq(u8(), lookup.readonlyIndexes.length, 'readonlyIndexes')]);
|
||
serializedLength += addressTableLookupLayout.encode({
|
||
accountKey: lookup.accountKey.toBytes(),
|
||
encodedWritableIndexesLength: new Uint8Array(encodedWritableIndexesLength),
|
||
writableIndexes: lookup.writableIndexes,
|
||
encodedReadonlyIndexesLength: new Uint8Array(encodedReadonlyIndexesLength),
|
||
readonlyIndexes: lookup.readonlyIndexes
|
||
}, serializedAddressTableLookups, serializedLength);
|
||
}
|
||
return serializedAddressTableLookups.slice(0, serializedLength);
|
||
}
|
||
static deserialize(serializedMessage) {
|
||
let byteArray = [...serializedMessage];
|
||
const prefix = guardedShift(byteArray);
|
||
const maskedPrefix = prefix & VERSION_PREFIX_MASK;
|
||
assert$1(prefix !== maskedPrefix, `Expected versioned message but received legacy message`);
|
||
const version = maskedPrefix;
|
||
assert$1(version === 0, `Expected versioned message with version 0 but found version ${version}`);
|
||
const header = {
|
||
numRequiredSignatures: guardedShift(byteArray),
|
||
numReadonlySignedAccounts: guardedShift(byteArray),
|
||
numReadonlyUnsignedAccounts: guardedShift(byteArray)
|
||
};
|
||
const staticAccountKeys = [];
|
||
const staticAccountKeysLength = decodeLength(byteArray);
|
||
for (let i = 0; i < staticAccountKeysLength; i++) {
|
||
staticAccountKeys.push(new PublicKey(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH)));
|
||
}
|
||
const recentBlockhash = bs58$1.encode(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
|
||
const instructionCount = decodeLength(byteArray);
|
||
const compiledInstructions = [];
|
||
for (let i = 0; i < instructionCount; i++) {
|
||
const programIdIndex = guardedShift(byteArray);
|
||
const accountKeyIndexesLength = decodeLength(byteArray);
|
||
const accountKeyIndexes = guardedSplice(byteArray, 0, accountKeyIndexesLength);
|
||
const dataLength = decodeLength(byteArray);
|
||
const data = new Uint8Array(guardedSplice(byteArray, 0, dataLength));
|
||
compiledInstructions.push({
|
||
programIdIndex,
|
||
accountKeyIndexes,
|
||
data
|
||
});
|
||
}
|
||
const addressTableLookupsCount = decodeLength(byteArray);
|
||
const addressTableLookups = [];
|
||
for (let i = 0; i < addressTableLookupsCount; i++) {
|
||
const accountKey = new PublicKey(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
|
||
const writableIndexesLength = decodeLength(byteArray);
|
||
const writableIndexes = guardedSplice(byteArray, 0, writableIndexesLength);
|
||
const readonlyIndexesLength = decodeLength(byteArray);
|
||
const readonlyIndexes = guardedSplice(byteArray, 0, readonlyIndexesLength);
|
||
addressTableLookups.push({
|
||
accountKey,
|
||
writableIndexes,
|
||
readonlyIndexes
|
||
});
|
||
}
|
||
return new MessageV0({
|
||
header,
|
||
staticAccountKeys,
|
||
recentBlockhash,
|
||
compiledInstructions,
|
||
addressTableLookups
|
||
});
|
||
}
|
||
}
|
||
|
||
// eslint-disable-next-line no-redeclare
|
||
const VersionedMessage = {
|
||
deserializeMessageVersion(serializedMessage) {
|
||
const prefix = serializedMessage[0];
|
||
const maskedPrefix = prefix & VERSION_PREFIX_MASK;
|
||
|
||
// if the highest bit of the prefix is not set, the message is not versioned
|
||
if (maskedPrefix === prefix) {
|
||
return 'legacy';
|
||
}
|
||
|
||
// the lower 7 bits of the prefix indicate the message version
|
||
return maskedPrefix;
|
||
},
|
||
deserialize: serializedMessage => {
|
||
const version = VersionedMessage.deserializeMessageVersion(serializedMessage);
|
||
if (version === 'legacy') {
|
||
return Message.from(serializedMessage);
|
||
}
|
||
if (version === 0) {
|
||
return MessageV0.deserialize(serializedMessage);
|
||
} else {
|
||
throw new Error(`Transaction message version ${version} deserialization is not supported`);
|
||
}
|
||
}
|
||
};
|
||
|
||
/** @internal */
|
||
|
||
/**
|
||
* Transaction signature as base-58 encoded string
|
||
*/
|
||
|
||
let TransactionStatus = /*#__PURE__*/function (TransactionStatus) {
|
||
TransactionStatus[TransactionStatus["BLOCKHEIGHT_EXCEEDED"] = 0] = "BLOCKHEIGHT_EXCEEDED";
|
||
TransactionStatus[TransactionStatus["PROCESSED"] = 1] = "PROCESSED";
|
||
TransactionStatus[TransactionStatus["TIMED_OUT"] = 2] = "TIMED_OUT";
|
||
TransactionStatus[TransactionStatus["NONCE_INVALID"] = 3] = "NONCE_INVALID";
|
||
return TransactionStatus;
|
||
}({});
|
||
|
||
/**
|
||
* Default (empty) signature
|
||
*/
|
||
const DEFAULT_SIGNATURE = buffer.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
|
||
|
||
/**
|
||
* Account metadata used to define instructions
|
||
*/
|
||
|
||
/**
|
||
* List of TransactionInstruction object fields that may be initialized at construction
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for Transaction.serialize()
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
|
||
/**
|
||
* Transaction Instruction class
|
||
*/
|
||
class TransactionInstruction {
|
||
constructor(opts) {
|
||
/**
|
||
* Public keys to include in this transaction
|
||
* Boolean represents whether this pubkey needs to sign the transaction
|
||
*/
|
||
this.keys = void 0;
|
||
/**
|
||
* Program Id to execute
|
||
*/
|
||
this.programId = void 0;
|
||
/**
|
||
* Program input
|
||
*/
|
||
this.data = buffer.Buffer.alloc(0);
|
||
this.programId = opts.programId;
|
||
this.keys = opts.keys;
|
||
if (opts.data) {
|
||
this.data = opts.data;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
toJSON() {
|
||
return {
|
||
keys: this.keys.map(({
|
||
pubkey,
|
||
isSigner,
|
||
isWritable
|
||
}) => ({
|
||
pubkey: pubkey.toJSON(),
|
||
isSigner,
|
||
isWritable
|
||
})),
|
||
programId: this.programId.toJSON(),
|
||
data: [...this.data]
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Pair of signature and corresponding public key
|
||
*/
|
||
|
||
/**
|
||
* List of Transaction object fields that may be initialized at construction
|
||
*/
|
||
|
||
// For backward compatibility; an unfortunate consequence of being
|
||
// forced to over-export types by the documentation generator.
|
||
// See https://github.com/solana-labs/solana/pull/25820
|
||
|
||
/**
|
||
* Blockhash-based transactions have a lifetime that are defined by
|
||
* the blockhash they include. Any transaction whose blockhash is
|
||
* too old will be rejected.
|
||
*/
|
||
|
||
/**
|
||
* Use these options to construct a durable nonce transaction.
|
||
*/
|
||
|
||
/**
|
||
* Nonce information to be used to build an offline Transaction.
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
|
||
/**
|
||
* Transaction class
|
||
*/
|
||
class Transaction {
|
||
/**
|
||
* The first (payer) Transaction signature
|
||
*
|
||
* @returns {Buffer | null} Buffer of payer's signature
|
||
*/
|
||
get signature() {
|
||
if (this.signatures.length > 0) {
|
||
return this.signatures[0].signature;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* The transaction fee payer
|
||
*/
|
||
|
||
// Construct a transaction with a blockhash and lastValidBlockHeight
|
||
|
||
// Construct a transaction using a durable nonce
|
||
|
||
/**
|
||
* @deprecated `TransactionCtorFields` has been deprecated and will be removed in a future version.
|
||
* Please supply a `TransactionBlockhashCtor` instead.
|
||
*/
|
||
|
||
/**
|
||
* Construct an empty Transaction
|
||
*/
|
||
constructor(opts) {
|
||
/**
|
||
* Signatures for the transaction. Typically created by invoking the
|
||
* `sign()` method
|
||
*/
|
||
this.signatures = [];
|
||
this.feePayer = void 0;
|
||
/**
|
||
* The instructions to atomically execute
|
||
*/
|
||
this.instructions = [];
|
||
/**
|
||
* A recent transaction id. Must be populated by the caller
|
||
*/
|
||
this.recentBlockhash = void 0;
|
||
/**
|
||
* the last block chain can advance to before tx is declared expired
|
||
* */
|
||
this.lastValidBlockHeight = void 0;
|
||
/**
|
||
* Optional Nonce information. If populated, transaction will use a durable
|
||
* Nonce hash instead of a recentBlockhash. Must be populated by the caller
|
||
*/
|
||
this.nonceInfo = void 0;
|
||
/**
|
||
* If this is a nonce transaction this represents the minimum slot from which
|
||
* to evaluate if the nonce has advanced when attempting to confirm the
|
||
* transaction. This protects against a case where the transaction confirmation
|
||
* logic loads the nonce account from an old slot and assumes the mismatch in
|
||
* nonce value implies that the nonce has been advanced.
|
||
*/
|
||
this.minNonceContextSlot = void 0;
|
||
/**
|
||
* @internal
|
||
*/
|
||
this._message = void 0;
|
||
/**
|
||
* @internal
|
||
*/
|
||
this._json = void 0;
|
||
if (!opts) {
|
||
return;
|
||
}
|
||
if (opts.feePayer) {
|
||
this.feePayer = opts.feePayer;
|
||
}
|
||
if (opts.signatures) {
|
||
this.signatures = opts.signatures;
|
||
}
|
||
if (Object.prototype.hasOwnProperty.call(opts, 'nonceInfo')) {
|
||
const {
|
||
minContextSlot,
|
||
nonceInfo
|
||
} = opts;
|
||
this.minNonceContextSlot = minContextSlot;
|
||
this.nonceInfo = nonceInfo;
|
||
} else if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
|
||
const {
|
||
blockhash,
|
||
lastValidBlockHeight
|
||
} = opts;
|
||
this.recentBlockhash = blockhash;
|
||
this.lastValidBlockHeight = lastValidBlockHeight;
|
||
} else {
|
||
const {
|
||
recentBlockhash,
|
||
nonceInfo
|
||
} = opts;
|
||
if (nonceInfo) {
|
||
this.nonceInfo = nonceInfo;
|
||
}
|
||
this.recentBlockhash = recentBlockhash;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
toJSON() {
|
||
return {
|
||
recentBlockhash: this.recentBlockhash || null,
|
||
feePayer: this.feePayer ? this.feePayer.toJSON() : null,
|
||
nonceInfo: this.nonceInfo ? {
|
||
nonce: this.nonceInfo.nonce,
|
||
nonceInstruction: this.nonceInfo.nonceInstruction.toJSON()
|
||
} : null,
|
||
instructions: this.instructions.map(instruction => instruction.toJSON()),
|
||
signers: this.signatures.map(({
|
||
publicKey
|
||
}) => {
|
||
return publicKey.toJSON();
|
||
})
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Add one or more instructions to this Transaction
|
||
*
|
||
* @param {Array< Transaction | TransactionInstruction | TransactionInstructionCtorFields >} items - Instructions to add to the Transaction
|
||
*/
|
||
add(...items) {
|
||
if (items.length === 0) {
|
||
throw new Error('No instructions');
|
||
}
|
||
items.forEach(item => {
|
||
if ('instructions' in item) {
|
||
this.instructions = this.instructions.concat(item.instructions);
|
||
} else if ('data' in item && 'programId' in item && 'keys' in item) {
|
||
this.instructions.push(item);
|
||
} else {
|
||
this.instructions.push(new TransactionInstruction(item));
|
||
}
|
||
});
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Compile transaction data
|
||
*/
|
||
compileMessage() {
|
||
if (this._message && JSON.stringify(this.toJSON()) === JSON.stringify(this._json)) {
|
||
return this._message;
|
||
}
|
||
let recentBlockhash;
|
||
let instructions;
|
||
if (this.nonceInfo) {
|
||
recentBlockhash = this.nonceInfo.nonce;
|
||
if (this.instructions[0] != this.nonceInfo.nonceInstruction) {
|
||
instructions = [this.nonceInfo.nonceInstruction, ...this.instructions];
|
||
} else {
|
||
instructions = this.instructions;
|
||
}
|
||
} else {
|
||
recentBlockhash = this.recentBlockhash;
|
||
instructions = this.instructions;
|
||
}
|
||
if (!recentBlockhash) {
|
||
throw new Error('Transaction recentBlockhash required');
|
||
}
|
||
if (instructions.length < 1) {
|
||
console.warn('No instructions provided');
|
||
}
|
||
let feePayer;
|
||
if (this.feePayer) {
|
||
feePayer = this.feePayer;
|
||
} else if (this.signatures.length > 0 && this.signatures[0].publicKey) {
|
||
// Use implicit fee payer
|
||
feePayer = this.signatures[0].publicKey;
|
||
} else {
|
||
throw new Error('Transaction fee payer required');
|
||
}
|
||
for (let i = 0; i < instructions.length; i++) {
|
||
if (instructions[i].programId === undefined) {
|
||
throw new Error(`Transaction instruction index ${i} has undefined program id`);
|
||
}
|
||
}
|
||
const programIds = [];
|
||
const accountMetas = [];
|
||
instructions.forEach(instruction => {
|
||
instruction.keys.forEach(accountMeta => {
|
||
accountMetas.push({
|
||
...accountMeta
|
||
});
|
||
});
|
||
const programId = instruction.programId.toString();
|
||
if (!programIds.includes(programId)) {
|
||
programIds.push(programId);
|
||
}
|
||
});
|
||
|
||
// Append programID account metas
|
||
programIds.forEach(programId => {
|
||
accountMetas.push({
|
||
pubkey: new PublicKey(programId),
|
||
isSigner: false,
|
||
isWritable: false
|
||
});
|
||
});
|
||
|
||
// Cull duplicate account metas
|
||
const uniqueMetas = [];
|
||
accountMetas.forEach(accountMeta => {
|
||
const pubkeyString = accountMeta.pubkey.toString();
|
||
const uniqueIndex = uniqueMetas.findIndex(x => {
|
||
return x.pubkey.toString() === pubkeyString;
|
||
});
|
||
if (uniqueIndex > -1) {
|
||
uniqueMetas[uniqueIndex].isWritable = uniqueMetas[uniqueIndex].isWritable || accountMeta.isWritable;
|
||
uniqueMetas[uniqueIndex].isSigner = uniqueMetas[uniqueIndex].isSigner || accountMeta.isSigner;
|
||
} else {
|
||
uniqueMetas.push(accountMeta);
|
||
}
|
||
});
|
||
|
||
// Sort. Prioritizing first by signer, then by writable
|
||
uniqueMetas.sort(function (x, y) {
|
||
if (x.isSigner !== y.isSigner) {
|
||
// Signers always come before non-signers
|
||
return x.isSigner ? -1 : 1;
|
||
}
|
||
if (x.isWritable !== y.isWritable) {
|
||
// Writable accounts always come before read-only accounts
|
||
return x.isWritable ? -1 : 1;
|
||
}
|
||
// Otherwise, sort by pubkey, stringwise.
|
||
const options = {
|
||
localeMatcher: 'best fit',
|
||
usage: 'sort',
|
||
sensitivity: 'variant',
|
||
ignorePunctuation: false,
|
||
numeric: false,
|
||
caseFirst: 'lower'
|
||
};
|
||
return x.pubkey.toBase58().localeCompare(y.pubkey.toBase58(), 'en', options);
|
||
});
|
||
|
||
// Move fee payer to the front
|
||
const feePayerIndex = uniqueMetas.findIndex(x => {
|
||
return x.pubkey.equals(feePayer);
|
||
});
|
||
if (feePayerIndex > -1) {
|
||
const [payerMeta] = uniqueMetas.splice(feePayerIndex, 1);
|
||
payerMeta.isSigner = true;
|
||
payerMeta.isWritable = true;
|
||
uniqueMetas.unshift(payerMeta);
|
||
} else {
|
||
uniqueMetas.unshift({
|
||
pubkey: feePayer,
|
||
isSigner: true,
|
||
isWritable: true
|
||
});
|
||
}
|
||
|
||
// Disallow unknown signers
|
||
for (const signature of this.signatures) {
|
||
const uniqueIndex = uniqueMetas.findIndex(x => {
|
||
return x.pubkey.equals(signature.publicKey);
|
||
});
|
||
if (uniqueIndex > -1) {
|
||
if (!uniqueMetas[uniqueIndex].isSigner) {
|
||
uniqueMetas[uniqueIndex].isSigner = true;
|
||
console.warn('Transaction references a signature that is unnecessary, ' + 'only the fee payer and instruction signer accounts should sign a transaction. ' + 'This behavior is deprecated and will throw an error in the next major version release.');
|
||
}
|
||
} else {
|
||
throw new Error(`unknown signer: ${signature.publicKey.toString()}`);
|
||
}
|
||
}
|
||
let numRequiredSignatures = 0;
|
||
let numReadonlySignedAccounts = 0;
|
||
let numReadonlyUnsignedAccounts = 0;
|
||
|
||
// Split out signing from non-signing keys and count header values
|
||
const signedKeys = [];
|
||
const unsignedKeys = [];
|
||
uniqueMetas.forEach(({
|
||
pubkey,
|
||
isSigner,
|
||
isWritable
|
||
}) => {
|
||
if (isSigner) {
|
||
signedKeys.push(pubkey.toString());
|
||
numRequiredSignatures += 1;
|
||
if (!isWritable) {
|
||
numReadonlySignedAccounts += 1;
|
||
}
|
||
} else {
|
||
unsignedKeys.push(pubkey.toString());
|
||
if (!isWritable) {
|
||
numReadonlyUnsignedAccounts += 1;
|
||
}
|
||
}
|
||
});
|
||
const accountKeys = signedKeys.concat(unsignedKeys);
|
||
const compiledInstructions = instructions.map(instruction => {
|
||
const {
|
||
data,
|
||
programId
|
||
} = instruction;
|
||
return {
|
||
programIdIndex: accountKeys.indexOf(programId.toString()),
|
||
accounts: instruction.keys.map(meta => accountKeys.indexOf(meta.pubkey.toString())),
|
||
data: bs58$1.encode(data)
|
||
};
|
||
});
|
||
compiledInstructions.forEach(instruction => {
|
||
assert$1(instruction.programIdIndex >= 0);
|
||
instruction.accounts.forEach(keyIndex => assert$1(keyIndex >= 0));
|
||
});
|
||
return new Message({
|
||
header: {
|
||
numRequiredSignatures,
|
||
numReadonlySignedAccounts,
|
||
numReadonlyUnsignedAccounts
|
||
},
|
||
accountKeys,
|
||
recentBlockhash,
|
||
instructions: compiledInstructions
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_compile() {
|
||
const message = this.compileMessage();
|
||
const signedKeys = message.accountKeys.slice(0, message.header.numRequiredSignatures);
|
||
if (this.signatures.length === signedKeys.length) {
|
||
const valid = this.signatures.every((pair, index) => {
|
||
return signedKeys[index].equals(pair.publicKey);
|
||
});
|
||
if (valid) return message;
|
||
}
|
||
this.signatures = signedKeys.map(publicKey => ({
|
||
signature: null,
|
||
publicKey
|
||
}));
|
||
return message;
|
||
}
|
||
|
||
/**
|
||
* Get a buffer of the Transaction data that need to be covered by signatures
|
||
*/
|
||
serializeMessage() {
|
||
return this._compile().serialize();
|
||
}
|
||
|
||
/**
|
||
* Get the estimated fee associated with a transaction
|
||
*
|
||
* @param {Connection} connection Connection to RPC Endpoint.
|
||
*
|
||
* @returns {Promise<number | null>} The estimated fee for the transaction
|
||
*/
|
||
async getEstimatedFee(connection) {
|
||
return (await connection.getFeeForMessage(this.compileMessage())).value;
|
||
}
|
||
|
||
/**
|
||
* Specify the public keys which will be used to sign the Transaction.
|
||
* The first signer will be used as the transaction fee payer account.
|
||
*
|
||
* Signatures can be added with either `partialSign` or `addSignature`
|
||
*
|
||
* @deprecated Deprecated since v0.84.0. Only the fee payer needs to be
|
||
* specified and it can be set in the Transaction constructor or with the
|
||
* `feePayer` property.
|
||
*/
|
||
setSigners(...signers) {
|
||
if (signers.length === 0) {
|
||
throw new Error('No signers');
|
||
}
|
||
const seen = new Set();
|
||
this.signatures = signers.filter(publicKey => {
|
||
const key = publicKey.toString();
|
||
if (seen.has(key)) {
|
||
return false;
|
||
} else {
|
||
seen.add(key);
|
||
return true;
|
||
}
|
||
}).map(publicKey => ({
|
||
signature: null,
|
||
publicKey
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* Sign the Transaction with the specified signers. Multiple signatures may
|
||
* be applied to a Transaction. The first signature is considered "primary"
|
||
* and is used identify and confirm transactions.
|
||
*
|
||
* If the Transaction `feePayer` is not set, the first signer will be used
|
||
* as the transaction fee payer account.
|
||
*
|
||
* Transaction fields should not be modified after the first call to `sign`,
|
||
* as doing so may invalidate the signature and cause the Transaction to be
|
||
* rejected.
|
||
*
|
||
* The Transaction must be assigned a valid `recentBlockhash` before invoking this method
|
||
*
|
||
* @param {Array<Signer>} signers Array of signers that will sign the transaction
|
||
*/
|
||
sign(...signers) {
|
||
if (signers.length === 0) {
|
||
throw new Error('No signers');
|
||
}
|
||
|
||
// Dedupe signers
|
||
const seen = new Set();
|
||
const uniqueSigners = [];
|
||
for (const signer of signers) {
|
||
const key = signer.publicKey.toString();
|
||
if (seen.has(key)) {
|
||
continue;
|
||
} else {
|
||
seen.add(key);
|
||
uniqueSigners.push(signer);
|
||
}
|
||
}
|
||
this.signatures = uniqueSigners.map(signer => ({
|
||
signature: null,
|
||
publicKey: signer.publicKey
|
||
}));
|
||
const message = this._compile();
|
||
this._partialSign(message, ...uniqueSigners);
|
||
}
|
||
|
||
/**
|
||
* Partially sign a transaction with the specified accounts. All accounts must
|
||
* correspond to either the fee payer or a signer account in the transaction
|
||
* instructions.
|
||
*
|
||
* All the caveats from the `sign` method apply to `partialSign`
|
||
*
|
||
* @param {Array<Signer>} signers Array of signers that will sign the transaction
|
||
*/
|
||
partialSign(...signers) {
|
||
if (signers.length === 0) {
|
||
throw new Error('No signers');
|
||
}
|
||
|
||
// Dedupe signers
|
||
const seen = new Set();
|
||
const uniqueSigners = [];
|
||
for (const signer of signers) {
|
||
const key = signer.publicKey.toString();
|
||
if (seen.has(key)) {
|
||
continue;
|
||
} else {
|
||
seen.add(key);
|
||
uniqueSigners.push(signer);
|
||
}
|
||
}
|
||
const message = this._compile();
|
||
this._partialSign(message, ...uniqueSigners);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_partialSign(message, ...signers) {
|
||
const signData = message.serialize();
|
||
signers.forEach(signer => {
|
||
const signature = sign(signData, signer.secretKey);
|
||
this._addSignature(signer.publicKey, toBuffer(signature));
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Add an externally created signature to a transaction. The public key
|
||
* must correspond to either the fee payer or a signer account in the transaction
|
||
* instructions.
|
||
*
|
||
* @param {PublicKey} pubkey Public key that will be added to the transaction.
|
||
* @param {Buffer} signature An externally created signature to add to the transaction.
|
||
*/
|
||
addSignature(pubkey, signature) {
|
||
this._compile(); // Ensure signatures array is populated
|
||
this._addSignature(pubkey, signature);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_addSignature(pubkey, signature) {
|
||
assert$1(signature.length === 64);
|
||
const index = this.signatures.findIndex(sigpair => pubkey.equals(sigpair.publicKey));
|
||
if (index < 0) {
|
||
throw new Error(`unknown signer: ${pubkey.toString()}`);
|
||
}
|
||
this.signatures[index].signature = buffer.Buffer.from(signature);
|
||
}
|
||
|
||
/**
|
||
* Verify signatures of a Transaction
|
||
* Optional parameter specifies if we're expecting a fully signed Transaction or a partially signed one.
|
||
* If no boolean is provided, we expect a fully signed Transaction by default.
|
||
*
|
||
* @param {boolean} [requireAllSignatures=true] Require a fully signed Transaction
|
||
*/
|
||
verifySignatures(requireAllSignatures = true) {
|
||
const signatureErrors = this._getMessageSignednessErrors(this.serializeMessage(), requireAllSignatures);
|
||
return !signatureErrors;
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_getMessageSignednessErrors(message, requireAllSignatures) {
|
||
const errors = {};
|
||
for (const {
|
||
signature,
|
||
publicKey
|
||
} of this.signatures) {
|
||
if (signature === null) {
|
||
if (requireAllSignatures) {
|
||
(errors.missing ||= []).push(publicKey);
|
||
}
|
||
} else {
|
||
if (!verify(signature, message, publicKey.toBytes())) {
|
||
(errors.invalid ||= []).push(publicKey);
|
||
}
|
||
}
|
||
}
|
||
return errors.invalid || errors.missing ? errors : undefined;
|
||
}
|
||
|
||
/**
|
||
* Serialize the Transaction in the wire format.
|
||
*
|
||
* @param {Buffer} [config] Config of transaction.
|
||
*
|
||
* @returns {Buffer} Signature of transaction in wire format.
|
||
*/
|
||
serialize(config) {
|
||
const {
|
||
requireAllSignatures,
|
||
verifySignatures
|
||
} = Object.assign({
|
||
requireAllSignatures: true,
|
||
verifySignatures: true
|
||
}, config);
|
||
const signData = this.serializeMessage();
|
||
if (verifySignatures) {
|
||
const sigErrors = this._getMessageSignednessErrors(signData, requireAllSignatures);
|
||
if (sigErrors) {
|
||
let errorMessage = 'Signature verification failed.';
|
||
if (sigErrors.invalid) {
|
||
errorMessage += `\nInvalid signature for public key${sigErrors.invalid.length === 1 ? '' : '(s)'} [\`${sigErrors.invalid.map(p => p.toBase58()).join('`, `')}\`].`;
|
||
}
|
||
if (sigErrors.missing) {
|
||
errorMessage += `\nMissing signature for public key${sigErrors.missing.length === 1 ? '' : '(s)'} [\`${sigErrors.missing.map(p => p.toBase58()).join('`, `')}\`].`;
|
||
}
|
||
throw new Error(errorMessage);
|
||
}
|
||
}
|
||
return this._serialize(signData);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_serialize(signData) {
|
||
const {
|
||
signatures
|
||
} = this;
|
||
const signatureCount = [];
|
||
encodeLength(signatureCount, signatures.length);
|
||
const transactionLength = signatureCount.length + signatures.length * 64 + signData.length;
|
||
const wireTransaction = buffer.Buffer.alloc(transactionLength);
|
||
assert$1(signatures.length < 256);
|
||
buffer.Buffer.from(signatureCount).copy(wireTransaction, 0);
|
||
signatures.forEach(({
|
||
signature
|
||
}, index) => {
|
||
if (signature !== null) {
|
||
assert$1(signature.length === 64, `signature has invalid length`);
|
||
buffer.Buffer.from(signature).copy(wireTransaction, signatureCount.length + index * 64);
|
||
}
|
||
});
|
||
signData.copy(wireTransaction, signatureCount.length + signatures.length * 64);
|
||
assert$1(wireTransaction.length <= PACKET_DATA_SIZE, `Transaction too large: ${wireTransaction.length} > ${PACKET_DATA_SIZE}`);
|
||
return wireTransaction;
|
||
}
|
||
|
||
/**
|
||
* Deprecated method
|
||
* @internal
|
||
*/
|
||
get keys() {
|
||
assert$1(this.instructions.length === 1);
|
||
return this.instructions[0].keys.map(keyObj => keyObj.pubkey);
|
||
}
|
||
|
||
/**
|
||
* Deprecated method
|
||
* @internal
|
||
*/
|
||
get programId() {
|
||
assert$1(this.instructions.length === 1);
|
||
return this.instructions[0].programId;
|
||
}
|
||
|
||
/**
|
||
* Deprecated method
|
||
* @internal
|
||
*/
|
||
get data() {
|
||
assert$1(this.instructions.length === 1);
|
||
return this.instructions[0].data;
|
||
}
|
||
|
||
/**
|
||
* Parse a wire transaction into a Transaction object.
|
||
*
|
||
* @param {Buffer | Uint8Array | Array<number>} buffer Signature of wire Transaction
|
||
*
|
||
* @returns {Transaction} Transaction associated with the signature
|
||
*/
|
||
static from(buffer$1) {
|
||
// Slice up wire data
|
||
let byteArray = [...buffer$1];
|
||
const signatureCount = decodeLength(byteArray);
|
||
let signatures = [];
|
||
for (let i = 0; i < signatureCount; i++) {
|
||
const signature = guardedSplice(byteArray, 0, SIGNATURE_LENGTH_IN_BYTES);
|
||
signatures.push(bs58$1.encode(buffer.Buffer.from(signature)));
|
||
}
|
||
return Transaction.populate(Message.from(byteArray), signatures);
|
||
}
|
||
|
||
/**
|
||
* Populate Transaction object from message and signatures
|
||
*
|
||
* @param {Message} message Message of transaction
|
||
* @param {Array<string>} signatures List of signatures to assign to the transaction
|
||
*
|
||
* @returns {Transaction} The populated Transaction
|
||
*/
|
||
static populate(message, signatures = []) {
|
||
const transaction = new Transaction();
|
||
transaction.recentBlockhash = message.recentBlockhash;
|
||
if (message.header.numRequiredSignatures > 0) {
|
||
transaction.feePayer = message.accountKeys[0];
|
||
}
|
||
signatures.forEach((signature, index) => {
|
||
const sigPubkeyPair = {
|
||
signature: signature == bs58$1.encode(DEFAULT_SIGNATURE) ? null : bs58$1.decode(signature),
|
||
publicKey: message.accountKeys[index]
|
||
};
|
||
transaction.signatures.push(sigPubkeyPair);
|
||
});
|
||
message.instructions.forEach(instruction => {
|
||
const keys = instruction.accounts.map(account => {
|
||
const pubkey = message.accountKeys[account];
|
||
return {
|
||
pubkey,
|
||
isSigner: transaction.signatures.some(keyObj => keyObj.publicKey.toString() === pubkey.toString()) || message.isAccountSigner(account),
|
||
isWritable: message.isAccountWritable(account)
|
||
};
|
||
});
|
||
transaction.instructions.push(new TransactionInstruction({
|
||
keys,
|
||
programId: message.accountKeys[instruction.programIdIndex],
|
||
data: bs58$1.decode(instruction.data)
|
||
}));
|
||
});
|
||
transaction._message = message;
|
||
transaction._json = transaction.toJSON();
|
||
return transaction;
|
||
}
|
||
}
|
||
|
||
class TransactionMessage {
|
||
constructor(args) {
|
||
this.payerKey = void 0;
|
||
this.instructions = void 0;
|
||
this.recentBlockhash = void 0;
|
||
this.payerKey = args.payerKey;
|
||
this.instructions = args.instructions;
|
||
this.recentBlockhash = args.recentBlockhash;
|
||
}
|
||
static decompile(message, args) {
|
||
const {
|
||
header,
|
||
compiledInstructions,
|
||
recentBlockhash
|
||
} = message;
|
||
const {
|
||
numRequiredSignatures,
|
||
numReadonlySignedAccounts,
|
||
numReadonlyUnsignedAccounts
|
||
} = header;
|
||
const numWritableSignedAccounts = numRequiredSignatures - numReadonlySignedAccounts;
|
||
assert$1(numWritableSignedAccounts > 0, 'Message header is invalid');
|
||
const numWritableUnsignedAccounts = message.staticAccountKeys.length - numRequiredSignatures - numReadonlyUnsignedAccounts;
|
||
assert$1(numWritableUnsignedAccounts >= 0, 'Message header is invalid');
|
||
const accountKeys = message.getAccountKeys(args);
|
||
const payerKey = accountKeys.get(0);
|
||
if (payerKey === undefined) {
|
||
throw new Error('Failed to decompile message because no account keys were found');
|
||
}
|
||
const instructions = [];
|
||
for (const compiledIx of compiledInstructions) {
|
||
const keys = [];
|
||
for (const keyIndex of compiledIx.accountKeyIndexes) {
|
||
const pubkey = accountKeys.get(keyIndex);
|
||
if (pubkey === undefined) {
|
||
throw new Error(`Failed to find key for account key index ${keyIndex}`);
|
||
}
|
||
const isSigner = keyIndex < numRequiredSignatures;
|
||
let isWritable;
|
||
if (isSigner) {
|
||
isWritable = keyIndex < numWritableSignedAccounts;
|
||
} else if (keyIndex < accountKeys.staticAccountKeys.length) {
|
||
isWritable = keyIndex - numRequiredSignatures < numWritableUnsignedAccounts;
|
||
} else {
|
||
isWritable = keyIndex - accountKeys.staticAccountKeys.length <
|
||
// accountKeysFromLookups cannot be undefined because we already found a pubkey for this index above
|
||
accountKeys.accountKeysFromLookups.writable.length;
|
||
}
|
||
keys.push({
|
||
pubkey,
|
||
isSigner: keyIndex < header.numRequiredSignatures,
|
||
isWritable
|
||
});
|
||
}
|
||
const programId = accountKeys.get(compiledIx.programIdIndex);
|
||
if (programId === undefined) {
|
||
throw new Error(`Failed to find program id for program id index ${compiledIx.programIdIndex}`);
|
||
}
|
||
instructions.push(new TransactionInstruction({
|
||
programId,
|
||
data: toBuffer(compiledIx.data),
|
||
keys
|
||
}));
|
||
}
|
||
return new TransactionMessage({
|
||
payerKey,
|
||
instructions,
|
||
recentBlockhash
|
||
});
|
||
}
|
||
compileToLegacyMessage() {
|
||
return Message.compile({
|
||
payerKey: this.payerKey,
|
||
recentBlockhash: this.recentBlockhash,
|
||
instructions: this.instructions
|
||
});
|
||
}
|
||
compileToV0Message(addressLookupTableAccounts) {
|
||
return MessageV0.compile({
|
||
payerKey: this.payerKey,
|
||
recentBlockhash: this.recentBlockhash,
|
||
instructions: this.instructions,
|
||
addressLookupTableAccounts
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Versioned transaction class
|
||
*/
|
||
class VersionedTransaction {
|
||
get version() {
|
||
return this.message.version;
|
||
}
|
||
constructor(message, signatures) {
|
||
this.signatures = void 0;
|
||
this.message = void 0;
|
||
if (signatures !== undefined) {
|
||
assert$1(signatures.length === message.header.numRequiredSignatures, 'Expected signatures length to be equal to the number of required signatures');
|
||
this.signatures = signatures;
|
||
} else {
|
||
const defaultSignatures = [];
|
||
for (let i = 0; i < message.header.numRequiredSignatures; i++) {
|
||
defaultSignatures.push(new Uint8Array(SIGNATURE_LENGTH_IN_BYTES));
|
||
}
|
||
this.signatures = defaultSignatures;
|
||
}
|
||
this.message = message;
|
||
}
|
||
serialize() {
|
||
const serializedMessage = this.message.serialize();
|
||
const encodedSignaturesLength = Array();
|
||
encodeLength(encodedSignaturesLength, this.signatures.length);
|
||
const transactionLayout = struct([blob(encodedSignaturesLength.length, 'encodedSignaturesLength'), seq(signature(), this.signatures.length, 'signatures'), blob(serializedMessage.length, 'serializedMessage')]);
|
||
const serializedTransaction = new Uint8Array(2048);
|
||
const serializedTransactionLength = transactionLayout.encode({
|
||
encodedSignaturesLength: new Uint8Array(encodedSignaturesLength),
|
||
signatures: this.signatures,
|
||
serializedMessage
|
||
}, serializedTransaction);
|
||
return serializedTransaction.slice(0, serializedTransactionLength);
|
||
}
|
||
static deserialize(serializedTransaction) {
|
||
let byteArray = [...serializedTransaction];
|
||
const signatures = [];
|
||
const signaturesLength = decodeLength(byteArray);
|
||
for (let i = 0; i < signaturesLength; i++) {
|
||
signatures.push(new Uint8Array(guardedSplice(byteArray, 0, SIGNATURE_LENGTH_IN_BYTES)));
|
||
}
|
||
const message = VersionedMessage.deserialize(new Uint8Array(byteArray));
|
||
return new VersionedTransaction(message, signatures);
|
||
}
|
||
sign(signers) {
|
||
const messageData = this.message.serialize();
|
||
const signerPubkeys = this.message.staticAccountKeys.slice(0, this.message.header.numRequiredSignatures);
|
||
for (const signer of signers) {
|
||
const signerIndex = signerPubkeys.findIndex(pubkey => pubkey.equals(signer.publicKey));
|
||
assert$1(signerIndex >= 0, `Cannot sign with non signer key ${signer.publicKey.toBase58()}`);
|
||
this.signatures[signerIndex] = sign(messageData, signer.secretKey);
|
||
}
|
||
}
|
||
addSignature(publicKey, signature) {
|
||
assert$1(signature.byteLength === 64, 'Signature must be 64 bytes long');
|
||
const signerPubkeys = this.message.staticAccountKeys.slice(0, this.message.header.numRequiredSignatures);
|
||
const signerIndex = signerPubkeys.findIndex(pubkey => pubkey.equals(publicKey));
|
||
assert$1(signerIndex >= 0, `Can not add signature; \`${publicKey.toBase58()}\` is not required to sign this transaction`);
|
||
this.signatures[signerIndex] = signature;
|
||
}
|
||
}
|
||
|
||
// TODO: These constants should be removed in favor of reading them out of a
|
||
// Syscall account
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const NUM_TICKS_PER_SECOND = 160;
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const DEFAULT_TICKS_PER_SLOT = 64;
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
|
||
|
||
const SYSVAR_CLOCK_PUBKEY = new PublicKey('SysvarC1ock11111111111111111111111111111111');
|
||
const SYSVAR_EPOCH_SCHEDULE_PUBKEY = new PublicKey('SysvarEpochSchedu1e111111111111111111111111');
|
||
const SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey('Sysvar1nstructions1111111111111111111111111');
|
||
const SYSVAR_RECENT_BLOCKHASHES_PUBKEY = new PublicKey('SysvarRecentB1ockHashes11111111111111111111');
|
||
const SYSVAR_RENT_PUBKEY = new PublicKey('SysvarRent111111111111111111111111111111111');
|
||
const SYSVAR_REWARDS_PUBKEY = new PublicKey('SysvarRewards111111111111111111111111111111');
|
||
const SYSVAR_SLOT_HASHES_PUBKEY = new PublicKey('SysvarS1otHashes111111111111111111111111111');
|
||
const SYSVAR_SLOT_HISTORY_PUBKEY = new PublicKey('SysvarS1otHistory11111111111111111111111111');
|
||
const SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey('SysvarStakeHistory1111111111111111111111111');
|
||
|
||
/**
|
||
* Sign, send and confirm a transaction.
|
||
*
|
||
* If `commitment` option is not specified, defaults to 'max' commitment.
|
||
*
|
||
* @param {Connection} connection
|
||
* @param {Transaction} transaction
|
||
* @param {Array<Signer>} signers
|
||
* @param {ConfirmOptions} [options]
|
||
* @returns {Promise<TransactionSignature>}
|
||
*/
|
||
async function sendAndConfirmTransaction(connection, transaction, signers, options) {
|
||
const sendOptions = options && {
|
||
skipPreflight: options.skipPreflight,
|
||
preflightCommitment: options.preflightCommitment || options.commitment,
|
||
maxRetries: options.maxRetries,
|
||
minContextSlot: options.minContextSlot
|
||
};
|
||
const signature = await connection.sendTransaction(transaction, signers, sendOptions);
|
||
let status;
|
||
if (transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null) {
|
||
status = (await connection.confirmTransaction({
|
||
abortSignal: options?.abortSignal,
|
||
signature: signature,
|
||
blockhash: transaction.recentBlockhash,
|
||
lastValidBlockHeight: transaction.lastValidBlockHeight
|
||
}, options && options.commitment)).value;
|
||
} else if (transaction.minNonceContextSlot != null && transaction.nonceInfo != null) {
|
||
const {
|
||
nonceInstruction
|
||
} = transaction.nonceInfo;
|
||
const nonceAccountPubkey = nonceInstruction.keys[0].pubkey;
|
||
status = (await connection.confirmTransaction({
|
||
abortSignal: options?.abortSignal,
|
||
minContextSlot: transaction.minNonceContextSlot,
|
||
nonceAccountPubkey,
|
||
nonceValue: transaction.nonceInfo.nonce,
|
||
signature
|
||
}, options && options.commitment)).value;
|
||
} else {
|
||
if (options?.abortSignal != null) {
|
||
console.warn('sendAndConfirmTransaction(): A transaction with a deprecated confirmation strategy was ' + 'supplied along with an `abortSignal`. Only transactions having `lastValidBlockHeight` ' + 'or a combination of `nonceInfo` and `minNonceContextSlot` are abortable.');
|
||
}
|
||
status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
|
||
}
|
||
if (status.err) {
|
||
throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
|
||
}
|
||
return signature;
|
||
}
|
||
|
||
// zzz
|
||
function sleep(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms));
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
|
||
/**
|
||
* Populate a buffer of instruction data using an InstructionType
|
||
* @internal
|
||
*/
|
||
function encodeData(type, fields) {
|
||
const allocLength = type.layout.span >= 0 ? type.layout.span : getAlloc(type, fields);
|
||
const data = buffer.Buffer.alloc(allocLength);
|
||
const layoutFields = Object.assign({
|
||
instruction: type.index
|
||
}, fields);
|
||
type.layout.encode(layoutFields, data);
|
||
return data;
|
||
}
|
||
|
||
/**
|
||
* Decode instruction data buffer using an InstructionType
|
||
* @internal
|
||
*/
|
||
function decodeData$1(type, buffer) {
|
||
let data;
|
||
try {
|
||
data = type.layout.decode(buffer);
|
||
} catch (err) {
|
||
throw new Error('invalid instruction; ' + err);
|
||
}
|
||
if (data.instruction !== type.index) {
|
||
throw new Error(`invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`);
|
||
}
|
||
return data;
|
||
}
|
||
|
||
/**
|
||
* https://github.com/solana-labs/solana/blob/90bedd7e067b5b8f3ddbb45da00a4e9cabb22c62/sdk/src/fee_calculator.rs#L7-L11
|
||
*
|
||
* @internal
|
||
*/
|
||
const FeeCalculatorLayout = nu64('lamportsPerSignature');
|
||
|
||
/**
|
||
* Calculator for transaction fees.
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0.
|
||
*/
|
||
|
||
/**
|
||
* See https://github.com/solana-labs/solana/blob/0ea2843ec9cdc517572b8e62c959f41b55cf4453/sdk/src/nonce_state.rs#L29-L32
|
||
*
|
||
* @internal
|
||
*/
|
||
const NonceAccountLayout = struct([u32('version'), u32('state'), publicKey('authorizedPubkey'), publicKey('nonce'), struct([FeeCalculatorLayout], 'feeCalculator')]);
|
||
const NONCE_ACCOUNT_LENGTH = NonceAccountLayout.span;
|
||
|
||
/**
|
||
* A durable nonce is a 32 byte value encoded as a base58 string.
|
||
*/
|
||
|
||
/**
|
||
* NonceAccount class
|
||
*/
|
||
class NonceAccount {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor(args) {
|
||
this.authorizedPubkey = void 0;
|
||
this.nonce = void 0;
|
||
this.feeCalculator = void 0;
|
||
this.authorizedPubkey = args.authorizedPubkey;
|
||
this.nonce = args.nonce;
|
||
this.feeCalculator = args.feeCalculator;
|
||
}
|
||
|
||
/**
|
||
* Deserialize NonceAccount from the account data.
|
||
*
|
||
* @param buffer account data
|
||
* @return NonceAccount
|
||
*/
|
||
static fromAccountData(buffer) {
|
||
const nonceAccount = NonceAccountLayout.decode(toBuffer(buffer), 0);
|
||
return new NonceAccount({
|
||
authorizedPubkey: new PublicKey(nonceAccount.authorizedPubkey),
|
||
nonce: new PublicKey(nonceAccount.nonce).toString(),
|
||
feeCalculator: nonceAccount.feeCalculator
|
||
});
|
||
}
|
||
}
|
||
|
||
var browser$1 = {};
|
||
|
||
Object.defineProperty(browser$1, "__esModule", { value: true });
|
||
/**
|
||
* Convert a little-endian buffer into a BigInt.
|
||
* @param buf The little-endian buffer to convert
|
||
* @returns A BigInt with the little-endian representation of buf.
|
||
*/
|
||
function toBigIntLE(buf) {
|
||
{
|
||
const reversed = Buffer.from(buf);
|
||
reversed.reverse();
|
||
const hex = reversed.toString('hex');
|
||
if (hex.length === 0) {
|
||
return BigInt(0);
|
||
}
|
||
return BigInt(`0x${hex}`);
|
||
}
|
||
}
|
||
var toBigIntLE_1 = browser$1.toBigIntLE = toBigIntLE;
|
||
/**
|
||
* Convert a big-endian buffer into a BigInt
|
||
* @param buf The big-endian buffer to convert.
|
||
* @returns A BigInt with the big-endian representation of buf.
|
||
*/
|
||
function toBigIntBE(buf) {
|
||
{
|
||
const hex = buf.toString('hex');
|
||
if (hex.length === 0) {
|
||
return BigInt(0);
|
||
}
|
||
return BigInt(`0x${hex}`);
|
||
}
|
||
}
|
||
browser$1.toBigIntBE = toBigIntBE;
|
||
/**
|
||
* Convert a BigInt to a little-endian buffer.
|
||
* @param num The BigInt to convert.
|
||
* @param width The number of bytes that the resulting buffer should be.
|
||
* @returns A little-endian buffer representation of num.
|
||
*/
|
||
function toBufferLE(num, width) {
|
||
{
|
||
const hex = num.toString(16);
|
||
const buffer = Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex');
|
||
buffer.reverse();
|
||
return buffer;
|
||
}
|
||
}
|
||
var toBufferLE_1 = browser$1.toBufferLE = toBufferLE;
|
||
/**
|
||
* Convert a BigInt to a big-endian buffer.
|
||
* @param num The BigInt to convert.
|
||
* @param width The number of bytes that the resulting buffer should be.
|
||
* @returns A big-endian buffer representation of num.
|
||
*/
|
||
function toBufferBE(num, width) {
|
||
{
|
||
const hex = num.toString(16);
|
||
return Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex');
|
||
}
|
||
}
|
||
browser$1.toBufferBE = toBufferBE;
|
||
|
||
const encodeDecode = layout => {
|
||
const decode = layout.decode.bind(layout);
|
||
const encode = layout.encode.bind(layout);
|
||
return {
|
||
decode,
|
||
encode
|
||
};
|
||
};
|
||
const bigInt = length => property => {
|
||
const layout = blob(length, property);
|
||
const {
|
||
encode,
|
||
decode
|
||
} = encodeDecode(layout);
|
||
const bigIntLayout = layout;
|
||
bigIntLayout.decode = (buffer$1, offset) => {
|
||
const src = decode(buffer$1, offset);
|
||
return toBigIntLE_1(buffer.Buffer.from(src));
|
||
};
|
||
bigIntLayout.encode = (bigInt, buffer, offset) => {
|
||
const src = toBufferLE_1(bigInt, length);
|
||
return encode(src, buffer, offset);
|
||
};
|
||
return bigIntLayout;
|
||
};
|
||
const u64 = bigInt(8);
|
||
|
||
/**
|
||
* Create account system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Transfer system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Assign system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Create account with seed system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Create nonce account system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Create nonce account with seed system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Initialize nonce account system instruction params
|
||
*/
|
||
|
||
/**
|
||
* Advance nonce account system instruction params
|
||
*/
|
||
|
||
/**
|
||
* Withdraw nonce account system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Authorize nonce account system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Allocate account system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Allocate account with seed system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Assign account with seed system transaction params
|
||
*/
|
||
|
||
/**
|
||
* Transfer with seed system transaction params
|
||
*/
|
||
|
||
/** Decoded transfer system transaction instruction */
|
||
|
||
/** Decoded transferWithSeed system transaction instruction */
|
||
|
||
/**
|
||
* System Instruction class
|
||
*/
|
||
class SystemInstruction {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Decode a system instruction and retrieve the instruction type.
|
||
*/
|
||
static decodeInstructionType(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const instructionTypeLayout = u32('instruction');
|
||
const typeIndex = instructionTypeLayout.decode(instruction.data);
|
||
let type;
|
||
for (const [ixType, layout] of Object.entries(SYSTEM_INSTRUCTION_LAYOUTS)) {
|
||
if (layout.index == typeIndex) {
|
||
type = ixType;
|
||
break;
|
||
}
|
||
}
|
||
if (!type) {
|
||
throw new Error('Instruction type incorrect; not a SystemInstruction');
|
||
}
|
||
return type;
|
||
}
|
||
|
||
/**
|
||
* Decode a create account system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeCreateAccount(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 2);
|
||
const {
|
||
lamports,
|
||
space,
|
||
programId
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Create, instruction.data);
|
||
return {
|
||
fromPubkey: instruction.keys[0].pubkey,
|
||
newAccountPubkey: instruction.keys[1].pubkey,
|
||
lamports,
|
||
space,
|
||
programId: new PublicKey(programId)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a transfer system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeTransfer(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 2);
|
||
const {
|
||
lamports
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Transfer, instruction.data);
|
||
return {
|
||
fromPubkey: instruction.keys[0].pubkey,
|
||
toPubkey: instruction.keys[1].pubkey,
|
||
lamports
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a transfer with seed system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeTransferWithSeed(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
const {
|
||
lamports,
|
||
seed,
|
||
programId
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.TransferWithSeed, instruction.data);
|
||
return {
|
||
fromPubkey: instruction.keys[0].pubkey,
|
||
basePubkey: instruction.keys[1].pubkey,
|
||
toPubkey: instruction.keys[2].pubkey,
|
||
lamports,
|
||
seed,
|
||
programId: new PublicKey(programId)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode an allocate system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAllocate(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 1);
|
||
const {
|
||
space
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Allocate, instruction.data);
|
||
return {
|
||
accountPubkey: instruction.keys[0].pubkey,
|
||
space
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode an allocate with seed system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAllocateWithSeed(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 1);
|
||
const {
|
||
base,
|
||
seed,
|
||
space,
|
||
programId
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AllocateWithSeed, instruction.data);
|
||
return {
|
||
accountPubkey: instruction.keys[0].pubkey,
|
||
basePubkey: new PublicKey(base),
|
||
seed,
|
||
space,
|
||
programId: new PublicKey(programId)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode an assign system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAssign(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 1);
|
||
const {
|
||
programId
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Assign, instruction.data);
|
||
return {
|
||
accountPubkey: instruction.keys[0].pubkey,
|
||
programId: new PublicKey(programId)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode an assign with seed system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAssignWithSeed(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 1);
|
||
const {
|
||
base,
|
||
seed,
|
||
programId
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AssignWithSeed, instruction.data);
|
||
return {
|
||
accountPubkey: instruction.keys[0].pubkey,
|
||
basePubkey: new PublicKey(base),
|
||
seed,
|
||
programId: new PublicKey(programId)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a create account with seed system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeCreateWithSeed(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 2);
|
||
const {
|
||
base,
|
||
seed,
|
||
lamports,
|
||
space,
|
||
programId
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.CreateWithSeed, instruction.data);
|
||
return {
|
||
fromPubkey: instruction.keys[0].pubkey,
|
||
newAccountPubkey: instruction.keys[1].pubkey,
|
||
basePubkey: new PublicKey(base),
|
||
seed,
|
||
lamports,
|
||
space,
|
||
programId: new PublicKey(programId)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a nonce initialize system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeNonceInitialize(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
const {
|
||
authorized
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount, instruction.data);
|
||
return {
|
||
noncePubkey: instruction.keys[0].pubkey,
|
||
authorizedPubkey: new PublicKey(authorized)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a nonce advance system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeNonceAdvance(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AdvanceNonceAccount, instruction.data);
|
||
return {
|
||
noncePubkey: instruction.keys[0].pubkey,
|
||
authorizedPubkey: instruction.keys[2].pubkey
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a nonce withdraw system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeNonceWithdraw(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 5);
|
||
const {
|
||
lamports
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.WithdrawNonceAccount, instruction.data);
|
||
return {
|
||
noncePubkey: instruction.keys[0].pubkey,
|
||
toPubkey: instruction.keys[1].pubkey,
|
||
authorizedPubkey: instruction.keys[4].pubkey,
|
||
lamports
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a nonce authorize system instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeNonceAuthorize(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 2);
|
||
const {
|
||
authorized
|
||
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount, instruction.data);
|
||
return {
|
||
noncePubkey: instruction.keys[0].pubkey,
|
||
authorizedPubkey: instruction.keys[1].pubkey,
|
||
newAuthorizedPubkey: new PublicKey(authorized)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkProgramId(programId) {
|
||
if (!programId.equals(SystemProgram.programId)) {
|
||
throw new Error('invalid instruction; programId is not SystemProgram');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkKeyLength(keys, expectedLength) {
|
||
if (keys.length < expectedLength) {
|
||
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* An enumeration of valid SystemInstructionType's
|
||
*/
|
||
|
||
/**
|
||
* An enumeration of valid system InstructionType's
|
||
* @internal
|
||
*/
|
||
const SYSTEM_INSTRUCTION_LAYOUTS = Object.freeze({
|
||
Create: {
|
||
index: 0,
|
||
layout: struct([u32('instruction'), ns64('lamports'), ns64('space'), publicKey('programId')])
|
||
},
|
||
Assign: {
|
||
index: 1,
|
||
layout: struct([u32('instruction'), publicKey('programId')])
|
||
},
|
||
Transfer: {
|
||
index: 2,
|
||
layout: struct([u32('instruction'), u64('lamports')])
|
||
},
|
||
CreateWithSeed: {
|
||
index: 3,
|
||
layout: struct([u32('instruction'), publicKey('base'), rustString('seed'), ns64('lamports'), ns64('space'), publicKey('programId')])
|
||
},
|
||
AdvanceNonceAccount: {
|
||
index: 4,
|
||
layout: struct([u32('instruction')])
|
||
},
|
||
WithdrawNonceAccount: {
|
||
index: 5,
|
||
layout: struct([u32('instruction'), ns64('lamports')])
|
||
},
|
||
InitializeNonceAccount: {
|
||
index: 6,
|
||
layout: struct([u32('instruction'), publicKey('authorized')])
|
||
},
|
||
AuthorizeNonceAccount: {
|
||
index: 7,
|
||
layout: struct([u32('instruction'), publicKey('authorized')])
|
||
},
|
||
Allocate: {
|
||
index: 8,
|
||
layout: struct([u32('instruction'), ns64('space')])
|
||
},
|
||
AllocateWithSeed: {
|
||
index: 9,
|
||
layout: struct([u32('instruction'), publicKey('base'), rustString('seed'), ns64('space'), publicKey('programId')])
|
||
},
|
||
AssignWithSeed: {
|
||
index: 10,
|
||
layout: struct([u32('instruction'), publicKey('base'), rustString('seed'), publicKey('programId')])
|
||
},
|
||
TransferWithSeed: {
|
||
index: 11,
|
||
layout: struct([u32('instruction'), u64('lamports'), rustString('seed'), publicKey('programId')])
|
||
},
|
||
UpgradeNonceAccount: {
|
||
index: 12,
|
||
layout: struct([u32('instruction')])
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Factory class for transactions to interact with the System program
|
||
*/
|
||
class SystemProgram {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Public key that identifies the System program
|
||
*/
|
||
|
||
/**
|
||
* Generate a transaction instruction that creates a new account
|
||
*/
|
||
static createAccount(params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.Create;
|
||
const data = encodeData(type, {
|
||
lamports: params.lamports,
|
||
space: params.space,
|
||
programId: toBuffer(params.programId.toBuffer())
|
||
});
|
||
return new TransactionInstruction({
|
||
keys: [{
|
||
pubkey: params.fromPubkey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.newAccountPubkey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction instruction that transfers lamports from one account to another
|
||
*/
|
||
static transfer(params) {
|
||
let data;
|
||
let keys;
|
||
if ('basePubkey' in params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.TransferWithSeed;
|
||
data = encodeData(type, {
|
||
lamports: BigInt(params.lamports),
|
||
seed: params.seed,
|
||
programId: toBuffer(params.programId.toBuffer())
|
||
});
|
||
keys = [{
|
||
pubkey: params.fromPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.basePubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: params.toPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}];
|
||
} else {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.Transfer;
|
||
data = encodeData(type, {
|
||
lamports: BigInt(params.lamports)
|
||
});
|
||
keys = [{
|
||
pubkey: params.fromPubkey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.toPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}];
|
||
}
|
||
return new TransactionInstruction({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction instruction that assigns an account to a program
|
||
*/
|
||
static assign(params) {
|
||
let data;
|
||
let keys;
|
||
if ('basePubkey' in params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.AssignWithSeed;
|
||
data = encodeData(type, {
|
||
base: toBuffer(params.basePubkey.toBuffer()),
|
||
seed: params.seed,
|
||
programId: toBuffer(params.programId.toBuffer())
|
||
});
|
||
keys = [{
|
||
pubkey: params.accountPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.basePubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
} else {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.Assign;
|
||
data = encodeData(type, {
|
||
programId: toBuffer(params.programId.toBuffer())
|
||
});
|
||
keys = [{
|
||
pubkey: params.accountPubkey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}];
|
||
}
|
||
return new TransactionInstruction({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction instruction that creates a new account at
|
||
* an address generated with `from`, a seed, and programId
|
||
*/
|
||
static createAccountWithSeed(params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.CreateWithSeed;
|
||
const data = encodeData(type, {
|
||
base: toBuffer(params.basePubkey.toBuffer()),
|
||
seed: params.seed,
|
||
lamports: params.lamports,
|
||
space: params.space,
|
||
programId: toBuffer(params.programId.toBuffer())
|
||
});
|
||
let keys = [{
|
||
pubkey: params.fromPubkey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.newAccountPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}];
|
||
if (params.basePubkey != params.fromPubkey) {
|
||
keys.push({
|
||
pubkey: params.basePubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
});
|
||
}
|
||
return new TransactionInstruction({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction that creates a new Nonce account
|
||
*/
|
||
static createNonceAccount(params) {
|
||
const transaction = new Transaction();
|
||
if ('basePubkey' in params && 'seed' in params) {
|
||
transaction.add(SystemProgram.createAccountWithSeed({
|
||
fromPubkey: params.fromPubkey,
|
||
newAccountPubkey: params.noncePubkey,
|
||
basePubkey: params.basePubkey,
|
||
seed: params.seed,
|
||
lamports: params.lamports,
|
||
space: NONCE_ACCOUNT_LENGTH,
|
||
programId: this.programId
|
||
}));
|
||
} else {
|
||
transaction.add(SystemProgram.createAccount({
|
||
fromPubkey: params.fromPubkey,
|
||
newAccountPubkey: params.noncePubkey,
|
||
lamports: params.lamports,
|
||
space: NONCE_ACCOUNT_LENGTH,
|
||
programId: this.programId
|
||
}));
|
||
}
|
||
const initParams = {
|
||
noncePubkey: params.noncePubkey,
|
||
authorizedPubkey: params.authorizedPubkey
|
||
};
|
||
transaction.add(this.nonceInitialize(initParams));
|
||
return transaction;
|
||
}
|
||
|
||
/**
|
||
* Generate an instruction to initialize a Nonce account
|
||
*/
|
||
static nonceInitialize(params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount;
|
||
const data = encodeData(type, {
|
||
authorized: toBuffer(params.authorizedPubkey.toBuffer())
|
||
});
|
||
const instructionData = {
|
||
keys: [{
|
||
pubkey: params.noncePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_RENT_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
};
|
||
return new TransactionInstruction(instructionData);
|
||
}
|
||
|
||
/**
|
||
* Generate an instruction to advance the nonce in a Nonce account
|
||
*/
|
||
static nonceAdvance(params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.AdvanceNonceAccount;
|
||
const data = encodeData(type);
|
||
const instructionData = {
|
||
keys: [{
|
||
pubkey: params.noncePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: params.authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
};
|
||
return new TransactionInstruction(instructionData);
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction instruction that withdraws lamports from a Nonce account
|
||
*/
|
||
static nonceWithdraw(params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.WithdrawNonceAccount;
|
||
const data = encodeData(type, {
|
||
lamports: params.lamports
|
||
});
|
||
return new TransactionInstruction({
|
||
keys: [{
|
||
pubkey: params.noncePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.toPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_RENT_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: params.authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction instruction that authorizes a new PublicKey as the authority
|
||
* on a Nonce account.
|
||
*/
|
||
static nonceAuthorize(params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount;
|
||
const data = encodeData(type, {
|
||
authorized: toBuffer(params.newAuthorizedPubkey.toBuffer())
|
||
});
|
||
return new TransactionInstruction({
|
||
keys: [{
|
||
pubkey: params.noncePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction instruction that allocates space in an account without funding
|
||
*/
|
||
static allocate(params) {
|
||
let data;
|
||
let keys;
|
||
if ('basePubkey' in params) {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.AllocateWithSeed;
|
||
data = encodeData(type, {
|
||
base: toBuffer(params.basePubkey.toBuffer()),
|
||
seed: params.seed,
|
||
space: params.space,
|
||
programId: toBuffer(params.programId.toBuffer())
|
||
});
|
||
keys = [{
|
||
pubkey: params.accountPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.basePubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
} else {
|
||
const type = SYSTEM_INSTRUCTION_LAYOUTS.Allocate;
|
||
data = encodeData(type, {
|
||
space: params.space
|
||
});
|
||
keys = [{
|
||
pubkey: params.accountPubkey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}];
|
||
}
|
||
return new TransactionInstruction({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
}
|
||
SystemProgram.programId = new PublicKey('11111111111111111111111111111111');
|
||
|
||
// Keep program chunks under PACKET_DATA_SIZE, leaving enough room for the
|
||
// rest of the Transaction fields
|
||
//
|
||
// TODO: replace 300 with a proper constant for the size of the other
|
||
// Transaction fields
|
||
const CHUNK_SIZE = PACKET_DATA_SIZE - 300;
|
||
|
||
/**
|
||
* Program loader interface
|
||
*/
|
||
class Loader {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Amount of program data placed in each load Transaction
|
||
*/
|
||
|
||
/**
|
||
* Minimum number of signatures required to load a program not including
|
||
* retries
|
||
*
|
||
* Can be used to calculate transaction fees
|
||
*/
|
||
static getMinNumSignatures(dataLength) {
|
||
return 2 * (
|
||
// Every transaction requires two signatures (payer + program)
|
||
Math.ceil(dataLength / Loader.chunkSize) + 1 +
|
||
// Add one for Create transaction
|
||
1) // Add one for Finalize transaction
|
||
;
|
||
}
|
||
|
||
/**
|
||
* Loads a generic program
|
||
*
|
||
* @param connection The connection to use
|
||
* @param payer System account that pays to load the program
|
||
* @param program Account to load the program into
|
||
* @param programId Public key that identifies the loader
|
||
* @param data Program octets
|
||
* @return true if program was loaded successfully, false if program was already loaded
|
||
*/
|
||
static async load(connection, payer, program, programId, data) {
|
||
{
|
||
const balanceNeeded = await connection.getMinimumBalanceForRentExemption(data.length);
|
||
|
||
// Fetch program account info to check if it has already been created
|
||
const programInfo = await connection.getAccountInfo(program.publicKey, 'confirmed');
|
||
let transaction = null;
|
||
if (programInfo !== null) {
|
||
if (programInfo.executable) {
|
||
console.error('Program load failed, account is already executable');
|
||
return false;
|
||
}
|
||
if (programInfo.data.length !== data.length) {
|
||
transaction = transaction || new Transaction();
|
||
transaction.add(SystemProgram.allocate({
|
||
accountPubkey: program.publicKey,
|
||
space: data.length
|
||
}));
|
||
}
|
||
if (!programInfo.owner.equals(programId)) {
|
||
transaction = transaction || new Transaction();
|
||
transaction.add(SystemProgram.assign({
|
||
accountPubkey: program.publicKey,
|
||
programId
|
||
}));
|
||
}
|
||
if (programInfo.lamports < balanceNeeded) {
|
||
transaction = transaction || new Transaction();
|
||
transaction.add(SystemProgram.transfer({
|
||
fromPubkey: payer.publicKey,
|
||
toPubkey: program.publicKey,
|
||
lamports: balanceNeeded - programInfo.lamports
|
||
}));
|
||
}
|
||
} else {
|
||
transaction = new Transaction().add(SystemProgram.createAccount({
|
||
fromPubkey: payer.publicKey,
|
||
newAccountPubkey: program.publicKey,
|
||
lamports: balanceNeeded > 0 ? balanceNeeded : 1,
|
||
space: data.length,
|
||
programId
|
||
}));
|
||
}
|
||
|
||
// If the account is already created correctly, skip this step
|
||
// and proceed directly to loading instructions
|
||
if (transaction !== null) {
|
||
await sendAndConfirmTransaction(connection, transaction, [payer, program], {
|
||
commitment: 'confirmed'
|
||
});
|
||
}
|
||
}
|
||
const dataLayout = struct([u32('instruction'), u32('offset'), u32('bytesLength'), u32('bytesLengthPadding'), seq(u8('byte'), offset(u32(), -8), 'bytes')]);
|
||
const chunkSize = Loader.chunkSize;
|
||
let offset$1 = 0;
|
||
let array = data;
|
||
let transactions = [];
|
||
while (array.length > 0) {
|
||
const bytes = array.slice(0, chunkSize);
|
||
const data = buffer.Buffer.alloc(chunkSize + 16);
|
||
dataLayout.encode({
|
||
instruction: 0,
|
||
// Load instruction
|
||
offset: offset$1,
|
||
bytes: bytes,
|
||
bytesLength: 0,
|
||
bytesLengthPadding: 0
|
||
}, data);
|
||
const transaction = new Transaction().add({
|
||
keys: [{
|
||
pubkey: program.publicKey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}],
|
||
programId,
|
||
data
|
||
});
|
||
transactions.push(sendAndConfirmTransaction(connection, transaction, [payer, program], {
|
||
commitment: 'confirmed'
|
||
}));
|
||
|
||
// Delay between sends in an attempt to reduce rate limit errors
|
||
if (connection._rpcEndpoint.includes('solana.com')) {
|
||
const REQUESTS_PER_SECOND = 4;
|
||
await sleep(1000 / REQUESTS_PER_SECOND);
|
||
}
|
||
offset$1 += chunkSize;
|
||
array = array.slice(chunkSize);
|
||
}
|
||
await Promise.all(transactions);
|
||
|
||
// Finalize the account loaded with program data for execution
|
||
{
|
||
const dataLayout = struct([u32('instruction')]);
|
||
const data = buffer.Buffer.alloc(dataLayout.span);
|
||
dataLayout.encode({
|
||
instruction: 1 // Finalize instruction
|
||
}, data);
|
||
const transaction = new Transaction().add({
|
||
keys: [{
|
||
pubkey: program.publicKey,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_RENT_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}],
|
||
programId,
|
||
data
|
||
});
|
||
const deployCommitment = 'processed';
|
||
const finalizeSignature = await connection.sendTransaction(transaction, [payer, program], {
|
||
preflightCommitment: deployCommitment
|
||
});
|
||
const {
|
||
context,
|
||
value
|
||
} = await connection.confirmTransaction({
|
||
signature: finalizeSignature,
|
||
lastValidBlockHeight: transaction.lastValidBlockHeight,
|
||
blockhash: transaction.recentBlockhash
|
||
}, deployCommitment);
|
||
if (value.err) {
|
||
throw new Error(`Transaction ${finalizeSignature} failed (${JSON.stringify(value)})`);
|
||
}
|
||
// We prevent programs from being usable until the slot after their deployment.
|
||
// See https://github.com/solana-labs/solana/pull/29654
|
||
while (true // eslint-disable-line no-constant-condition
|
||
) {
|
||
try {
|
||
const currentSlot = await connection.getSlot({
|
||
commitment: deployCommitment
|
||
});
|
||
if (currentSlot > context.slot) {
|
||
break;
|
||
}
|
||
} catch {
|
||
/* empty */
|
||
}
|
||
await new Promise(resolve => setTimeout(resolve, Math.round(MS_PER_SLOT / 2)));
|
||
}
|
||
}
|
||
|
||
// success
|
||
return true;
|
||
}
|
||
}
|
||
Loader.chunkSize = CHUNK_SIZE;
|
||
|
||
/**
|
||
* @deprecated Deprecated since Solana v1.17.20.
|
||
*/
|
||
const BPF_LOADER_PROGRAM_ID = new PublicKey('BPFLoader2111111111111111111111111111111111');
|
||
|
||
/**
|
||
* Factory class for transactions to interact with a program loader
|
||
*
|
||
* @deprecated Deprecated since Solana v1.17.20.
|
||
*/
|
||
class BpfLoader {
|
||
/**
|
||
* Minimum number of signatures required to load a program not including
|
||
* retries
|
||
*
|
||
* Can be used to calculate transaction fees
|
||
*/
|
||
static getMinNumSignatures(dataLength) {
|
||
return Loader.getMinNumSignatures(dataLength);
|
||
}
|
||
|
||
/**
|
||
* Load a SBF program
|
||
*
|
||
* @param connection The connection to use
|
||
* @param payer Account that will pay program loading fees
|
||
* @param program Account to load the program into
|
||
* @param elf The entire ELF containing the SBF program
|
||
* @param loaderProgramId The program id of the BPF loader to use
|
||
* @return true if program was loaded successfully, false if program was already loaded
|
||
*/
|
||
static load(connection, payer, program, elf, loaderProgramId) {
|
||
return Loader.load(connection, payer, program, loaderProgramId, elf);
|
||
}
|
||
}
|
||
|
||
var objToString = Object.prototype.toString;
|
||
var objKeys = Object.keys || function(obj) {
|
||
var keys = [];
|
||
for (var name in obj) {
|
||
keys.push(name);
|
||
}
|
||
return keys;
|
||
};
|
||
|
||
function stringify$1(val, isArrayProp) {
|
||
var i, max, str, keys, key, propVal, toStr;
|
||
if (val === true) {
|
||
return "true";
|
||
}
|
||
if (val === false) {
|
||
return "false";
|
||
}
|
||
switch (typeof val) {
|
||
case "object":
|
||
if (val === null) {
|
||
return null;
|
||
} else if (val.toJSON && typeof val.toJSON === "function") {
|
||
return stringify$1(val.toJSON(), isArrayProp);
|
||
} else {
|
||
toStr = objToString.call(val);
|
||
if (toStr === "[object Array]") {
|
||
str = '[';
|
||
max = val.length - 1;
|
||
for(i = 0; i < max; i++) {
|
||
str += stringify$1(val[i], true) + ',';
|
||
}
|
||
if (max > -1) {
|
||
str += stringify$1(val[i], true);
|
||
}
|
||
return str + ']';
|
||
} else if (toStr === "[object Object]") {
|
||
// only object is left
|
||
keys = objKeys(val).sort();
|
||
max = keys.length;
|
||
str = "";
|
||
i = 0;
|
||
while (i < max) {
|
||
key = keys[i];
|
||
propVal = stringify$1(val[key], false);
|
||
if (propVal !== undefined) {
|
||
if (str) {
|
||
str += ',';
|
||
}
|
||
str += JSON.stringify(key) + ':' + propVal;
|
||
}
|
||
i++;
|
||
}
|
||
return '{' + str + '}';
|
||
} else {
|
||
return JSON.stringify(val);
|
||
}
|
||
}
|
||
case "function":
|
||
case "undefined":
|
||
return isArrayProp ? null : undefined;
|
||
case "string":
|
||
return JSON.stringify(val);
|
||
default:
|
||
return isFinite(val) ? val : null;
|
||
}
|
||
}
|
||
|
||
var fastStableStringify = function(val) {
|
||
var returnVal = stringify$1(val, false);
|
||
if (returnVal !== undefined) {
|
||
return ''+ returnVal;
|
||
}
|
||
};
|
||
|
||
var fastStableStringify$1 = /*@__PURE__*/getDefaultExportFromCjs(fastStableStringify);
|
||
|
||
/**
|
||
* A `StructFailure` represents a single specific failure in validation.
|
||
*/
|
||
|
||
/**
|
||
* `StructError` objects are thrown (or returned) when validation fails.
|
||
*
|
||
* Validation logic is design to exit early for maximum performance. The error
|
||
* represents the first error encountered during validation. For more detail,
|
||
* the `error.failures` property is a generator function that can be run to
|
||
* continue validation and receive all the failures in the data.
|
||
*/
|
||
class StructError extends TypeError {
|
||
constructor(failure, failures) {
|
||
let cached;
|
||
const {
|
||
message,
|
||
...rest
|
||
} = failure;
|
||
const {
|
||
path
|
||
} = failure;
|
||
const msg = path.length === 0 ? message : "At path: " + path.join('.') + " -- " + message;
|
||
super(msg);
|
||
Object.assign(this, rest);
|
||
this.name = this.constructor.name;
|
||
|
||
this.failures = () => {
|
||
var _cached;
|
||
|
||
return (_cached = cached) != null ? _cached : cached = [failure, ...failures()];
|
||
};
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* Check if a value is an iterator.
|
||
*/
|
||
function isIterable(x) {
|
||
return isObject(x) && typeof x[Symbol.iterator] === 'function';
|
||
}
|
||
/**
|
||
* Check if a value is a plain object.
|
||
*/
|
||
|
||
|
||
function isObject(x) {
|
||
return typeof x === 'object' && x != null;
|
||
}
|
||
/**
|
||
* Return a value as a printable string.
|
||
*/
|
||
|
||
function print(value) {
|
||
return typeof value === 'string' ? JSON.stringify(value) : "" + value;
|
||
}
|
||
/**
|
||
* Shifts (removes and returns) the first value from the `input` iterator.
|
||
* Like `Array.prototype.shift()` but for an `Iterator`.
|
||
*/
|
||
|
||
function shiftIterator(input) {
|
||
const {
|
||
done,
|
||
value
|
||
} = input.next();
|
||
return done ? undefined : value;
|
||
}
|
||
/**
|
||
* Convert a single validation result to a failure.
|
||
*/
|
||
|
||
function toFailure(result, context, struct, value) {
|
||
if (result === true) {
|
||
return;
|
||
} else if (result === false) {
|
||
result = {};
|
||
} else if (typeof result === 'string') {
|
||
result = {
|
||
message: result
|
||
};
|
||
}
|
||
|
||
const {
|
||
path,
|
||
branch
|
||
} = context;
|
||
const {
|
||
type
|
||
} = struct;
|
||
const {
|
||
refinement,
|
||
message = "Expected a value of type `" + type + "`" + (refinement ? " with refinement `" + refinement + "`" : '') + ", but received: `" + print(value) + "`"
|
||
} = result;
|
||
return {
|
||
value,
|
||
type,
|
||
refinement,
|
||
key: path[path.length - 1],
|
||
path,
|
||
branch,
|
||
...result,
|
||
message
|
||
};
|
||
}
|
||
/**
|
||
* Convert a validation result to an iterable of failures.
|
||
*/
|
||
|
||
function* toFailures(result, context, struct, value) {
|
||
if (!isIterable(result)) {
|
||
result = [result];
|
||
}
|
||
|
||
for (const r of result) {
|
||
const failure = toFailure(r, context, struct, value);
|
||
|
||
if (failure) {
|
||
yield failure;
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* Check a value against a struct, traversing deeply into nested values, and
|
||
* returning an iterator of failures or success.
|
||
*/
|
||
|
||
function* run(value, struct, options = {}) {
|
||
const {
|
||
path = [],
|
||
branch = [value],
|
||
coerce = false,
|
||
mask = false
|
||
} = options;
|
||
const ctx = {
|
||
path,
|
||
branch
|
||
};
|
||
|
||
if (coerce) {
|
||
value = struct.coercer(value, ctx);
|
||
|
||
if (mask && struct.type !== 'type' && isObject(struct.schema) && isObject(value) && !Array.isArray(value)) {
|
||
for (const key in value) {
|
||
if (struct.schema[key] === undefined) {
|
||
delete value[key];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
let valid = true;
|
||
|
||
for (const failure of struct.validator(value, ctx)) {
|
||
valid = false;
|
||
yield [failure, undefined];
|
||
}
|
||
|
||
for (let [k, v, s] of struct.entries(value, ctx)) {
|
||
const ts = run(v, s, {
|
||
path: k === undefined ? path : [...path, k],
|
||
branch: k === undefined ? branch : [...branch, v],
|
||
coerce,
|
||
mask
|
||
});
|
||
|
||
for (const t of ts) {
|
||
if (t[0]) {
|
||
valid = false;
|
||
yield [t[0], undefined];
|
||
} else if (coerce) {
|
||
v = t[1];
|
||
|
||
if (k === undefined) {
|
||
value = v;
|
||
} else if (value instanceof Map) {
|
||
value.set(k, v);
|
||
} else if (value instanceof Set) {
|
||
value.add(v);
|
||
} else if (isObject(value)) {
|
||
value[k] = v;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (valid) {
|
||
for (const failure of struct.refiner(value, ctx)) {
|
||
valid = false;
|
||
yield [failure, undefined];
|
||
}
|
||
}
|
||
|
||
if (valid) {
|
||
yield [undefined, value];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* `Struct` objects encapsulate the validation logic for a specific type of
|
||
* values. Once constructed, you use the `assert`, `is` or `validate` helpers to
|
||
* validate unknown input data against the struct.
|
||
*/
|
||
|
||
class Struct {
|
||
constructor(props) {
|
||
const {
|
||
type,
|
||
schema,
|
||
validator,
|
||
refiner,
|
||
coercer = value => value,
|
||
entries = function* () {}
|
||
} = props;
|
||
this.type = type;
|
||
this.schema = schema;
|
||
this.entries = entries;
|
||
this.coercer = coercer;
|
||
|
||
if (validator) {
|
||
this.validator = (value, context) => {
|
||
const result = validator(value, context);
|
||
return toFailures(result, context, this, value);
|
||
};
|
||
} else {
|
||
this.validator = () => [];
|
||
}
|
||
|
||
if (refiner) {
|
||
this.refiner = (value, context) => {
|
||
const result = refiner(value, context);
|
||
return toFailures(result, context, this, value);
|
||
};
|
||
} else {
|
||
this.refiner = () => [];
|
||
}
|
||
}
|
||
/**
|
||
* Assert that a value passes the struct's validation, throwing if it doesn't.
|
||
*/
|
||
|
||
|
||
assert(value) {
|
||
return assert(value, this);
|
||
}
|
||
/**
|
||
* Create a value with the struct's coercion logic, then validate it.
|
||
*/
|
||
|
||
|
||
create(value) {
|
||
return create(value, this);
|
||
}
|
||
/**
|
||
* Check if a value passes the struct's validation.
|
||
*/
|
||
|
||
|
||
is(value) {
|
||
return is(value, this);
|
||
}
|
||
/**
|
||
* Mask a value, coercing and validating it, but returning only the subset of
|
||
* properties defined by the struct's schema.
|
||
*/
|
||
|
||
|
||
mask(value) {
|
||
return mask(value, this);
|
||
}
|
||
/**
|
||
* Validate a value with the struct's validation logic, returning a tuple
|
||
* representing the result.
|
||
*
|
||
* You may optionally pass `true` for the `withCoercion` argument to coerce
|
||
* the value before attempting to validate it. If you do, the result will
|
||
* contain the coerced result when successful.
|
||
*/
|
||
|
||
|
||
validate(value, options = {}) {
|
||
return validate$1(value, this, options);
|
||
}
|
||
|
||
}
|
||
/**
|
||
* Assert that a value passes a struct, throwing if it doesn't.
|
||
*/
|
||
|
||
function assert(value, struct) {
|
||
const result = validate$1(value, struct);
|
||
|
||
if (result[0]) {
|
||
throw result[0];
|
||
}
|
||
}
|
||
/**
|
||
* Create a value with the coercion logic of struct and validate it.
|
||
*/
|
||
|
||
function create(value, struct) {
|
||
const result = validate$1(value, struct, {
|
||
coerce: true
|
||
});
|
||
|
||
if (result[0]) {
|
||
throw result[0];
|
||
} else {
|
||
return result[1];
|
||
}
|
||
}
|
||
/**
|
||
* Mask a value, returning only the subset of properties defined by a struct.
|
||
*/
|
||
|
||
function mask(value, struct) {
|
||
const result = validate$1(value, struct, {
|
||
coerce: true,
|
||
mask: true
|
||
});
|
||
|
||
if (result[0]) {
|
||
throw result[0];
|
||
} else {
|
||
return result[1];
|
||
}
|
||
}
|
||
/**
|
||
* Check if a value passes a struct.
|
||
*/
|
||
|
||
function is(value, struct) {
|
||
const result = validate$1(value, struct);
|
||
return !result[0];
|
||
}
|
||
/**
|
||
* Validate a value against a struct, returning an error if invalid, or the
|
||
* value (with potential coercion) if valid.
|
||
*/
|
||
|
||
function validate$1(value, struct, options = {}) {
|
||
const tuples = run(value, struct, options);
|
||
const tuple = shiftIterator(tuples);
|
||
|
||
if (tuple[0]) {
|
||
const error = new StructError(tuple[0], function* () {
|
||
for (const t of tuples) {
|
||
if (t[0]) {
|
||
yield t[0];
|
||
}
|
||
}
|
||
});
|
||
return [error, undefined];
|
||
} else {
|
||
const v = tuple[1];
|
||
return [undefined, v];
|
||
}
|
||
}
|
||
/**
|
||
* Define a new struct type with a custom validation function.
|
||
*/
|
||
|
||
function define(name, validator) {
|
||
return new Struct({
|
||
type: name,
|
||
schema: null,
|
||
validator
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Ensure that any value passes validation.
|
||
*/
|
||
|
||
function any() {
|
||
return define('any', () => true);
|
||
}
|
||
function array(Element) {
|
||
return new Struct({
|
||
type: 'array',
|
||
schema: Element,
|
||
|
||
*entries(value) {
|
||
if (Element && Array.isArray(value)) {
|
||
for (const [i, v] of value.entries()) {
|
||
yield [i, v, Element];
|
||
}
|
||
}
|
||
},
|
||
|
||
coercer(value) {
|
||
return Array.isArray(value) ? value.slice() : value;
|
||
},
|
||
|
||
validator(value) {
|
||
return Array.isArray(value) || "Expected an array value, but received: " + print(value);
|
||
}
|
||
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that a value is a boolean.
|
||
*/
|
||
|
||
function boolean() {
|
||
return define('boolean', value => {
|
||
return typeof value === 'boolean';
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that a value is an instance of a specific class.
|
||
*/
|
||
|
||
function instance(Class) {
|
||
return define('instance', value => {
|
||
return value instanceof Class || "Expected a `" + Class.name + "` instance, but received: " + print(value);
|
||
});
|
||
}
|
||
function literal(constant) {
|
||
const description = print(constant);
|
||
const t = typeof constant;
|
||
return new Struct({
|
||
type: 'literal',
|
||
schema: t === 'string' || t === 'number' || t === 'boolean' ? constant : null,
|
||
|
||
validator(value) {
|
||
return value === constant || "Expected the literal `" + description + "`, but received: " + print(value);
|
||
}
|
||
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that no value ever passes validation.
|
||
*/
|
||
|
||
function never() {
|
||
return define('never', () => false);
|
||
}
|
||
/**
|
||
* Augment an existing struct to allow `null` values.
|
||
*/
|
||
|
||
function nullable(struct) {
|
||
return new Struct({ ...struct,
|
||
validator: (value, ctx) => value === null || struct.validator(value, ctx),
|
||
refiner: (value, ctx) => value === null || struct.refiner(value, ctx)
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that a value is a number.
|
||
*/
|
||
|
||
function number() {
|
||
return define('number', value => {
|
||
return typeof value === 'number' && !isNaN(value) || "Expected a number, but received: " + print(value);
|
||
});
|
||
}
|
||
/**
|
||
* Augment a struct to allow `undefined` values.
|
||
*/
|
||
|
||
function optional(struct) {
|
||
return new Struct({ ...struct,
|
||
validator: (value, ctx) => value === undefined || struct.validator(value, ctx),
|
||
refiner: (value, ctx) => value === undefined || struct.refiner(value, ctx)
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that a value is an object with keys and values of specific types, but
|
||
* without ensuring any specific shape of properties.
|
||
*
|
||
* Like TypeScript's `Record` utility.
|
||
*/
|
||
|
||
function record(Key, Value) {
|
||
return new Struct({
|
||
type: 'record',
|
||
schema: null,
|
||
|
||
*entries(value) {
|
||
if (isObject(value)) {
|
||
for (const k in value) {
|
||
const v = value[k];
|
||
yield [k, k, Key];
|
||
yield [k, v, Value];
|
||
}
|
||
}
|
||
},
|
||
|
||
validator(value) {
|
||
return isObject(value) || "Expected an object, but received: " + print(value);
|
||
}
|
||
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that a value is a string.
|
||
*/
|
||
|
||
function string() {
|
||
return define('string', value => {
|
||
return typeof value === 'string' || "Expected a string, but received: " + print(value);
|
||
});
|
||
}
|
||
function tuple(Elements) {
|
||
const Never = never();
|
||
return new Struct({
|
||
type: 'tuple',
|
||
schema: null,
|
||
|
||
*entries(value) {
|
||
if (Array.isArray(value)) {
|
||
const length = Math.max(Elements.length, value.length);
|
||
|
||
for (let i = 0; i < length; i++) {
|
||
yield [i, value[i], Elements[i] || Never];
|
||
}
|
||
}
|
||
},
|
||
|
||
validator(value) {
|
||
return Array.isArray(value) || "Expected an array, but received: " + print(value);
|
||
}
|
||
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that a value has a set of known properties of specific types.
|
||
*
|
||
* Note: Unrecognized properties are allowed and untouched. This is similar to
|
||
* how TypeScript's structural typing works.
|
||
*/
|
||
|
||
function type(schema) {
|
||
const keys = Object.keys(schema);
|
||
return new Struct({
|
||
type: 'type',
|
||
schema,
|
||
|
||
*entries(value) {
|
||
if (isObject(value)) {
|
||
for (const k of keys) {
|
||
yield [k, value[k], schema[k]];
|
||
}
|
||
}
|
||
},
|
||
|
||
validator(value) {
|
||
return isObject(value) || "Expected an object, but received: " + print(value);
|
||
}
|
||
|
||
});
|
||
}
|
||
function union(Structs) {
|
||
const description = Structs.map(s => s.type).join(' | ');
|
||
return new Struct({
|
||
type: 'union',
|
||
schema: null,
|
||
|
||
validator(value, ctx) {
|
||
const failures = [];
|
||
|
||
for (const S of Structs) {
|
||
const [...tuples] = run(value, S, ctx);
|
||
const [first] = tuples;
|
||
|
||
if (!first[0]) {
|
||
return [];
|
||
} else {
|
||
for (const [failure] of tuples) {
|
||
if (failure) {
|
||
failures.push(failure);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return ["Expected the value to satisfy a union of `" + description + "`, but received: " + print(value), ...failures];
|
||
}
|
||
|
||
});
|
||
}
|
||
/**
|
||
* Ensure that any value passes validation, without widening its type to `any`.
|
||
*/
|
||
|
||
function unknown() {
|
||
return define('unknown', () => true);
|
||
}
|
||
|
||
/**
|
||
* Augment a `Struct` to add an additional coercion step to its input.
|
||
*
|
||
* This allows you to transform input data before validating it, to increase the
|
||
* likelihood that it passes validation—for example for default values, parsing
|
||
* different formats, etc.
|
||
*
|
||
* Note: You must use `create(value, Struct)` on the value to have the coercion
|
||
* take effect! Using simply `assert()` or `is()` will not use coercion.
|
||
*/
|
||
|
||
function coerce(struct, condition, coercer) {
|
||
return new Struct({ ...struct,
|
||
coercer: (value, ctx) => {
|
||
return is(value, condition) ? struct.coercer(coercer(value, ctx), ctx) : struct.coercer(value, ctx);
|
||
}
|
||
});
|
||
}
|
||
|
||
// Unique ID creation requires a high quality random # generator. In the browser we therefore
|
||
// require the crypto API and do not support built-in fallback to lower quality random number
|
||
// generators (like Math.random()).
|
||
var getRandomValues;
|
||
var rnds8 = new Uint8Array(16);
|
||
function rng() {
|
||
// lazy load so that environments that need to polyfill have a chance to do so
|
||
if (!getRandomValues) {
|
||
// getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
|
||
// find the complete implementation of crypto (msCrypto) on IE11.
|
||
getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
|
||
|
||
if (!getRandomValues) {
|
||
throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
|
||
}
|
||
}
|
||
|
||
return getRandomValues(rnds8);
|
||
}
|
||
|
||
var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
|
||
|
||
function validate(uuid) {
|
||
return typeof uuid === 'string' && REGEX.test(uuid);
|
||
}
|
||
|
||
/**
|
||
* Convert array of 16 byte values to UUID string format of the form:
|
||
* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
||
*/
|
||
|
||
var byteToHex = [];
|
||
|
||
for (var i = 0; i < 256; ++i) {
|
||
byteToHex.push((i + 0x100).toString(16).substr(1));
|
||
}
|
||
|
||
function stringify(arr) {
|
||
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||
// Note: Be careful editing this code! It's been tuned for performance
|
||
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
|
||
var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one
|
||
// of the following:
|
||
// - One or more input array values don't map to a hex octet (leading to
|
||
// "undefined" in the uuid)
|
||
// - Invalid input values for the RFC `version` or `variant` fields
|
||
|
||
if (!validate(uuid)) {
|
||
throw TypeError('Stringified UUID is invalid');
|
||
}
|
||
|
||
return uuid;
|
||
}
|
||
|
||
//
|
||
// Inspired by https://github.com/LiosK/UUID.js
|
||
// and http://docs.python.org/library/uuid.html
|
||
|
||
var _nodeId;
|
||
|
||
var _clockseq; // Previous uuid creation time
|
||
|
||
|
||
var _lastMSecs = 0;
|
||
var _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details
|
||
|
||
function v1(options, buf, offset) {
|
||
var i = buf && offset || 0;
|
||
var b = buf || new Array(16);
|
||
options = options || {};
|
||
var node = options.node || _nodeId;
|
||
var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not
|
||
// specified. We do this lazily to minimize issues related to insufficient
|
||
// system entropy. See #189
|
||
|
||
if (node == null || clockseq == null) {
|
||
var seedBytes = options.random || (options.rng || rng)();
|
||
|
||
if (node == null) {
|
||
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
|
||
node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]];
|
||
}
|
||
|
||
if (clockseq == null) {
|
||
// Per 4.2.2, randomize (14 bit) clockseq
|
||
clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff;
|
||
}
|
||
} // UUID timestamps are 100 nano-second units since the Gregorian epoch,
|
||
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
|
||
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
|
||
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
|
||
|
||
|
||
var msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock
|
||
// cycle to simulate higher resolution clock
|
||
|
||
var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs)
|
||
|
||
var dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression
|
||
|
||
if (dt < 0 && options.clockseq === undefined) {
|
||
clockseq = clockseq + 1 & 0x3fff;
|
||
} // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
|
||
// time interval
|
||
|
||
|
||
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
|
||
nsecs = 0;
|
||
} // Per 4.2.1.2 Throw error if too many uuids are requested
|
||
|
||
|
||
if (nsecs >= 10000) {
|
||
throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");
|
||
}
|
||
|
||
_lastMSecs = msecs;
|
||
_lastNSecs = nsecs;
|
||
_clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
|
||
|
||
msecs += 12219292800000; // `time_low`
|
||
|
||
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
|
||
b[i++] = tl >>> 24 & 0xff;
|
||
b[i++] = tl >>> 16 & 0xff;
|
||
b[i++] = tl >>> 8 & 0xff;
|
||
b[i++] = tl & 0xff; // `time_mid`
|
||
|
||
var tmh = msecs / 0x100000000 * 10000 & 0xfffffff;
|
||
b[i++] = tmh >>> 8 & 0xff;
|
||
b[i++] = tmh & 0xff; // `time_high_and_version`
|
||
|
||
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
|
||
|
||
b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
|
||
|
||
b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low`
|
||
|
||
b[i++] = clockseq & 0xff; // `node`
|
||
|
||
for (var n = 0; n < 6; ++n) {
|
||
b[i + n] = node[n];
|
||
}
|
||
|
||
return buf || stringify(b);
|
||
}
|
||
|
||
function parse(uuid) {
|
||
if (!validate(uuid)) {
|
||
throw TypeError('Invalid UUID');
|
||
}
|
||
|
||
var v;
|
||
var arr = new Uint8Array(16); // Parse ########-....-....-....-............
|
||
|
||
arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24;
|
||
arr[1] = v >>> 16 & 0xff;
|
||
arr[2] = v >>> 8 & 0xff;
|
||
arr[3] = v & 0xff; // Parse ........-####-....-....-............
|
||
|
||
arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8;
|
||
arr[5] = v & 0xff; // Parse ........-....-####-....-............
|
||
|
||
arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8;
|
||
arr[7] = v & 0xff; // Parse ........-....-....-####-............
|
||
|
||
arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8;
|
||
arr[9] = v & 0xff; // Parse ........-....-....-....-############
|
||
// (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes)
|
||
|
||
arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff;
|
||
arr[11] = v / 0x100000000 & 0xff;
|
||
arr[12] = v >>> 24 & 0xff;
|
||
arr[13] = v >>> 16 & 0xff;
|
||
arr[14] = v >>> 8 & 0xff;
|
||
arr[15] = v & 0xff;
|
||
return arr;
|
||
}
|
||
|
||
function stringToBytes(str) {
|
||
str = unescape(encodeURIComponent(str)); // UTF8 escape
|
||
|
||
var bytes = [];
|
||
|
||
for (var i = 0; i < str.length; ++i) {
|
||
bytes.push(str.charCodeAt(i));
|
||
}
|
||
|
||
return bytes;
|
||
}
|
||
|
||
var DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
|
||
var URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
|
||
function v35 (name, version, hashfunc) {
|
||
function generateUUID(value, namespace, buf, offset) {
|
||
if (typeof value === 'string') {
|
||
value = stringToBytes(value);
|
||
}
|
||
|
||
if (typeof namespace === 'string') {
|
||
namespace = parse(namespace);
|
||
}
|
||
|
||
if (namespace.length !== 16) {
|
||
throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)');
|
||
} // Compute hash of namespace and value, Per 4.3
|
||
// Future: Use spread syntax when supported on all platforms, e.g. `bytes =
|
||
// hashfunc([...namespace, ... value])`
|
||
|
||
|
||
var bytes = new Uint8Array(16 + value.length);
|
||
bytes.set(namespace);
|
||
bytes.set(value, namespace.length);
|
||
bytes = hashfunc(bytes);
|
||
bytes[6] = bytes[6] & 0x0f | version;
|
||
bytes[8] = bytes[8] & 0x3f | 0x80;
|
||
|
||
if (buf) {
|
||
offset = offset || 0;
|
||
|
||
for (var i = 0; i < 16; ++i) {
|
||
buf[offset + i] = bytes[i];
|
||
}
|
||
|
||
return buf;
|
||
}
|
||
|
||
return stringify(bytes);
|
||
} // Function#name is not settable on some platforms (#270)
|
||
|
||
|
||
try {
|
||
generateUUID.name = name; // eslint-disable-next-line no-empty
|
||
} catch (err) {} // For CommonJS default export support
|
||
|
||
|
||
generateUUID.DNS = DNS;
|
||
generateUUID.URL = URL;
|
||
return generateUUID;
|
||
}
|
||
|
||
/*
|
||
* Browser-compatible JavaScript MD5
|
||
*
|
||
* Modification of JavaScript MD5
|
||
* https://github.com/blueimp/JavaScript-MD5
|
||
*
|
||
* Copyright 2011, Sebastian Tschan
|
||
* https://blueimp.net
|
||
*
|
||
* Licensed under the MIT license:
|
||
* https://opensource.org/licenses/MIT
|
||
*
|
||
* Based on
|
||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||
* Digest Algorithm, as defined in RFC 1321.
|
||
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
|
||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||
* Distributed under the BSD License
|
||
* See http://pajhome.org.uk/crypt/md5 for more info.
|
||
*/
|
||
function md5(bytes) {
|
||
if (typeof bytes === 'string') {
|
||
var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
|
||
|
||
bytes = new Uint8Array(msg.length);
|
||
|
||
for (var i = 0; i < msg.length; ++i) {
|
||
bytes[i] = msg.charCodeAt(i);
|
||
}
|
||
}
|
||
|
||
return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8));
|
||
}
|
||
/*
|
||
* Convert an array of little-endian words to an array of bytes
|
||
*/
|
||
|
||
|
||
function md5ToHexEncodedArray(input) {
|
||
var output = [];
|
||
var length32 = input.length * 32;
|
||
var hexTab = '0123456789abcdef';
|
||
|
||
for (var i = 0; i < length32; i += 8) {
|
||
var x = input[i >> 5] >>> i % 32 & 0xff;
|
||
var hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16);
|
||
output.push(hex);
|
||
}
|
||
|
||
return output;
|
||
}
|
||
/**
|
||
* Calculate output length with padding and bit length
|
||
*/
|
||
|
||
|
||
function getOutputLength(inputLength8) {
|
||
return (inputLength8 + 64 >>> 9 << 4) + 14 + 1;
|
||
}
|
||
/*
|
||
* Calculate the MD5 of an array of little-endian words, and a bit length.
|
||
*/
|
||
|
||
|
||
function wordsToMd5(x, len) {
|
||
/* append padding */
|
||
x[len >> 5] |= 0x80 << len % 32;
|
||
x[getOutputLength(len) - 1] = len;
|
||
var a = 1732584193;
|
||
var b = -271733879;
|
||
var c = -1732584194;
|
||
var d = 271733878;
|
||
|
||
for (var i = 0; i < x.length; i += 16) {
|
||
var olda = a;
|
||
var oldb = b;
|
||
var oldc = c;
|
||
var oldd = d;
|
||
a = md5ff(a, b, c, d, x[i], 7, -680876936);
|
||
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
|
||
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
|
||
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
|
||
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
|
||
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
|
||
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
|
||
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
|
||
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
|
||
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
|
||
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
|
||
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
|
||
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
|
||
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
|
||
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
|
||
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
|
||
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
|
||
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
|
||
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
|
||
b = md5gg(b, c, d, a, x[i], 20, -373897302);
|
||
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
|
||
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
|
||
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
|
||
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
|
||
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
|
||
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
|
||
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
|
||
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
|
||
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
|
||
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
|
||
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
|
||
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
|
||
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
|
||
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
|
||
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
|
||
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
|
||
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
|
||
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
|
||
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
|
||
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
|
||
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
|
||
d = md5hh(d, a, b, c, x[i], 11, -358537222);
|
||
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
|
||
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
|
||
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
|
||
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
|
||
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
|
||
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
|
||
a = md5ii(a, b, c, d, x[i], 6, -198630844);
|
||
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
|
||
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
|
||
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
|
||
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
|
||
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
|
||
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
|
||
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
|
||
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
|
||
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
|
||
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
|
||
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
|
||
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
|
||
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
|
||
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
|
||
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
|
||
a = safeAdd(a, olda);
|
||
b = safeAdd(b, oldb);
|
||
c = safeAdd(c, oldc);
|
||
d = safeAdd(d, oldd);
|
||
}
|
||
|
||
return [a, b, c, d];
|
||
}
|
||
/*
|
||
* Convert an array bytes to an array of little-endian words
|
||
* Characters >255 have their high-byte silently ignored.
|
||
*/
|
||
|
||
|
||
function bytesToWords(input) {
|
||
if (input.length === 0) {
|
||
return [];
|
||
}
|
||
|
||
var length8 = input.length * 8;
|
||
var output = new Uint32Array(getOutputLength(length8));
|
||
|
||
for (var i = 0; i < length8; i += 8) {
|
||
output[i >> 5] |= (input[i / 8] & 0xff) << i % 32;
|
||
}
|
||
|
||
return output;
|
||
}
|
||
/*
|
||
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||
* to work around bugs in some JS interpreters.
|
||
*/
|
||
|
||
|
||
function safeAdd(x, y) {
|
||
var lsw = (x & 0xffff) + (y & 0xffff);
|
||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||
return msw << 16 | lsw & 0xffff;
|
||
}
|
||
/*
|
||
* Bitwise rotate a 32-bit number to the left.
|
||
*/
|
||
|
||
|
||
function bitRotateLeft(num, cnt) {
|
||
return num << cnt | num >>> 32 - cnt;
|
||
}
|
||
/*
|
||
* These functions implement the four basic operations the algorithm uses.
|
||
*/
|
||
|
||
|
||
function md5cmn(q, a, b, x, s, t) {
|
||
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
|
||
}
|
||
|
||
function md5ff(a, b, c, d, x, s, t) {
|
||
return md5cmn(b & c | ~b & d, a, b, x, s, t);
|
||
}
|
||
|
||
function md5gg(a, b, c, d, x, s, t) {
|
||
return md5cmn(b & d | c & ~d, a, b, x, s, t);
|
||
}
|
||
|
||
function md5hh(a, b, c, d, x, s, t) {
|
||
return md5cmn(b ^ c ^ d, a, b, x, s, t);
|
||
}
|
||
|
||
function md5ii(a, b, c, d, x, s, t) {
|
||
return md5cmn(c ^ (b | ~d), a, b, x, s, t);
|
||
}
|
||
|
||
var v3 = v35('v3', 0x30, md5);
|
||
var v3$1 = v3;
|
||
|
||
function v4(options, buf, offset) {
|
||
options = options || {};
|
||
var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
||
|
||
rnds[6] = rnds[6] & 0x0f | 0x40;
|
||
rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
|
||
|
||
if (buf) {
|
||
offset = offset || 0;
|
||
|
||
for (var i = 0; i < 16; ++i) {
|
||
buf[offset + i] = rnds[i];
|
||
}
|
||
|
||
return buf;
|
||
}
|
||
|
||
return stringify(rnds);
|
||
}
|
||
|
||
// Adapted from Chris Veness' SHA1 code at
|
||
// http://www.movable-type.co.uk/scripts/sha1.html
|
||
function f(s, x, y, z) {
|
||
switch (s) {
|
||
case 0:
|
||
return x & y ^ ~x & z;
|
||
|
||
case 1:
|
||
return x ^ y ^ z;
|
||
|
||
case 2:
|
||
return x & y ^ x & z ^ y & z;
|
||
|
||
case 3:
|
||
return x ^ y ^ z;
|
||
}
|
||
}
|
||
|
||
function ROTL(x, n) {
|
||
return x << n | x >>> 32 - n;
|
||
}
|
||
|
||
function sha1(bytes) {
|
||
var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
|
||
var H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
|
||
|
||
if (typeof bytes === 'string') {
|
||
var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
|
||
|
||
bytes = [];
|
||
|
||
for (var i = 0; i < msg.length; ++i) {
|
||
bytes.push(msg.charCodeAt(i));
|
||
}
|
||
} else if (!Array.isArray(bytes)) {
|
||
// Convert Array-like to Array
|
||
bytes = Array.prototype.slice.call(bytes);
|
||
}
|
||
|
||
bytes.push(0x80);
|
||
var l = bytes.length / 4 + 2;
|
||
var N = Math.ceil(l / 16);
|
||
var M = new Array(N);
|
||
|
||
for (var _i = 0; _i < N; ++_i) {
|
||
var arr = new Uint32Array(16);
|
||
|
||
for (var j = 0; j < 16; ++j) {
|
||
arr[j] = bytes[_i * 64 + j * 4] << 24 | bytes[_i * 64 + j * 4 + 1] << 16 | bytes[_i * 64 + j * 4 + 2] << 8 | bytes[_i * 64 + j * 4 + 3];
|
||
}
|
||
|
||
M[_i] = arr;
|
||
}
|
||
|
||
M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32);
|
||
M[N - 1][14] = Math.floor(M[N - 1][14]);
|
||
M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff;
|
||
|
||
for (var _i2 = 0; _i2 < N; ++_i2) {
|
||
var W = new Uint32Array(80);
|
||
|
||
for (var t = 0; t < 16; ++t) {
|
||
W[t] = M[_i2][t];
|
||
}
|
||
|
||
for (var _t = 16; _t < 80; ++_t) {
|
||
W[_t] = ROTL(W[_t - 3] ^ W[_t - 8] ^ W[_t - 14] ^ W[_t - 16], 1);
|
||
}
|
||
|
||
var a = H[0];
|
||
var b = H[1];
|
||
var c = H[2];
|
||
var d = H[3];
|
||
var e = H[4];
|
||
|
||
for (var _t2 = 0; _t2 < 80; ++_t2) {
|
||
var s = Math.floor(_t2 / 20);
|
||
var T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[_t2] >>> 0;
|
||
e = d;
|
||
d = c;
|
||
c = ROTL(b, 30) >>> 0;
|
||
b = a;
|
||
a = T;
|
||
}
|
||
|
||
H[0] = H[0] + a >>> 0;
|
||
H[1] = H[1] + b >>> 0;
|
||
H[2] = H[2] + c >>> 0;
|
||
H[3] = H[3] + d >>> 0;
|
||
H[4] = H[4] + e >>> 0;
|
||
}
|
||
|
||
return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff];
|
||
}
|
||
|
||
var v5 = v35('v5', 0x50, sha1);
|
||
var v5$1 = v5;
|
||
|
||
var nil = '00000000-0000-0000-0000-000000000000';
|
||
|
||
function version(uuid) {
|
||
if (!validate(uuid)) {
|
||
throw TypeError('Invalid UUID');
|
||
}
|
||
|
||
return parseInt(uuid.substr(14, 1), 16);
|
||
}
|
||
|
||
var esmBrowser = /*#__PURE__*/Object.freeze({
|
||
__proto__: null,
|
||
NIL: nil,
|
||
parse: parse,
|
||
stringify: stringify,
|
||
v1: v1,
|
||
v3: v3$1,
|
||
v4: v4,
|
||
v5: v5$1,
|
||
validate: validate,
|
||
version: version
|
||
});
|
||
|
||
var require$$0 = /*@__PURE__*/getAugmentedNamespace(esmBrowser);
|
||
|
||
const uuid$1 = require$$0.v4;
|
||
|
||
/**
|
||
* Generates a JSON-RPC 1.0 or 2.0 request
|
||
* @param {String} method Name of method to call
|
||
* @param {Array|Object} params Array of parameters passed to the method as specified, or an object of parameter names and corresponding value
|
||
* @param {String|Number|null} [id] Request ID can be a string, number, null for explicit notification or left out for automatic generation
|
||
* @param {Object} [options]
|
||
* @param {Number} [options.version=2] JSON-RPC version to use (1 or 2)
|
||
* @param {Boolean} [options.notificationIdNull=false] When true, version 2 requests will set id to null instead of omitting it
|
||
* @param {Function} [options.generator] Passed the request, and the options object and is expected to return a request ID
|
||
* @throws {TypeError} If any of the parameters are invalid
|
||
* @return {Object} A JSON-RPC 1.0 or 2.0 request
|
||
* @memberOf Utils
|
||
*/
|
||
const generateRequest$1 = function(method, params, id, options) {
|
||
if(typeof method !== 'string') {
|
||
throw new TypeError(method + ' must be a string');
|
||
}
|
||
|
||
options = options || {};
|
||
|
||
// check valid version provided
|
||
const version = typeof options.version === 'number' ? options.version : 2;
|
||
if (version !== 1 && version !== 2) {
|
||
throw new TypeError(version + ' must be 1 or 2');
|
||
}
|
||
|
||
const request = {
|
||
method: method
|
||
};
|
||
|
||
if(version === 2) {
|
||
request.jsonrpc = '2.0';
|
||
}
|
||
|
||
if(params) {
|
||
// params given, but invalid?
|
||
if(typeof params !== 'object' && !Array.isArray(params)) {
|
||
throw new TypeError(params + ' must be an object, array or omitted');
|
||
}
|
||
request.params = params;
|
||
}
|
||
|
||
// if id was left out, generate one (null means explicit notification)
|
||
if(typeof(id) === 'undefined') {
|
||
const generator = typeof options.generator === 'function' ? options.generator : function() { return uuid$1(); };
|
||
request.id = generator(request, options);
|
||
} else if (version === 2 && id === null) {
|
||
// we have a version 2 notification
|
||
if (options.notificationIdNull) {
|
||
request.id = null; // id will not be set at all unless option provided
|
||
}
|
||
} else {
|
||
request.id = id;
|
||
}
|
||
|
||
return request;
|
||
};
|
||
|
||
var generateRequest_1 = generateRequest$1;
|
||
|
||
const uuid = require$$0.v4;
|
||
const generateRequest = generateRequest_1;
|
||
|
||
/**
|
||
* Constructor for a Jayson Browser Client that does not depend any node.js core libraries
|
||
* @class ClientBrowser
|
||
* @param {Function} callServer Method that calls the server, receives the stringified request and a regular node-style callback
|
||
* @param {Object} [options]
|
||
* @param {Function} [options.reviver] Reviver function for JSON
|
||
* @param {Function} [options.replacer] Replacer function for JSON
|
||
* @param {Number} [options.version=2] JSON-RPC version to use (1|2)
|
||
* @param {Function} [options.generator] Function to use for generating request IDs
|
||
* @param {Boolean} [options.notificationIdNull=false] When true, version 2 requests will set id to null instead of omitting it
|
||
* @return {ClientBrowser}
|
||
*/
|
||
const ClientBrowser = function(callServer, options) {
|
||
if(!(this instanceof ClientBrowser)) {
|
||
return new ClientBrowser(callServer, options);
|
||
}
|
||
|
||
if (!options) {
|
||
options = {};
|
||
}
|
||
|
||
this.options = {
|
||
reviver: typeof options.reviver !== 'undefined' ? options.reviver : null,
|
||
replacer: typeof options.replacer !== 'undefined' ? options.replacer : null,
|
||
generator: typeof options.generator !== 'undefined' ? options.generator : function() { return uuid(); },
|
||
version: typeof options.version !== 'undefined' ? options.version : 2,
|
||
notificationIdNull: typeof options.notificationIdNull === 'boolean' ? options.notificationIdNull : false,
|
||
};
|
||
|
||
this.callServer = callServer;
|
||
};
|
||
|
||
var browser = ClientBrowser;
|
||
|
||
/**
|
||
* Creates a request and dispatches it if given a callback.
|
||
* @param {String|Array} method A batch request if passed an Array, or a method name if passed a String
|
||
* @param {Array|Object} [params] Parameters for the method
|
||
* @param {String|Number} [id] Optional id. If undefined an id will be generated. If null it creates a notification request
|
||
* @param {Function} [callback] Request callback. If specified, executes the request rather than only returning it.
|
||
* @throws {TypeError} Invalid parameters
|
||
* @return {Object} JSON-RPC 1.0 or 2.0 compatible request
|
||
*/
|
||
ClientBrowser.prototype.request = function(method, params, id, callback) {
|
||
const self = this;
|
||
let request = null;
|
||
|
||
// is this a batch request?
|
||
const isBatch = Array.isArray(method) && typeof params === 'function';
|
||
|
||
if (this.options.version === 1 && isBatch) {
|
||
throw new TypeError('JSON-RPC 1.0 does not support batching');
|
||
}
|
||
|
||
// is this a raw request?
|
||
const isRaw = !isBatch && method && typeof method === 'object' && typeof params === 'function';
|
||
|
||
if(isBatch || isRaw) {
|
||
callback = params;
|
||
request = method;
|
||
} else {
|
||
if(typeof id === 'function') {
|
||
callback = id;
|
||
// specifically undefined because "null" is a notification request
|
||
id = undefined;
|
||
}
|
||
|
||
const hasCallback = typeof callback === 'function';
|
||
|
||
try {
|
||
request = generateRequest(method, params, id, {
|
||
generator: this.options.generator,
|
||
version: this.options.version,
|
||
notificationIdNull: this.options.notificationIdNull,
|
||
});
|
||
} catch(err) {
|
||
if(hasCallback) {
|
||
return callback(err);
|
||
}
|
||
throw err;
|
||
}
|
||
|
||
// no callback means we should just return a raw request
|
||
if(!hasCallback) {
|
||
return request;
|
||
}
|
||
|
||
}
|
||
|
||
let message;
|
||
try {
|
||
message = JSON.stringify(request, this.options.replacer);
|
||
} catch(err) {
|
||
return callback(err);
|
||
}
|
||
|
||
this.callServer(message, function(err, response) {
|
||
self._parseResponse(err, response, callback);
|
||
});
|
||
|
||
// always return the raw request
|
||
return request;
|
||
};
|
||
|
||
/**
|
||
* Parses a response from a server
|
||
* @param {Object} err Error to pass on that is unrelated to the actual response
|
||
* @param {String} responseText JSON-RPC 1.0 or 2.0 response
|
||
* @param {Function} callback Callback that will receive different arguments depending on the amount of parameters
|
||
* @private
|
||
*/
|
||
ClientBrowser.prototype._parseResponse = function(err, responseText, callback) {
|
||
if(err) {
|
||
callback(err);
|
||
return;
|
||
}
|
||
|
||
if(!responseText) {
|
||
// empty response text, assume that is correct because it could be a
|
||
// notification which jayson does not give any body for
|
||
return callback();
|
||
}
|
||
|
||
let response;
|
||
try {
|
||
response = JSON.parse(responseText, this.options.reviver);
|
||
} catch(err) {
|
||
return callback(err);
|
||
}
|
||
|
||
if(callback.length === 3) {
|
||
// if callback length is 3, we split callback arguments on error and response
|
||
|
||
// is batch response?
|
||
if(Array.isArray(response)) {
|
||
|
||
// neccesary to split strictly on validity according to spec here
|
||
const isError = function(res) {
|
||
return typeof res.error !== 'undefined';
|
||
};
|
||
|
||
const isNotError = function (res) {
|
||
return !isError(res);
|
||
};
|
||
|
||
return callback(null, response.filter(isError), response.filter(isNotError));
|
||
|
||
} else {
|
||
|
||
// split regardless of validity
|
||
return callback(null, response.error, response.result);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
callback(null, response);
|
||
};
|
||
|
||
var RpcClient = /*@__PURE__*/getDefaultExportFromCjs(browser);
|
||
|
||
const MINIMUM_SLOT_PER_EPOCH = 32;
|
||
|
||
// Returns the number of trailing zeros in the binary representation of self.
|
||
function trailingZeros(n) {
|
||
let trailingZeros = 0;
|
||
while (n > 1) {
|
||
n /= 2;
|
||
trailingZeros++;
|
||
}
|
||
return trailingZeros;
|
||
}
|
||
|
||
// Returns the smallest power of two greater than or equal to n
|
||
function nextPowerOfTwo(n) {
|
||
if (n === 0) return 1;
|
||
n--;
|
||
n |= n >> 1;
|
||
n |= n >> 2;
|
||
n |= n >> 4;
|
||
n |= n >> 8;
|
||
n |= n >> 16;
|
||
n |= n >> 32;
|
||
return n + 1;
|
||
}
|
||
|
||
/**
|
||
* Epoch schedule
|
||
* (see https://docs.solana.com/terminology#epoch)
|
||
* Can be retrieved with the {@link Connection.getEpochSchedule} method
|
||
*/
|
||
class EpochSchedule {
|
||
constructor(slotsPerEpoch, leaderScheduleSlotOffset, warmup, firstNormalEpoch, firstNormalSlot) {
|
||
/** The maximum number of slots in each epoch */
|
||
this.slotsPerEpoch = void 0;
|
||
/** The number of slots before beginning of an epoch to calculate a leader schedule for that epoch */
|
||
this.leaderScheduleSlotOffset = void 0;
|
||
/** Indicates whether epochs start short and grow */
|
||
this.warmup = void 0;
|
||
/** The first epoch with `slotsPerEpoch` slots */
|
||
this.firstNormalEpoch = void 0;
|
||
/** The first slot of `firstNormalEpoch` */
|
||
this.firstNormalSlot = void 0;
|
||
this.slotsPerEpoch = slotsPerEpoch;
|
||
this.leaderScheduleSlotOffset = leaderScheduleSlotOffset;
|
||
this.warmup = warmup;
|
||
this.firstNormalEpoch = firstNormalEpoch;
|
||
this.firstNormalSlot = firstNormalSlot;
|
||
}
|
||
getEpoch(slot) {
|
||
return this.getEpochAndSlotIndex(slot)[0];
|
||
}
|
||
getEpochAndSlotIndex(slot) {
|
||
if (slot < this.firstNormalSlot) {
|
||
const epoch = trailingZeros(nextPowerOfTwo(slot + MINIMUM_SLOT_PER_EPOCH + 1)) - trailingZeros(MINIMUM_SLOT_PER_EPOCH) - 1;
|
||
const epochLen = this.getSlotsInEpoch(epoch);
|
||
const slotIndex = slot - (epochLen - MINIMUM_SLOT_PER_EPOCH);
|
||
return [epoch, slotIndex];
|
||
} else {
|
||
const normalSlotIndex = slot - this.firstNormalSlot;
|
||
const normalEpochIndex = Math.floor(normalSlotIndex / this.slotsPerEpoch);
|
||
const epoch = this.firstNormalEpoch + normalEpochIndex;
|
||
const slotIndex = normalSlotIndex % this.slotsPerEpoch;
|
||
return [epoch, slotIndex];
|
||
}
|
||
}
|
||
getFirstSlotInEpoch(epoch) {
|
||
if (epoch <= this.firstNormalEpoch) {
|
||
return (Math.pow(2, epoch) - 1) * MINIMUM_SLOT_PER_EPOCH;
|
||
} else {
|
||
return (epoch - this.firstNormalEpoch) * this.slotsPerEpoch + this.firstNormalSlot;
|
||
}
|
||
}
|
||
getLastSlotInEpoch(epoch) {
|
||
return this.getFirstSlotInEpoch(epoch) + this.getSlotsInEpoch(epoch) - 1;
|
||
}
|
||
getSlotsInEpoch(epoch) {
|
||
if (epoch < this.firstNormalEpoch) {
|
||
return Math.pow(2, epoch + trailingZeros(MINIMUM_SLOT_PER_EPOCH));
|
||
} else {
|
||
return this.slotsPerEpoch;
|
||
}
|
||
}
|
||
}
|
||
|
||
class SendTransactionError extends Error {
|
||
constructor(message, logs) {
|
||
super(message);
|
||
this.logs = void 0;
|
||
this.logs = logs;
|
||
}
|
||
}
|
||
|
||
// Keep in sync with client/src/rpc_custom_errors.rs
|
||
// Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
|
||
const SolanaJSONRPCErrorCode = {
|
||
JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: -32001,
|
||
JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: -32002,
|
||
JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: -32003,
|
||
JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: -32004,
|
||
JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY: -32005,
|
||
JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: -32006,
|
||
JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: -32007,
|
||
JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: -32008,
|
||
JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: -32009,
|
||
JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: -32010,
|
||
JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: -32011,
|
||
JSON_RPC_SCAN_ERROR: -32012,
|
||
JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: -32013,
|
||
JSON_RPC_SERVER_ERROR_BLOCK_STATUS_NOT_AVAILABLE_YET: -32014,
|
||
JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION: -32015,
|
||
JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED: -32016
|
||
};
|
||
class SolanaJSONRPCError extends Error {
|
||
constructor({
|
||
code,
|
||
message,
|
||
data
|
||
}, customMessage) {
|
||
super(customMessage != null ? `${customMessage}: ${message}` : message);
|
||
this.code = void 0;
|
||
this.data = void 0;
|
||
this.code = code;
|
||
this.data = data;
|
||
this.name = 'SolanaJSONRPCError';
|
||
}
|
||
}
|
||
|
||
var fetchImpl = globalThis.fetch;
|
||
|
||
var client = {};
|
||
|
||
var interopRequireDefault = {exports: {}};
|
||
|
||
(function (module) {
|
||
function _interopRequireDefault(obj) {
|
||
return obj && obj.__esModule ? obj : {
|
||
"default": obj
|
||
};
|
||
}
|
||
module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (interopRequireDefault));
|
||
|
||
var interopRequireDefaultExports = interopRequireDefault.exports;
|
||
|
||
var regeneratorRuntime$1 = {exports: {}};
|
||
|
||
var _typeof = {exports: {}};
|
||
|
||
var hasRequired_typeof;
|
||
|
||
function require_typeof () {
|
||
if (hasRequired_typeof) return _typeof.exports;
|
||
hasRequired_typeof = 1;
|
||
(function (module) {
|
||
function _typeof(o) {
|
||
"@babel/helpers - typeof";
|
||
|
||
return (module.exports = _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
|
||
return typeof o;
|
||
} : function (o) {
|
||
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
||
}, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(o);
|
||
}
|
||
module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (_typeof));
|
||
return _typeof.exports;
|
||
}
|
||
|
||
var hasRequiredRegeneratorRuntime;
|
||
|
||
function requireRegeneratorRuntime () {
|
||
if (hasRequiredRegeneratorRuntime) return regeneratorRuntime$1.exports;
|
||
hasRequiredRegeneratorRuntime = 1;
|
||
(function (module) {
|
||
var _typeof = require_typeof()["default"];
|
||
function _regeneratorRuntime() {
|
||
module.exports = _regeneratorRuntime = function _regeneratorRuntime() {
|
||
return e;
|
||
}, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
var t,
|
||
e = {},
|
||
r = Object.prototype,
|
||
n = r.hasOwnProperty,
|
||
o = Object.defineProperty || function (t, e, r) {
|
||
t[e] = r.value;
|
||
},
|
||
i = "function" == typeof Symbol ? Symbol : {},
|
||
a = i.iterator || "@@iterator",
|
||
c = i.asyncIterator || "@@asyncIterator",
|
||
u = i.toStringTag || "@@toStringTag";
|
||
function define(t, e, r) {
|
||
return Object.defineProperty(t, e, {
|
||
value: r,
|
||
enumerable: !0,
|
||
configurable: !0,
|
||
writable: !0
|
||
}), t[e];
|
||
}
|
||
try {
|
||
define({}, "");
|
||
} catch (t) {
|
||
define = function define(t, e, r) {
|
||
return t[e] = r;
|
||
};
|
||
}
|
||
function wrap(t, e, r, n) {
|
||
var i = e && e.prototype instanceof Generator ? e : Generator,
|
||
a = Object.create(i.prototype),
|
||
c = new Context(n || []);
|
||
return o(a, "_invoke", {
|
||
value: makeInvokeMethod(t, r, c)
|
||
}), a;
|
||
}
|
||
function tryCatch(t, e, r) {
|
||
try {
|
||
return {
|
||
type: "normal",
|
||
arg: t.call(e, r)
|
||
};
|
||
} catch (t) {
|
||
return {
|
||
type: "throw",
|
||
arg: t
|
||
};
|
||
}
|
||
}
|
||
e.wrap = wrap;
|
||
var h = "suspendedStart",
|
||
l = "suspendedYield",
|
||
f = "executing",
|
||
s = "completed",
|
||
y = {};
|
||
function Generator() {}
|
||
function GeneratorFunction() {}
|
||
function GeneratorFunctionPrototype() {}
|
||
var p = {};
|
||
define(p, a, function () {
|
||
return this;
|
||
});
|
||
var d = Object.getPrototypeOf,
|
||
v = d && d(d(values([])));
|
||
v && v !== r && n.call(v, a) && (p = v);
|
||
var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p);
|
||
function defineIteratorMethods(t) {
|
||
["next", "throw", "return"].forEach(function (e) {
|
||
define(t, e, function (t) {
|
||
return this._invoke(e, t);
|
||
});
|
||
});
|
||
}
|
||
function AsyncIterator(t, e) {
|
||
function invoke(r, o, i, a) {
|
||
var c = tryCatch(t[r], t, o);
|
||
if ("throw" !== c.type) {
|
||
var u = c.arg,
|
||
h = u.value;
|
||
return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) {
|
||
invoke("next", t, i, a);
|
||
}, function (t) {
|
||
invoke("throw", t, i, a);
|
||
}) : e.resolve(h).then(function (t) {
|
||
u.value = t, i(u);
|
||
}, function (t) {
|
||
return invoke("throw", t, i, a);
|
||
});
|
||
}
|
||
a(c.arg);
|
||
}
|
||
var r;
|
||
o(this, "_invoke", {
|
||
value: function value(t, n) {
|
||
function callInvokeWithMethodAndArg() {
|
||
return new e(function (e, r) {
|
||
invoke(t, n, e, r);
|
||
});
|
||
}
|
||
return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
|
||
}
|
||
});
|
||
}
|
||
function makeInvokeMethod(e, r, n) {
|
||
var o = h;
|
||
return function (i, a) {
|
||
if (o === f) throw new Error("Generator is already running");
|
||
if (o === s) {
|
||
if ("throw" === i) throw a;
|
||
return {
|
||
value: t,
|
||
done: !0
|
||
};
|
||
}
|
||
for (n.method = i, n.arg = a;;) {
|
||
var c = n.delegate;
|
||
if (c) {
|
||
var u = maybeInvokeDelegate(c, n);
|
||
if (u) {
|
||
if (u === y) continue;
|
||
return u;
|
||
}
|
||
}
|
||
if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
|
||
if (o === h) throw o = s, n.arg;
|
||
n.dispatchException(n.arg);
|
||
} else "return" === n.method && n.abrupt("return", n.arg);
|
||
o = f;
|
||
var p = tryCatch(e, r, n);
|
||
if ("normal" === p.type) {
|
||
if (o = n.done ? s : l, p.arg === y) continue;
|
||
return {
|
||
value: p.arg,
|
||
done: n.done
|
||
};
|
||
}
|
||
"throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg);
|
||
}
|
||
};
|
||
}
|
||
function maybeInvokeDelegate(e, r) {
|
||
var n = r.method,
|
||
o = e.iterator[n];
|
||
if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y;
|
||
var i = tryCatch(o, e.iterator, r.arg);
|
||
if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y;
|
||
var a = i.arg;
|
||
return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y);
|
||
}
|
||
function pushTryEntry(t) {
|
||
var e = {
|
||
tryLoc: t[0]
|
||
};
|
||
1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e);
|
||
}
|
||
function resetTryEntry(t) {
|
||
var e = t.completion || {};
|
||
e.type = "normal", delete e.arg, t.completion = e;
|
||
}
|
||
function Context(t) {
|
||
this.tryEntries = [{
|
||
tryLoc: "root"
|
||
}], t.forEach(pushTryEntry, this), this.reset(!0);
|
||
}
|
||
function values(e) {
|
||
if (e || "" === e) {
|
||
var r = e[a];
|
||
if (r) return r.call(e);
|
||
if ("function" == typeof e.next) return e;
|
||
if (!isNaN(e.length)) {
|
||
var o = -1,
|
||
i = function next() {
|
||
for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next;
|
||
return next.value = t, next.done = !0, next;
|
||
};
|
||
return i.next = i;
|
||
}
|
||
}
|
||
throw new TypeError(_typeof(e) + " is not iterable");
|
||
}
|
||
return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", {
|
||
value: GeneratorFunctionPrototype,
|
||
configurable: !0
|
||
}), o(GeneratorFunctionPrototype, "constructor", {
|
||
value: GeneratorFunction,
|
||
configurable: !0
|
||
}), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) {
|
||
var e = "function" == typeof t && t.constructor;
|
||
return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name));
|
||
}, e.mark = function (t) {
|
||
return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t;
|
||
}, e.awrap = function (t) {
|
||
return {
|
||
__await: t
|
||
};
|
||
}, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () {
|
||
return this;
|
||
}), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) {
|
||
void 0 === i && (i = Promise);
|
||
var a = new AsyncIterator(wrap(t, r, n, o), i);
|
||
return e.isGeneratorFunction(r) ? a : a.next().then(function (t) {
|
||
return t.done ? t.value : a.next();
|
||
});
|
||
}, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () {
|
||
return this;
|
||
}), define(g, "toString", function () {
|
||
return "[object Generator]";
|
||
}), e.keys = function (t) {
|
||
var e = Object(t),
|
||
r = [];
|
||
for (var n in e) r.push(n);
|
||
return r.reverse(), function next() {
|
||
for (; r.length;) {
|
||
var t = r.pop();
|
||
if (t in e) return next.value = t, next.done = !1, next;
|
||
}
|
||
return next.done = !0, next;
|
||
};
|
||
}, e.values = values, Context.prototype = {
|
||
constructor: Context,
|
||
reset: function reset(e) {
|
||
if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t);
|
||
},
|
||
stop: function stop() {
|
||
this.done = !0;
|
||
var t = this.tryEntries[0].completion;
|
||
if ("throw" === t.type) throw t.arg;
|
||
return this.rval;
|
||
},
|
||
dispatchException: function dispatchException(e) {
|
||
if (this.done) throw e;
|
||
var r = this;
|
||
function handle(n, o) {
|
||
return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o;
|
||
}
|
||
for (var o = this.tryEntries.length - 1; o >= 0; --o) {
|
||
var i = this.tryEntries[o],
|
||
a = i.completion;
|
||
if ("root" === i.tryLoc) return handle("end");
|
||
if (i.tryLoc <= this.prev) {
|
||
var c = n.call(i, "catchLoc"),
|
||
u = n.call(i, "finallyLoc");
|
||
if (c && u) {
|
||
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
|
||
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
|
||
} else if (c) {
|
||
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
|
||
} else {
|
||
if (!u) throw new Error("try statement without catch or finally");
|
||
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
|
||
}
|
||
}
|
||
}
|
||
},
|
||
abrupt: function abrupt(t, e) {
|
||
for (var r = this.tryEntries.length - 1; r >= 0; --r) {
|
||
var o = this.tryEntries[r];
|
||
if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) {
|
||
var i = o;
|
||
break;
|
||
}
|
||
}
|
||
i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null);
|
||
var a = i ? i.completion : {};
|
||
return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a);
|
||
},
|
||
complete: function complete(t, e) {
|
||
if ("throw" === t.type) throw t.arg;
|
||
return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y;
|
||
},
|
||
finish: function finish(t) {
|
||
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
|
||
var r = this.tryEntries[e];
|
||
if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y;
|
||
}
|
||
},
|
||
"catch": function _catch(t) {
|
||
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
|
||
var r = this.tryEntries[e];
|
||
if (r.tryLoc === t) {
|
||
var n = r.completion;
|
||
if ("throw" === n.type) {
|
||
var o = n.arg;
|
||
resetTryEntry(r);
|
||
}
|
||
return o;
|
||
}
|
||
}
|
||
throw new Error("illegal catch attempt");
|
||
},
|
||
delegateYield: function delegateYield(e, r, n) {
|
||
return this.delegate = {
|
||
iterator: values(e),
|
||
resultName: r,
|
||
nextLoc: n
|
||
}, "next" === this.method && (this.arg = t), y;
|
||
}
|
||
}, e;
|
||
}
|
||
module.exports = _regeneratorRuntime, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (regeneratorRuntime$1));
|
||
return regeneratorRuntime$1.exports;
|
||
}
|
||
|
||
var regenerator;
|
||
var hasRequiredRegenerator;
|
||
|
||
function requireRegenerator () {
|
||
if (hasRequiredRegenerator) return regenerator;
|
||
hasRequiredRegenerator = 1;
|
||
// TODO(Babel 8): Remove this file.
|
||
|
||
var runtime = requireRegeneratorRuntime()();
|
||
regenerator = runtime;
|
||
|
||
// Copied from https://github.com/facebook/regenerator/blob/main/packages/runtime/runtime.js#L736=
|
||
try {
|
||
regeneratorRuntime = runtime;
|
||
} catch (accidentalStrictMode) {
|
||
if (typeof globalThis === "object") {
|
||
globalThis.regeneratorRuntime = runtime;
|
||
} else {
|
||
Function("r", "regeneratorRuntime = r")(runtime);
|
||
}
|
||
}
|
||
return regenerator;
|
||
}
|
||
|
||
var asyncToGenerator = {exports: {}};
|
||
|
||
var hasRequiredAsyncToGenerator;
|
||
|
||
function requireAsyncToGenerator () {
|
||
if (hasRequiredAsyncToGenerator) return asyncToGenerator.exports;
|
||
hasRequiredAsyncToGenerator = 1;
|
||
(function (module) {
|
||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
||
try {
|
||
var info = gen[key](arg);
|
||
var value = info.value;
|
||
} catch (error) {
|
||
reject(error);
|
||
return;
|
||
}
|
||
if (info.done) {
|
||
resolve(value);
|
||
} else {
|
||
Promise.resolve(value).then(_next, _throw);
|
||
}
|
||
}
|
||
function _asyncToGenerator(fn) {
|
||
return function () {
|
||
var self = this,
|
||
args = arguments;
|
||
return new Promise(function (resolve, reject) {
|
||
var gen = fn.apply(self, args);
|
||
function _next(value) {
|
||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
||
}
|
||
function _throw(err) {
|
||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
||
}
|
||
_next(undefined);
|
||
});
|
||
};
|
||
}
|
||
module.exports = _asyncToGenerator, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (asyncToGenerator));
|
||
return asyncToGenerator.exports;
|
||
}
|
||
|
||
var classCallCheck = {exports: {}};
|
||
|
||
var hasRequiredClassCallCheck;
|
||
|
||
function requireClassCallCheck () {
|
||
if (hasRequiredClassCallCheck) return classCallCheck.exports;
|
||
hasRequiredClassCallCheck = 1;
|
||
(function (module) {
|
||
function _classCallCheck(instance, Constructor) {
|
||
if (!(instance instanceof Constructor)) {
|
||
throw new TypeError("Cannot call a class as a function");
|
||
}
|
||
}
|
||
module.exports = _classCallCheck, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (classCallCheck));
|
||
return classCallCheck.exports;
|
||
}
|
||
|
||
var createClass = {exports: {}};
|
||
|
||
var toPropertyKey = {exports: {}};
|
||
|
||
var toPrimitive = {exports: {}};
|
||
|
||
var hasRequiredToPrimitive;
|
||
|
||
function requireToPrimitive () {
|
||
if (hasRequiredToPrimitive) return toPrimitive.exports;
|
||
hasRequiredToPrimitive = 1;
|
||
(function (module) {
|
||
var _typeof = require_typeof()["default"];
|
||
function _toPrimitive(input, hint) {
|
||
if (_typeof(input) !== "object" || input === null) return input;
|
||
var prim = input[Symbol.toPrimitive];
|
||
if (prim !== undefined) {
|
||
var res = prim.call(input, hint || "default");
|
||
if (_typeof(res) !== "object") return res;
|
||
throw new TypeError("@@toPrimitive must return a primitive value.");
|
||
}
|
||
return (hint === "string" ? String : Number)(input);
|
||
}
|
||
module.exports = _toPrimitive, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (toPrimitive));
|
||
return toPrimitive.exports;
|
||
}
|
||
|
||
var hasRequiredToPropertyKey;
|
||
|
||
function requireToPropertyKey () {
|
||
if (hasRequiredToPropertyKey) return toPropertyKey.exports;
|
||
hasRequiredToPropertyKey = 1;
|
||
(function (module) {
|
||
var _typeof = require_typeof()["default"];
|
||
var toPrimitive = requireToPrimitive();
|
||
function _toPropertyKey(arg) {
|
||
var key = toPrimitive(arg, "string");
|
||
return _typeof(key) === "symbol" ? key : String(key);
|
||
}
|
||
module.exports = _toPropertyKey, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (toPropertyKey));
|
||
return toPropertyKey.exports;
|
||
}
|
||
|
||
var hasRequiredCreateClass;
|
||
|
||
function requireCreateClass () {
|
||
if (hasRequiredCreateClass) return createClass.exports;
|
||
hasRequiredCreateClass = 1;
|
||
(function (module) {
|
||
var toPropertyKey = requireToPropertyKey();
|
||
function _defineProperties(target, props) {
|
||
for (var i = 0; i < props.length; i++) {
|
||
var descriptor = props[i];
|
||
descriptor.enumerable = descriptor.enumerable || false;
|
||
descriptor.configurable = true;
|
||
if ("value" in descriptor) descriptor.writable = true;
|
||
Object.defineProperty(target, toPropertyKey(descriptor.key), descriptor);
|
||
}
|
||
}
|
||
function _createClass(Constructor, protoProps, staticProps) {
|
||
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
||
if (staticProps) _defineProperties(Constructor, staticProps);
|
||
Object.defineProperty(Constructor, "prototype", {
|
||
writable: false
|
||
});
|
||
return Constructor;
|
||
}
|
||
module.exports = _createClass, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (createClass));
|
||
return createClass.exports;
|
||
}
|
||
|
||
var inherits = {exports: {}};
|
||
|
||
var setPrototypeOf = {exports: {}};
|
||
|
||
var hasRequiredSetPrototypeOf;
|
||
|
||
function requireSetPrototypeOf () {
|
||
if (hasRequiredSetPrototypeOf) return setPrototypeOf.exports;
|
||
hasRequiredSetPrototypeOf = 1;
|
||
(function (module) {
|
||
function _setPrototypeOf(o, p) {
|
||
module.exports = _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
|
||
o.__proto__ = p;
|
||
return o;
|
||
}, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
return _setPrototypeOf(o, p);
|
||
}
|
||
module.exports = _setPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (setPrototypeOf));
|
||
return setPrototypeOf.exports;
|
||
}
|
||
|
||
var hasRequiredInherits;
|
||
|
||
function requireInherits () {
|
||
if (hasRequiredInherits) return inherits.exports;
|
||
hasRequiredInherits = 1;
|
||
(function (module) {
|
||
var setPrototypeOf = requireSetPrototypeOf();
|
||
function _inherits(subClass, superClass) {
|
||
if (typeof superClass !== "function" && superClass !== null) {
|
||
throw new TypeError("Super expression must either be null or a function");
|
||
}
|
||
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
||
constructor: {
|
||
value: subClass,
|
||
writable: true,
|
||
configurable: true
|
||
}
|
||
});
|
||
Object.defineProperty(subClass, "prototype", {
|
||
writable: false
|
||
});
|
||
if (superClass) setPrototypeOf(subClass, superClass);
|
||
}
|
||
module.exports = _inherits, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (inherits));
|
||
return inherits.exports;
|
||
}
|
||
|
||
var possibleConstructorReturn = {exports: {}};
|
||
|
||
var assertThisInitialized = {exports: {}};
|
||
|
||
var hasRequiredAssertThisInitialized;
|
||
|
||
function requireAssertThisInitialized () {
|
||
if (hasRequiredAssertThisInitialized) return assertThisInitialized.exports;
|
||
hasRequiredAssertThisInitialized = 1;
|
||
(function (module) {
|
||
function _assertThisInitialized(self) {
|
||
if (self === void 0) {
|
||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
||
}
|
||
return self;
|
||
}
|
||
module.exports = _assertThisInitialized, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (assertThisInitialized));
|
||
return assertThisInitialized.exports;
|
||
}
|
||
|
||
var hasRequiredPossibleConstructorReturn;
|
||
|
||
function requirePossibleConstructorReturn () {
|
||
if (hasRequiredPossibleConstructorReturn) return possibleConstructorReturn.exports;
|
||
hasRequiredPossibleConstructorReturn = 1;
|
||
(function (module) {
|
||
var _typeof = require_typeof()["default"];
|
||
var assertThisInitialized = requireAssertThisInitialized();
|
||
function _possibleConstructorReturn(self, call) {
|
||
if (call && (_typeof(call) === "object" || typeof call === "function")) {
|
||
return call;
|
||
} else if (call !== void 0) {
|
||
throw new TypeError("Derived constructors may only return object or undefined");
|
||
}
|
||
return assertThisInitialized(self);
|
||
}
|
||
module.exports = _possibleConstructorReturn, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (possibleConstructorReturn));
|
||
return possibleConstructorReturn.exports;
|
||
}
|
||
|
||
var getPrototypeOf = {exports: {}};
|
||
|
||
var hasRequiredGetPrototypeOf;
|
||
|
||
function requireGetPrototypeOf () {
|
||
if (hasRequiredGetPrototypeOf) return getPrototypeOf.exports;
|
||
hasRequiredGetPrototypeOf = 1;
|
||
(function (module) {
|
||
function _getPrototypeOf(o) {
|
||
module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
|
||
return o.__proto__ || Object.getPrototypeOf(o);
|
||
}, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
return _getPrototypeOf(o);
|
||
}
|
||
module.exports = _getPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||
} (getPrototypeOf));
|
||
return getPrototypeOf.exports;
|
||
}
|
||
|
||
var eventemitter3 = {exports: {}};
|
||
|
||
var hasRequiredEventemitter3;
|
||
|
||
function requireEventemitter3 () {
|
||
if (hasRequiredEventemitter3) return eventemitter3.exports;
|
||
hasRequiredEventemitter3 = 1;
|
||
(function (module) {
|
||
|
||
var has = Object.prototype.hasOwnProperty
|
||
, prefix = '~';
|
||
|
||
/**
|
||
* Constructor to create a storage for our `EE` objects.
|
||
* An `Events` instance is a plain object whose properties are event names.
|
||
*
|
||
* @constructor
|
||
* @private
|
||
*/
|
||
function Events() {}
|
||
|
||
//
|
||
// We try to not inherit from `Object.prototype`. In some engines creating an
|
||
// instance in this way is faster than calling `Object.create(null)` directly.
|
||
// If `Object.create(null)` is not supported we prefix the event names with a
|
||
// character to make sure that the built-in object properties are not
|
||
// overridden or used as an attack vector.
|
||
//
|
||
if (Object.create) {
|
||
Events.prototype = Object.create(null);
|
||
|
||
//
|
||
// This hack is needed because the `__proto__` property is still inherited in
|
||
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
|
||
//
|
||
if (!new Events().__proto__) prefix = false;
|
||
}
|
||
|
||
/**
|
||
* Representation of a single event listener.
|
||
*
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} context The context to invoke the listener with.
|
||
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
|
||
* @constructor
|
||
* @private
|
||
*/
|
||
function EE(fn, context, once) {
|
||
this.fn = fn;
|
||
this.context = context;
|
||
this.once = once || false;
|
||
}
|
||
|
||
/**
|
||
* Add a listener for a given event.
|
||
*
|
||
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} context The context to invoke the listener with.
|
||
* @param {Boolean} once Specify if the listener is a one-time listener.
|
||
* @returns {EventEmitter}
|
||
* @private
|
||
*/
|
||
function addListener(emitter, event, fn, context, once) {
|
||
if (typeof fn !== 'function') {
|
||
throw new TypeError('The listener must be a function');
|
||
}
|
||
|
||
var listener = new EE(fn, context || emitter, once)
|
||
, evt = prefix ? prefix + event : event;
|
||
|
||
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
|
||
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
|
||
else emitter._events[evt] = [emitter._events[evt], listener];
|
||
|
||
return emitter;
|
||
}
|
||
|
||
/**
|
||
* Clear event by name.
|
||
*
|
||
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
||
* @param {(String|Symbol)} evt The Event name.
|
||
* @private
|
||
*/
|
||
function clearEvent(emitter, evt) {
|
||
if (--emitter._eventsCount === 0) emitter._events = new Events();
|
||
else delete emitter._events[evt];
|
||
}
|
||
|
||
/**
|
||
* Minimal `EventEmitter` interface that is molded against the Node.js
|
||
* `EventEmitter` interface.
|
||
*
|
||
* @constructor
|
||
* @public
|
||
*/
|
||
function EventEmitter() {
|
||
this._events = new Events();
|
||
this._eventsCount = 0;
|
||
}
|
||
|
||
/**
|
||
* Return an array listing the events for which the emitter has registered
|
||
* listeners.
|
||
*
|
||
* @returns {Array}
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.eventNames = function eventNames() {
|
||
var names = []
|
||
, events
|
||
, name;
|
||
|
||
if (this._eventsCount === 0) return names;
|
||
|
||
for (name in (events = this._events)) {
|
||
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
||
}
|
||
|
||
if (Object.getOwnPropertySymbols) {
|
||
return names.concat(Object.getOwnPropertySymbols(events));
|
||
}
|
||
|
||
return names;
|
||
};
|
||
|
||
/**
|
||
* Return the listeners registered for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @returns {Array} The registered listeners.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.listeners = function listeners(event) {
|
||
var evt = prefix ? prefix + event : event
|
||
, handlers = this._events[evt];
|
||
|
||
if (!handlers) return [];
|
||
if (handlers.fn) return [handlers.fn];
|
||
|
||
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
|
||
ee[i] = handlers[i].fn;
|
||
}
|
||
|
||
return ee;
|
||
};
|
||
|
||
/**
|
||
* Return the number of listeners listening to a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @returns {Number} The number of listeners.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.listenerCount = function listenerCount(event) {
|
||
var evt = prefix ? prefix + event : event
|
||
, listeners = this._events[evt];
|
||
|
||
if (!listeners) return 0;
|
||
if (listeners.fn) return 1;
|
||
return listeners.length;
|
||
};
|
||
|
||
/**
|
||
* Calls each of the listeners registered for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @returns {Boolean} `true` if the event had listeners, else `false`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
||
var evt = prefix ? prefix + event : event;
|
||
|
||
if (!this._events[evt]) return false;
|
||
|
||
var listeners = this._events[evt]
|
||
, len = arguments.length
|
||
, args
|
||
, i;
|
||
|
||
if (listeners.fn) {
|
||
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
|
||
|
||
switch (len) {
|
||
case 1: return listeners.fn.call(listeners.context), true;
|
||
case 2: return listeners.fn.call(listeners.context, a1), true;
|
||
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
|
||
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
||
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
||
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
||
}
|
||
|
||
for (i = 1, args = new Array(len -1); i < len; i++) {
|
||
args[i - 1] = arguments[i];
|
||
}
|
||
|
||
listeners.fn.apply(listeners.context, args);
|
||
} else {
|
||
var length = listeners.length
|
||
, j;
|
||
|
||
for (i = 0; i < length; i++) {
|
||
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
|
||
|
||
switch (len) {
|
||
case 1: listeners[i].fn.call(listeners[i].context); break;
|
||
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
|
||
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
|
||
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
|
||
default:
|
||
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
|
||
args[j - 1] = arguments[j];
|
||
}
|
||
|
||
listeners[i].fn.apply(listeners[i].context, args);
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Add a listener for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} [context=this] The context to invoke the listener with.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.on = function on(event, fn, context) {
|
||
return addListener(this, event, fn, context, false);
|
||
};
|
||
|
||
/**
|
||
* Add a one-time listener for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} [context=this] The context to invoke the listener with.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.once = function once(event, fn, context) {
|
||
return addListener(this, event, fn, context, true);
|
||
};
|
||
|
||
/**
|
||
* Remove the listeners of a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn Only remove the listeners that match this function.
|
||
* @param {*} context Only remove the listeners that have this context.
|
||
* @param {Boolean} once Only remove one-time listeners.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
||
var evt = prefix ? prefix + event : event;
|
||
|
||
if (!this._events[evt]) return this;
|
||
if (!fn) {
|
||
clearEvent(this, evt);
|
||
return this;
|
||
}
|
||
|
||
var listeners = this._events[evt];
|
||
|
||
if (listeners.fn) {
|
||
if (
|
||
listeners.fn === fn &&
|
||
(!once || listeners.once) &&
|
||
(!context || listeners.context === context)
|
||
) {
|
||
clearEvent(this, evt);
|
||
}
|
||
} else {
|
||
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
||
if (
|
||
listeners[i].fn !== fn ||
|
||
(once && !listeners[i].once) ||
|
||
(context && listeners[i].context !== context)
|
||
) {
|
||
events.push(listeners[i]);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Reset the array, or remove it completely if we have no more listeners.
|
||
//
|
||
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
||
else clearEvent(this, evt);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Remove all listeners, or those of the specified event.
|
||
*
|
||
* @param {(String|Symbol)} [event] The event name.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
||
var evt;
|
||
|
||
if (event) {
|
||
evt = prefix ? prefix + event : event;
|
||
if (this._events[evt]) clearEvent(this, evt);
|
||
} else {
|
||
this._events = new Events();
|
||
this._eventsCount = 0;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
//
|
||
// Alias methods names because people roll like that.
|
||
//
|
||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
||
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
||
|
||
//
|
||
// Expose the prefix.
|
||
//
|
||
EventEmitter.prefixed = prefix;
|
||
|
||
//
|
||
// Allow `EventEmitter` to be imported as module namespace.
|
||
//
|
||
EventEmitter.EventEmitter = EventEmitter;
|
||
|
||
//
|
||
// Expose the module.
|
||
//
|
||
{
|
||
module.exports = EventEmitter;
|
||
}
|
||
} (eventemitter3));
|
||
return eventemitter3.exports;
|
||
}
|
||
|
||
/**
|
||
* "Client" wraps "ws" or a browser-implemented "WebSocket" library
|
||
* according to the environment providing JSON RPC 2.0 support on top.
|
||
* @module Client
|
||
*/
|
||
|
||
(function (exports) {
|
||
|
||
var _interopRequireDefault = interopRequireDefaultExports;
|
||
|
||
Object.defineProperty(exports, "__esModule", {
|
||
value: true
|
||
});
|
||
exports["default"] = void 0;
|
||
|
||
var _regenerator = _interopRequireDefault(requireRegenerator());
|
||
|
||
var _asyncToGenerator2 = _interopRequireDefault(requireAsyncToGenerator());
|
||
|
||
var _typeof2 = _interopRequireDefault(require_typeof());
|
||
|
||
var _classCallCheck2 = _interopRequireDefault(requireClassCallCheck());
|
||
|
||
var _createClass2 = _interopRequireDefault(requireCreateClass());
|
||
|
||
var _inherits2 = _interopRequireDefault(requireInherits());
|
||
|
||
var _possibleConstructorReturn2 = _interopRequireDefault(requirePossibleConstructorReturn());
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(requireGetPrototypeOf());
|
||
|
||
var _eventemitter = requireEventemitter3();
|
||
|
||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
|
||
|
||
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
||
|
||
var __rest = function (s, e) {
|
||
var t = {};
|
||
|
||
for (var p in s) {
|
||
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
|
||
}
|
||
|
||
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
|
||
}
|
||
return t;
|
||
}; // @ts-ignore
|
||
|
||
|
||
var CommonClient = /*#__PURE__*/function (_EventEmitter) {
|
||
(0, _inherits2["default"])(CommonClient, _EventEmitter);
|
||
|
||
var _super = _createSuper(CommonClient);
|
||
|
||
/**
|
||
* Instantiate a Client class.
|
||
* @constructor
|
||
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
|
||
* @param {String} address - url to a websocket server
|
||
* @param {Object} options - ws options object with reconnect parameters
|
||
* @param {Function} generate_request_id - custom generation request Id
|
||
* @return {CommonClient}
|
||
*/
|
||
function CommonClient(webSocketFactory) {
|
||
var _this;
|
||
|
||
var address = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "ws://localhost:8080";
|
||
|
||
var _a = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||
|
||
var generate_request_id = arguments.length > 3 ? arguments[3] : undefined;
|
||
(0, _classCallCheck2["default"])(this, CommonClient);
|
||
|
||
var _a$autoconnect = _a.autoconnect,
|
||
autoconnect = _a$autoconnect === void 0 ? true : _a$autoconnect,
|
||
_a$reconnect = _a.reconnect,
|
||
reconnect = _a$reconnect === void 0 ? true : _a$reconnect,
|
||
_a$reconnect_interval = _a.reconnect_interval,
|
||
reconnect_interval = _a$reconnect_interval === void 0 ? 1000 : _a$reconnect_interval,
|
||
_a$max_reconnects = _a.max_reconnects,
|
||
max_reconnects = _a$max_reconnects === void 0 ? 5 : _a$max_reconnects,
|
||
rest_options = __rest(_a, ["autoconnect", "reconnect", "reconnect_interval", "max_reconnects"]);
|
||
|
||
_this = _super.call(this);
|
||
_this.webSocketFactory = webSocketFactory;
|
||
_this.queue = {};
|
||
_this.rpc_id = 0;
|
||
_this.address = address;
|
||
_this.autoconnect = autoconnect;
|
||
_this.ready = false;
|
||
_this.reconnect = reconnect;
|
||
_this.reconnect_timer_id = undefined;
|
||
_this.reconnect_interval = reconnect_interval;
|
||
_this.max_reconnects = max_reconnects;
|
||
_this.rest_options = rest_options;
|
||
_this.current_reconnects = 0;
|
||
|
||
_this.generate_request_id = generate_request_id || function () {
|
||
return ++_this.rpc_id;
|
||
};
|
||
|
||
if (_this.autoconnect) _this._connect(_this.address, Object.assign({
|
||
autoconnect: _this.autoconnect,
|
||
reconnect: _this.reconnect,
|
||
reconnect_interval: _this.reconnect_interval,
|
||
max_reconnects: _this.max_reconnects
|
||
}, _this.rest_options));
|
||
return _this;
|
||
}
|
||
/**
|
||
* Connects to a defined server if not connected already.
|
||
* @method
|
||
* @return {Undefined}
|
||
*/
|
||
|
||
|
||
(0, _createClass2["default"])(CommonClient, [{
|
||
key: "connect",
|
||
value: function connect() {
|
||
if (this.socket) return;
|
||
|
||
this._connect(this.address, Object.assign({
|
||
autoconnect: this.autoconnect,
|
||
reconnect: this.reconnect,
|
||
reconnect_interval: this.reconnect_interval,
|
||
max_reconnects: this.max_reconnects
|
||
}, this.rest_options));
|
||
}
|
||
/**
|
||
* Calls a registered RPC method on server.
|
||
* @method
|
||
* @param {String} method - RPC method name
|
||
* @param {Object|Array} params - optional method parameters
|
||
* @param {Number} timeout - RPC reply timeout value
|
||
* @param {Object} ws_opts - options passed to ws
|
||
* @return {Promise}
|
||
*/
|
||
|
||
}, {
|
||
key: "call",
|
||
value: function call(method, params, timeout, ws_opts) {
|
||
var _this2 = this;
|
||
|
||
if (!ws_opts && "object" === (0, _typeof2["default"])(timeout)) {
|
||
ws_opts = timeout;
|
||
timeout = null;
|
||
}
|
||
|
||
return new Promise(function (resolve, reject) {
|
||
if (!_this2.ready) return reject(new Error("socket not ready"));
|
||
|
||
var rpc_id = _this2.generate_request_id(method, params);
|
||
|
||
var message = {
|
||
jsonrpc: "2.0",
|
||
method: method,
|
||
params: params || null,
|
||
id: rpc_id
|
||
};
|
||
|
||
_this2.socket.send(JSON.stringify(message), ws_opts, function (error) {
|
||
if (error) return reject(error);
|
||
_this2.queue[rpc_id] = {
|
||
promise: [resolve, reject]
|
||
};
|
||
|
||
if (timeout) {
|
||
_this2.queue[rpc_id].timeout = setTimeout(function () {
|
||
delete _this2.queue[rpc_id];
|
||
reject(new Error("reply timeout"));
|
||
}, timeout);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
/**
|
||
* Logins with the other side of the connection.
|
||
* @method
|
||
* @param {Object} params - Login credentials object
|
||
* @return {Promise}
|
||
*/
|
||
|
||
}, {
|
||
key: "login",
|
||
value: function () {
|
||
var _login = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(params) {
|
||
var resp;
|
||
return _regenerator["default"].wrap(function _callee$(_context) {
|
||
while (1) {
|
||
switch (_context.prev = _context.next) {
|
||
case 0:
|
||
_context.next = 2;
|
||
return this.call("rpc.login", params);
|
||
|
||
case 2:
|
||
resp = _context.sent;
|
||
|
||
if (resp) {
|
||
_context.next = 5;
|
||
break;
|
||
}
|
||
|
||
throw new Error("authentication failed");
|
||
|
||
case 5:
|
||
return _context.abrupt("return", resp);
|
||
|
||
case 6:
|
||
case "end":
|
||
return _context.stop();
|
||
}
|
||
}
|
||
}, _callee, this);
|
||
}));
|
||
|
||
function login(_x) {
|
||
return _login.apply(this, arguments);
|
||
}
|
||
|
||
return login;
|
||
}()
|
||
/**
|
||
* Fetches a list of client's methods registered on server.
|
||
* @method
|
||
* @return {Array}
|
||
*/
|
||
|
||
}, {
|
||
key: "listMethods",
|
||
value: function () {
|
||
var _listMethods = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() {
|
||
return _regenerator["default"].wrap(function _callee2$(_context2) {
|
||
while (1) {
|
||
switch (_context2.prev = _context2.next) {
|
||
case 0:
|
||
_context2.next = 2;
|
||
return this.call("__listMethods");
|
||
|
||
case 2:
|
||
return _context2.abrupt("return", _context2.sent);
|
||
|
||
case 3:
|
||
case "end":
|
||
return _context2.stop();
|
||
}
|
||
}
|
||
}, _callee2, this);
|
||
}));
|
||
|
||
function listMethods() {
|
||
return _listMethods.apply(this, arguments);
|
||
}
|
||
|
||
return listMethods;
|
||
}()
|
||
/**
|
||
* Sends a JSON-RPC 2.0 notification to server.
|
||
* @method
|
||
* @param {String} method - RPC method name
|
||
* @param {Object} params - optional method parameters
|
||
* @return {Promise}
|
||
*/
|
||
|
||
}, {
|
||
key: "notify",
|
||
value: function notify(method, params) {
|
||
var _this3 = this;
|
||
|
||
return new Promise(function (resolve, reject) {
|
||
if (!_this3.ready) return reject(new Error("socket not ready"));
|
||
var message = {
|
||
jsonrpc: "2.0",
|
||
method: method,
|
||
params: params || null
|
||
};
|
||
|
||
_this3.socket.send(JSON.stringify(message), function (error) {
|
||
if (error) return reject(error);
|
||
resolve();
|
||
});
|
||
});
|
||
}
|
||
/**
|
||
* Subscribes for a defined event.
|
||
* @method
|
||
* @param {String|Array} event - event name
|
||
* @return {Undefined}
|
||
* @throws {Error}
|
||
*/
|
||
|
||
}, {
|
||
key: "subscribe",
|
||
value: function () {
|
||
var _subscribe = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(event) {
|
||
var result;
|
||
return _regenerator["default"].wrap(function _callee3$(_context3) {
|
||
while (1) {
|
||
switch (_context3.prev = _context3.next) {
|
||
case 0:
|
||
if (typeof event === "string") event = [event];
|
||
_context3.next = 3;
|
||
return this.call("rpc.on", event);
|
||
|
||
case 3:
|
||
result = _context3.sent;
|
||
|
||
if (!(typeof event === "string" && result[event] !== "ok")) {
|
||
_context3.next = 6;
|
||
break;
|
||
}
|
||
|
||
throw new Error("Failed subscribing to an event '" + event + "' with: " + result[event]);
|
||
|
||
case 6:
|
||
return _context3.abrupt("return", result);
|
||
|
||
case 7:
|
||
case "end":
|
||
return _context3.stop();
|
||
}
|
||
}
|
||
}, _callee3, this);
|
||
}));
|
||
|
||
function subscribe(_x2) {
|
||
return _subscribe.apply(this, arguments);
|
||
}
|
||
|
||
return subscribe;
|
||
}()
|
||
/**
|
||
* Unsubscribes from a defined event.
|
||
* @method
|
||
* @param {String|Array} event - event name
|
||
* @return {Undefined}
|
||
* @throws {Error}
|
||
*/
|
||
|
||
}, {
|
||
key: "unsubscribe",
|
||
value: function () {
|
||
var _unsubscribe = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(event) {
|
||
var result;
|
||
return _regenerator["default"].wrap(function _callee4$(_context4) {
|
||
while (1) {
|
||
switch (_context4.prev = _context4.next) {
|
||
case 0:
|
||
if (typeof event === "string") event = [event];
|
||
_context4.next = 3;
|
||
return this.call("rpc.off", event);
|
||
|
||
case 3:
|
||
result = _context4.sent;
|
||
|
||
if (!(typeof event === "string" && result[event] !== "ok")) {
|
||
_context4.next = 6;
|
||
break;
|
||
}
|
||
|
||
throw new Error("Failed unsubscribing from an event with: " + result);
|
||
|
||
case 6:
|
||
return _context4.abrupt("return", result);
|
||
|
||
case 7:
|
||
case "end":
|
||
return _context4.stop();
|
||
}
|
||
}
|
||
}, _callee4, this);
|
||
}));
|
||
|
||
function unsubscribe(_x3) {
|
||
return _unsubscribe.apply(this, arguments);
|
||
}
|
||
|
||
return unsubscribe;
|
||
}()
|
||
/**
|
||
* Closes a WebSocket connection gracefully.
|
||
* @method
|
||
* @param {Number} code - socket close code
|
||
* @param {String} data - optional data to be sent before closing
|
||
* @return {Undefined}
|
||
*/
|
||
|
||
}, {
|
||
key: "close",
|
||
value: function close(code, data) {
|
||
this.socket.close(code || 1000, data);
|
||
}
|
||
/**
|
||
* Connection/Message handler.
|
||
* @method
|
||
* @private
|
||
* @param {String} address - WebSocket API address
|
||
* @param {Object} options - ws options object
|
||
* @return {Undefined}
|
||
*/
|
||
|
||
}, {
|
||
key: "_connect",
|
||
value: function _connect(address, options) {
|
||
var _this4 = this;
|
||
|
||
clearTimeout(this.reconnect_timer_id);
|
||
this.socket = this.webSocketFactory(address, options);
|
||
this.socket.addEventListener("open", function () {
|
||
_this4.ready = true;
|
||
|
||
_this4.emit("open");
|
||
|
||
_this4.current_reconnects = 0;
|
||
});
|
||
this.socket.addEventListener("message", function (_ref) {
|
||
var message = _ref.data;
|
||
if (message instanceof ArrayBuffer) message = Buffer.from(message).toString();
|
||
|
||
try {
|
||
message = JSON.parse(message);
|
||
} catch (error) {
|
||
return;
|
||
} // check if any listeners are attached and forward event
|
||
|
||
|
||
if (message.notification && _this4.listeners(message.notification).length) {
|
||
if (!Object.keys(message.params).length) return _this4.emit(message.notification);
|
||
var args = [message.notification];
|
||
if (message.params.constructor === Object) args.push(message.params);else // using for-loop instead of unshift/spread because performance is better
|
||
for (var i = 0; i < message.params.length; i++) {
|
||
args.push(message.params[i]);
|
||
} // run as microtask so that pending queue messages are resolved first
|
||
// eslint-disable-next-line prefer-spread
|
||
|
||
return Promise.resolve().then(function () {
|
||
_this4.emit.apply(_this4, args);
|
||
});
|
||
}
|
||
|
||
if (!_this4.queue[message.id]) {
|
||
// general JSON RPC 2.0 events
|
||
if (message.method && message.params) {
|
||
// run as microtask so that pending queue messages are resolved first
|
||
return Promise.resolve().then(function () {
|
||
_this4.emit(message.method, message.params);
|
||
});
|
||
}
|
||
|
||
return;
|
||
} // reject early since server's response is invalid
|
||
|
||
|
||
if ("error" in message === "result" in message) _this4.queue[message.id].promise[1](new Error("Server response malformed. Response must include either \"result\"" + " or \"error\", but not both."));
|
||
if (_this4.queue[message.id].timeout) clearTimeout(_this4.queue[message.id].timeout);
|
||
if (message.error) _this4.queue[message.id].promise[1](message.error);else _this4.queue[message.id].promise[0](message.result);
|
||
delete _this4.queue[message.id];
|
||
});
|
||
this.socket.addEventListener("error", function (error) {
|
||
return _this4.emit("error", error);
|
||
});
|
||
this.socket.addEventListener("close", function (_ref2) {
|
||
var code = _ref2.code,
|
||
reason = _ref2.reason;
|
||
if (_this4.ready) // Delay close event until internal state is updated
|
||
setTimeout(function () {
|
||
return _this4.emit("close", code, reason);
|
||
}, 0);
|
||
_this4.ready = false;
|
||
_this4.socket = undefined;
|
||
if (code === 1000) return;
|
||
_this4.current_reconnects++;
|
||
if (_this4.reconnect && (_this4.max_reconnects > _this4.current_reconnects || _this4.max_reconnects === 0)) _this4.reconnect_timer_id = setTimeout(function () {
|
||
return _this4._connect(address, options);
|
||
}, _this4.reconnect_interval);
|
||
});
|
||
}
|
||
}]);
|
||
return CommonClient;
|
||
}(_eventemitter.EventEmitter);
|
||
|
||
exports["default"] = CommonClient;
|
||
} (client));
|
||
|
||
var RpcWebSocketCommonClient = /*@__PURE__*/getDefaultExportFromCjs(client);
|
||
|
||
var websocket_browser = {};
|
||
|
||
/**
|
||
* WebSocket implements a browser-side WebSocket specification.
|
||
* @module Client
|
||
*/
|
||
|
||
(function (exports) {
|
||
|
||
var _interopRequireDefault = interopRequireDefaultExports;
|
||
|
||
Object.defineProperty(exports, "__esModule", {
|
||
value: true
|
||
});
|
||
exports["default"] = _default;
|
||
|
||
var _classCallCheck2 = _interopRequireDefault(requireClassCallCheck());
|
||
|
||
var _createClass2 = _interopRequireDefault(requireCreateClass());
|
||
|
||
var _inherits2 = _interopRequireDefault(requireInherits());
|
||
|
||
var _possibleConstructorReturn2 = _interopRequireDefault(requirePossibleConstructorReturn());
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(requireGetPrototypeOf());
|
||
|
||
var _eventemitter = requireEventemitter3();
|
||
|
||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
|
||
|
||
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
||
|
||
var WebSocketBrowserImpl = /*#__PURE__*/function (_EventEmitter) {
|
||
(0, _inherits2["default"])(WebSocketBrowserImpl, _EventEmitter);
|
||
|
||
var _super = _createSuper(WebSocketBrowserImpl);
|
||
|
||
/** Instantiate a WebSocket class
|
||
* @constructor
|
||
* @param {String} address - url to a websocket server
|
||
* @param {(Object)} options - websocket options
|
||
* @param {(String|Array)} protocols - a list of protocols
|
||
* @return {WebSocketBrowserImpl} - returns a WebSocket instance
|
||
*/
|
||
function WebSocketBrowserImpl(address, options, protocols) {
|
||
var _this;
|
||
|
||
(0, _classCallCheck2["default"])(this, WebSocketBrowserImpl);
|
||
_this = _super.call(this);
|
||
_this.socket = new window.WebSocket(address, protocols);
|
||
|
||
_this.socket.onopen = function () {
|
||
return _this.emit("open");
|
||
};
|
||
|
||
_this.socket.onmessage = function (event) {
|
||
return _this.emit("message", event.data);
|
||
};
|
||
|
||
_this.socket.onerror = function (error) {
|
||
return _this.emit("error", error);
|
||
};
|
||
|
||
_this.socket.onclose = function (event) {
|
||
_this.emit("close", event.code, event.reason);
|
||
};
|
||
|
||
return _this;
|
||
}
|
||
/**
|
||
* Sends data through a websocket connection
|
||
* @method
|
||
* @param {(String|Object)} data - data to be sent via websocket
|
||
* @param {Object} optionsOrCallback - ws options
|
||
* @param {Function} callback - a callback called once the data is sent
|
||
* @return {Undefined}
|
||
*/
|
||
|
||
|
||
(0, _createClass2["default"])(WebSocketBrowserImpl, [{
|
||
key: "send",
|
||
value: function send(data, optionsOrCallback, callback) {
|
||
var cb = callback || optionsOrCallback;
|
||
|
||
try {
|
||
this.socket.send(data);
|
||
cb();
|
||
} catch (error) {
|
||
cb(error);
|
||
}
|
||
}
|
||
/**
|
||
* Closes an underlying socket
|
||
* @method
|
||
* @param {Number} code - status code explaining why the connection is being closed
|
||
* @param {String} reason - a description why the connection is closing
|
||
* @return {Undefined}
|
||
* @throws {Error}
|
||
*/
|
||
|
||
}, {
|
||
key: "close",
|
||
value: function close(code, reason) {
|
||
this.socket.close(code, reason);
|
||
}
|
||
}, {
|
||
key: "addEventListener",
|
||
value: function addEventListener(type, listener, options) {
|
||
this.socket.addEventListener(type, listener, options);
|
||
}
|
||
}]);
|
||
return WebSocketBrowserImpl;
|
||
}(_eventemitter.EventEmitter);
|
||
/**
|
||
* factory method for common WebSocket instance
|
||
* @method
|
||
* @param {String} address - url to a websocket server
|
||
* @param {(Object)} options - websocket options
|
||
* @return {Undefined}
|
||
*/
|
||
|
||
|
||
function _default(address, options) {
|
||
return new WebSocketBrowserImpl(address, options);
|
||
}
|
||
} (websocket_browser));
|
||
|
||
var createRpc = /*@__PURE__*/getDefaultExportFromCjs(websocket_browser);
|
||
|
||
class RpcWebSocketClient extends RpcWebSocketCommonClient {
|
||
constructor(address, options, generate_request_id) {
|
||
const webSocketFactory = url => {
|
||
const rpc = createRpc(url, {
|
||
autoconnect: true,
|
||
max_reconnects: 5,
|
||
reconnect: true,
|
||
reconnect_interval: 1000,
|
||
...options
|
||
});
|
||
if ('socket' in rpc) {
|
||
this.underlyingSocket = rpc.socket;
|
||
} else {
|
||
this.underlyingSocket = rpc;
|
||
}
|
||
return rpc;
|
||
};
|
||
super(webSocketFactory, address, options, generate_request_id);
|
||
this.underlyingSocket = void 0;
|
||
}
|
||
call(...args) {
|
||
const readyState = this.underlyingSocket?.readyState;
|
||
if (readyState === 1 /* WebSocket.OPEN */) {
|
||
return super.call(...args);
|
||
}
|
||
return Promise.reject(new Error('Tried to call a JSON-RPC method `' + args[0] + '` but the socket was not `CONNECTING` or `OPEN` (`readyState` was ' + readyState + ')'));
|
||
}
|
||
notify(...args) {
|
||
const readyState = this.underlyingSocket?.readyState;
|
||
if (readyState === 1 /* WebSocket.OPEN */) {
|
||
return super.notify(...args);
|
||
}
|
||
return Promise.reject(new Error('Tried to send a JSON-RPC notification `' + args[0] + '` but the socket was not `CONNECTING` or `OPEN` (`readyState` was ' + readyState + ')'));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
|
||
/**
|
||
* Decode account data buffer using an AccountType
|
||
* @internal
|
||
*/
|
||
function decodeData(type, data) {
|
||
let decoded;
|
||
try {
|
||
decoded = type.layout.decode(data);
|
||
} catch (err) {
|
||
throw new Error('invalid instruction; ' + err);
|
||
}
|
||
if (decoded.typeIndex !== type.index) {
|
||
throw new Error(`invalid account data; account type mismatch ${decoded.typeIndex} != ${type.index}`);
|
||
}
|
||
return decoded;
|
||
}
|
||
|
||
/// The serialized size of lookup table metadata
|
||
const LOOKUP_TABLE_META_SIZE = 56;
|
||
class AddressLookupTableAccount {
|
||
constructor(args) {
|
||
this.key = void 0;
|
||
this.state = void 0;
|
||
this.key = args.key;
|
||
this.state = args.state;
|
||
}
|
||
isActive() {
|
||
const U64_MAX = BigInt('0xffffffffffffffff');
|
||
return this.state.deactivationSlot === U64_MAX;
|
||
}
|
||
static deserialize(accountData) {
|
||
const meta = decodeData(LookupTableMetaLayout, accountData);
|
||
const serializedAddressesLen = accountData.length - LOOKUP_TABLE_META_SIZE;
|
||
assert$1(serializedAddressesLen >= 0, 'lookup table is invalid');
|
||
assert$1(serializedAddressesLen % 32 === 0, 'lookup table is invalid');
|
||
const numSerializedAddresses = serializedAddressesLen / 32;
|
||
const {
|
||
addresses
|
||
} = struct([seq(publicKey(), numSerializedAddresses, 'addresses')]).decode(accountData.slice(LOOKUP_TABLE_META_SIZE));
|
||
return {
|
||
deactivationSlot: meta.deactivationSlot,
|
||
lastExtendedSlot: meta.lastExtendedSlot,
|
||
lastExtendedSlotStartIndex: meta.lastExtendedStartIndex,
|
||
authority: meta.authority.length !== 0 ? new PublicKey(meta.authority[0]) : undefined,
|
||
addresses: addresses.map(address => new PublicKey(address))
|
||
};
|
||
}
|
||
}
|
||
const LookupTableMetaLayout = {
|
||
index: 1,
|
||
layout: struct([u32('typeIndex'), u64('deactivationSlot'), nu64('lastExtendedSlot'), u8('lastExtendedStartIndex'), u8(),
|
||
// option
|
||
seq(publicKey(), offset(u8(), -1), 'authority')])
|
||
};
|
||
|
||
const URL_RE = /^[^:]+:\/\/([^:[]+|\[[^\]]+\])(:\d+)?(.*)/i;
|
||
function makeWebsocketUrl(endpoint) {
|
||
const matches = endpoint.match(URL_RE);
|
||
if (matches == null) {
|
||
throw TypeError(`Failed to validate endpoint URL \`${endpoint}\``);
|
||
}
|
||
const [_,
|
||
// eslint-disable-line @typescript-eslint/no-unused-vars
|
||
hostish, portWithColon, rest] = matches;
|
||
const protocol = endpoint.startsWith('https:') ? 'wss:' : 'ws:';
|
||
const startPort = portWithColon == null ? null : parseInt(portWithColon.slice(1), 10);
|
||
const websocketPort =
|
||
// Only shift the port by +1 as a convention for ws(s) only if given endpoint
|
||
// is explicitly specifying the endpoint port (HTTP-based RPC), assuming
|
||
// we're directly trying to connect to solana-validator's ws listening port.
|
||
// When the endpoint omits the port, we're connecting to the protocol
|
||
// default ports: http(80) or https(443) and it's assumed we're behind a reverse
|
||
// proxy which manages WebSocket upgrade and backend port redirection.
|
||
startPort == null ? '' : `:${startPort + 1}`;
|
||
return `${protocol}//${hostish}${websocketPort}${rest}`;
|
||
}
|
||
|
||
const PublicKeyFromString = coerce(instance(PublicKey), string(), value => new PublicKey(value));
|
||
const RawAccountDataResult = tuple([string(), literal('base64')]);
|
||
const BufferFromRawAccountData = coerce(instance(buffer.Buffer), RawAccountDataResult, value => buffer.Buffer.from(value[0], 'base64'));
|
||
|
||
/**
|
||
* Attempt to use a recent blockhash for up to 30 seconds
|
||
* @internal
|
||
*/
|
||
const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
|
||
|
||
/**
|
||
* HACK.
|
||
* Copied from rpc-websockets/dist/lib/client.
|
||
* Otherwise, `yarn build` fails with:
|
||
* https://gist.github.com/steveluscher/c057eca81d479ef705cdb53162f9971d
|
||
*/
|
||
|
||
/** @internal */
|
||
/** @internal */
|
||
/** @internal */
|
||
/** @internal */
|
||
|
||
/** @internal */
|
||
/**
|
||
* @internal
|
||
* Every subscription contains the args used to open the subscription with
|
||
* the server, and a list of callers interested in notifications.
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
* A subscription may be in various states of connectedness. Only when it is
|
||
* fully connected will it have a server subscription id associated with it.
|
||
* This id can be returned to the server to unsubscribe the client entirely.
|
||
*/
|
||
|
||
/**
|
||
* A type that encapsulates a subscription's RPC method
|
||
* names and notification (callback) signature.
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
* Utility type that keeps tagged unions intact while omitting properties.
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
* This type represents a single subscribable 'topic.' It's made up of:
|
||
*
|
||
* - The args used to open the subscription with the server,
|
||
* - The state of the subscription, in terms of its connectedness, and
|
||
* - The set of callbacks to call when the server publishes notifications
|
||
*
|
||
* This record gets indexed by `SubscriptionConfigHash` and is used to
|
||
* set up subscriptions, fan out notifications, and track subscription state.
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
|
||
/**
|
||
* Extra contextual information for RPC responses
|
||
*/
|
||
|
||
/**
|
||
* Options for sending transactions
|
||
*/
|
||
|
||
/**
|
||
* Options for confirming transactions
|
||
*/
|
||
|
||
/**
|
||
* Options for getConfirmedSignaturesForAddress2
|
||
*/
|
||
|
||
/**
|
||
* Options for getSignaturesForAddress
|
||
*/
|
||
|
||
/**
|
||
* RPC Response with extra contextual information
|
||
*/
|
||
|
||
/**
|
||
* A strategy for confirming transactions that uses the last valid
|
||
* block height for a given blockhash to check for transaction expiration.
|
||
*/
|
||
|
||
/**
|
||
* A strategy for confirming durable nonce transactions.
|
||
*/
|
||
|
||
/**
|
||
* Properties shared by all transaction confirmation strategies
|
||
*/
|
||
|
||
/**
|
||
* This type represents all transaction confirmation strategies
|
||
*/
|
||
|
||
/* @internal */
|
||
function assertEndpointUrl(putativeUrl) {
|
||
if (/^https?:/.test(putativeUrl) === false) {
|
||
throw new TypeError('Endpoint URL must start with `http:` or `https:`.');
|
||
}
|
||
return putativeUrl;
|
||
}
|
||
|
||
/** @internal */
|
||
function extractCommitmentFromConfig(commitmentOrConfig) {
|
||
let commitment;
|
||
let config;
|
||
if (typeof commitmentOrConfig === 'string') {
|
||
commitment = commitmentOrConfig;
|
||
} else if (commitmentOrConfig) {
|
||
const {
|
||
commitment: specifiedCommitment,
|
||
...specifiedConfig
|
||
} = commitmentOrConfig;
|
||
commitment = specifiedCommitment;
|
||
config = specifiedConfig;
|
||
}
|
||
return {
|
||
commitment,
|
||
config
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
function createRpcResult(result) {
|
||
return union([type({
|
||
jsonrpc: literal('2.0'),
|
||
id: string(),
|
||
result
|
||
}), type({
|
||
jsonrpc: literal('2.0'),
|
||
id: string(),
|
||
error: type({
|
||
code: unknown(),
|
||
message: string(),
|
||
data: optional(any())
|
||
})
|
||
})]);
|
||
}
|
||
const UnknownRpcResult = createRpcResult(unknown());
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
function jsonRpcResult(schema) {
|
||
return coerce(createRpcResult(schema), UnknownRpcResult, value => {
|
||
if ('error' in value) {
|
||
return value;
|
||
} else {
|
||
return {
|
||
...value,
|
||
result: create(value.result, schema)
|
||
};
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
function jsonRpcResultAndContext(value) {
|
||
return jsonRpcResult(type({
|
||
context: type({
|
||
slot: number()
|
||
}),
|
||
value
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
function notificationResultAndContext(value) {
|
||
return type({
|
||
context: type({
|
||
slot: number()
|
||
}),
|
||
value
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
function versionedMessageFromResponse(version, response) {
|
||
if (version === 0) {
|
||
return new MessageV0({
|
||
header: response.header,
|
||
staticAccountKeys: response.accountKeys.map(accountKey => new PublicKey(accountKey)),
|
||
recentBlockhash: response.recentBlockhash,
|
||
compiledInstructions: response.instructions.map(ix => ({
|
||
programIdIndex: ix.programIdIndex,
|
||
accountKeyIndexes: ix.accounts,
|
||
data: bs58$1.decode(ix.data)
|
||
})),
|
||
addressTableLookups: response.addressTableLookups
|
||
});
|
||
} else {
|
||
return new Message(response);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* The level of commitment desired when querying state
|
||
* <pre>
|
||
* 'processed': Query the most recent block which has reached 1 confirmation by the connected node
|
||
* 'confirmed': Query the most recent block which has reached 1 confirmation by the cluster
|
||
* 'finalized': Query the most recent block which has been finalized by the cluster
|
||
* </pre>
|
||
*/
|
||
|
||
// Deprecated as of v1.5.5
|
||
|
||
/**
|
||
* A subset of Commitment levels, which are at least optimistically confirmed
|
||
* <pre>
|
||
* 'confirmed': Query the most recent block which has reached 1 confirmation by the cluster
|
||
* 'finalized': Query the most recent block which has been finalized by the cluster
|
||
* </pre>
|
||
*/
|
||
|
||
/**
|
||
* Filter for largest accounts query
|
||
* <pre>
|
||
* 'circulating': Return the largest accounts that are part of the circulating supply
|
||
* 'nonCirculating': Return the largest accounts that are not part of the circulating supply
|
||
* </pre>
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getAccountInfo` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getBalance` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getBlock` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getBlock` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getStakeMinimumDelegation` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getBlockHeight` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getEpochInfo` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getInflationReward` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getLatestBlockhash` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `isBlockhashValid` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getSlot` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getSlotLeader` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getTransaction` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getTransaction` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getLargestAccounts` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing `getSupply` request behavior
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for changing query behavior
|
||
*/
|
||
|
||
/**
|
||
* Information describing a cluster node
|
||
*/
|
||
|
||
/**
|
||
* Information describing a vote account
|
||
*/
|
||
|
||
/**
|
||
* A collection of cluster vote accounts
|
||
*/
|
||
|
||
/**
|
||
* Network Inflation
|
||
* (see https://docs.solana.com/implemented-proposals/ed_overview)
|
||
*/
|
||
|
||
const GetInflationGovernorResult = type({
|
||
foundation: number(),
|
||
foundationTerm: number(),
|
||
initial: number(),
|
||
taper: number(),
|
||
terminal: number()
|
||
});
|
||
|
||
/**
|
||
* The inflation reward for an epoch
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getInflationReward" message
|
||
*/
|
||
const GetInflationRewardResult = jsonRpcResult(array(nullable(type({
|
||
epoch: number(),
|
||
effectiveSlot: number(),
|
||
amount: number(),
|
||
postBalance: number(),
|
||
commission: optional(nullable(number()))
|
||
}))));
|
||
|
||
/**
|
||
* Configuration object for changing `getRecentPrioritizationFees` query behavior
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getRecentPrioritizationFees" message
|
||
*/
|
||
const GetRecentPrioritizationFeesResult = array(type({
|
||
slot: number(),
|
||
prioritizationFee: number()
|
||
}));
|
||
/**
|
||
* Expected JSON RPC response for the "getInflationRate" message
|
||
*/
|
||
const GetInflationRateResult = type({
|
||
total: number(),
|
||
validator: number(),
|
||
foundation: number(),
|
||
epoch: number()
|
||
});
|
||
|
||
/**
|
||
* Information about the current epoch
|
||
*/
|
||
|
||
const GetEpochInfoResult = type({
|
||
epoch: number(),
|
||
slotIndex: number(),
|
||
slotsInEpoch: number(),
|
||
absoluteSlot: number(),
|
||
blockHeight: optional(number()),
|
||
transactionCount: optional(number())
|
||
});
|
||
const GetEpochScheduleResult = type({
|
||
slotsPerEpoch: number(),
|
||
leaderScheduleSlotOffset: number(),
|
||
warmup: boolean(),
|
||
firstNormalEpoch: number(),
|
||
firstNormalSlot: number()
|
||
});
|
||
|
||
/**
|
||
* Leader schedule
|
||
* (see https://docs.solana.com/terminology#leader-schedule)
|
||
*/
|
||
|
||
const GetLeaderScheduleResult = record(string(), array(number()));
|
||
|
||
/**
|
||
* Transaction error or null
|
||
*/
|
||
const TransactionErrorResult = nullable(union([type({}), string()]));
|
||
|
||
/**
|
||
* Signature status for a transaction
|
||
*/
|
||
const SignatureStatusResult = type({
|
||
err: TransactionErrorResult
|
||
});
|
||
|
||
/**
|
||
* Transaction signature received notification
|
||
*/
|
||
const SignatureReceivedResult = literal('receivedSignature');
|
||
|
||
/**
|
||
* Version info for a node
|
||
*/
|
||
|
||
const VersionResult = type({
|
||
'solana-core': string(),
|
||
'feature-set': optional(number())
|
||
});
|
||
const SimulatedTransactionResponseStruct = jsonRpcResultAndContext(type({
|
||
err: nullable(union([type({}), string()])),
|
||
logs: nullable(array(string())),
|
||
accounts: optional(nullable(array(nullable(type({
|
||
executable: boolean(),
|
||
owner: string(),
|
||
lamports: number(),
|
||
data: array(string()),
|
||
rentEpoch: optional(number())
|
||
}))))),
|
||
unitsConsumed: optional(number()),
|
||
returnData: optional(nullable(type({
|
||
programId: string(),
|
||
data: tuple([string(), literal('base64')])
|
||
})))
|
||
}));
|
||
|
||
/**
|
||
* Metadata for a parsed confirmed transaction on the ledger
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link ParsedTransactionMeta} instead.
|
||
*/
|
||
|
||
/**
|
||
* Collection of addresses loaded by a transaction using address table lookups
|
||
*/
|
||
|
||
/**
|
||
* Metadata for a parsed transaction on the ledger
|
||
*/
|
||
|
||
/**
|
||
* Metadata for a confirmed transaction on the ledger
|
||
*/
|
||
|
||
/**
|
||
* A processed transaction from the RPC API
|
||
*/
|
||
|
||
/**
|
||
* A processed transaction from the RPC API
|
||
*/
|
||
|
||
/**
|
||
* A processed transaction message from the RPC API
|
||
*/
|
||
|
||
/**
|
||
* A confirmed transaction on the ledger
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0.
|
||
*/
|
||
|
||
/**
|
||
* A partially decoded transaction instruction
|
||
*/
|
||
|
||
/**
|
||
* A parsed transaction message account
|
||
*/
|
||
|
||
/**
|
||
* A parsed transaction instruction
|
||
*/
|
||
|
||
/**
|
||
* A parsed address table lookup
|
||
*/
|
||
|
||
/**
|
||
* A parsed transaction message
|
||
*/
|
||
|
||
/**
|
||
* A parsed transaction
|
||
*/
|
||
|
||
/**
|
||
* A parsed and confirmed transaction on the ledger
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link ParsedTransactionWithMeta} instead.
|
||
*/
|
||
|
||
/**
|
||
* A parsed transaction on the ledger with meta
|
||
*/
|
||
|
||
/**
|
||
* A processed block fetched from the RPC API
|
||
*/
|
||
|
||
/**
|
||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
|
||
*/
|
||
|
||
/**
|
||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
|
||
*/
|
||
|
||
/**
|
||
* A block with parsed transactions
|
||
*/
|
||
|
||
/**
|
||
* A block with parsed transactions where the `transactionDetails` mode is `accounts`
|
||
*/
|
||
|
||
/**
|
||
* A block with parsed transactions where the `transactionDetails` mode is `none`
|
||
*/
|
||
|
||
/**
|
||
* A processed block fetched from the RPC API
|
||
*/
|
||
|
||
/**
|
||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
|
||
*/
|
||
|
||
/**
|
||
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
|
||
*/
|
||
|
||
/**
|
||
* A confirmed block on the ledger
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0.
|
||
*/
|
||
|
||
/**
|
||
* A Block on the ledger with signatures only
|
||
*/
|
||
|
||
/**
|
||
* recent block production information
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getBlockProduction" message
|
||
*/
|
||
const BlockProductionResponseStruct = jsonRpcResultAndContext(type({
|
||
byIdentity: record(string(), array(number())),
|
||
range: type({
|
||
firstSlot: number(),
|
||
lastSlot: number()
|
||
})
|
||
}));
|
||
|
||
/**
|
||
* A performance sample
|
||
*/
|
||
|
||
function createRpcClient(url, httpHeaders, customFetch, fetchMiddleware, disableRetryOnRateLimit, httpAgent) {
|
||
const fetch = customFetch ? customFetch : fetchImpl;
|
||
let agent;
|
||
{
|
||
if (httpAgent != null) {
|
||
console.warn('You have supplied an `httpAgent` when creating a `Connection` in a browser environment.' + 'It has been ignored; `httpAgent` is only used in Node environments.');
|
||
}
|
||
}
|
||
let fetchWithMiddleware;
|
||
if (fetchMiddleware) {
|
||
fetchWithMiddleware = async (info, init) => {
|
||
const modifiedFetchArgs = await new Promise((resolve, reject) => {
|
||
try {
|
||
fetchMiddleware(info, init, (modifiedInfo, modifiedInit) => resolve([modifiedInfo, modifiedInit]));
|
||
} catch (error) {
|
||
reject(error);
|
||
}
|
||
});
|
||
return await fetch(...modifiedFetchArgs);
|
||
};
|
||
}
|
||
const clientBrowser = new RpcClient(async (request, callback) => {
|
||
const options = {
|
||
method: 'POST',
|
||
body: request,
|
||
agent,
|
||
headers: Object.assign({
|
||
'Content-Type': 'application/json'
|
||
}, httpHeaders || {}, COMMON_HTTP_HEADERS)
|
||
};
|
||
try {
|
||
let too_many_requests_retries = 5;
|
||
let res;
|
||
let waitTime = 500;
|
||
for (;;) {
|
||
if (fetchWithMiddleware) {
|
||
res = await fetchWithMiddleware(url, options);
|
||
} else {
|
||
res = await fetch(url, options);
|
||
}
|
||
if (res.status !== 429 /* Too many requests */) {
|
||
break;
|
||
}
|
||
if (disableRetryOnRateLimit === true) {
|
||
break;
|
||
}
|
||
too_many_requests_retries -= 1;
|
||
if (too_many_requests_retries === 0) {
|
||
break;
|
||
}
|
||
console.error(`Server responded with ${res.status} ${res.statusText}. Retrying after ${waitTime}ms delay...`);
|
||
await sleep(waitTime);
|
||
waitTime *= 2;
|
||
}
|
||
const text = await res.text();
|
||
if (res.ok) {
|
||
callback(null, text);
|
||
} else {
|
||
callback(new Error(`${res.status} ${res.statusText}: ${text}`));
|
||
}
|
||
} catch (err) {
|
||
if (err instanceof Error) callback(err);
|
||
}
|
||
}, {});
|
||
return clientBrowser;
|
||
}
|
||
function createRpcRequest(client) {
|
||
return (method, args) => {
|
||
return new Promise((resolve, reject) => {
|
||
client.request(method, args, (err, response) => {
|
||
if (err) {
|
||
reject(err);
|
||
return;
|
||
}
|
||
resolve(response);
|
||
});
|
||
});
|
||
};
|
||
}
|
||
function createRpcBatchRequest(client) {
|
||
return requests => {
|
||
return new Promise((resolve, reject) => {
|
||
// Do nothing if requests is empty
|
||
if (requests.length === 0) resolve([]);
|
||
const batch = requests.map(params => {
|
||
return client.request(params.methodName, params.args);
|
||
});
|
||
client.request(batch, (err, response) => {
|
||
if (err) {
|
||
reject(err);
|
||
return;
|
||
}
|
||
resolve(response);
|
||
});
|
||
});
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getInflationGovernor" message
|
||
*/
|
||
const GetInflationGovernorRpcResult = jsonRpcResult(GetInflationGovernorResult);
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getInflationRate" message
|
||
*/
|
||
const GetInflationRateRpcResult = jsonRpcResult(GetInflationRateResult);
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getRecentPrioritizationFees" message
|
||
*/
|
||
const GetRecentPrioritizationFeesRpcResult = jsonRpcResult(GetRecentPrioritizationFeesResult);
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getEpochInfo" message
|
||
*/
|
||
const GetEpochInfoRpcResult = jsonRpcResult(GetEpochInfoResult);
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getEpochSchedule" message
|
||
*/
|
||
const GetEpochScheduleRpcResult = jsonRpcResult(GetEpochScheduleResult);
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getLeaderSchedule" message
|
||
*/
|
||
const GetLeaderScheduleRpcResult = jsonRpcResult(GetLeaderScheduleResult);
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "minimumLedgerSlot" and "getFirstAvailableBlock" messages
|
||
*/
|
||
const SlotRpcResult = jsonRpcResult(number());
|
||
|
||
/**
|
||
* Supply
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getSupply" message
|
||
*/
|
||
const GetSupplyRpcResult = jsonRpcResultAndContext(type({
|
||
total: number(),
|
||
circulating: number(),
|
||
nonCirculating: number(),
|
||
nonCirculatingAccounts: array(PublicKeyFromString)
|
||
}));
|
||
|
||
/**
|
||
* Token amount object which returns a token amount in different formats
|
||
* for various client use cases.
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC structure for token amounts
|
||
*/
|
||
const TokenAmountResult = type({
|
||
amount: string(),
|
||
uiAmount: nullable(number()),
|
||
decimals: number(),
|
||
uiAmountString: optional(string())
|
||
});
|
||
|
||
/**
|
||
* Token address and balance.
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getTokenLargestAccounts" message
|
||
*/
|
||
const GetTokenLargestAccountsResult = jsonRpcResultAndContext(array(type({
|
||
address: PublicKeyFromString,
|
||
amount: string(),
|
||
uiAmount: nullable(number()),
|
||
decimals: number(),
|
||
uiAmountString: optional(string())
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getTokenAccountsByOwner" message
|
||
*/
|
||
const GetTokenAccountsByOwner = jsonRpcResultAndContext(array(type({
|
||
pubkey: PublicKeyFromString,
|
||
account: type({
|
||
executable: boolean(),
|
||
owner: PublicKeyFromString,
|
||
lamports: number(),
|
||
data: BufferFromRawAccountData,
|
||
rentEpoch: number()
|
||
})
|
||
})));
|
||
const ParsedAccountDataResult = type({
|
||
program: string(),
|
||
parsed: unknown(),
|
||
space: number()
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getTokenAccountsByOwner" message with parsed data
|
||
*/
|
||
const GetParsedTokenAccountsByOwner = jsonRpcResultAndContext(array(type({
|
||
pubkey: PublicKeyFromString,
|
||
account: type({
|
||
executable: boolean(),
|
||
owner: PublicKeyFromString,
|
||
lamports: number(),
|
||
data: ParsedAccountDataResult,
|
||
rentEpoch: number()
|
||
})
|
||
})));
|
||
|
||
/**
|
||
* Pair of an account address and its balance
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getLargestAccounts" message
|
||
*/
|
||
const GetLargestAccountsRpcResult = jsonRpcResultAndContext(array(type({
|
||
lamports: number(),
|
||
address: PublicKeyFromString
|
||
})));
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const AccountInfoResult = type({
|
||
executable: boolean(),
|
||
owner: PublicKeyFromString,
|
||
lamports: number(),
|
||
data: BufferFromRawAccountData,
|
||
rentEpoch: number()
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const KeyedAccountInfoResult = type({
|
||
pubkey: PublicKeyFromString,
|
||
account: AccountInfoResult
|
||
});
|
||
const ParsedOrRawAccountData = coerce(union([instance(buffer.Buffer), ParsedAccountDataResult]), union([RawAccountDataResult, ParsedAccountDataResult]), value => {
|
||
if (Array.isArray(value)) {
|
||
return create(value, BufferFromRawAccountData);
|
||
} else {
|
||
return value;
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const ParsedAccountInfoResult = type({
|
||
executable: boolean(),
|
||
owner: PublicKeyFromString,
|
||
lamports: number(),
|
||
data: ParsedOrRawAccountData,
|
||
rentEpoch: number()
|
||
});
|
||
const KeyedParsedAccountInfoResult = type({
|
||
pubkey: PublicKeyFromString,
|
||
account: ParsedAccountInfoResult
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const StakeActivationResult = type({
|
||
state: union([literal('active'), literal('inactive'), literal('activating'), literal('deactivating')]),
|
||
active: number(),
|
||
inactive: number()
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getConfirmedSignaturesForAddress2" message
|
||
*/
|
||
|
||
const GetConfirmedSignaturesForAddress2RpcResult = jsonRpcResult(array(type({
|
||
signature: string(),
|
||
slot: number(),
|
||
err: TransactionErrorResult,
|
||
memo: nullable(string()),
|
||
blockTime: optional(nullable(number()))
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getSignaturesForAddress" message
|
||
*/
|
||
const GetSignaturesForAddressRpcResult = jsonRpcResult(array(type({
|
||
signature: string(),
|
||
slot: number(),
|
||
err: TransactionErrorResult,
|
||
memo: nullable(string()),
|
||
blockTime: optional(nullable(number()))
|
||
})));
|
||
|
||
/***
|
||
* Expected JSON RPC response for the "accountNotification" message
|
||
*/
|
||
const AccountNotificationResult = type({
|
||
subscription: number(),
|
||
result: notificationResultAndContext(AccountInfoResult)
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const ProgramAccountInfoResult = type({
|
||
pubkey: PublicKeyFromString,
|
||
account: AccountInfoResult
|
||
});
|
||
|
||
/***
|
||
* Expected JSON RPC response for the "programNotification" message
|
||
*/
|
||
const ProgramAccountNotificationResult = type({
|
||
subscription: number(),
|
||
result: notificationResultAndContext(ProgramAccountInfoResult)
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const SlotInfoResult = type({
|
||
parent: number(),
|
||
slot: number(),
|
||
root: number()
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "slotNotification" message
|
||
*/
|
||
const SlotNotificationResult = type({
|
||
subscription: number(),
|
||
result: SlotInfoResult
|
||
});
|
||
|
||
/**
|
||
* Slot updates which can be used for tracking the live progress of a cluster.
|
||
* - `"firstShredReceived"`: connected node received the first shred of a block.
|
||
* Indicates that a new block that is being produced.
|
||
* - `"completed"`: connected node has received all shreds of a block. Indicates
|
||
* a block was recently produced.
|
||
* - `"optimisticConfirmation"`: block was optimistically confirmed by the
|
||
* cluster. It is not guaranteed that an optimistic confirmation notification
|
||
* will be sent for every finalized blocks.
|
||
* - `"root"`: the connected node rooted this block.
|
||
* - `"createdBank"`: the connected node has started validating this block.
|
||
* - `"frozen"`: the connected node has validated this block.
|
||
* - `"dead"`: the connected node failed to validate this block.
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const SlotUpdateResult = union([type({
|
||
type: union([literal('firstShredReceived'), literal('completed'), literal('optimisticConfirmation'), literal('root')]),
|
||
slot: number(),
|
||
timestamp: number()
|
||
}), type({
|
||
type: literal('createdBank'),
|
||
parent: number(),
|
||
slot: number(),
|
||
timestamp: number()
|
||
}), type({
|
||
type: literal('frozen'),
|
||
slot: number(),
|
||
timestamp: number(),
|
||
stats: type({
|
||
numTransactionEntries: number(),
|
||
numSuccessfulTransactions: number(),
|
||
numFailedTransactions: number(),
|
||
maxTransactionsPerEntry: number()
|
||
})
|
||
}), type({
|
||
type: literal('dead'),
|
||
slot: number(),
|
||
timestamp: number(),
|
||
err: string()
|
||
})]);
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "slotsUpdatesNotification" message
|
||
*/
|
||
const SlotUpdateNotificationResult = type({
|
||
subscription: number(),
|
||
result: SlotUpdateResult
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "signatureNotification" message
|
||
*/
|
||
const SignatureNotificationResult = type({
|
||
subscription: number(),
|
||
result: notificationResultAndContext(union([SignatureStatusResult, SignatureReceivedResult]))
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "rootNotification" message
|
||
*/
|
||
const RootNotificationResult = type({
|
||
subscription: number(),
|
||
result: number()
|
||
});
|
||
const ContactInfoResult = type({
|
||
pubkey: string(),
|
||
gossip: nullable(string()),
|
||
tpu: nullable(string()),
|
||
rpc: nullable(string()),
|
||
version: nullable(string())
|
||
});
|
||
const VoteAccountInfoResult = type({
|
||
votePubkey: string(),
|
||
nodePubkey: string(),
|
||
activatedStake: number(),
|
||
epochVoteAccount: boolean(),
|
||
epochCredits: array(tuple([number(), number(), number()])),
|
||
commission: number(),
|
||
lastVote: number(),
|
||
rootSlot: nullable(number())
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getVoteAccounts" message
|
||
*/
|
||
const GetVoteAccounts = jsonRpcResult(type({
|
||
current: array(VoteAccountInfoResult),
|
||
delinquent: array(VoteAccountInfoResult)
|
||
}));
|
||
const ConfirmationStatus = union([literal('processed'), literal('confirmed'), literal('finalized')]);
|
||
const SignatureStatusResponse = type({
|
||
slot: number(),
|
||
confirmations: nullable(number()),
|
||
err: TransactionErrorResult,
|
||
confirmationStatus: optional(ConfirmationStatus)
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getSignatureStatuses" message
|
||
*/
|
||
const GetSignatureStatusesRpcResult = jsonRpcResultAndContext(array(nullable(SignatureStatusResponse)));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getMinimumBalanceForRentExemption" message
|
||
*/
|
||
const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult(number());
|
||
const AddressTableLookupStruct = type({
|
||
accountKey: PublicKeyFromString,
|
||
writableIndexes: array(number()),
|
||
readonlyIndexes: array(number())
|
||
});
|
||
const ConfirmedTransactionResult = type({
|
||
signatures: array(string()),
|
||
message: type({
|
||
accountKeys: array(string()),
|
||
header: type({
|
||
numRequiredSignatures: number(),
|
||
numReadonlySignedAccounts: number(),
|
||
numReadonlyUnsignedAccounts: number()
|
||
}),
|
||
instructions: array(type({
|
||
accounts: array(number()),
|
||
data: string(),
|
||
programIdIndex: number()
|
||
})),
|
||
recentBlockhash: string(),
|
||
addressTableLookups: optional(array(AddressTableLookupStruct))
|
||
})
|
||
});
|
||
const AnnotatedAccountKey = type({
|
||
pubkey: PublicKeyFromString,
|
||
signer: boolean(),
|
||
writable: boolean(),
|
||
source: optional(union([literal('transaction'), literal('lookupTable')]))
|
||
});
|
||
const ConfirmedTransactionAccountsModeResult = type({
|
||
accountKeys: array(AnnotatedAccountKey),
|
||
signatures: array(string())
|
||
});
|
||
const ParsedInstructionResult = type({
|
||
parsed: unknown(),
|
||
program: string(),
|
||
programId: PublicKeyFromString
|
||
});
|
||
const RawInstructionResult = type({
|
||
accounts: array(PublicKeyFromString),
|
||
data: string(),
|
||
programId: PublicKeyFromString
|
||
});
|
||
const InstructionResult = union([RawInstructionResult, ParsedInstructionResult]);
|
||
const UnknownInstructionResult = union([type({
|
||
parsed: unknown(),
|
||
program: string(),
|
||
programId: string()
|
||
}), type({
|
||
accounts: array(string()),
|
||
data: string(),
|
||
programId: string()
|
||
})]);
|
||
const ParsedOrRawInstruction = coerce(InstructionResult, UnknownInstructionResult, value => {
|
||
if ('accounts' in value) {
|
||
return create(value, RawInstructionResult);
|
||
} else {
|
||
return create(value, ParsedInstructionResult);
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const ParsedConfirmedTransactionResult = type({
|
||
signatures: array(string()),
|
||
message: type({
|
||
accountKeys: array(AnnotatedAccountKey),
|
||
instructions: array(ParsedOrRawInstruction),
|
||
recentBlockhash: string(),
|
||
addressTableLookups: optional(nullable(array(AddressTableLookupStruct)))
|
||
})
|
||
});
|
||
const TokenBalanceResult = type({
|
||
accountIndex: number(),
|
||
mint: string(),
|
||
owner: optional(string()),
|
||
uiTokenAmount: TokenAmountResult
|
||
});
|
||
const LoadedAddressesResult = type({
|
||
writable: array(PublicKeyFromString),
|
||
readonly: array(PublicKeyFromString)
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const ConfirmedTransactionMetaResult = type({
|
||
err: TransactionErrorResult,
|
||
fee: number(),
|
||
innerInstructions: optional(nullable(array(type({
|
||
index: number(),
|
||
instructions: array(type({
|
||
accounts: array(number()),
|
||
data: string(),
|
||
programIdIndex: number()
|
||
}))
|
||
})))),
|
||
preBalances: array(number()),
|
||
postBalances: array(number()),
|
||
logMessages: optional(nullable(array(string()))),
|
||
preTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
||
postTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
||
loadedAddresses: optional(LoadedAddressesResult),
|
||
computeUnitsConsumed: optional(number())
|
||
});
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const ParsedConfirmedTransactionMetaResult = type({
|
||
err: TransactionErrorResult,
|
||
fee: number(),
|
||
innerInstructions: optional(nullable(array(type({
|
||
index: number(),
|
||
instructions: array(ParsedOrRawInstruction)
|
||
})))),
|
||
preBalances: array(number()),
|
||
postBalances: array(number()),
|
||
logMessages: optional(nullable(array(string()))),
|
||
preTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
||
postTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
||
loadedAddresses: optional(LoadedAddressesResult),
|
||
computeUnitsConsumed: optional(number())
|
||
});
|
||
const TransactionVersionStruct = union([literal(0), literal('legacy')]);
|
||
|
||
/** @internal */
|
||
const RewardsResult = type({
|
||
pubkey: string(),
|
||
lamports: number(),
|
||
postBalance: nullable(number()),
|
||
rewardType: nullable(string()),
|
||
commission: optional(nullable(number()))
|
||
});
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getBlock" message
|
||
*/
|
||
const GetBlockRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
transactions: array(type({
|
||
transaction: ConfirmedTransactionResult,
|
||
meta: nullable(ConfirmedTransactionMetaResult),
|
||
version: optional(TransactionVersionStruct)
|
||
})),
|
||
rewards: optional(array(RewardsResult)),
|
||
blockTime: nullable(number()),
|
||
blockHeight: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
|
||
*/
|
||
const GetNoneModeBlockRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
rewards: optional(array(RewardsResult)),
|
||
blockTime: nullable(number()),
|
||
blockHeight: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
|
||
*/
|
||
const GetAccountsModeBlockRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
transactions: array(type({
|
||
transaction: ConfirmedTransactionAccountsModeResult,
|
||
meta: nullable(ConfirmedTransactionMetaResult),
|
||
version: optional(TransactionVersionStruct)
|
||
})),
|
||
rewards: optional(array(RewardsResult)),
|
||
blockTime: nullable(number()),
|
||
blockHeight: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected parsed JSON RPC response for the "getBlock" message
|
||
*/
|
||
const GetParsedBlockRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
transactions: array(type({
|
||
transaction: ParsedConfirmedTransactionResult,
|
||
meta: nullable(ParsedConfirmedTransactionMetaResult),
|
||
version: optional(TransactionVersionStruct)
|
||
})),
|
||
rewards: optional(array(RewardsResult)),
|
||
blockTime: nullable(number()),
|
||
blockHeight: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
|
||
*/
|
||
const GetParsedAccountsModeBlockRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
transactions: array(type({
|
||
transaction: ConfirmedTransactionAccountsModeResult,
|
||
meta: nullable(ParsedConfirmedTransactionMetaResult),
|
||
version: optional(TransactionVersionStruct)
|
||
})),
|
||
rewards: optional(array(RewardsResult)),
|
||
blockTime: nullable(number()),
|
||
blockHeight: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
|
||
*/
|
||
const GetParsedNoneModeBlockRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
rewards: optional(array(RewardsResult)),
|
||
blockTime: nullable(number()),
|
||
blockHeight: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getConfirmedBlock" message
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link GetBlockRpcResult} instead.
|
||
*/
|
||
const GetConfirmedBlockRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
transactions: array(type({
|
||
transaction: ConfirmedTransactionResult,
|
||
meta: nullable(ConfirmedTransactionMetaResult)
|
||
})),
|
||
rewards: optional(array(RewardsResult)),
|
||
blockTime: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getBlock" message
|
||
*/
|
||
const GetBlockSignaturesRpcResult = jsonRpcResult(nullable(type({
|
||
blockhash: string(),
|
||
previousBlockhash: string(),
|
||
parentSlot: number(),
|
||
signatures: array(string()),
|
||
blockTime: nullable(number())
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getTransaction" message
|
||
*/
|
||
const GetTransactionRpcResult = jsonRpcResult(nullable(type({
|
||
slot: number(),
|
||
meta: nullable(ConfirmedTransactionMetaResult),
|
||
blockTime: optional(nullable(number())),
|
||
transaction: ConfirmedTransactionResult,
|
||
version: optional(TransactionVersionStruct)
|
||
})));
|
||
|
||
/**
|
||
* Expected parsed JSON RPC response for the "getTransaction" message
|
||
*/
|
||
const GetParsedTransactionRpcResult = jsonRpcResult(nullable(type({
|
||
slot: number(),
|
||
transaction: ParsedConfirmedTransactionResult,
|
||
meta: nullable(ParsedConfirmedTransactionMetaResult),
|
||
blockTime: optional(nullable(number())),
|
||
version: optional(TransactionVersionStruct)
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getRecentBlockhash" message
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link GetLatestBlockhashRpcResult} instead.
|
||
*/
|
||
const GetRecentBlockhashAndContextRpcResult = jsonRpcResultAndContext(type({
|
||
blockhash: string(),
|
||
feeCalculator: type({
|
||
lamportsPerSignature: number()
|
||
})
|
||
}));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getLatestBlockhash" message
|
||
*/
|
||
const GetLatestBlockhashRpcResult = jsonRpcResultAndContext(type({
|
||
blockhash: string(),
|
||
lastValidBlockHeight: number()
|
||
}));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "isBlockhashValid" message
|
||
*/
|
||
const IsBlockhashValidRpcResult = jsonRpcResultAndContext(boolean());
|
||
const PerfSampleResult = type({
|
||
slot: number(),
|
||
numTransactions: number(),
|
||
numSlots: number(),
|
||
samplePeriodSecs: number()
|
||
});
|
||
|
||
/*
|
||
* Expected JSON RPC response for "getRecentPerformanceSamples" message
|
||
*/
|
||
const GetRecentPerformanceSamplesRpcResult = jsonRpcResult(array(PerfSampleResult));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "getFeeCalculatorForBlockhash" message
|
||
*/
|
||
const GetFeeCalculatorRpcResult = jsonRpcResultAndContext(nullable(type({
|
||
feeCalculator: type({
|
||
lamportsPerSignature: number()
|
||
})
|
||
})));
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "requestAirdrop" message
|
||
*/
|
||
const RequestAirdropRpcResult = jsonRpcResult(string());
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "sendTransaction" message
|
||
*/
|
||
const SendTransactionRpcResult = jsonRpcResult(string());
|
||
|
||
/**
|
||
* Information about the latest slot being processed by a node
|
||
*/
|
||
|
||
/**
|
||
* Parsed account data
|
||
*/
|
||
|
||
/**
|
||
* Stake Activation data
|
||
*/
|
||
|
||
/**
|
||
* Data slice argument for getProgramAccounts
|
||
*/
|
||
|
||
/**
|
||
* Memory comparison filter for getProgramAccounts
|
||
*/
|
||
|
||
/**
|
||
* Data size comparison filter for getProgramAccounts
|
||
*/
|
||
|
||
/**
|
||
* A filter object for getProgramAccounts
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for getProgramAccounts requests
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for getParsedProgramAccounts
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for getMultipleAccounts
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for `getStakeActivation`
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for `getStakeActivation`
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for `getStakeActivation`
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for `getNonce`
|
||
*/
|
||
|
||
/**
|
||
* Configuration object for `getNonceAndContext`
|
||
*/
|
||
|
||
/**
|
||
* Information describing an account
|
||
*/
|
||
|
||
/**
|
||
* Account information identified by pubkey
|
||
*/
|
||
|
||
/**
|
||
* Callback function for account change notifications
|
||
*/
|
||
|
||
/**
|
||
* Callback function for program account change notifications
|
||
*/
|
||
|
||
/**
|
||
* Callback function for slot change notifications
|
||
*/
|
||
|
||
/**
|
||
* Callback function for slot update notifications
|
||
*/
|
||
|
||
/**
|
||
* Callback function for signature status notifications
|
||
*/
|
||
|
||
/**
|
||
* Signature status notification with transaction result
|
||
*/
|
||
|
||
/**
|
||
* Signature received notification
|
||
*/
|
||
|
||
/**
|
||
* Callback function for signature notifications
|
||
*/
|
||
|
||
/**
|
||
* Signature subscription options
|
||
*/
|
||
|
||
/**
|
||
* Callback function for root change notifications
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
const LogsResult = type({
|
||
err: TransactionErrorResult,
|
||
logs: array(string()),
|
||
signature: string()
|
||
});
|
||
|
||
/**
|
||
* Logs result.
|
||
*/
|
||
|
||
/**
|
||
* Expected JSON RPC response for the "logsNotification" message.
|
||
*/
|
||
const LogsNotificationResult = type({
|
||
result: notificationResultAndContext(LogsResult),
|
||
subscription: number()
|
||
});
|
||
|
||
/**
|
||
* Filter for log subscriptions.
|
||
*/
|
||
|
||
/**
|
||
* Callback function for log notifications.
|
||
*/
|
||
|
||
/**
|
||
* Signature result
|
||
*/
|
||
|
||
/**
|
||
* Transaction error
|
||
*/
|
||
|
||
/**
|
||
* Transaction confirmation status
|
||
* <pre>
|
||
* 'processed': Transaction landed in a block which has reached 1 confirmation by the connected node
|
||
* 'confirmed': Transaction landed in a block which has reached 1 confirmation by the cluster
|
||
* 'finalized': Transaction landed in a block which has been finalized by the cluster
|
||
* </pre>
|
||
*/
|
||
|
||
/**
|
||
* Signature status
|
||
*/
|
||
|
||
/**
|
||
* A confirmed signature with its status
|
||
*/
|
||
|
||
/**
|
||
* An object defining headers to be passed to the RPC server
|
||
*/
|
||
|
||
/**
|
||
* The type of the JavaScript `fetch()` API
|
||
*/
|
||
|
||
/**
|
||
* A callback used to augment the outgoing HTTP request
|
||
*/
|
||
|
||
/**
|
||
* Configuration for instantiating a Connection
|
||
*/
|
||
|
||
/** @internal */
|
||
const COMMON_HTTP_HEADERS = {
|
||
'solana-client': `js/${"0.0.0-development" }`
|
||
};
|
||
|
||
/**
|
||
* A connection to a fullnode JSON RPC endpoint
|
||
*/
|
||
class Connection {
|
||
/**
|
||
* Establish a JSON RPC connection
|
||
*
|
||
* @param endpoint URL to the fullnode JSON RPC endpoint
|
||
* @param commitmentOrConfig optional default commitment level or optional ConnectionConfig configuration object
|
||
*/
|
||
constructor(endpoint, _commitmentOrConfig) {
|
||
/** @internal */
|
||
this._commitment = void 0;
|
||
/** @internal */
|
||
this._confirmTransactionInitialTimeout = void 0;
|
||
/** @internal */
|
||
this._rpcEndpoint = void 0;
|
||
/** @internal */
|
||
this._rpcWsEndpoint = void 0;
|
||
/** @internal */
|
||
this._rpcClient = void 0;
|
||
/** @internal */
|
||
this._rpcRequest = void 0;
|
||
/** @internal */
|
||
this._rpcBatchRequest = void 0;
|
||
/** @internal */
|
||
this._rpcWebSocket = void 0;
|
||
/** @internal */
|
||
this._rpcWebSocketConnected = false;
|
||
/** @internal */
|
||
this._rpcWebSocketHeartbeat = null;
|
||
/** @internal */
|
||
this._rpcWebSocketIdleTimeout = null;
|
||
/** @internal
|
||
* A number that we increment every time an active connection closes.
|
||
* Used to determine whether the same socket connection that was open
|
||
* when an async operation started is the same one that's active when
|
||
* its continuation fires.
|
||
*
|
||
*/
|
||
this._rpcWebSocketGeneration = 0;
|
||
/** @internal */
|
||
this._disableBlockhashCaching = false;
|
||
/** @internal */
|
||
this._pollingBlockhash = false;
|
||
/** @internal */
|
||
this._blockhashInfo = {
|
||
latestBlockhash: null,
|
||
lastFetch: 0,
|
||
transactionSignatures: [],
|
||
simulatedSignatures: []
|
||
};
|
||
/** @internal */
|
||
this._nextClientSubscriptionId = 0;
|
||
/** @internal */
|
||
this._subscriptionDisposeFunctionsByClientSubscriptionId = {};
|
||
/** @internal */
|
||
this._subscriptionHashByClientSubscriptionId = {};
|
||
/** @internal */
|
||
this._subscriptionStateChangeCallbacksByHash = {};
|
||
/** @internal */
|
||
this._subscriptionCallbacksByServerSubscriptionId = {};
|
||
/** @internal */
|
||
this._subscriptionsByHash = {};
|
||
/**
|
||
* Special case.
|
||
* After a signature is processed, RPCs automatically dispose of the
|
||
* subscription on the server side. We need to track which of these
|
||
* subscriptions have been disposed in such a way, so that we know
|
||
* whether the client is dealing with a not-yet-processed signature
|
||
* (in which case we must tear down the server subscription) or an
|
||
* already-processed signature (in which case the client can simply
|
||
* clear out the subscription locally without telling the server).
|
||
*
|
||
* NOTE: There is a proposal to eliminate this special case, here:
|
||
* https://github.com/solana-labs/solana/issues/18892
|
||
*/
|
||
/** @internal */
|
||
this._subscriptionsAutoDisposedByRpc = new Set();
|
||
/*
|
||
* Returns the current block height of the node
|
||
*/
|
||
this.getBlockHeight = (() => {
|
||
const requestPromises = {};
|
||
return async commitmentOrConfig => {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
|
||
const requestHash = fastStableStringify$1(args);
|
||
requestPromises[requestHash] = requestPromises[requestHash] ?? (async () => {
|
||
try {
|
||
const unsafeRes = await this._rpcRequest('getBlockHeight', args);
|
||
const res = create(unsafeRes, jsonRpcResult(number()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get block height information');
|
||
}
|
||
return res.result;
|
||
} finally {
|
||
delete requestPromises[requestHash];
|
||
}
|
||
})();
|
||
return await requestPromises[requestHash];
|
||
};
|
||
})();
|
||
let wsEndpoint;
|
||
let httpHeaders;
|
||
let fetch;
|
||
let fetchMiddleware;
|
||
let disableRetryOnRateLimit;
|
||
let httpAgent;
|
||
if (_commitmentOrConfig && typeof _commitmentOrConfig === 'string') {
|
||
this._commitment = _commitmentOrConfig;
|
||
} else if (_commitmentOrConfig) {
|
||
this._commitment = _commitmentOrConfig.commitment;
|
||
this._confirmTransactionInitialTimeout = _commitmentOrConfig.confirmTransactionInitialTimeout;
|
||
wsEndpoint = _commitmentOrConfig.wsEndpoint;
|
||
httpHeaders = _commitmentOrConfig.httpHeaders;
|
||
fetch = _commitmentOrConfig.fetch;
|
||
fetchMiddleware = _commitmentOrConfig.fetchMiddleware;
|
||
disableRetryOnRateLimit = _commitmentOrConfig.disableRetryOnRateLimit;
|
||
httpAgent = _commitmentOrConfig.httpAgent;
|
||
}
|
||
this._rpcEndpoint = assertEndpointUrl(endpoint);
|
||
this._rpcWsEndpoint = wsEndpoint || makeWebsocketUrl(endpoint);
|
||
this._rpcClient = createRpcClient(endpoint, httpHeaders, fetch, fetchMiddleware, disableRetryOnRateLimit, httpAgent);
|
||
this._rpcRequest = createRpcRequest(this._rpcClient);
|
||
this._rpcBatchRequest = createRpcBatchRequest(this._rpcClient);
|
||
this._rpcWebSocket = new RpcWebSocketClient(this._rpcWsEndpoint, {
|
||
autoconnect: false,
|
||
max_reconnects: Infinity
|
||
});
|
||
this._rpcWebSocket.on('open', this._wsOnOpen.bind(this));
|
||
this._rpcWebSocket.on('error', this._wsOnError.bind(this));
|
||
this._rpcWebSocket.on('close', this._wsOnClose.bind(this));
|
||
this._rpcWebSocket.on('accountNotification', this._wsOnAccountNotification.bind(this));
|
||
this._rpcWebSocket.on('programNotification', this._wsOnProgramAccountNotification.bind(this));
|
||
this._rpcWebSocket.on('slotNotification', this._wsOnSlotNotification.bind(this));
|
||
this._rpcWebSocket.on('slotsUpdatesNotification', this._wsOnSlotUpdatesNotification.bind(this));
|
||
this._rpcWebSocket.on('signatureNotification', this._wsOnSignatureNotification.bind(this));
|
||
this._rpcWebSocket.on('rootNotification', this._wsOnRootNotification.bind(this));
|
||
this._rpcWebSocket.on('logsNotification', this._wsOnLogsNotification.bind(this));
|
||
}
|
||
|
||
/**
|
||
* The default commitment used for requests
|
||
*/
|
||
get commitment() {
|
||
return this._commitment;
|
||
}
|
||
|
||
/**
|
||
* The RPC endpoint
|
||
*/
|
||
get rpcEndpoint() {
|
||
return this._rpcEndpoint;
|
||
}
|
||
|
||
/**
|
||
* Fetch the balance for the specified public key, return with context
|
||
*/
|
||
async getBalanceAndContext(publicKey, commitmentOrConfig) {
|
||
/** @internal */
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([publicKey.toBase58()], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getBalance', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(number()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get balance for ${publicKey.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the balance for the specified public key
|
||
*/
|
||
async getBalance(publicKey, commitmentOrConfig) {
|
||
return await this.getBalanceAndContext(publicKey, commitmentOrConfig).then(x => x.value).catch(e => {
|
||
throw new Error('failed to get balance of account ' + publicKey.toBase58() + ': ' + e);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Fetch the estimated production time of a block
|
||
*/
|
||
async getBlockTime(slot) {
|
||
const unsafeRes = await this._rpcRequest('getBlockTime', [slot]);
|
||
const res = create(unsafeRes, jsonRpcResult(nullable(number())));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get block time for slot ${slot}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the lowest slot that the node has information about in its ledger.
|
||
* This value may increase over time if the node is configured to purge older ledger data
|
||
*/
|
||
async getMinimumLedgerSlot() {
|
||
const unsafeRes = await this._rpcRequest('minimumLedgerSlot', []);
|
||
const res = create(unsafeRes, jsonRpcResult(number()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get minimum ledger slot');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the slot of the lowest confirmed block that has not been purged from the ledger
|
||
*/
|
||
async getFirstAvailableBlock() {
|
||
const unsafeRes = await this._rpcRequest('getFirstAvailableBlock', []);
|
||
const res = create(unsafeRes, SlotRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get first available block');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch information about the current supply
|
||
*/
|
||
async getSupply(config) {
|
||
let configArg = {};
|
||
if (typeof config === 'string') {
|
||
configArg = {
|
||
commitment: config
|
||
};
|
||
} else if (config) {
|
||
configArg = {
|
||
...config,
|
||
commitment: config && config.commitment || this.commitment
|
||
};
|
||
} else {
|
||
configArg = {
|
||
commitment: this.commitment
|
||
};
|
||
}
|
||
const unsafeRes = await this._rpcRequest('getSupply', [configArg]);
|
||
const res = create(unsafeRes, GetSupplyRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get supply');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the current supply of a token mint
|
||
*/
|
||
async getTokenSupply(tokenMintAddress, commitment) {
|
||
const args = this._buildArgs([tokenMintAddress.toBase58()], commitment);
|
||
const unsafeRes = await this._rpcRequest('getTokenSupply', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get token supply');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the current balance of a token account
|
||
*/
|
||
async getTokenAccountBalance(tokenAddress, commitment) {
|
||
const args = this._buildArgs([tokenAddress.toBase58()], commitment);
|
||
const unsafeRes = await this._rpcRequest('getTokenAccountBalance', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get token account balance');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch all the token accounts owned by the specified account
|
||
*
|
||
* @return {Promise<RpcResponseAndContext<GetProgramAccountsResponse>}
|
||
*/
|
||
async getTokenAccountsByOwner(ownerAddress, filter, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
let _args = [ownerAddress.toBase58()];
|
||
if ('mint' in filter) {
|
||
_args.push({
|
||
mint: filter.mint.toBase58()
|
||
});
|
||
} else {
|
||
_args.push({
|
||
programId: filter.programId.toBase58()
|
||
});
|
||
}
|
||
const args = this._buildArgs(_args, commitment, 'base64', config);
|
||
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
|
||
const res = create(unsafeRes, GetTokenAccountsByOwner);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get token accounts owned by account ${ownerAddress.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch parsed token accounts owned by the specified account
|
||
*
|
||
* @return {Promise<RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo<ParsedAccountData>}>>>}
|
||
*/
|
||
async getParsedTokenAccountsByOwner(ownerAddress, filter, commitment) {
|
||
let _args = [ownerAddress.toBase58()];
|
||
if ('mint' in filter) {
|
||
_args.push({
|
||
mint: filter.mint.toBase58()
|
||
});
|
||
} else {
|
||
_args.push({
|
||
programId: filter.programId.toBase58()
|
||
});
|
||
}
|
||
const args = this._buildArgs(_args, commitment, 'jsonParsed');
|
||
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
|
||
const res = create(unsafeRes, GetParsedTokenAccountsByOwner);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get token accounts owned by account ${ownerAddress.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the 20 largest accounts with their current balances
|
||
*/
|
||
async getLargestAccounts(config) {
|
||
const arg = {
|
||
...config,
|
||
commitment: config && config.commitment || this.commitment
|
||
};
|
||
const args = arg.filter || arg.commitment ? [arg] : [];
|
||
const unsafeRes = await this._rpcRequest('getLargestAccounts', args);
|
||
const res = create(unsafeRes, GetLargestAccountsRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get largest accounts');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the 20 largest token accounts with their current balances
|
||
* for a given mint.
|
||
*/
|
||
async getTokenLargestAccounts(mintAddress, commitment) {
|
||
const args = this._buildArgs([mintAddress.toBase58()], commitment);
|
||
const unsafeRes = await this._rpcRequest('getTokenLargestAccounts', args);
|
||
const res = create(unsafeRes, GetTokenLargestAccountsResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get token largest accounts');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch all the account info for the specified public key, return with context
|
||
*/
|
||
async getAccountInfoAndContext(publicKey, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([publicKey.toBase58()], commitment, 'base64', config);
|
||
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(nullable(AccountInfoResult)));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get info about account ${publicKey.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch parsed account info for the specified public key
|
||
*/
|
||
async getParsedAccountInfo(publicKey, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([publicKey.toBase58()], commitment, 'jsonParsed', config);
|
||
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(nullable(ParsedAccountInfoResult)));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get info about account ${publicKey.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch all the account info for the specified public key
|
||
*/
|
||
async getAccountInfo(publicKey, commitmentOrConfig) {
|
||
try {
|
||
const res = await this.getAccountInfoAndContext(publicKey, commitmentOrConfig);
|
||
return res.value;
|
||
} catch (e) {
|
||
throw new Error('failed to get info about account ' + publicKey.toBase58() + ': ' + e);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Fetch all the account info for multiple accounts specified by an array of public keys, return with context
|
||
*/
|
||
async getMultipleParsedAccounts(publicKeys, rawConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(rawConfig);
|
||
const keys = publicKeys.map(key => key.toBase58());
|
||
const args = this._buildArgs([keys], commitment, 'jsonParsed', config);
|
||
const unsafeRes = await this._rpcRequest('getMultipleAccounts', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(array(nullable(ParsedAccountInfoResult))));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get info for accounts ${keys}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch all the account info for multiple accounts specified by an array of public keys, return with context
|
||
*/
|
||
async getMultipleAccountsInfoAndContext(publicKeys, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const keys = publicKeys.map(key => key.toBase58());
|
||
const args = this._buildArgs([keys], commitment, 'base64', config);
|
||
const unsafeRes = await this._rpcRequest('getMultipleAccounts', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(array(nullable(AccountInfoResult))));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get info for accounts ${keys}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch all the account info for multiple accounts specified by an array of public keys
|
||
*/
|
||
async getMultipleAccountsInfo(publicKeys, commitmentOrConfig) {
|
||
const res = await this.getMultipleAccountsInfoAndContext(publicKeys, commitmentOrConfig);
|
||
return res.value;
|
||
}
|
||
|
||
/**
|
||
* Returns epoch activation information for a stake account that has been delegated
|
||
*/
|
||
async getStakeActivation(publicKey, commitmentOrConfig, epoch) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([publicKey.toBase58()], commitment, undefined /* encoding */, {
|
||
...config,
|
||
epoch: epoch != null ? epoch : config?.epoch
|
||
});
|
||
const unsafeRes = await this._rpcRequest('getStakeActivation', args);
|
||
const res = create(unsafeRes, jsonRpcResult(StakeActivationResult));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get Stake Activation ${publicKey.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch all the accounts owned by the specified program id
|
||
*
|
||
* @return {Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>>}
|
||
*/
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async getProgramAccounts(programId, configOrCommitment) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(configOrCommitment);
|
||
const {
|
||
encoding,
|
||
...configWithoutEncoding
|
||
} = config || {};
|
||
const args = this._buildArgs([programId.toBase58()], commitment, encoding || 'base64', configWithoutEncoding);
|
||
const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
|
||
const baseSchema = array(KeyedAccountInfoResult);
|
||
const res = configWithoutEncoding.withContext === true ? create(unsafeRes, jsonRpcResultAndContext(baseSchema)) : create(unsafeRes, jsonRpcResult(baseSchema));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get accounts owned by program ${programId.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch and parse all the accounts owned by the specified program id
|
||
*
|
||
* @return {Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer | ParsedAccountData>}>>}
|
||
*/
|
||
async getParsedProgramAccounts(programId, configOrCommitment) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(configOrCommitment);
|
||
const args = this._buildArgs([programId.toBase58()], commitment, 'jsonParsed', config);
|
||
const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
|
||
const res = create(unsafeRes, jsonRpcResult(array(KeyedParsedAccountInfoResult)));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get accounts owned by program ${programId.toBase58()}`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/** @deprecated Instead, call `confirmTransaction` and pass in {@link TransactionConfirmationStrategy} */
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async confirmTransaction(strategy, commitment) {
|
||
let rawSignature;
|
||
if (typeof strategy == 'string') {
|
||
rawSignature = strategy;
|
||
} else {
|
||
const config = strategy;
|
||
if (config.abortSignal?.aborted) {
|
||
return Promise.reject(config.abortSignal.reason);
|
||
}
|
||
rawSignature = config.signature;
|
||
}
|
||
let decodedSignature;
|
||
try {
|
||
decodedSignature = bs58$1.decode(rawSignature);
|
||
} catch (err) {
|
||
throw new Error('signature must be base58 encoded: ' + rawSignature);
|
||
}
|
||
assert$1(decodedSignature.length === 64, 'signature has invalid length');
|
||
if (typeof strategy === 'string') {
|
||
return await this.confirmTransactionUsingLegacyTimeoutStrategy({
|
||
commitment: commitment || this.commitment,
|
||
signature: rawSignature
|
||
});
|
||
} else if ('lastValidBlockHeight' in strategy) {
|
||
return await this.confirmTransactionUsingBlockHeightExceedanceStrategy({
|
||
commitment: commitment || this.commitment,
|
||
strategy
|
||
});
|
||
} else {
|
||
return await this.confirmTransactionUsingDurableNonceStrategy({
|
||
commitment: commitment || this.commitment,
|
||
strategy
|
||
});
|
||
}
|
||
}
|
||
getCancellationPromise(signal) {
|
||
return new Promise((_, reject) => {
|
||
if (signal == null) {
|
||
return;
|
||
}
|
||
if (signal.aborted) {
|
||
reject(signal.reason);
|
||
} else {
|
||
signal.addEventListener('abort', () => {
|
||
reject(signal.reason);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
getTransactionConfirmationPromise({
|
||
commitment,
|
||
signature
|
||
}) {
|
||
let signatureSubscriptionId;
|
||
let disposeSignatureSubscriptionStateChangeObserver;
|
||
let done = false;
|
||
const confirmationPromise = new Promise((resolve, reject) => {
|
||
try {
|
||
signatureSubscriptionId = this.onSignature(signature, (result, context) => {
|
||
signatureSubscriptionId = undefined;
|
||
const response = {
|
||
context,
|
||
value: result
|
||
};
|
||
resolve({
|
||
__type: TransactionStatus.PROCESSED,
|
||
response
|
||
});
|
||
}, commitment);
|
||
const subscriptionSetupPromise = new Promise(resolveSubscriptionSetup => {
|
||
if (signatureSubscriptionId == null) {
|
||
resolveSubscriptionSetup();
|
||
} else {
|
||
disposeSignatureSubscriptionStateChangeObserver = this._onSubscriptionStateChange(signatureSubscriptionId, nextState => {
|
||
if (nextState === 'subscribed') {
|
||
resolveSubscriptionSetup();
|
||
}
|
||
});
|
||
}
|
||
});
|
||
(async () => {
|
||
await subscriptionSetupPromise;
|
||
if (done) return;
|
||
const response = await this.getSignatureStatus(signature);
|
||
if (done) return;
|
||
if (response == null) {
|
||
return;
|
||
}
|
||
const {
|
||
context,
|
||
value
|
||
} = response;
|
||
if (value == null) {
|
||
return;
|
||
}
|
||
if (value?.err) {
|
||
reject(value.err);
|
||
} else {
|
||
switch (commitment) {
|
||
case 'confirmed':
|
||
case 'single':
|
||
case 'singleGossip':
|
||
{
|
||
if (value.confirmationStatus === 'processed') {
|
||
return;
|
||
}
|
||
break;
|
||
}
|
||
case 'finalized':
|
||
case 'max':
|
||
case 'root':
|
||
{
|
||
if (value.confirmationStatus === 'processed' || value.confirmationStatus === 'confirmed') {
|
||
return;
|
||
}
|
||
break;
|
||
}
|
||
// exhaust enums to ensure full coverage
|
||
case 'processed':
|
||
case 'recent':
|
||
}
|
||
done = true;
|
||
resolve({
|
||
__type: TransactionStatus.PROCESSED,
|
||
response: {
|
||
context,
|
||
value
|
||
}
|
||
});
|
||
}
|
||
})();
|
||
} catch (err) {
|
||
reject(err);
|
||
}
|
||
});
|
||
const abortConfirmation = () => {
|
||
if (disposeSignatureSubscriptionStateChangeObserver) {
|
||
disposeSignatureSubscriptionStateChangeObserver();
|
||
disposeSignatureSubscriptionStateChangeObserver = undefined;
|
||
}
|
||
if (signatureSubscriptionId != null) {
|
||
this.removeSignatureListener(signatureSubscriptionId);
|
||
signatureSubscriptionId = undefined;
|
||
}
|
||
};
|
||
return {
|
||
abortConfirmation,
|
||
confirmationPromise
|
||
};
|
||
}
|
||
async confirmTransactionUsingBlockHeightExceedanceStrategy({
|
||
commitment,
|
||
strategy: {
|
||
abortSignal,
|
||
lastValidBlockHeight,
|
||
signature
|
||
}
|
||
}) {
|
||
let done = false;
|
||
const expiryPromise = new Promise(resolve => {
|
||
const checkBlockHeight = async () => {
|
||
try {
|
||
const blockHeight = await this.getBlockHeight(commitment);
|
||
return blockHeight;
|
||
} catch (_e) {
|
||
return -1;
|
||
}
|
||
};
|
||
(async () => {
|
||
let currentBlockHeight = await checkBlockHeight();
|
||
if (done) return;
|
||
while (currentBlockHeight <= lastValidBlockHeight) {
|
||
await sleep(1000);
|
||
if (done) return;
|
||
currentBlockHeight = await checkBlockHeight();
|
||
if (done) return;
|
||
}
|
||
resolve({
|
||
__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED
|
||
});
|
||
})();
|
||
});
|
||
const {
|
||
abortConfirmation,
|
||
confirmationPromise
|
||
} = this.getTransactionConfirmationPromise({
|
||
commitment,
|
||
signature
|
||
});
|
||
const cancellationPromise = this.getCancellationPromise(abortSignal);
|
||
let result;
|
||
try {
|
||
const outcome = await Promise.race([cancellationPromise, confirmationPromise, expiryPromise]);
|
||
if (outcome.__type === TransactionStatus.PROCESSED) {
|
||
result = outcome.response;
|
||
} else {
|
||
throw new TransactionExpiredBlockheightExceededError(signature);
|
||
}
|
||
} finally {
|
||
done = true;
|
||
abortConfirmation();
|
||
}
|
||
return result;
|
||
}
|
||
async confirmTransactionUsingDurableNonceStrategy({
|
||
commitment,
|
||
strategy: {
|
||
abortSignal,
|
||
minContextSlot,
|
||
nonceAccountPubkey,
|
||
nonceValue,
|
||
signature
|
||
}
|
||
}) {
|
||
let done = false;
|
||
const expiryPromise = new Promise(resolve => {
|
||
let currentNonceValue = nonceValue;
|
||
let lastCheckedSlot = null;
|
||
const getCurrentNonceValue = async () => {
|
||
try {
|
||
const {
|
||
context,
|
||
value: nonceAccount
|
||
} = await this.getNonceAndContext(nonceAccountPubkey, {
|
||
commitment,
|
||
minContextSlot
|
||
});
|
||
lastCheckedSlot = context.slot;
|
||
return nonceAccount?.nonce;
|
||
} catch (e) {
|
||
// If for whatever reason we can't reach/read the nonce
|
||
// account, just keep using the last-known value.
|
||
return currentNonceValue;
|
||
}
|
||
};
|
||
(async () => {
|
||
currentNonceValue = await getCurrentNonceValue();
|
||
if (done) return;
|
||
while (true // eslint-disable-line no-constant-condition
|
||
) {
|
||
if (nonceValue !== currentNonceValue) {
|
||
resolve({
|
||
__type: TransactionStatus.NONCE_INVALID,
|
||
slotInWhichNonceDidAdvance: lastCheckedSlot
|
||
});
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
if (done) return;
|
||
currentNonceValue = await getCurrentNonceValue();
|
||
if (done) return;
|
||
}
|
||
})();
|
||
});
|
||
const {
|
||
abortConfirmation,
|
||
confirmationPromise
|
||
} = this.getTransactionConfirmationPromise({
|
||
commitment,
|
||
signature
|
||
});
|
||
const cancellationPromise = this.getCancellationPromise(abortSignal);
|
||
let result;
|
||
try {
|
||
const outcome = await Promise.race([cancellationPromise, confirmationPromise, expiryPromise]);
|
||
if (outcome.__type === TransactionStatus.PROCESSED) {
|
||
result = outcome.response;
|
||
} else {
|
||
// Double check that the transaction is indeed unconfirmed.
|
||
let signatureStatus;
|
||
while (true // eslint-disable-line no-constant-condition
|
||
) {
|
||
const status = await this.getSignatureStatus(signature);
|
||
if (status == null) {
|
||
break;
|
||
}
|
||
if (status.context.slot < (outcome.slotInWhichNonceDidAdvance ?? minContextSlot)) {
|
||
await sleep(400);
|
||
continue;
|
||
}
|
||
signatureStatus = status;
|
||
break;
|
||
}
|
||
if (signatureStatus?.value) {
|
||
const commitmentForStatus = commitment || 'finalized';
|
||
const {
|
||
confirmationStatus
|
||
} = signatureStatus.value;
|
||
switch (commitmentForStatus) {
|
||
case 'processed':
|
||
case 'recent':
|
||
if (confirmationStatus !== 'processed' && confirmationStatus !== 'confirmed' && confirmationStatus !== 'finalized') {
|
||
throw new TransactionExpiredNonceInvalidError(signature);
|
||
}
|
||
break;
|
||
case 'confirmed':
|
||
case 'single':
|
||
case 'singleGossip':
|
||
if (confirmationStatus !== 'confirmed' && confirmationStatus !== 'finalized') {
|
||
throw new TransactionExpiredNonceInvalidError(signature);
|
||
}
|
||
break;
|
||
case 'finalized':
|
||
case 'max':
|
||
case 'root':
|
||
if (confirmationStatus !== 'finalized') {
|
||
throw new TransactionExpiredNonceInvalidError(signature);
|
||
}
|
||
break;
|
||
default:
|
||
// Exhaustive switch.
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||
(_ => {})(commitmentForStatus);
|
||
}
|
||
result = {
|
||
context: signatureStatus.context,
|
||
value: {
|
||
err: signatureStatus.value.err
|
||
}
|
||
};
|
||
} else {
|
||
throw new TransactionExpiredNonceInvalidError(signature);
|
||
}
|
||
}
|
||
} finally {
|
||
done = true;
|
||
abortConfirmation();
|
||
}
|
||
return result;
|
||
}
|
||
async confirmTransactionUsingLegacyTimeoutStrategy({
|
||
commitment,
|
||
signature
|
||
}) {
|
||
let timeoutId;
|
||
const expiryPromise = new Promise(resolve => {
|
||
let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
|
||
switch (commitment) {
|
||
case 'processed':
|
||
case 'recent':
|
||
case 'single':
|
||
case 'confirmed':
|
||
case 'singleGossip':
|
||
{
|
||
timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
|
||
break;
|
||
}
|
||
}
|
||
timeoutId = setTimeout(() => resolve({
|
||
__type: TransactionStatus.TIMED_OUT,
|
||
timeoutMs
|
||
}), timeoutMs);
|
||
});
|
||
const {
|
||
abortConfirmation,
|
||
confirmationPromise
|
||
} = this.getTransactionConfirmationPromise({
|
||
commitment,
|
||
signature
|
||
});
|
||
let result;
|
||
try {
|
||
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
|
||
if (outcome.__type === TransactionStatus.PROCESSED) {
|
||
result = outcome.response;
|
||
} else {
|
||
throw new TransactionExpiredTimeoutError(signature, outcome.timeoutMs / 1000);
|
||
}
|
||
} finally {
|
||
clearTimeout(timeoutId);
|
||
abortConfirmation();
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Return the list of nodes that are currently participating in the cluster
|
||
*/
|
||
async getClusterNodes() {
|
||
const unsafeRes = await this._rpcRequest('getClusterNodes', []);
|
||
const res = create(unsafeRes, jsonRpcResult(array(ContactInfoResult)));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get cluster nodes');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Return the list of nodes that are currently participating in the cluster
|
||
*/
|
||
async getVoteAccounts(commitment) {
|
||
const args = this._buildArgs([], commitment);
|
||
const unsafeRes = await this._rpcRequest('getVoteAccounts', args);
|
||
const res = create(unsafeRes, GetVoteAccounts);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get vote accounts');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the current slot that the node is processing
|
||
*/
|
||
async getSlot(commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getSlot', args);
|
||
const res = create(unsafeRes, jsonRpcResult(number()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get slot');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the current slot leader of the cluster
|
||
*/
|
||
async getSlotLeader(commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getSlotLeader', args);
|
||
const res = create(unsafeRes, jsonRpcResult(string()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get slot leader');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch `limit` number of slot leaders starting from `startSlot`
|
||
*
|
||
* @param startSlot fetch slot leaders starting from this slot
|
||
* @param limit number of slot leaders to return
|
||
*/
|
||
async getSlotLeaders(startSlot, limit) {
|
||
const args = [startSlot, limit];
|
||
const unsafeRes = await this._rpcRequest('getSlotLeaders', args);
|
||
const res = create(unsafeRes, jsonRpcResult(array(PublicKeyFromString)));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get slot leaders');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the current status of a signature
|
||
*/
|
||
async getSignatureStatus(signature, config) {
|
||
const {
|
||
context,
|
||
value: values
|
||
} = await this.getSignatureStatuses([signature], config);
|
||
assert$1(values.length === 1);
|
||
const value = values[0];
|
||
return {
|
||
context,
|
||
value
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Fetch the current statuses of a batch of signatures
|
||
*/
|
||
async getSignatureStatuses(signatures, config) {
|
||
const params = [signatures];
|
||
if (config) {
|
||
params.push(config);
|
||
}
|
||
const unsafeRes = await this._rpcRequest('getSignatureStatuses', params);
|
||
const res = create(unsafeRes, GetSignatureStatusesRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get signature status');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the current transaction count of the cluster
|
||
*/
|
||
async getTransactionCount(commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getTransactionCount', args);
|
||
const res = create(unsafeRes, jsonRpcResult(number()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get transaction count');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the current total currency supply of the cluster in lamports
|
||
*
|
||
* @deprecated Deprecated since v1.2.8. Please use {@link getSupply} instead.
|
||
*/
|
||
async getTotalSupply(commitment) {
|
||
const result = await this.getSupply({
|
||
commitment,
|
||
excludeNonCirculatingAccountsList: true
|
||
});
|
||
return result.value.total;
|
||
}
|
||
|
||
/**
|
||
* Fetch the cluster InflationGovernor parameters
|
||
*/
|
||
async getInflationGovernor(commitment) {
|
||
const args = this._buildArgs([], commitment);
|
||
const unsafeRes = await this._rpcRequest('getInflationGovernor', args);
|
||
const res = create(unsafeRes, GetInflationGovernorRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get inflation');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the inflation reward for a list of addresses for an epoch
|
||
*/
|
||
async getInflationReward(addresses, epoch, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([addresses.map(pubkey => pubkey.toBase58())], commitment, undefined /* encoding */, {
|
||
...config,
|
||
epoch: epoch != null ? epoch : config?.epoch
|
||
});
|
||
const unsafeRes = await this._rpcRequest('getInflationReward', args);
|
||
const res = create(unsafeRes, GetInflationRewardResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get inflation reward');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the specific inflation values for the current epoch
|
||
*/
|
||
async getInflationRate() {
|
||
const unsafeRes = await this._rpcRequest('getInflationRate', []);
|
||
const res = create(unsafeRes, GetInflationRateRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get inflation rate');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the Epoch Info parameters
|
||
*/
|
||
async getEpochInfo(commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getEpochInfo', args);
|
||
const res = create(unsafeRes, GetEpochInfoRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get epoch info');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the Epoch Schedule parameters
|
||
*/
|
||
async getEpochSchedule() {
|
||
const unsafeRes = await this._rpcRequest('getEpochSchedule', []);
|
||
const res = create(unsafeRes, GetEpochScheduleRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get epoch schedule');
|
||
}
|
||
const epochSchedule = res.result;
|
||
return new EpochSchedule(epochSchedule.slotsPerEpoch, epochSchedule.leaderScheduleSlotOffset, epochSchedule.warmup, epochSchedule.firstNormalEpoch, epochSchedule.firstNormalSlot);
|
||
}
|
||
|
||
/**
|
||
* Fetch the leader schedule for the current epoch
|
||
* @return {Promise<RpcResponseAndContext<LeaderSchedule>>}
|
||
*/
|
||
async getLeaderSchedule() {
|
||
const unsafeRes = await this._rpcRequest('getLeaderSchedule', []);
|
||
const res = create(unsafeRes, GetLeaderScheduleRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get leader schedule');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the minimum balance needed to exempt an account of `dataLength`
|
||
* size from rent
|
||
*/
|
||
async getMinimumBalanceForRentExemption(dataLength, commitment) {
|
||
const args = this._buildArgs([dataLength], commitment);
|
||
const unsafeRes = await this._rpcRequest('getMinimumBalanceForRentExemption', args);
|
||
const res = create(unsafeRes, GetMinimumBalanceForRentExemptionRpcResult);
|
||
if ('error' in res) {
|
||
console.warn('Unable to fetch minimum balance for rent exemption');
|
||
return 0;
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch a recent blockhash from the cluster, return with context
|
||
* @return {Promise<RpcResponseAndContext<{blockhash: Blockhash, feeCalculator: FeeCalculator}>>}
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link getLatestBlockhash} instead.
|
||
*/
|
||
async getRecentBlockhashAndContext(commitment) {
|
||
const args = this._buildArgs([], commitment);
|
||
const unsafeRes = await this._rpcRequest('getRecentBlockhash', args);
|
||
const res = create(unsafeRes, GetRecentBlockhashAndContextRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get recent blockhash');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch recent performance samples
|
||
* @return {Promise<Array<PerfSample>>}
|
||
*/
|
||
async getRecentPerformanceSamples(limit) {
|
||
const unsafeRes = await this._rpcRequest('getRecentPerformanceSamples', limit ? [limit] : []);
|
||
const res = create(unsafeRes, GetRecentPerformanceSamplesRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get recent performance samples');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the fee calculator for a recent blockhash from the cluster, return with context
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link getFeeForMessage} instead.
|
||
*/
|
||
async getFeeCalculatorForBlockhash(blockhash, commitment) {
|
||
const args = this._buildArgs([blockhash], commitment);
|
||
const unsafeRes = await this._rpcRequest('getFeeCalculatorForBlockhash', args);
|
||
const res = create(unsafeRes, GetFeeCalculatorRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get fee calculator');
|
||
}
|
||
const {
|
||
context,
|
||
value
|
||
} = res.result;
|
||
return {
|
||
context,
|
||
value: value !== null ? value.feeCalculator : null
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Fetch the fee for a message from the cluster, return with context
|
||
*/
|
||
async getFeeForMessage(message, commitment) {
|
||
const wireMessage = toBuffer(message.serialize()).toString('base64');
|
||
const args = this._buildArgs([wireMessage], commitment);
|
||
const unsafeRes = await this._rpcRequest('getFeeForMessage', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(nullable(number())));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get fee for message');
|
||
}
|
||
if (res.result === null) {
|
||
throw new Error('invalid blockhash');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch a list of prioritization fees from recent blocks.
|
||
*/
|
||
async getRecentPrioritizationFees(config) {
|
||
const accounts = config?.lockedWritableAccounts?.map(key => key.toBase58());
|
||
const args = accounts?.length ? [accounts] : [];
|
||
const unsafeRes = await this._rpcRequest('getRecentPrioritizationFees', args);
|
||
const res = create(unsafeRes, GetRecentPrioritizationFeesRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get recent prioritization fees');
|
||
}
|
||
return res.result;
|
||
}
|
||
/**
|
||
* Fetch a recent blockhash from the cluster
|
||
* @return {Promise<{blockhash: Blockhash, feeCalculator: FeeCalculator}>}
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link getLatestBlockhash} instead.
|
||
*/
|
||
async getRecentBlockhash(commitment) {
|
||
try {
|
||
const res = await this.getRecentBlockhashAndContext(commitment);
|
||
return res.value;
|
||
} catch (e) {
|
||
throw new Error('failed to get recent blockhash: ' + e);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Fetch the latest blockhash from the cluster
|
||
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
||
*/
|
||
async getLatestBlockhash(commitmentOrConfig) {
|
||
try {
|
||
const res = await this.getLatestBlockhashAndContext(commitmentOrConfig);
|
||
return res.value;
|
||
} catch (e) {
|
||
throw new Error('failed to get recent blockhash: ' + e);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Fetch the latest blockhash from the cluster
|
||
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
||
*/
|
||
async getLatestBlockhashAndContext(commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getLatestBlockhash', args);
|
||
const res = create(unsafeRes, GetLatestBlockhashRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get latest blockhash');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Returns whether a blockhash is still valid or not
|
||
*/
|
||
async isBlockhashValid(blockhash, rawConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(rawConfig);
|
||
const args = this._buildArgs([blockhash], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('isBlockhashValid', args);
|
||
const res = create(unsafeRes, IsBlockhashValidRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to determine if the blockhash `' + blockhash + '`is valid');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the node version
|
||
*/
|
||
async getVersion() {
|
||
const unsafeRes = await this._rpcRequest('getVersion', []);
|
||
const res = create(unsafeRes, jsonRpcResult(VersionResult));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get version');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch the genesis hash
|
||
*/
|
||
async getGenesisHash() {
|
||
const unsafeRes = await this._rpcRequest('getGenesisHash', []);
|
||
const res = create(unsafeRes, jsonRpcResult(string()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get genesis hash');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch a processed block from the cluster.
|
||
*
|
||
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
||
* setting the `maxSupportedTransactionVersion` property.
|
||
*/
|
||
|
||
/**
|
||
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
||
* setting the `maxSupportedTransactionVersion` property.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
/**
|
||
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
||
* setting the `maxSupportedTransactionVersion` property.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
/**
|
||
* Fetch a processed block from the cluster.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
/**
|
||
* Fetch a processed block from the cluster.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async getBlock(slot, rawConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(rawConfig);
|
||
const args = this._buildArgsAtLeastConfirmed([slot], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getBlock', args);
|
||
try {
|
||
switch (config?.transactionDetails) {
|
||
case 'accounts':
|
||
{
|
||
const res = create(unsafeRes, GetAccountsModeBlockRpcResult);
|
||
if ('error' in res) {
|
||
throw res.error;
|
||
}
|
||
return res.result;
|
||
}
|
||
case 'none':
|
||
{
|
||
const res = create(unsafeRes, GetNoneModeBlockRpcResult);
|
||
if ('error' in res) {
|
||
throw res.error;
|
||
}
|
||
return res.result;
|
||
}
|
||
default:
|
||
{
|
||
const res = create(unsafeRes, GetBlockRpcResult);
|
||
if ('error' in res) {
|
||
throw res.error;
|
||
}
|
||
const {
|
||
result
|
||
} = res;
|
||
return result ? {
|
||
...result,
|
||
transactions: result.transactions.map(({
|
||
transaction,
|
||
meta,
|
||
version
|
||
}) => ({
|
||
meta,
|
||
transaction: {
|
||
...transaction,
|
||
message: versionedMessageFromResponse(version, transaction.message)
|
||
},
|
||
version
|
||
}))
|
||
} : null;
|
||
}
|
||
}
|
||
} catch (e) {
|
||
throw new SolanaJSONRPCError(e, 'failed to get confirmed block');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Fetch parsed transaction details for a confirmed or finalized block
|
||
*/
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async getParsedBlock(slot, rawConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(rawConfig);
|
||
const args = this._buildArgsAtLeastConfirmed([slot], commitment, 'jsonParsed', config);
|
||
const unsafeRes = await this._rpcRequest('getBlock', args);
|
||
try {
|
||
switch (config?.transactionDetails) {
|
||
case 'accounts':
|
||
{
|
||
const res = create(unsafeRes, GetParsedAccountsModeBlockRpcResult);
|
||
if ('error' in res) {
|
||
throw res.error;
|
||
}
|
||
return res.result;
|
||
}
|
||
case 'none':
|
||
{
|
||
const res = create(unsafeRes, GetParsedNoneModeBlockRpcResult);
|
||
if ('error' in res) {
|
||
throw res.error;
|
||
}
|
||
return res.result;
|
||
}
|
||
default:
|
||
{
|
||
const res = create(unsafeRes, GetParsedBlockRpcResult);
|
||
if ('error' in res) {
|
||
throw res.error;
|
||
}
|
||
return res.result;
|
||
}
|
||
}
|
||
} catch (e) {
|
||
throw new SolanaJSONRPCError(e, 'failed to get block');
|
||
}
|
||
}
|
||
/*
|
||
* Returns recent block production information from the current or previous epoch
|
||
*/
|
||
async getBlockProduction(configOrCommitment) {
|
||
let extra;
|
||
let commitment;
|
||
if (typeof configOrCommitment === 'string') {
|
||
commitment = configOrCommitment;
|
||
} else if (configOrCommitment) {
|
||
const {
|
||
commitment: c,
|
||
...rest
|
||
} = configOrCommitment;
|
||
commitment = c;
|
||
extra = rest;
|
||
}
|
||
const args = this._buildArgs([], commitment, 'base64', extra);
|
||
const unsafeRes = await this._rpcRequest('getBlockProduction', args);
|
||
const res = create(unsafeRes, BlockProductionResponseStruct);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get block production information');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch a confirmed or finalized transaction from the cluster.
|
||
*
|
||
* @deprecated Instead, call `getTransaction` using a
|
||
* `GetVersionedTransactionConfig` by setting the
|
||
* `maxSupportedTransactionVersion` property.
|
||
*/
|
||
|
||
/**
|
||
* Fetch a confirmed or finalized transaction from the cluster.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
/**
|
||
* Fetch a confirmed or finalized transaction from the cluster.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async getTransaction(signature, rawConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(rawConfig);
|
||
const args = this._buildArgsAtLeastConfirmed([signature], commitment, undefined /* encoding */, config);
|
||
const unsafeRes = await this._rpcRequest('getTransaction', args);
|
||
const res = create(unsafeRes, GetTransactionRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
|
||
}
|
||
const result = res.result;
|
||
if (!result) return result;
|
||
return {
|
||
...result,
|
||
transaction: {
|
||
...result.transaction,
|
||
message: versionedMessageFromResponse(result.version, result.transaction.message)
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Fetch parsed transaction details for a confirmed or finalized transaction
|
||
*/
|
||
async getParsedTransaction(signature, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed', config);
|
||
const unsafeRes = await this._rpcRequest('getTransaction', args);
|
||
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch parsed transaction details for a batch of confirmed transactions
|
||
*/
|
||
async getParsedTransactions(signatures, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const batch = signatures.map(signature => {
|
||
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed', config);
|
||
return {
|
||
methodName: 'getTransaction',
|
||
args
|
||
};
|
||
});
|
||
const unsafeRes = await this._rpcBatchRequest(batch);
|
||
const res = unsafeRes.map(unsafeRes => {
|
||
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
|
||
}
|
||
return res.result;
|
||
});
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* Fetch transaction details for a batch of confirmed transactions.
|
||
* Similar to {@link getParsedTransactions} but returns a {@link TransactionResponse}.
|
||
*
|
||
* @deprecated Instead, call `getTransactions` using a
|
||
* `GetVersionedTransactionConfig` by setting the
|
||
* `maxSupportedTransactionVersion` property.
|
||
*/
|
||
|
||
/**
|
||
* Fetch transaction details for a batch of confirmed transactions.
|
||
* Similar to {@link getParsedTransactions} but returns a {@link
|
||
* VersionedTransactionResponse}.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
/**
|
||
* Fetch transaction details for a batch of confirmed transactions.
|
||
* Similar to {@link getParsedTransactions} but returns a {@link
|
||
* VersionedTransactionResponse}.
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async getTransactions(signatures, commitmentOrConfig) {
|
||
const {
|
||
commitment,
|
||
config
|
||
} = extractCommitmentFromConfig(commitmentOrConfig);
|
||
const batch = signatures.map(signature => {
|
||
const args = this._buildArgsAtLeastConfirmed([signature], commitment, undefined /* encoding */, config);
|
||
return {
|
||
methodName: 'getTransaction',
|
||
args
|
||
};
|
||
});
|
||
const unsafeRes = await this._rpcBatchRequest(batch);
|
||
const res = unsafeRes.map(unsafeRes => {
|
||
const res = create(unsafeRes, GetTransactionRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
|
||
}
|
||
const result = res.result;
|
||
if (!result) return result;
|
||
return {
|
||
...result,
|
||
transaction: {
|
||
...result.transaction,
|
||
message: versionedMessageFromResponse(result.version, result.transaction.message)
|
||
}
|
||
};
|
||
});
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* Fetch a list of Transactions and transaction statuses from the cluster
|
||
* for a confirmed block.
|
||
*
|
||
* @deprecated Deprecated since v1.13.0. Please use {@link getBlock} instead.
|
||
*/
|
||
async getConfirmedBlock(slot, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed([slot], commitment);
|
||
const unsafeRes = await this._rpcRequest('getConfirmedBlock', args);
|
||
const res = create(unsafeRes, GetConfirmedBlockRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
|
||
}
|
||
const result = res.result;
|
||
if (!result) {
|
||
throw new Error('Confirmed block ' + slot + ' not found');
|
||
}
|
||
const block = {
|
||
...result,
|
||
transactions: result.transactions.map(({
|
||
transaction,
|
||
meta
|
||
}) => {
|
||
const message = new Message(transaction.message);
|
||
return {
|
||
meta,
|
||
transaction: {
|
||
...transaction,
|
||
message
|
||
}
|
||
};
|
||
})
|
||
};
|
||
return {
|
||
...block,
|
||
transactions: block.transactions.map(({
|
||
transaction,
|
||
meta
|
||
}) => {
|
||
return {
|
||
meta,
|
||
transaction: Transaction.populate(transaction.message, transaction.signatures)
|
||
};
|
||
})
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Fetch confirmed blocks between two slots
|
||
*/
|
||
async getBlocks(startSlot, endSlot, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed(endSlot !== undefined ? [startSlot, endSlot] : [startSlot], commitment);
|
||
const unsafeRes = await this._rpcRequest('getBlocks', args);
|
||
const res = create(unsafeRes, jsonRpcResult(array(number())));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get blocks');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch a list of Signatures from the cluster for a block, excluding rewards
|
||
*/
|
||
async getBlockSignatures(slot, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed([slot], commitment, undefined, {
|
||
transactionDetails: 'signatures',
|
||
rewards: false
|
||
});
|
||
const unsafeRes = await this._rpcRequest('getBlock', args);
|
||
const res = create(unsafeRes, GetBlockSignaturesRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get block');
|
||
}
|
||
const result = res.result;
|
||
if (!result) {
|
||
throw new Error('Block ' + slot + ' not found');
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Fetch a list of Signatures from the cluster for a confirmed block, excluding rewards
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link getBlockSignatures} instead.
|
||
*/
|
||
async getConfirmedBlockSignatures(slot, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed([slot], commitment, undefined, {
|
||
transactionDetails: 'signatures',
|
||
rewards: false
|
||
});
|
||
const unsafeRes = await this._rpcRequest('getConfirmedBlock', args);
|
||
const res = create(unsafeRes, GetBlockSignaturesRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
|
||
}
|
||
const result = res.result;
|
||
if (!result) {
|
||
throw new Error('Confirmed block ' + slot + ' not found');
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Fetch a transaction details for a confirmed transaction
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link getTransaction} instead.
|
||
*/
|
||
async getConfirmedTransaction(signature, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed([signature], commitment);
|
||
const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args);
|
||
const res = create(unsafeRes, GetTransactionRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
|
||
}
|
||
const result = res.result;
|
||
if (!result) return result;
|
||
const message = new Message(result.transaction.message);
|
||
const signatures = result.transaction.signatures;
|
||
return {
|
||
...result,
|
||
transaction: Transaction.populate(message, signatures)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Fetch parsed transaction details for a confirmed transaction
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link getParsedTransaction} instead.
|
||
*/
|
||
async getParsedConfirmedTransaction(signature, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed');
|
||
const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args);
|
||
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed transaction');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Fetch parsed transaction details for a batch of confirmed transactions
|
||
*
|
||
* @deprecated Deprecated since Solana v1.8.0. Please use {@link getParsedTransactions} instead.
|
||
*/
|
||
async getParsedConfirmedTransactions(signatures, commitment) {
|
||
const batch = signatures.map(signature => {
|
||
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed');
|
||
return {
|
||
methodName: 'getConfirmedTransaction',
|
||
args
|
||
};
|
||
});
|
||
const unsafeRes = await this._rpcBatchRequest(batch);
|
||
const res = unsafeRes.map(unsafeRes => {
|
||
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed transactions');
|
||
}
|
||
return res.result;
|
||
});
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* Fetch a list of all the confirmed signatures for transactions involving an address
|
||
* within a specified slot range. Max range allowed is 10,000 slots.
|
||
*
|
||
* @deprecated Deprecated since v1.3. Please use {@link getConfirmedSignaturesForAddress2} instead.
|
||
*
|
||
* @param address queried address
|
||
* @param startSlot start slot, inclusive
|
||
* @param endSlot end slot, inclusive
|
||
*/
|
||
async getConfirmedSignaturesForAddress(address, startSlot, endSlot) {
|
||
let options = {};
|
||
let firstAvailableBlock = await this.getFirstAvailableBlock();
|
||
while (!('until' in options)) {
|
||
startSlot--;
|
||
if (startSlot <= 0 || startSlot < firstAvailableBlock) {
|
||
break;
|
||
}
|
||
try {
|
||
const block = await this.getConfirmedBlockSignatures(startSlot, 'finalized');
|
||
if (block.signatures.length > 0) {
|
||
options.until = block.signatures[block.signatures.length - 1].toString();
|
||
}
|
||
} catch (err) {
|
||
if (err instanceof Error && err.message.includes('skipped')) {
|
||
continue;
|
||
} else {
|
||
throw err;
|
||
}
|
||
}
|
||
}
|
||
let highestConfirmedRoot = await this.getSlot('finalized');
|
||
while (!('before' in options)) {
|
||
endSlot++;
|
||
if (endSlot > highestConfirmedRoot) {
|
||
break;
|
||
}
|
||
try {
|
||
const block = await this.getConfirmedBlockSignatures(endSlot);
|
||
if (block.signatures.length > 0) {
|
||
options.before = block.signatures[block.signatures.length - 1].toString();
|
||
}
|
||
} catch (err) {
|
||
if (err instanceof Error && err.message.includes('skipped')) {
|
||
continue;
|
||
} else {
|
||
throw err;
|
||
}
|
||
}
|
||
}
|
||
const confirmedSignatureInfo = await this.getConfirmedSignaturesForAddress2(address, options);
|
||
return confirmedSignatureInfo.map(info => info.signature);
|
||
}
|
||
|
||
/**
|
||
* Returns confirmed signatures for transactions involving an
|
||
* address backwards in time from the provided signature or most recent confirmed block
|
||
*
|
||
*
|
||
* @param address queried address
|
||
* @param options
|
||
*/
|
||
async getConfirmedSignaturesForAddress2(address, options, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed([address.toBase58()], commitment, undefined, options);
|
||
const unsafeRes = await this._rpcRequest('getConfirmedSignaturesForAddress2', args);
|
||
const res = create(unsafeRes, GetConfirmedSignaturesForAddress2RpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed signatures for address');
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Returns confirmed signatures for transactions involving an
|
||
* address backwards in time from the provided signature or most recent confirmed block
|
||
*
|
||
*
|
||
* @param address queried address
|
||
* @param options
|
||
*/
|
||
async getSignaturesForAddress(address, options, commitment) {
|
||
const args = this._buildArgsAtLeastConfirmed([address.toBase58()], commitment, undefined, options);
|
||
const unsafeRes = await this._rpcRequest('getSignaturesForAddress', args);
|
||
const res = create(unsafeRes, GetSignaturesForAddressRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, 'failed to get signatures for address');
|
||
}
|
||
return res.result;
|
||
}
|
||
async getAddressLookupTable(accountKey, config) {
|
||
const {
|
||
context,
|
||
value: accountInfo
|
||
} = await this.getAccountInfoAndContext(accountKey, config);
|
||
let value = null;
|
||
if (accountInfo !== null) {
|
||
value = new AddressLookupTableAccount({
|
||
key: accountKey,
|
||
state: AddressLookupTableAccount.deserialize(accountInfo.data)
|
||
});
|
||
}
|
||
return {
|
||
context,
|
||
value
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Fetch the contents of a Nonce account from the cluster, return with context
|
||
*/
|
||
async getNonceAndContext(nonceAccount, commitmentOrConfig) {
|
||
const {
|
||
context,
|
||
value: accountInfo
|
||
} = await this.getAccountInfoAndContext(nonceAccount, commitmentOrConfig);
|
||
let value = null;
|
||
if (accountInfo !== null) {
|
||
value = NonceAccount.fromAccountData(accountInfo.data);
|
||
}
|
||
return {
|
||
context,
|
||
value
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Fetch the contents of a Nonce account from the cluster
|
||
*/
|
||
async getNonce(nonceAccount, commitmentOrConfig) {
|
||
return await this.getNonceAndContext(nonceAccount, commitmentOrConfig).then(x => x.value).catch(e => {
|
||
throw new Error('failed to get nonce for account ' + nonceAccount.toBase58() + ': ' + e);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Request an allocation of lamports to the specified address
|
||
*
|
||
* ```typescript
|
||
* import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
|
||
*
|
||
* (async () => {
|
||
* const connection = new Connection("https://api.testnet.solana.com", "confirmed");
|
||
* const myAddress = new PublicKey("2nr1bHFT86W9tGnyvmYW4vcHKsQB3sVQfnddasz4kExM");
|
||
* const signature = await connection.requestAirdrop(myAddress, LAMPORTS_PER_SOL);
|
||
* await connection.confirmTransaction(signature);
|
||
* })();
|
||
* ```
|
||
*/
|
||
async requestAirdrop(to, lamports) {
|
||
const unsafeRes = await this._rpcRequest('requestAirdrop', [to.toBase58(), lamports]);
|
||
const res = create(unsafeRes, RequestAirdropRpcResult);
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `airdrop to ${to.toBase58()} failed`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
async _blockhashWithExpiryBlockHeight(disableCache) {
|
||
if (!disableCache) {
|
||
// Wait for polling to finish
|
||
while (this._pollingBlockhash) {
|
||
await sleep(100);
|
||
}
|
||
const timeSinceFetch = Date.now() - this._blockhashInfo.lastFetch;
|
||
const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
|
||
if (this._blockhashInfo.latestBlockhash !== null && !expired) {
|
||
return this._blockhashInfo.latestBlockhash;
|
||
}
|
||
}
|
||
return await this._pollNewBlockhash();
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
async _pollNewBlockhash() {
|
||
this._pollingBlockhash = true;
|
||
try {
|
||
const startTime = Date.now();
|
||
const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
|
||
const cachedBlockhash = cachedLatestBlockhash ? cachedLatestBlockhash.blockhash : null;
|
||
for (let i = 0; i < 50; i++) {
|
||
const latestBlockhash = await this.getLatestBlockhash('finalized');
|
||
if (cachedBlockhash !== latestBlockhash.blockhash) {
|
||
this._blockhashInfo = {
|
||
latestBlockhash,
|
||
lastFetch: Date.now(),
|
||
transactionSignatures: [],
|
||
simulatedSignatures: []
|
||
};
|
||
return latestBlockhash;
|
||
}
|
||
|
||
// Sleep for approximately half a slot
|
||
await sleep(MS_PER_SLOT / 2);
|
||
}
|
||
throw new Error(`Unable to obtain a new blockhash after ${Date.now() - startTime}ms`);
|
||
} finally {
|
||
this._pollingBlockhash = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* get the stake minimum delegation
|
||
*/
|
||
async getStakeMinimumDelegation(config) {
|
||
const {
|
||
commitment,
|
||
config: configArg
|
||
} = extractCommitmentFromConfig(config);
|
||
const args = this._buildArgs([], commitment, 'base64', configArg);
|
||
const unsafeRes = await this._rpcRequest('getStakeMinimumDelegation', args);
|
||
const res = create(unsafeRes, jsonRpcResultAndContext(number()));
|
||
if ('error' in res) {
|
||
throw new SolanaJSONRPCError(res.error, `failed to get stake minimum delegation`);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Simulate a transaction
|
||
*
|
||
* @deprecated Instead, call {@link simulateTransaction} with {@link
|
||
* VersionedTransaction} and {@link SimulateTransactionConfig} parameters
|
||
*/
|
||
|
||
/**
|
||
* Simulate a transaction
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
/**
|
||
* Simulate a transaction
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async simulateTransaction(transactionOrMessage, configOrSigners, includeAccounts) {
|
||
if ('message' in transactionOrMessage) {
|
||
const versionedTx = transactionOrMessage;
|
||
const wireTransaction = versionedTx.serialize();
|
||
const encodedTransaction = buffer.Buffer.from(wireTransaction).toString('base64');
|
||
if (Array.isArray(configOrSigners) || includeAccounts !== undefined) {
|
||
throw new Error('Invalid arguments');
|
||
}
|
||
const config = configOrSigners || {};
|
||
config.encoding = 'base64';
|
||
if (!('commitment' in config)) {
|
||
config.commitment = this.commitment;
|
||
}
|
||
const args = [encodedTransaction, config];
|
||
const unsafeRes = await this._rpcRequest('simulateTransaction', args);
|
||
const res = create(unsafeRes, SimulatedTransactionResponseStruct);
|
||
if ('error' in res) {
|
||
throw new Error('failed to simulate transaction: ' + res.error.message);
|
||
}
|
||
return res.result;
|
||
}
|
||
let transaction;
|
||
if (transactionOrMessage instanceof Transaction) {
|
||
let originalTx = transactionOrMessage;
|
||
transaction = new Transaction();
|
||
transaction.feePayer = originalTx.feePayer;
|
||
transaction.instructions = transactionOrMessage.instructions;
|
||
transaction.nonceInfo = originalTx.nonceInfo;
|
||
transaction.signatures = originalTx.signatures;
|
||
} else {
|
||
transaction = Transaction.populate(transactionOrMessage);
|
||
// HACK: this function relies on mutating the populated transaction
|
||
transaction._message = transaction._json = undefined;
|
||
}
|
||
if (configOrSigners !== undefined && !Array.isArray(configOrSigners)) {
|
||
throw new Error('Invalid arguments');
|
||
}
|
||
const signers = configOrSigners;
|
||
if (transaction.nonceInfo && signers) {
|
||
transaction.sign(...signers);
|
||
} else {
|
||
let disableCache = this._disableBlockhashCaching;
|
||
for (;;) {
|
||
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
|
||
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
||
transaction.recentBlockhash = latestBlockhash.blockhash;
|
||
if (!signers) break;
|
||
transaction.sign(...signers);
|
||
if (!transaction.signature) {
|
||
throw new Error('!signature'); // should never happen
|
||
}
|
||
const signature = transaction.signature.toString('base64');
|
||
if (!this._blockhashInfo.simulatedSignatures.includes(signature) && !this._blockhashInfo.transactionSignatures.includes(signature)) {
|
||
// The signature of this transaction has not been seen before with the
|
||
// current recentBlockhash, all done. Let's break
|
||
this._blockhashInfo.simulatedSignatures.push(signature);
|
||
break;
|
||
} else {
|
||
// This transaction would be treated as duplicate (its derived signature
|
||
// matched to one of already recorded signatures).
|
||
// So, we must fetch a new blockhash for a different signature by disabling
|
||
// our cache not to wait for the cache expiration (BLOCKHASH_CACHE_TIMEOUT_MS).
|
||
disableCache = true;
|
||
}
|
||
}
|
||
}
|
||
const message = transaction._compile();
|
||
const signData = message.serialize();
|
||
const wireTransaction = transaction._serialize(signData);
|
||
const encodedTransaction = wireTransaction.toString('base64');
|
||
const config = {
|
||
encoding: 'base64',
|
||
commitment: this.commitment
|
||
};
|
||
if (includeAccounts) {
|
||
const addresses = (Array.isArray(includeAccounts) ? includeAccounts : message.nonProgramIds()).map(key => key.toBase58());
|
||
config['accounts'] = {
|
||
encoding: 'base64',
|
||
addresses
|
||
};
|
||
}
|
||
if (signers) {
|
||
config.sigVerify = true;
|
||
}
|
||
const args = [encodedTransaction, config];
|
||
const unsafeRes = await this._rpcRequest('simulateTransaction', args);
|
||
const res = create(unsafeRes, SimulatedTransactionResponseStruct);
|
||
if ('error' in res) {
|
||
let logs;
|
||
if ('data' in res.error) {
|
||
logs = res.error.data.logs;
|
||
if (logs && Array.isArray(logs)) {
|
||
const traceIndent = '\n ';
|
||
const logTrace = traceIndent + logs.join(traceIndent);
|
||
console.error(res.error.message, logTrace);
|
||
}
|
||
}
|
||
throw new SendTransactionError('failed to simulate transaction: ' + res.error.message, logs);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* Sign and send a transaction
|
||
*
|
||
* @deprecated Instead, call {@link sendTransaction} with a {@link
|
||
* VersionedTransaction}
|
||
*/
|
||
|
||
/**
|
||
* Send a signed transaction
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
|
||
/**
|
||
* Sign and send a transaction
|
||
*/
|
||
// eslint-disable-next-line no-dupe-class-members
|
||
async sendTransaction(transaction, signersOrOptions, options) {
|
||
if ('version' in transaction) {
|
||
if (signersOrOptions && Array.isArray(signersOrOptions)) {
|
||
throw new Error('Invalid arguments');
|
||
}
|
||
const wireTransaction = transaction.serialize();
|
||
return await this.sendRawTransaction(wireTransaction, signersOrOptions);
|
||
}
|
||
if (signersOrOptions === undefined || !Array.isArray(signersOrOptions)) {
|
||
throw new Error('Invalid arguments');
|
||
}
|
||
const signers = signersOrOptions;
|
||
if (transaction.nonceInfo) {
|
||
transaction.sign(...signers);
|
||
} else {
|
||
let disableCache = this._disableBlockhashCaching;
|
||
for (;;) {
|
||
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
|
||
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
||
transaction.recentBlockhash = latestBlockhash.blockhash;
|
||
transaction.sign(...signers);
|
||
if (!transaction.signature) {
|
||
throw new Error('!signature'); // should never happen
|
||
}
|
||
const signature = transaction.signature.toString('base64');
|
||
if (!this._blockhashInfo.transactionSignatures.includes(signature)) {
|
||
// The signature of this transaction has not been seen before with the
|
||
// current recentBlockhash, all done. Let's break
|
||
this._blockhashInfo.transactionSignatures.push(signature);
|
||
break;
|
||
} else {
|
||
// This transaction would be treated as duplicate (its derived signature
|
||
// matched to one of already recorded signatures).
|
||
// So, we must fetch a new blockhash for a different signature by disabling
|
||
// our cache not to wait for the cache expiration (BLOCKHASH_CACHE_TIMEOUT_MS).
|
||
disableCache = true;
|
||
}
|
||
}
|
||
}
|
||
const wireTransaction = transaction.serialize();
|
||
return await this.sendRawTransaction(wireTransaction, options);
|
||
}
|
||
|
||
/**
|
||
* Send a transaction that has already been signed and serialized into the
|
||
* wire format
|
||
*/
|
||
async sendRawTransaction(rawTransaction, options) {
|
||
const encodedTransaction = toBuffer(rawTransaction).toString('base64');
|
||
const result = await this.sendEncodedTransaction(encodedTransaction, options);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Send a transaction that has already been signed, serialized into the
|
||
* wire format, and encoded as a base64 string
|
||
*/
|
||
async sendEncodedTransaction(encodedTransaction, options) {
|
||
const config = {
|
||
encoding: 'base64'
|
||
};
|
||
const skipPreflight = options && options.skipPreflight;
|
||
const preflightCommitment = skipPreflight === true ? 'processed' // FIXME Remove when https://github.com/anza-xyz/agave/pull/483 is deployed.
|
||
: options && options.preflightCommitment || this.commitment;
|
||
if (options && options.maxRetries != null) {
|
||
config.maxRetries = options.maxRetries;
|
||
}
|
||
if (options && options.minContextSlot != null) {
|
||
config.minContextSlot = options.minContextSlot;
|
||
}
|
||
if (skipPreflight) {
|
||
config.skipPreflight = skipPreflight;
|
||
}
|
||
if (preflightCommitment) {
|
||
config.preflightCommitment = preflightCommitment;
|
||
}
|
||
const args = [encodedTransaction, config];
|
||
const unsafeRes = await this._rpcRequest('sendTransaction', args);
|
||
const res = create(unsafeRes, SendTransactionRpcResult);
|
||
if ('error' in res) {
|
||
let logs;
|
||
if ('data' in res.error) {
|
||
logs = res.error.data.logs;
|
||
}
|
||
throw new SendTransactionError('failed to send transaction: ' + res.error.message, logs);
|
||
}
|
||
return res.result;
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnOpen() {
|
||
this._rpcWebSocketConnected = true;
|
||
this._rpcWebSocketHeartbeat = setInterval(() => {
|
||
// Ping server every 5s to prevent idle timeouts
|
||
(async () => {
|
||
try {
|
||
await this._rpcWebSocket.notify('ping');
|
||
// eslint-disable-next-line no-empty
|
||
} catch {}
|
||
})();
|
||
}, 5000);
|
||
this._updateSubscriptions();
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnError(err) {
|
||
this._rpcWebSocketConnected = false;
|
||
console.error('ws error:', err.message);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnClose(code) {
|
||
this._rpcWebSocketConnected = false;
|
||
this._rpcWebSocketGeneration = (this._rpcWebSocketGeneration + 1) % Number.MAX_SAFE_INTEGER;
|
||
if (this._rpcWebSocketIdleTimeout) {
|
||
clearTimeout(this._rpcWebSocketIdleTimeout);
|
||
this._rpcWebSocketIdleTimeout = null;
|
||
}
|
||
if (this._rpcWebSocketHeartbeat) {
|
||
clearInterval(this._rpcWebSocketHeartbeat);
|
||
this._rpcWebSocketHeartbeat = null;
|
||
}
|
||
if (code === 1000) {
|
||
// explicit close, check if any subscriptions have been made since close
|
||
this._updateSubscriptions();
|
||
return;
|
||
}
|
||
|
||
// implicit close, prepare subscriptions for auto-reconnect
|
||
this._subscriptionCallbacksByServerSubscriptionId = {};
|
||
Object.entries(this._subscriptionsByHash).forEach(([hash, subscription]) => {
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
state: 'pending'
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_setSubscription(hash, nextSubscription) {
|
||
const prevState = this._subscriptionsByHash[hash]?.state;
|
||
this._subscriptionsByHash[hash] = nextSubscription;
|
||
if (prevState !== nextSubscription.state) {
|
||
const stateChangeCallbacks = this._subscriptionStateChangeCallbacksByHash[hash];
|
||
if (stateChangeCallbacks) {
|
||
stateChangeCallbacks.forEach(cb => {
|
||
try {
|
||
cb(nextSubscription.state);
|
||
// eslint-disable-next-line no-empty
|
||
} catch {}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_onSubscriptionStateChange(clientSubscriptionId, callback) {
|
||
const hash = this._subscriptionHashByClientSubscriptionId[clientSubscriptionId];
|
||
if (hash == null) {
|
||
return () => {};
|
||
}
|
||
const stateChangeCallbacks = this._subscriptionStateChangeCallbacksByHash[hash] ||= new Set();
|
||
stateChangeCallbacks.add(callback);
|
||
return () => {
|
||
stateChangeCallbacks.delete(callback);
|
||
if (stateChangeCallbacks.size === 0) {
|
||
delete this._subscriptionStateChangeCallbacksByHash[hash];
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
async _updateSubscriptions() {
|
||
if (Object.keys(this._subscriptionsByHash).length === 0) {
|
||
if (this._rpcWebSocketConnected) {
|
||
this._rpcWebSocketConnected = false;
|
||
this._rpcWebSocketIdleTimeout = setTimeout(() => {
|
||
this._rpcWebSocketIdleTimeout = null;
|
||
try {
|
||
this._rpcWebSocket.close();
|
||
} catch (err) {
|
||
// swallow error if socket has already been closed.
|
||
if (err instanceof Error) {
|
||
console.log(`Error when closing socket connection: ${err.message}`);
|
||
}
|
||
}
|
||
}, 500);
|
||
}
|
||
return;
|
||
}
|
||
if (this._rpcWebSocketIdleTimeout !== null) {
|
||
clearTimeout(this._rpcWebSocketIdleTimeout);
|
||
this._rpcWebSocketIdleTimeout = null;
|
||
this._rpcWebSocketConnected = true;
|
||
}
|
||
if (!this._rpcWebSocketConnected) {
|
||
this._rpcWebSocket.connect();
|
||
return;
|
||
}
|
||
const activeWebSocketGeneration = this._rpcWebSocketGeneration;
|
||
const isCurrentConnectionStillActive = () => {
|
||
return activeWebSocketGeneration === this._rpcWebSocketGeneration;
|
||
};
|
||
await Promise.all(
|
||
// Don't be tempted to change this to `Object.entries`. We call
|
||
// `_updateSubscriptions` recursively when processing the state,
|
||
// so it's important that we look up the *current* version of
|
||
// each subscription, every time we process a hash.
|
||
Object.keys(this._subscriptionsByHash).map(async hash => {
|
||
const subscription = this._subscriptionsByHash[hash];
|
||
if (subscription === undefined) {
|
||
// This entry has since been deleted. Skip.
|
||
return;
|
||
}
|
||
switch (subscription.state) {
|
||
case 'pending':
|
||
case 'unsubscribed':
|
||
if (subscription.callbacks.size === 0) {
|
||
/**
|
||
* You can end up here when:
|
||
*
|
||
* - a subscription has recently unsubscribed
|
||
* without having new callbacks added to it
|
||
* while the unsubscribe was in flight, or
|
||
* - when a pending subscription has its
|
||
* listeners removed before a request was
|
||
* sent to the server.
|
||
*
|
||
* Being that nobody is interested in this
|
||
* subscription any longer, delete it.
|
||
*/
|
||
delete this._subscriptionsByHash[hash];
|
||
if (subscription.state === 'unsubscribed') {
|
||
delete this._subscriptionCallbacksByServerSubscriptionId[subscription.serverSubscriptionId];
|
||
}
|
||
await this._updateSubscriptions();
|
||
return;
|
||
}
|
||
await (async () => {
|
||
const {
|
||
args,
|
||
method
|
||
} = subscription;
|
||
try {
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
state: 'subscribing'
|
||
});
|
||
const serverSubscriptionId = await this._rpcWebSocket.call(method, args);
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
serverSubscriptionId,
|
||
state: 'subscribed'
|
||
});
|
||
this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId] = subscription.callbacks;
|
||
await this._updateSubscriptions();
|
||
} catch (e) {
|
||
if (e instanceof Error) {
|
||
console.error(`${method} error for argument`, args, e.message);
|
||
}
|
||
if (!isCurrentConnectionStillActive()) {
|
||
return;
|
||
}
|
||
// TODO: Maybe add an 'errored' state or a retry limit?
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
state: 'pending'
|
||
});
|
||
await this._updateSubscriptions();
|
||
}
|
||
})();
|
||
break;
|
||
case 'subscribed':
|
||
if (subscription.callbacks.size === 0) {
|
||
// By the time we successfully set up a subscription
|
||
// with the server, the client stopped caring about it.
|
||
// Tear it down now.
|
||
await (async () => {
|
||
const {
|
||
serverSubscriptionId,
|
||
unsubscribeMethod
|
||
} = subscription;
|
||
if (this._subscriptionsAutoDisposedByRpc.has(serverSubscriptionId)) {
|
||
/**
|
||
* Special case.
|
||
* If we're dealing with a subscription that has been auto-
|
||
* disposed by the RPC, then we can skip the RPC call to
|
||
* tear down the subscription here.
|
||
*
|
||
* NOTE: There is a proposal to eliminate this special case, here:
|
||
* https://github.com/solana-labs/solana/issues/18892
|
||
*/
|
||
this._subscriptionsAutoDisposedByRpc.delete(serverSubscriptionId);
|
||
} else {
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
state: 'unsubscribing'
|
||
});
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
state: 'unsubscribing'
|
||
});
|
||
try {
|
||
await this._rpcWebSocket.call(unsubscribeMethod, [serverSubscriptionId]);
|
||
} catch (e) {
|
||
if (e instanceof Error) {
|
||
console.error(`${unsubscribeMethod} error:`, e.message);
|
||
}
|
||
if (!isCurrentConnectionStillActive()) {
|
||
return;
|
||
}
|
||
// TODO: Maybe add an 'errored' state or a retry limit?
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
state: 'subscribed'
|
||
});
|
||
await this._updateSubscriptions();
|
||
return;
|
||
}
|
||
}
|
||
this._setSubscription(hash, {
|
||
...subscription,
|
||
state: 'unsubscribed'
|
||
});
|
||
await this._updateSubscriptions();
|
||
})();
|
||
}
|
||
break;
|
||
}
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_handleServerNotification(serverSubscriptionId, callbackArgs) {
|
||
const callbacks = this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId];
|
||
if (callbacks === undefined) {
|
||
return;
|
||
}
|
||
callbacks.forEach(cb => {
|
||
try {
|
||
cb(
|
||
// I failed to find a way to convince TypeScript that `cb` is of type
|
||
// `TCallback` which is certainly compatible with `Parameters<TCallback>`.
|
||
// See https://github.com/microsoft/TypeScript/issues/47615
|
||
// @ts-ignore
|
||
...callbackArgs);
|
||
} catch (e) {
|
||
console.error(e);
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnAccountNotification(notification) {
|
||
const {
|
||
result,
|
||
subscription
|
||
} = create(notification, AccountNotificationResult);
|
||
this._handleServerNotification(subscription, [result.value, result.context]);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_makeSubscription(subscriptionConfig,
|
||
/**
|
||
* When preparing `args` for a call to `_makeSubscription`, be sure
|
||
* to carefully apply a default `commitment` property, if necessary.
|
||
*
|
||
* - If the user supplied a `commitment` use that.
|
||
* - Otherwise, if the `Connection::commitment` is set, use that.
|
||
* - Otherwise, set it to the RPC server default: `finalized`.
|
||
*
|
||
* This is extremely important to ensure that these two fundamentally
|
||
* identical subscriptions produce the same identifying hash:
|
||
*
|
||
* - A subscription made without specifying a commitment.
|
||
* - A subscription made where the commitment specified is the same
|
||
* as the default applied to the subscription above.
|
||
*
|
||
* Example; these two subscriptions must produce the same hash:
|
||
*
|
||
* - An `accountSubscribe` subscription for `'PUBKEY'`
|
||
* - An `accountSubscribe` subscription for `'PUBKEY'` with commitment
|
||
* `'finalized'`.
|
||
*
|
||
* See the 'making a subscription with defaulted params omitted' test
|
||
* in `connection-subscriptions.ts` for more.
|
||
*/
|
||
args) {
|
||
const clientSubscriptionId = this._nextClientSubscriptionId++;
|
||
const hash = fastStableStringify$1([subscriptionConfig.method, args]);
|
||
const existingSubscription = this._subscriptionsByHash[hash];
|
||
if (existingSubscription === undefined) {
|
||
this._subscriptionsByHash[hash] = {
|
||
...subscriptionConfig,
|
||
args,
|
||
callbacks: new Set([subscriptionConfig.callback]),
|
||
state: 'pending'
|
||
};
|
||
} else {
|
||
existingSubscription.callbacks.add(subscriptionConfig.callback);
|
||
}
|
||
this._subscriptionHashByClientSubscriptionId[clientSubscriptionId] = hash;
|
||
this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId] = async () => {
|
||
delete this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId];
|
||
delete this._subscriptionHashByClientSubscriptionId[clientSubscriptionId];
|
||
const subscription = this._subscriptionsByHash[hash];
|
||
assert$1(subscription !== undefined, `Could not find a \`Subscription\` when tearing down client subscription #${clientSubscriptionId}`);
|
||
subscription.callbacks.delete(subscriptionConfig.callback);
|
||
await this._updateSubscriptions();
|
||
};
|
||
this._updateSubscriptions();
|
||
return clientSubscriptionId;
|
||
}
|
||
|
||
/**
|
||
* Register a callback to be invoked whenever the specified account changes
|
||
*
|
||
* @param publicKey Public key of the account to monitor
|
||
* @param callback Function to invoke whenever the account is changed
|
||
* @param commitment Specify the commitment level account changes must reach before notification
|
||
* @return subscription id
|
||
*/
|
||
onAccountChange(publicKey, callback, commitment) {
|
||
const args = this._buildArgs([publicKey.toBase58()], commitment || this._commitment || 'finalized',
|
||
// Apply connection/server default.
|
||
'base64');
|
||
return this._makeSubscription({
|
||
callback,
|
||
method: 'accountSubscribe',
|
||
unsubscribeMethod: 'accountUnsubscribe'
|
||
}, args);
|
||
}
|
||
|
||
/**
|
||
* Deregister an account notification callback
|
||
*
|
||
* @param clientSubscriptionId client subscription id to deregister
|
||
*/
|
||
async removeAccountChangeListener(clientSubscriptionId) {
|
||
await this._unsubscribeClientSubscription(clientSubscriptionId, 'account change');
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnProgramAccountNotification(notification) {
|
||
const {
|
||
result,
|
||
subscription
|
||
} = create(notification, ProgramAccountNotificationResult);
|
||
this._handleServerNotification(subscription, [{
|
||
accountId: result.value.pubkey,
|
||
accountInfo: result.value.account
|
||
}, result.context]);
|
||
}
|
||
|
||
/**
|
||
* Register a callback to be invoked whenever accounts owned by the
|
||
* specified program change
|
||
*
|
||
* @param programId Public key of the program to monitor
|
||
* @param callback Function to invoke whenever the account is changed
|
||
* @param commitment Specify the commitment level account changes must reach before notification
|
||
* @param filters The program account filters to pass into the RPC method
|
||
* @return subscription id
|
||
*/
|
||
onProgramAccountChange(programId, callback, commitment, filters) {
|
||
const args = this._buildArgs([programId.toBase58()], commitment || this._commitment || 'finalized',
|
||
// Apply connection/server default.
|
||
'base64' /* encoding */, filters ? {
|
||
filters: filters
|
||
} : undefined /* extra */);
|
||
return this._makeSubscription({
|
||
callback,
|
||
method: 'programSubscribe',
|
||
unsubscribeMethod: 'programUnsubscribe'
|
||
}, args);
|
||
}
|
||
|
||
/**
|
||
* Deregister an account notification callback
|
||
*
|
||
* @param clientSubscriptionId client subscription id to deregister
|
||
*/
|
||
async removeProgramAccountChangeListener(clientSubscriptionId) {
|
||
await this._unsubscribeClientSubscription(clientSubscriptionId, 'program account change');
|
||
}
|
||
|
||
/**
|
||
* Registers a callback to be invoked whenever logs are emitted.
|
||
*/
|
||
onLogs(filter, callback, commitment) {
|
||
const args = this._buildArgs([typeof filter === 'object' ? {
|
||
mentions: [filter.toString()]
|
||
} : filter], commitment || this._commitment || 'finalized' // Apply connection/server default.
|
||
);
|
||
return this._makeSubscription({
|
||
callback,
|
||
method: 'logsSubscribe',
|
||
unsubscribeMethod: 'logsUnsubscribe'
|
||
}, args);
|
||
}
|
||
|
||
/**
|
||
* Deregister a logs callback.
|
||
*
|
||
* @param clientSubscriptionId client subscription id to deregister.
|
||
*/
|
||
async removeOnLogsListener(clientSubscriptionId) {
|
||
await this._unsubscribeClientSubscription(clientSubscriptionId, 'logs');
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnLogsNotification(notification) {
|
||
const {
|
||
result,
|
||
subscription
|
||
} = create(notification, LogsNotificationResult);
|
||
this._handleServerNotification(subscription, [result.value, result.context]);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnSlotNotification(notification) {
|
||
const {
|
||
result,
|
||
subscription
|
||
} = create(notification, SlotNotificationResult);
|
||
this._handleServerNotification(subscription, [result]);
|
||
}
|
||
|
||
/**
|
||
* Register a callback to be invoked upon slot changes
|
||
*
|
||
* @param callback Function to invoke whenever the slot changes
|
||
* @return subscription id
|
||
*/
|
||
onSlotChange(callback) {
|
||
return this._makeSubscription({
|
||
callback,
|
||
method: 'slotSubscribe',
|
||
unsubscribeMethod: 'slotUnsubscribe'
|
||
}, [] /* args */);
|
||
}
|
||
|
||
/**
|
||
* Deregister a slot notification callback
|
||
*
|
||
* @param clientSubscriptionId client subscription id to deregister
|
||
*/
|
||
async removeSlotChangeListener(clientSubscriptionId) {
|
||
await this._unsubscribeClientSubscription(clientSubscriptionId, 'slot change');
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnSlotUpdatesNotification(notification) {
|
||
const {
|
||
result,
|
||
subscription
|
||
} = create(notification, SlotUpdateNotificationResult);
|
||
this._handleServerNotification(subscription, [result]);
|
||
}
|
||
|
||
/**
|
||
* Register a callback to be invoked upon slot updates. {@link SlotUpdate}'s
|
||
* may be useful to track live progress of a cluster.
|
||
*
|
||
* @param callback Function to invoke whenever the slot updates
|
||
* @return subscription id
|
||
*/
|
||
onSlotUpdate(callback) {
|
||
return this._makeSubscription({
|
||
callback,
|
||
method: 'slotsUpdatesSubscribe',
|
||
unsubscribeMethod: 'slotsUpdatesUnsubscribe'
|
||
}, [] /* args */);
|
||
}
|
||
|
||
/**
|
||
* Deregister a slot update notification callback
|
||
*
|
||
* @param clientSubscriptionId client subscription id to deregister
|
||
*/
|
||
async removeSlotUpdateListener(clientSubscriptionId) {
|
||
await this._unsubscribeClientSubscription(clientSubscriptionId, 'slot update');
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
|
||
async _unsubscribeClientSubscription(clientSubscriptionId, subscriptionName) {
|
||
const dispose = this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId];
|
||
if (dispose) {
|
||
await dispose();
|
||
} else {
|
||
console.warn('Ignored unsubscribe request because an active subscription with id ' + `\`${clientSubscriptionId}\` for '${subscriptionName}' events ` + 'could not be found.');
|
||
}
|
||
}
|
||
_buildArgs(args, override, encoding, extra) {
|
||
const commitment = override || this._commitment;
|
||
if (commitment || encoding || extra) {
|
||
let options = {};
|
||
if (encoding) {
|
||
options.encoding = encoding;
|
||
}
|
||
if (commitment) {
|
||
options.commitment = commitment;
|
||
}
|
||
if (extra) {
|
||
options = Object.assign(options, extra);
|
||
}
|
||
args.push(options);
|
||
}
|
||
return args;
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_buildArgsAtLeastConfirmed(args, override, encoding, extra) {
|
||
const commitment = override || this._commitment;
|
||
if (commitment && !['confirmed', 'finalized'].includes(commitment)) {
|
||
throw new Error('Using Connection with default commitment: `' + this._commitment + '`, but method requires at least `confirmed`');
|
||
}
|
||
return this._buildArgs(args, override, encoding, extra);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnSignatureNotification(notification) {
|
||
const {
|
||
result,
|
||
subscription
|
||
} = create(notification, SignatureNotificationResult);
|
||
if (result.value !== 'receivedSignature') {
|
||
/**
|
||
* Special case.
|
||
* After a signature is processed, RPCs automatically dispose of the
|
||
* subscription on the server side. We need to track which of these
|
||
* subscriptions have been disposed in such a way, so that we know
|
||
* whether the client is dealing with a not-yet-processed signature
|
||
* (in which case we must tear down the server subscription) or an
|
||
* already-processed signature (in which case the client can simply
|
||
* clear out the subscription locally without telling the server).
|
||
*
|
||
* NOTE: There is a proposal to eliminate this special case, here:
|
||
* https://github.com/solana-labs/solana/issues/18892
|
||
*/
|
||
this._subscriptionsAutoDisposedByRpc.add(subscription);
|
||
}
|
||
this._handleServerNotification(subscription, result.value === 'receivedSignature' ? [{
|
||
type: 'received'
|
||
}, result.context] : [{
|
||
type: 'status',
|
||
result: result.value
|
||
}, result.context]);
|
||
}
|
||
|
||
/**
|
||
* Register a callback to be invoked upon signature updates
|
||
*
|
||
* @param signature Transaction signature string in base 58
|
||
* @param callback Function to invoke on signature notifications
|
||
* @param commitment Specify the commitment level signature must reach before notification
|
||
* @return subscription id
|
||
*/
|
||
onSignature(signature, callback, commitment) {
|
||
const args = this._buildArgs([signature], commitment || this._commitment || 'finalized' // Apply connection/server default.
|
||
);
|
||
const clientSubscriptionId = this._makeSubscription({
|
||
callback: (notification, context) => {
|
||
if (notification.type === 'status') {
|
||
callback(notification.result, context);
|
||
// Signatures subscriptions are auto-removed by the RPC service
|
||
// so no need to explicitly send an unsubscribe message.
|
||
try {
|
||
this.removeSignatureListener(clientSubscriptionId);
|
||
// eslint-disable-next-line no-empty
|
||
} catch (_err) {
|
||
// Already removed.
|
||
}
|
||
}
|
||
},
|
||
method: 'signatureSubscribe',
|
||
unsubscribeMethod: 'signatureUnsubscribe'
|
||
}, args);
|
||
return clientSubscriptionId;
|
||
}
|
||
|
||
/**
|
||
* Register a callback to be invoked when a transaction is
|
||
* received and/or processed.
|
||
*
|
||
* @param signature Transaction signature string in base 58
|
||
* @param callback Function to invoke on signature notifications
|
||
* @param options Enable received notifications and set the commitment
|
||
* level that signature must reach before notification
|
||
* @return subscription id
|
||
*/
|
||
onSignatureWithOptions(signature, callback, options) {
|
||
const {
|
||
commitment,
|
||
...extra
|
||
} = {
|
||
...options,
|
||
commitment: options && options.commitment || this._commitment || 'finalized' // Apply connection/server default.
|
||
};
|
||
const args = this._buildArgs([signature], commitment, undefined /* encoding */, extra);
|
||
const clientSubscriptionId = this._makeSubscription({
|
||
callback: (notification, context) => {
|
||
callback(notification, context);
|
||
// Signatures subscriptions are auto-removed by the RPC service
|
||
// so no need to explicitly send an unsubscribe message.
|
||
try {
|
||
this.removeSignatureListener(clientSubscriptionId);
|
||
// eslint-disable-next-line no-empty
|
||
} catch (_err) {
|
||
// Already removed.
|
||
}
|
||
},
|
||
method: 'signatureSubscribe',
|
||
unsubscribeMethod: 'signatureUnsubscribe'
|
||
}, args);
|
||
return clientSubscriptionId;
|
||
}
|
||
|
||
/**
|
||
* Deregister a signature notification callback
|
||
*
|
||
* @param clientSubscriptionId client subscription id to deregister
|
||
*/
|
||
async removeSignatureListener(clientSubscriptionId) {
|
||
await this._unsubscribeClientSubscription(clientSubscriptionId, 'signature result');
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
_wsOnRootNotification(notification) {
|
||
const {
|
||
result,
|
||
subscription
|
||
} = create(notification, RootNotificationResult);
|
||
this._handleServerNotification(subscription, [result]);
|
||
}
|
||
|
||
/**
|
||
* Register a callback to be invoked upon root changes
|
||
*
|
||
* @param callback Function to invoke whenever the root changes
|
||
* @return subscription id
|
||
*/
|
||
onRootChange(callback) {
|
||
return this._makeSubscription({
|
||
callback,
|
||
method: 'rootSubscribe',
|
||
unsubscribeMethod: 'rootUnsubscribe'
|
||
}, [] /* args */);
|
||
}
|
||
|
||
/**
|
||
* Deregister a root notification callback
|
||
*
|
||
* @param clientSubscriptionId client subscription id to deregister
|
||
*/
|
||
async removeRootChangeListener(clientSubscriptionId) {
|
||
await this._unsubscribeClientSubscription(clientSubscriptionId, 'root change');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Keypair signer interface
|
||
*/
|
||
|
||
/**
|
||
* An account keypair used for signing transactions.
|
||
*/
|
||
class Keypair {
|
||
/**
|
||
* Create a new keypair instance.
|
||
* Generate random keypair if no {@link Ed25519Keypair} is provided.
|
||
*
|
||
* @param {Ed25519Keypair} keypair ed25519 keypair
|
||
*/
|
||
constructor(keypair) {
|
||
this._keypair = void 0;
|
||
this._keypair = keypair ?? generateKeypair();
|
||
}
|
||
|
||
/**
|
||
* Generate a new random keypair
|
||
*
|
||
* @returns {Keypair} Keypair
|
||
*/
|
||
static generate() {
|
||
return new Keypair(generateKeypair());
|
||
}
|
||
|
||
/**
|
||
* Create a keypair from a raw secret key byte array.
|
||
*
|
||
* This method should only be used to recreate a keypair from a previously
|
||
* generated secret key. Generating keypairs from a random seed should be done
|
||
* with the {@link Keypair.fromSeed} method.
|
||
*
|
||
* @throws error if the provided secret key is invalid and validation is not skipped.
|
||
*
|
||
* @param secretKey secret key byte array
|
||
* @param options skip secret key validation
|
||
*
|
||
* @returns {Keypair} Keypair
|
||
*/
|
||
static fromSecretKey(secretKey, options) {
|
||
if (secretKey.byteLength !== 64) {
|
||
throw new Error('bad secret key size');
|
||
}
|
||
const publicKey = secretKey.slice(32, 64);
|
||
if (!options || !options.skipValidation) {
|
||
const privateScalar = secretKey.slice(0, 32);
|
||
const computedPublicKey = getPublicKey(privateScalar);
|
||
for (let ii = 0; ii < 32; ii++) {
|
||
if (publicKey[ii] !== computedPublicKey[ii]) {
|
||
throw new Error('provided secretKey is invalid');
|
||
}
|
||
}
|
||
}
|
||
return new Keypair({
|
||
publicKey,
|
||
secretKey
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a keypair from a 32 byte seed.
|
||
*
|
||
* @param seed seed byte array
|
||
*
|
||
* @returns {Keypair} Keypair
|
||
*/
|
||
static fromSeed(seed) {
|
||
const publicKey = getPublicKey(seed);
|
||
const secretKey = new Uint8Array(64);
|
||
secretKey.set(seed);
|
||
secretKey.set(publicKey, 32);
|
||
return new Keypair({
|
||
publicKey,
|
||
secretKey
|
||
});
|
||
}
|
||
|
||
/**
|
||
* The public key for this keypair
|
||
*
|
||
* @returns {PublicKey} PublicKey
|
||
*/
|
||
get publicKey() {
|
||
return new PublicKey(this._keypair.publicKey);
|
||
}
|
||
|
||
/**
|
||
* The raw secret key for this keypair
|
||
* @returns {Uint8Array} Secret key in an array of Uint8 bytes
|
||
*/
|
||
get secretKey() {
|
||
return new Uint8Array(this._keypair.secretKey);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* An enumeration of valid LookupTableInstructionType's
|
||
*/
|
||
|
||
/**
|
||
* An enumeration of valid address lookup table InstructionType's
|
||
* @internal
|
||
*/
|
||
const LOOKUP_TABLE_INSTRUCTION_LAYOUTS = Object.freeze({
|
||
CreateLookupTable: {
|
||
index: 0,
|
||
layout: struct([u32('instruction'), u64('recentSlot'), u8('bumpSeed')])
|
||
},
|
||
FreezeLookupTable: {
|
||
index: 1,
|
||
layout: struct([u32('instruction')])
|
||
},
|
||
ExtendLookupTable: {
|
||
index: 2,
|
||
layout: struct([u32('instruction'), u64(), seq(publicKey(), offset(u32(), -8), 'addresses')])
|
||
},
|
||
DeactivateLookupTable: {
|
||
index: 3,
|
||
layout: struct([u32('instruction')])
|
||
},
|
||
CloseLookupTable: {
|
||
index: 4,
|
||
layout: struct([u32('instruction')])
|
||
}
|
||
});
|
||
class AddressLookupTableInstruction {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
static decodeInstructionType(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const instructionTypeLayout = u32('instruction');
|
||
const index = instructionTypeLayout.decode(instruction.data);
|
||
let type;
|
||
for (const [layoutType, layout] of Object.entries(LOOKUP_TABLE_INSTRUCTION_LAYOUTS)) {
|
||
if (layout.index == index) {
|
||
type = layoutType;
|
||
break;
|
||
}
|
||
}
|
||
if (!type) {
|
||
throw new Error('Invalid Instruction. Should be a LookupTable Instruction');
|
||
}
|
||
return type;
|
||
}
|
||
static decodeCreateLookupTable(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeysLength(instruction.keys, 4);
|
||
const {
|
||
recentSlot
|
||
} = decodeData$1(LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CreateLookupTable, instruction.data);
|
||
return {
|
||
authority: instruction.keys[1].pubkey,
|
||
payer: instruction.keys[2].pubkey,
|
||
recentSlot: Number(recentSlot)
|
||
};
|
||
}
|
||
static decodeExtendLookupTable(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
if (instruction.keys.length < 2) {
|
||
throw new Error(`invalid instruction; found ${instruction.keys.length} keys, expected at least 2`);
|
||
}
|
||
const {
|
||
addresses
|
||
} = decodeData$1(LOOKUP_TABLE_INSTRUCTION_LAYOUTS.ExtendLookupTable, instruction.data);
|
||
return {
|
||
lookupTable: instruction.keys[0].pubkey,
|
||
authority: instruction.keys[1].pubkey,
|
||
payer: instruction.keys.length > 2 ? instruction.keys[2].pubkey : undefined,
|
||
addresses: addresses.map(buffer => new PublicKey(buffer))
|
||
};
|
||
}
|
||
static decodeCloseLookupTable(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeysLength(instruction.keys, 3);
|
||
return {
|
||
lookupTable: instruction.keys[0].pubkey,
|
||
authority: instruction.keys[1].pubkey,
|
||
recipient: instruction.keys[2].pubkey
|
||
};
|
||
}
|
||
static decodeFreezeLookupTable(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeysLength(instruction.keys, 2);
|
||
return {
|
||
lookupTable: instruction.keys[0].pubkey,
|
||
authority: instruction.keys[1].pubkey
|
||
};
|
||
}
|
||
static decodeDeactivateLookupTable(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeysLength(instruction.keys, 2);
|
||
return {
|
||
lookupTable: instruction.keys[0].pubkey,
|
||
authority: instruction.keys[1].pubkey
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkProgramId(programId) {
|
||
if (!programId.equals(AddressLookupTableProgram.programId)) {
|
||
throw new Error('invalid instruction; programId is not AddressLookupTable Program');
|
||
}
|
||
}
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkKeysLength(keys, expectedLength) {
|
||
if (keys.length < expectedLength) {
|
||
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
|
||
}
|
||
}
|
||
}
|
||
class AddressLookupTableProgram {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
static createLookupTable(params) {
|
||
const [lookupTableAddress, bumpSeed] = PublicKey.findProgramAddressSync([params.authority.toBuffer(), toBufferLE_1(BigInt(params.recentSlot), 8)], this.programId);
|
||
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CreateLookupTable;
|
||
const data = encodeData(type, {
|
||
recentSlot: BigInt(params.recentSlot),
|
||
bumpSeed: bumpSeed
|
||
});
|
||
const keys = [{
|
||
pubkey: lookupTableAddress,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.authority,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: params.payer,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SystemProgram.programId,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}];
|
||
return [new TransactionInstruction({
|
||
programId: this.programId,
|
||
keys: keys,
|
||
data: data
|
||
}), lookupTableAddress];
|
||
}
|
||
static freezeLookupTable(params) {
|
||
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.FreezeLookupTable;
|
||
const data = encodeData(type);
|
||
const keys = [{
|
||
pubkey: params.lookupTable,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.authority,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
return new TransactionInstruction({
|
||
programId: this.programId,
|
||
keys: keys,
|
||
data: data
|
||
});
|
||
}
|
||
static extendLookupTable(params) {
|
||
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.ExtendLookupTable;
|
||
const data = encodeData(type, {
|
||
addresses: params.addresses.map(addr => addr.toBytes())
|
||
});
|
||
const keys = [{
|
||
pubkey: params.lookupTable,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.authority,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
if (params.payer) {
|
||
keys.push({
|
||
pubkey: params.payer,
|
||
isSigner: true,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SystemProgram.programId,
|
||
isSigner: false,
|
||
isWritable: false
|
||
});
|
||
}
|
||
return new TransactionInstruction({
|
||
programId: this.programId,
|
||
keys: keys,
|
||
data: data
|
||
});
|
||
}
|
||
static deactivateLookupTable(params) {
|
||
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.DeactivateLookupTable;
|
||
const data = encodeData(type);
|
||
const keys = [{
|
||
pubkey: params.lookupTable,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.authority,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
return new TransactionInstruction({
|
||
programId: this.programId,
|
||
keys: keys,
|
||
data: data
|
||
});
|
||
}
|
||
static closeLookupTable(params) {
|
||
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CloseLookupTable;
|
||
const data = encodeData(type);
|
||
const keys = [{
|
||
pubkey: params.lookupTable,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: params.authority,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: params.recipient,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}];
|
||
return new TransactionInstruction({
|
||
programId: this.programId,
|
||
keys: keys,
|
||
data: data
|
||
});
|
||
}
|
||
}
|
||
AddressLookupTableProgram.programId = new PublicKey('AddressLookupTab1e1111111111111111111111111');
|
||
|
||
/**
|
||
* Compute Budget Instruction class
|
||
*/
|
||
class ComputeBudgetInstruction {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Decode a compute budget instruction and retrieve the instruction type.
|
||
*/
|
||
static decodeInstructionType(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const instructionTypeLayout = u8('instruction');
|
||
const typeIndex = instructionTypeLayout.decode(instruction.data);
|
||
let type;
|
||
for (const [ixType, layout] of Object.entries(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS)) {
|
||
if (layout.index == typeIndex) {
|
||
type = ixType;
|
||
break;
|
||
}
|
||
}
|
||
if (!type) {
|
||
throw new Error('Instruction type incorrect; not a ComputeBudgetInstruction');
|
||
}
|
||
return type;
|
||
}
|
||
|
||
/**
|
||
* Decode request units compute budget instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeRequestUnits(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const {
|
||
units,
|
||
additionalFee
|
||
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits, instruction.data);
|
||
return {
|
||
units,
|
||
additionalFee
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode request heap frame compute budget instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeRequestHeapFrame(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const {
|
||
bytes
|
||
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame, instruction.data);
|
||
return {
|
||
bytes
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode set compute unit limit compute budget instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeSetComputeUnitLimit(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const {
|
||
units
|
||
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit, instruction.data);
|
||
return {
|
||
units
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode set compute unit price compute budget instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeSetComputeUnitPrice(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const {
|
||
microLamports
|
||
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice, instruction.data);
|
||
return {
|
||
microLamports
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkProgramId(programId) {
|
||
if (!programId.equals(ComputeBudgetProgram.programId)) {
|
||
throw new Error('invalid instruction; programId is not ComputeBudgetProgram');
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* An enumeration of valid ComputeBudgetInstructionType's
|
||
*/
|
||
|
||
/**
|
||
* Request units instruction params
|
||
*/
|
||
|
||
/**
|
||
* Request heap frame instruction params
|
||
*/
|
||
|
||
/**
|
||
* Set compute unit limit instruction params
|
||
*/
|
||
|
||
/**
|
||
* Set compute unit price instruction params
|
||
*/
|
||
|
||
/**
|
||
* An enumeration of valid ComputeBudget InstructionType's
|
||
* @internal
|
||
*/
|
||
const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze({
|
||
RequestUnits: {
|
||
index: 0,
|
||
layout: struct([u8('instruction'), u32('units'), u32('additionalFee')])
|
||
},
|
||
RequestHeapFrame: {
|
||
index: 1,
|
||
layout: struct([u8('instruction'), u32('bytes')])
|
||
},
|
||
SetComputeUnitLimit: {
|
||
index: 2,
|
||
layout: struct([u8('instruction'), u32('units')])
|
||
},
|
||
SetComputeUnitPrice: {
|
||
index: 3,
|
||
layout: struct([u8('instruction'), u64('microLamports')])
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Factory class for transaction instructions to interact with the Compute Budget program
|
||
*/
|
||
class ComputeBudgetProgram {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Public key that identifies the Compute Budget program
|
||
*/
|
||
|
||
/**
|
||
* @deprecated Instead, call {@link setComputeUnitLimit} and/or {@link setComputeUnitPrice}
|
||
*/
|
||
static requestUnits(params) {
|
||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits;
|
||
const data = encodeData(type, params);
|
||
return new TransactionInstruction({
|
||
keys: [],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
static requestHeapFrame(params) {
|
||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame;
|
||
const data = encodeData(type, params);
|
||
return new TransactionInstruction({
|
||
keys: [],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
static setComputeUnitLimit(params) {
|
||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit;
|
||
const data = encodeData(type, params);
|
||
return new TransactionInstruction({
|
||
keys: [],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
static setComputeUnitPrice(params) {
|
||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice;
|
||
const data = encodeData(type, {
|
||
microLamports: BigInt(params.microLamports)
|
||
});
|
||
return new TransactionInstruction({
|
||
keys: [],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
}
|
||
ComputeBudgetProgram.programId = new PublicKey('ComputeBudget111111111111111111111111111111');
|
||
|
||
const PRIVATE_KEY_BYTES$1 = 64;
|
||
const PUBLIC_KEY_BYTES$1 = 32;
|
||
const SIGNATURE_BYTES = 64;
|
||
|
||
/**
|
||
* Params for creating an ed25519 instruction using a public key
|
||
*/
|
||
|
||
/**
|
||
* Params for creating an ed25519 instruction using a private key
|
||
*/
|
||
|
||
const ED25519_INSTRUCTION_LAYOUT = struct([u8('numSignatures'), u8('padding'), u16('signatureOffset'), u16('signatureInstructionIndex'), u16('publicKeyOffset'), u16('publicKeyInstructionIndex'), u16('messageDataOffset'), u16('messageDataSize'), u16('messageInstructionIndex')]);
|
||
class Ed25519Program {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Public key that identifies the ed25519 program
|
||
*/
|
||
|
||
/**
|
||
* Create an ed25519 instruction with a public key and signature. The
|
||
* public key must be a buffer that is 32 bytes long, and the signature
|
||
* must be a buffer of 64 bytes.
|
||
*/
|
||
static createInstructionWithPublicKey(params) {
|
||
const {
|
||
publicKey,
|
||
message,
|
||
signature,
|
||
instructionIndex
|
||
} = params;
|
||
assert$1(publicKey.length === PUBLIC_KEY_BYTES$1, `Public Key must be ${PUBLIC_KEY_BYTES$1} bytes but received ${publicKey.length} bytes`);
|
||
assert$1(signature.length === SIGNATURE_BYTES, `Signature must be ${SIGNATURE_BYTES} bytes but received ${signature.length} bytes`);
|
||
const publicKeyOffset = ED25519_INSTRUCTION_LAYOUT.span;
|
||
const signatureOffset = publicKeyOffset + publicKey.length;
|
||
const messageDataOffset = signatureOffset + signature.length;
|
||
const numSignatures = 1;
|
||
const instructionData = buffer.Buffer.alloc(messageDataOffset + message.length);
|
||
const index = instructionIndex == null ? 0xffff // An index of `u16::MAX` makes it default to the current instruction.
|
||
: instructionIndex;
|
||
ED25519_INSTRUCTION_LAYOUT.encode({
|
||
numSignatures,
|
||
padding: 0,
|
||
signatureOffset,
|
||
signatureInstructionIndex: index,
|
||
publicKeyOffset,
|
||
publicKeyInstructionIndex: index,
|
||
messageDataOffset,
|
||
messageDataSize: message.length,
|
||
messageInstructionIndex: index
|
||
}, instructionData);
|
||
instructionData.fill(publicKey, publicKeyOffset);
|
||
instructionData.fill(signature, signatureOffset);
|
||
instructionData.fill(message, messageDataOffset);
|
||
return new TransactionInstruction({
|
||
keys: [],
|
||
programId: Ed25519Program.programId,
|
||
data: instructionData
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Create an ed25519 instruction with a private key. The private key
|
||
* must be a buffer that is 64 bytes long.
|
||
*/
|
||
static createInstructionWithPrivateKey(params) {
|
||
const {
|
||
privateKey,
|
||
message,
|
||
instructionIndex
|
||
} = params;
|
||
assert$1(privateKey.length === PRIVATE_KEY_BYTES$1, `Private key must be ${PRIVATE_KEY_BYTES$1} bytes but received ${privateKey.length} bytes`);
|
||
try {
|
||
const keypair = Keypair.fromSecretKey(privateKey);
|
||
const publicKey = keypair.publicKey.toBytes();
|
||
const signature = sign(message, keypair.secretKey);
|
||
return this.createInstructionWithPublicKey({
|
||
publicKey,
|
||
message,
|
||
signature,
|
||
instructionIndex
|
||
});
|
||
} catch (error) {
|
||
throw new Error(`Error creating instruction; ${error}`);
|
||
}
|
||
}
|
||
}
|
||
Ed25519Program.programId = new PublicKey('Ed25519SigVerify111111111111111111111111111');
|
||
|
||
const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
||
const _32n = /* @__PURE__ */ BigInt(32);
|
||
// We are not using BigUint64Array, because they are extremely slow as per 2022
|
||
function fromBig(n, le = false) {
|
||
if (le)
|
||
return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };
|
||
return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
|
||
}
|
||
function split(lst, le = false) {
|
||
let Ah = new Uint32Array(lst.length);
|
||
let Al = new Uint32Array(lst.length);
|
||
for (let i = 0; i < lst.length; i++) {
|
||
const { h, l } = fromBig(lst[i], le);
|
||
[Ah[i], Al[i]] = [h, l];
|
||
}
|
||
return [Ah, Al];
|
||
}
|
||
// Left rotate for Shift in [1, 32)
|
||
const rotlSH = (h, l, s) => (h << s) | (l >>> (32 - s));
|
||
const rotlSL = (h, l, s) => (l << s) | (h >>> (32 - s));
|
||
// Left rotate for Shift in (32, 64), NOTE: 32 is special case.
|
||
const rotlBH = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s));
|
||
const rotlBL = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s));
|
||
|
||
// SHA3 (keccak) is based on a new design: basically, the internal state is bigger than output size.
|
||
// It's called a sponge function.
|
||
// Various per round constants calculations
|
||
const [SHA3_PI, SHA3_ROTL, _SHA3_IOTA] = [[], [], []];
|
||
const _0n$1 = /* @__PURE__ */ BigInt(0);
|
||
const _1n$2 = /* @__PURE__ */ BigInt(1);
|
||
const _2n$1 = /* @__PURE__ */ BigInt(2);
|
||
const _7n = /* @__PURE__ */ BigInt(7);
|
||
const _256n = /* @__PURE__ */ BigInt(256);
|
||
const _0x71n = /* @__PURE__ */ BigInt(0x71);
|
||
for (let round = 0, R = _1n$2, x = 1, y = 0; round < 24; round++) {
|
||
// Pi
|
||
[x, y] = [y, (2 * x + 3 * y) % 5];
|
||
SHA3_PI.push(2 * (5 * y + x));
|
||
// Rotational
|
||
SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64);
|
||
// Iota
|
||
let t = _0n$1;
|
||
for (let j = 0; j < 7; j++) {
|
||
R = ((R << _1n$2) ^ ((R >> _7n) * _0x71n)) % _256n;
|
||
if (R & _2n$1)
|
||
t ^= _1n$2 << ((_1n$2 << /* @__PURE__ */ BigInt(j)) - _1n$2);
|
||
}
|
||
_SHA3_IOTA.push(t);
|
||
}
|
||
const [SHA3_IOTA_H, SHA3_IOTA_L] = /* @__PURE__ */ split(_SHA3_IOTA, true);
|
||
// Left rotation (without 0, 32, 64)
|
||
const rotlH = (h, l, s) => (s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s));
|
||
const rotlL = (h, l, s) => (s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s));
|
||
// Same as keccakf1600, but allows to skip some rounds
|
||
function keccakP(s, rounds = 24) {
|
||
const B = new Uint32Array(5 * 2);
|
||
// NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)
|
||
for (let round = 24 - rounds; round < 24; round++) {
|
||
// Theta θ
|
||
for (let x = 0; x < 10; x++)
|
||
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
||
for (let x = 0; x < 10; x += 2) {
|
||
const idx1 = (x + 8) % 10;
|
||
const idx0 = (x + 2) % 10;
|
||
const B0 = B[idx0];
|
||
const B1 = B[idx0 + 1];
|
||
const Th = rotlH(B0, B1, 1) ^ B[idx1];
|
||
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
|
||
for (let y = 0; y < 50; y += 10) {
|
||
s[x + y] ^= Th;
|
||
s[x + y + 1] ^= Tl;
|
||
}
|
||
}
|
||
// Rho (ρ) and Pi (π)
|
||
let curH = s[2];
|
||
let curL = s[3];
|
||
for (let t = 0; t < 24; t++) {
|
||
const shift = SHA3_ROTL[t];
|
||
const Th = rotlH(curH, curL, shift);
|
||
const Tl = rotlL(curH, curL, shift);
|
||
const PI = SHA3_PI[t];
|
||
curH = s[PI];
|
||
curL = s[PI + 1];
|
||
s[PI] = Th;
|
||
s[PI + 1] = Tl;
|
||
}
|
||
// Chi (χ)
|
||
for (let y = 0; y < 50; y += 10) {
|
||
for (let x = 0; x < 10; x++)
|
||
B[x] = s[y + x];
|
||
for (let x = 0; x < 10; x++)
|
||
s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
||
}
|
||
// Iota (ι)
|
||
s[0] ^= SHA3_IOTA_H[round];
|
||
s[1] ^= SHA3_IOTA_L[round];
|
||
}
|
||
B.fill(0);
|
||
}
|
||
class Keccak extends Hash {
|
||
// NOTE: we accept arguments in bytes instead of bits here.
|
||
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
||
super();
|
||
this.blockLen = blockLen;
|
||
this.suffix = suffix;
|
||
this.outputLen = outputLen;
|
||
this.enableXOF = enableXOF;
|
||
this.rounds = rounds;
|
||
this.pos = 0;
|
||
this.posOut = 0;
|
||
this.finished = false;
|
||
this.destroyed = false;
|
||
// Can be passed from user as dkLen
|
||
number$1(outputLen);
|
||
// 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes
|
||
if (0 >= this.blockLen || this.blockLen >= 200)
|
||
throw new Error('Sha3 supports only keccak-f1600 function');
|
||
this.state = new Uint8Array(200);
|
||
this.state32 = u32$1(this.state);
|
||
}
|
||
keccak() {
|
||
keccakP(this.state32, this.rounds);
|
||
this.posOut = 0;
|
||
this.pos = 0;
|
||
}
|
||
update(data) {
|
||
exists(this);
|
||
const { blockLen, state } = this;
|
||
data = toBytes(data);
|
||
const len = data.length;
|
||
for (let pos = 0; pos < len;) {
|
||
const take = Math.min(blockLen - this.pos, len - pos);
|
||
for (let i = 0; i < take; i++)
|
||
state[this.pos++] ^= data[pos++];
|
||
if (this.pos === blockLen)
|
||
this.keccak();
|
||
}
|
||
return this;
|
||
}
|
||
finish() {
|
||
if (this.finished)
|
||
return;
|
||
this.finished = true;
|
||
const { state, suffix, pos, blockLen } = this;
|
||
// Do the padding
|
||
state[pos] ^= suffix;
|
||
if ((suffix & 0x80) !== 0 && pos === blockLen - 1)
|
||
this.keccak();
|
||
state[blockLen - 1] ^= 0x80;
|
||
this.keccak();
|
||
}
|
||
writeInto(out) {
|
||
exists(this, false);
|
||
bytes(out);
|
||
this.finish();
|
||
const bufferOut = this.state;
|
||
const { blockLen } = this;
|
||
for (let pos = 0, len = out.length; pos < len;) {
|
||
if (this.posOut >= blockLen)
|
||
this.keccak();
|
||
const take = Math.min(blockLen - this.posOut, len - pos);
|
||
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
||
this.posOut += take;
|
||
pos += take;
|
||
}
|
||
return out;
|
||
}
|
||
xofInto(out) {
|
||
// Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF
|
||
if (!this.enableXOF)
|
||
throw new Error('XOF is not possible for this instance');
|
||
return this.writeInto(out);
|
||
}
|
||
xof(bytes) {
|
||
number$1(bytes);
|
||
return this.xofInto(new Uint8Array(bytes));
|
||
}
|
||
digestInto(out) {
|
||
output(out, this);
|
||
if (this.finished)
|
||
throw new Error('digest() was already called');
|
||
this.writeInto(out);
|
||
this.destroy();
|
||
return out;
|
||
}
|
||
digest() {
|
||
return this.digestInto(new Uint8Array(this.outputLen));
|
||
}
|
||
destroy() {
|
||
this.destroyed = true;
|
||
this.state.fill(0);
|
||
}
|
||
_cloneInto(to) {
|
||
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
||
to || (to = new Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
|
||
to.state32.set(this.state32);
|
||
to.pos = this.pos;
|
||
to.posOut = this.posOut;
|
||
to.finished = this.finished;
|
||
to.rounds = rounds;
|
||
// Suffix can change in cSHAKE
|
||
to.suffix = suffix;
|
||
to.outputLen = outputLen;
|
||
to.enableXOF = enableXOF;
|
||
to.destroyed = this.destroyed;
|
||
return to;
|
||
}
|
||
}
|
||
const gen = (suffix, blockLen, outputLen) => wrapConstructor(() => new Keccak(blockLen, suffix, outputLen));
|
||
/**
|
||
* keccak-256 hash function. Different from SHA3-256.
|
||
* @param message - that would be hashed
|
||
*/
|
||
const keccak_256 = /* @__PURE__ */ gen(0x01, 136, 256 / 8);
|
||
|
||
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
|
||
// BTC network is doing 2^67 hashes/sec as per early 2023.
|
||
// Round constants:
|
||
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
|
||
// prettier-ignore
|
||
const SHA256_K = /* @__PURE__ */ new Uint32Array([
|
||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||
]);
|
||
// Initial state:
|
||
// first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
|
||
// prettier-ignore
|
||
const SHA256_IV = /* @__PURE__ */ new Uint32Array([
|
||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||
]);
|
||
// Temporary buffer, not used to store anything between runs
|
||
// Named this way because it matches specification.
|
||
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
||
class SHA256 extends HashMD {
|
||
constructor() {
|
||
super(64, 32, 8, false);
|
||
// We cannot use array here since array allows indexing by variable
|
||
// which means optimizer/compiler cannot use registers.
|
||
this.A = SHA256_IV[0] | 0;
|
||
this.B = SHA256_IV[1] | 0;
|
||
this.C = SHA256_IV[2] | 0;
|
||
this.D = SHA256_IV[3] | 0;
|
||
this.E = SHA256_IV[4] | 0;
|
||
this.F = SHA256_IV[5] | 0;
|
||
this.G = SHA256_IV[6] | 0;
|
||
this.H = SHA256_IV[7] | 0;
|
||
}
|
||
get() {
|
||
const { A, B, C, D, E, F, G, H } = this;
|
||
return [A, B, C, D, E, F, G, H];
|
||
}
|
||
// prettier-ignore
|
||
set(A, B, C, D, E, F, G, H) {
|
||
this.A = A | 0;
|
||
this.B = B | 0;
|
||
this.C = C | 0;
|
||
this.D = D | 0;
|
||
this.E = E | 0;
|
||
this.F = F | 0;
|
||
this.G = G | 0;
|
||
this.H = H | 0;
|
||
}
|
||
process(view, offset) {
|
||
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
|
||
for (let i = 0; i < 16; i++, offset += 4)
|
||
SHA256_W[i] = view.getUint32(offset, false);
|
||
for (let i = 16; i < 64; i++) {
|
||
const W15 = SHA256_W[i - 15];
|
||
const W2 = SHA256_W[i - 2];
|
||
const s0 = rotr$1(W15, 7) ^ rotr$1(W15, 18) ^ (W15 >>> 3);
|
||
const s1 = rotr$1(W2, 17) ^ rotr$1(W2, 19) ^ (W2 >>> 10);
|
||
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
|
||
}
|
||
// Compression function main loop, 64 rounds
|
||
let { A, B, C, D, E, F, G, H } = this;
|
||
for (let i = 0; i < 64; i++) {
|
||
const sigma1 = rotr$1(E, 6) ^ rotr$1(E, 11) ^ rotr$1(E, 25);
|
||
const T1 = (H + sigma1 + Chi$1(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
|
||
const sigma0 = rotr$1(A, 2) ^ rotr$1(A, 13) ^ rotr$1(A, 22);
|
||
const T2 = (sigma0 + Maj$1(A, B, C)) | 0;
|
||
H = G;
|
||
G = F;
|
||
F = E;
|
||
E = (D + T1) | 0;
|
||
D = C;
|
||
C = B;
|
||
B = A;
|
||
A = (T1 + T2) | 0;
|
||
}
|
||
// Add the compressed chunk to the current hash value
|
||
A = (A + this.A) | 0;
|
||
B = (B + this.B) | 0;
|
||
C = (C + this.C) | 0;
|
||
D = (D + this.D) | 0;
|
||
E = (E + this.E) | 0;
|
||
F = (F + this.F) | 0;
|
||
G = (G + this.G) | 0;
|
||
H = (H + this.H) | 0;
|
||
this.set(A, B, C, D, E, F, G, H);
|
||
}
|
||
roundClean() {
|
||
SHA256_W.fill(0);
|
||
}
|
||
destroy() {
|
||
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
||
this.buffer.fill(0);
|
||
}
|
||
}
|
||
/**
|
||
* SHA2-256 hash function
|
||
* @param message - data that would be hashed
|
||
*/
|
||
const sha256 = /* @__PURE__ */ wrapConstructor$1(() => new SHA256());
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// Short Weierstrass curve. The formula is: y² = x³ + ax + b
|
||
function validatePointOpts(curve) {
|
||
const opts = validateBasic(curve);
|
||
validateObject(opts, {
|
||
a: 'field',
|
||
b: 'field',
|
||
}, {
|
||
allowedPrivateKeyLengths: 'array',
|
||
wrapPrivateKey: 'boolean',
|
||
isTorsionFree: 'function',
|
||
clearCofactor: 'function',
|
||
allowInfinityPoint: 'boolean',
|
||
fromBytes: 'function',
|
||
toBytes: 'function',
|
||
});
|
||
const { endo, Fp, a } = opts;
|
||
if (endo) {
|
||
if (!Fp.eql(a, Fp.ZERO)) {
|
||
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
|
||
}
|
||
if (typeof endo !== 'object' ||
|
||
typeof endo.beta !== 'bigint' ||
|
||
typeof endo.splitScalar !== 'function') {
|
||
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
|
||
}
|
||
}
|
||
return Object.freeze({ ...opts });
|
||
}
|
||
// ASN.1 DER encoding utilities
|
||
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
|
||
const DER = {
|
||
// asn.1 DER encoding utils
|
||
Err: class DERErr extends Error {
|
||
constructor(m = '') {
|
||
super(m);
|
||
}
|
||
},
|
||
_parseInt(data) {
|
||
const { Err: E } = DER;
|
||
if (data.length < 2 || data[0] !== 0x02)
|
||
throw new E('Invalid signature integer tag');
|
||
const len = data[1];
|
||
const res = data.subarray(2, len + 2);
|
||
if (!len || res.length !== len)
|
||
throw new E('Invalid signature integer: wrong length');
|
||
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
|
||
// since we always use positive integers here. It must always be empty:
|
||
// - add zero byte if exists
|
||
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
|
||
if (res[0] & 0b10000000)
|
||
throw new E('Invalid signature integer: negative');
|
||
if (res[0] === 0x00 && !(res[1] & 0b10000000))
|
||
throw new E('Invalid signature integer: unnecessary leading zero');
|
||
return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
|
||
},
|
||
toSig(hex) {
|
||
// parse DER signature
|
||
const { Err: E } = DER;
|
||
const data = typeof hex === 'string' ? h2b(hex) : hex;
|
||
abytes(data);
|
||
let l = data.length;
|
||
if (l < 2 || data[0] != 0x30)
|
||
throw new E('Invalid signature tag');
|
||
if (data[1] !== l - 2)
|
||
throw new E('Invalid signature: incorrect length');
|
||
const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));
|
||
const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);
|
||
if (rBytesLeft.length)
|
||
throw new E('Invalid signature: left bytes after parsing');
|
||
return { r, s };
|
||
},
|
||
hexFromSig(sig) {
|
||
// Add leading zero if first byte has negative bit enabled. More details in '_parseInt'
|
||
const slice = (s) => (Number.parseInt(s[0], 16) & 0b1000 ? '00' + s : s);
|
||
const h = (num) => {
|
||
const hex = num.toString(16);
|
||
return hex.length & 1 ? `0${hex}` : hex;
|
||
};
|
||
const s = slice(h(sig.s));
|
||
const r = slice(h(sig.r));
|
||
const shl = s.length / 2;
|
||
const rhl = r.length / 2;
|
||
const sl = h(shl);
|
||
const rl = h(rhl);
|
||
return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
|
||
},
|
||
};
|
||
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
||
// prettier-ignore
|
||
const _0n = BigInt(0), _1n$1 = BigInt(1); BigInt(2); const _3n = BigInt(3); BigInt(4);
|
||
function weierstrassPoints(opts) {
|
||
const CURVE = validatePointOpts(opts);
|
||
const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
|
||
const toBytes = CURVE.toBytes ||
|
||
((_c, point, _isCompressed) => {
|
||
const a = point.toAffine();
|
||
return concatBytes(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));
|
||
});
|
||
const fromBytes = CURVE.fromBytes ||
|
||
((bytes) => {
|
||
// const head = bytes[0];
|
||
const tail = bytes.subarray(1);
|
||
// if (head !== 0x04) throw new Error('Only non-compressed encoding is supported');
|
||
const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
|
||
const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
|
||
return { x, y };
|
||
});
|
||
/**
|
||
* y² = x³ + ax + b: Short weierstrass curve formula
|
||
* @returns y²
|
||
*/
|
||
function weierstrassEquation(x) {
|
||
const { a, b } = CURVE;
|
||
const x2 = Fp.sqr(x); // x * x
|
||
const x3 = Fp.mul(x2, x); // x2 * x
|
||
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
|
||
}
|
||
// Validate whether the passed curve params are valid.
|
||
// We check if curve equation works for generator point.
|
||
// `assertValidity()` won't work: `isTorsionFree()` is not available at this point in bls12-381.
|
||
// ProjectivePoint class has not been initialized yet.
|
||
if (!Fp.eql(Fp.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))
|
||
throw new Error('bad generator point: equation left != right');
|
||
// Valid group elements reside in range 1..n-1
|
||
function isWithinCurveOrder(num) {
|
||
return typeof num === 'bigint' && _0n < num && num < CURVE.n;
|
||
}
|
||
function assertGE(num) {
|
||
if (!isWithinCurveOrder(num))
|
||
throw new Error('Expected valid bigint: 0 < bigint < curve.n');
|
||
}
|
||
// Validates if priv key is valid and converts it to bigint.
|
||
// Supports options allowedPrivateKeyLengths and wrapPrivateKey.
|
||
function normPrivateKeyToScalar(key) {
|
||
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
||
if (lengths && typeof key !== 'bigint') {
|
||
if (isBytes$2(key))
|
||
key = bytesToHex(key);
|
||
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
||
if (typeof key !== 'string' || !lengths.includes(key.length))
|
||
throw new Error('Invalid key');
|
||
key = key.padStart(nByteLength * 2, '0');
|
||
}
|
||
let num;
|
||
try {
|
||
num =
|
||
typeof key === 'bigint'
|
||
? key
|
||
: bytesToNumberBE(ensureBytes('private key', key, nByteLength));
|
||
}
|
||
catch (error) {
|
||
throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
|
||
}
|
||
if (wrapPrivateKey)
|
||
num = mod(num, n); // disabled by default, enabled for BLS
|
||
assertGE(num); // num in range [1..N-1]
|
||
return num;
|
||
}
|
||
const pointPrecomputes = new Map();
|
||
function assertPrjPoint(other) {
|
||
if (!(other instanceof Point))
|
||
throw new Error('ProjectivePoint expected');
|
||
}
|
||
/**
|
||
* Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
|
||
* Default Point works in 2d / affine coordinates: (x, y)
|
||
* We're doing calculations in projective, because its operations don't require costly inversion.
|
||
*/
|
||
class Point {
|
||
constructor(px, py, pz) {
|
||
this.px = px;
|
||
this.py = py;
|
||
this.pz = pz;
|
||
if (px == null || !Fp.isValid(px))
|
||
throw new Error('x required');
|
||
if (py == null || !Fp.isValid(py))
|
||
throw new Error('y required');
|
||
if (pz == null || !Fp.isValid(pz))
|
||
throw new Error('z required');
|
||
}
|
||
// Does not validate if the point is on-curve.
|
||
// Use fromHex instead, or call assertValidity() later.
|
||
static fromAffine(p) {
|
||
const { x, y } = p || {};
|
||
if (!p || !Fp.isValid(x) || !Fp.isValid(y))
|
||
throw new Error('invalid affine point');
|
||
if (p instanceof Point)
|
||
throw new Error('projective point not allowed');
|
||
const is0 = (i) => Fp.eql(i, Fp.ZERO);
|
||
// fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
|
||
if (is0(x) && is0(y))
|
||
return Point.ZERO;
|
||
return new Point(x, y, Fp.ONE);
|
||
}
|
||
get x() {
|
||
return this.toAffine().x;
|
||
}
|
||
get y() {
|
||
return this.toAffine().y;
|
||
}
|
||
/**
|
||
* Takes a bunch of Projective Points but executes only one
|
||
* inversion on all of them. Inversion is very slow operation,
|
||
* so this improves performance massively.
|
||
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
||
*/
|
||
static normalizeZ(points) {
|
||
const toInv = Fp.invertBatch(points.map((p) => p.pz));
|
||
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
||
}
|
||
/**
|
||
* Converts hash string or Uint8Array to Point.
|
||
* @param hex short/long ECDSA hex
|
||
*/
|
||
static fromHex(hex) {
|
||
const P = Point.fromAffine(fromBytes(ensureBytes('pointHex', hex)));
|
||
P.assertValidity();
|
||
return P;
|
||
}
|
||
// Multiplies generator point by privateKey.
|
||
static fromPrivateKey(privateKey) {
|
||
return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
|
||
}
|
||
// "Private method", don't use it directly
|
||
_setWindowSize(windowSize) {
|
||
this._WINDOW_SIZE = windowSize;
|
||
pointPrecomputes.delete(this);
|
||
}
|
||
// A point on curve is valid if it conforms to equation.
|
||
assertValidity() {
|
||
if (this.is0()) {
|
||
// (0, 1, 0) aka ZERO is invalid in most contexts.
|
||
// In BLS, ZERO can be serialized, so we allow it.
|
||
// (0, 0, 0) is wrong representation of ZERO and is always invalid.
|
||
if (CURVE.allowInfinityPoint && !Fp.is0(this.py))
|
||
return;
|
||
throw new Error('bad point: ZERO');
|
||
}
|
||
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
|
||
const { x, y } = this.toAffine();
|
||
// Check if x, y are valid field elements
|
||
if (!Fp.isValid(x) || !Fp.isValid(y))
|
||
throw new Error('bad point: x or y not FE');
|
||
const left = Fp.sqr(y); // y²
|
||
const right = weierstrassEquation(x); // x³ + ax + b
|
||
if (!Fp.eql(left, right))
|
||
throw new Error('bad point: equation left != right');
|
||
if (!this.isTorsionFree())
|
||
throw new Error('bad point: not in prime-order subgroup');
|
||
}
|
||
hasEvenY() {
|
||
const { y } = this.toAffine();
|
||
if (Fp.isOdd)
|
||
return !Fp.isOdd(y);
|
||
throw new Error("Field doesn't support isOdd");
|
||
}
|
||
/**
|
||
* Compare one point to another.
|
||
*/
|
||
equals(other) {
|
||
assertPrjPoint(other);
|
||
const { px: X1, py: Y1, pz: Z1 } = this;
|
||
const { px: X2, py: Y2, pz: Z2 } = other;
|
||
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
|
||
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
|
||
return U1 && U2;
|
||
}
|
||
/**
|
||
* Flips point to one corresponding to (x, -y) in Affine coordinates.
|
||
*/
|
||
negate() {
|
||
return new Point(this.px, Fp.neg(this.py), this.pz);
|
||
}
|
||
// Renes-Costello-Batina exception-free doubling formula.
|
||
// There is 30% faster Jacobian formula, but it is not complete.
|
||
// https://eprint.iacr.org/2015/1060, algorithm 3
|
||
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
|
||
double() {
|
||
const { a, b } = CURVE;
|
||
const b3 = Fp.mul(b, _3n);
|
||
const { px: X1, py: Y1, pz: Z1 } = this;
|
||
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
||
let t0 = Fp.mul(X1, X1); // step 1
|
||
let t1 = Fp.mul(Y1, Y1);
|
||
let t2 = Fp.mul(Z1, Z1);
|
||
let t3 = Fp.mul(X1, Y1);
|
||
t3 = Fp.add(t3, t3); // step 5
|
||
Z3 = Fp.mul(X1, Z1);
|
||
Z3 = Fp.add(Z3, Z3);
|
||
X3 = Fp.mul(a, Z3);
|
||
Y3 = Fp.mul(b3, t2);
|
||
Y3 = Fp.add(X3, Y3); // step 10
|
||
X3 = Fp.sub(t1, Y3);
|
||
Y3 = Fp.add(t1, Y3);
|
||
Y3 = Fp.mul(X3, Y3);
|
||
X3 = Fp.mul(t3, X3);
|
||
Z3 = Fp.mul(b3, Z3); // step 15
|
||
t2 = Fp.mul(a, t2);
|
||
t3 = Fp.sub(t0, t2);
|
||
t3 = Fp.mul(a, t3);
|
||
t3 = Fp.add(t3, Z3);
|
||
Z3 = Fp.add(t0, t0); // step 20
|
||
t0 = Fp.add(Z3, t0);
|
||
t0 = Fp.add(t0, t2);
|
||
t0 = Fp.mul(t0, t3);
|
||
Y3 = Fp.add(Y3, t0);
|
||
t2 = Fp.mul(Y1, Z1); // step 25
|
||
t2 = Fp.add(t2, t2);
|
||
t0 = Fp.mul(t2, t3);
|
||
X3 = Fp.sub(X3, t0);
|
||
Z3 = Fp.mul(t2, t1);
|
||
Z3 = Fp.add(Z3, Z3); // step 30
|
||
Z3 = Fp.add(Z3, Z3);
|
||
return new Point(X3, Y3, Z3);
|
||
}
|
||
// Renes-Costello-Batina exception-free addition formula.
|
||
// There is 30% faster Jacobian formula, but it is not complete.
|
||
// https://eprint.iacr.org/2015/1060, algorithm 1
|
||
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
|
||
add(other) {
|
||
assertPrjPoint(other);
|
||
const { px: X1, py: Y1, pz: Z1 } = this;
|
||
const { px: X2, py: Y2, pz: Z2 } = other;
|
||
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
||
const a = CURVE.a;
|
||
const b3 = Fp.mul(CURVE.b, _3n);
|
||
let t0 = Fp.mul(X1, X2); // step 1
|
||
let t1 = Fp.mul(Y1, Y2);
|
||
let t2 = Fp.mul(Z1, Z2);
|
||
let t3 = Fp.add(X1, Y1);
|
||
let t4 = Fp.add(X2, Y2); // step 5
|
||
t3 = Fp.mul(t3, t4);
|
||
t4 = Fp.add(t0, t1);
|
||
t3 = Fp.sub(t3, t4);
|
||
t4 = Fp.add(X1, Z1);
|
||
let t5 = Fp.add(X2, Z2); // step 10
|
||
t4 = Fp.mul(t4, t5);
|
||
t5 = Fp.add(t0, t2);
|
||
t4 = Fp.sub(t4, t5);
|
||
t5 = Fp.add(Y1, Z1);
|
||
X3 = Fp.add(Y2, Z2); // step 15
|
||
t5 = Fp.mul(t5, X3);
|
||
X3 = Fp.add(t1, t2);
|
||
t5 = Fp.sub(t5, X3);
|
||
Z3 = Fp.mul(a, t4);
|
||
X3 = Fp.mul(b3, t2); // step 20
|
||
Z3 = Fp.add(X3, Z3);
|
||
X3 = Fp.sub(t1, Z3);
|
||
Z3 = Fp.add(t1, Z3);
|
||
Y3 = Fp.mul(X3, Z3);
|
||
t1 = Fp.add(t0, t0); // step 25
|
||
t1 = Fp.add(t1, t0);
|
||
t2 = Fp.mul(a, t2);
|
||
t4 = Fp.mul(b3, t4);
|
||
t1 = Fp.add(t1, t2);
|
||
t2 = Fp.sub(t0, t2); // step 30
|
||
t2 = Fp.mul(a, t2);
|
||
t4 = Fp.add(t4, t2);
|
||
t0 = Fp.mul(t1, t4);
|
||
Y3 = Fp.add(Y3, t0);
|
||
t0 = Fp.mul(t5, t4); // step 35
|
||
X3 = Fp.mul(t3, X3);
|
||
X3 = Fp.sub(X3, t0);
|
||
t0 = Fp.mul(t3, t1);
|
||
Z3 = Fp.mul(t5, Z3);
|
||
Z3 = Fp.add(Z3, t0); // step 40
|
||
return new Point(X3, Y3, Z3);
|
||
}
|
||
subtract(other) {
|
||
return this.add(other.negate());
|
||
}
|
||
is0() {
|
||
return this.equals(Point.ZERO);
|
||
}
|
||
wNAF(n) {
|
||
return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {
|
||
const toInv = Fp.invertBatch(comp.map((p) => p.pz));
|
||
return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
||
});
|
||
}
|
||
/**
|
||
* Non-constant-time multiplication. Uses double-and-add algorithm.
|
||
* It's faster, but should only be used when you don't care about
|
||
* an exposed private key e.g. sig verification, which works over *public* keys.
|
||
*/
|
||
multiplyUnsafe(n) {
|
||
const I = Point.ZERO;
|
||
if (n === _0n)
|
||
return I;
|
||
assertGE(n); // Will throw on 0
|
||
if (n === _1n$1)
|
||
return this;
|
||
const { endo } = CURVE;
|
||
if (!endo)
|
||
return wnaf.unsafeLadder(this, n);
|
||
// Apply endomorphism
|
||
let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
|
||
let k1p = I;
|
||
let k2p = I;
|
||
let d = this;
|
||
while (k1 > _0n || k2 > _0n) {
|
||
if (k1 & _1n$1)
|
||
k1p = k1p.add(d);
|
||
if (k2 & _1n$1)
|
||
k2p = k2p.add(d);
|
||
d = d.double();
|
||
k1 >>= _1n$1;
|
||
k2 >>= _1n$1;
|
||
}
|
||
if (k1neg)
|
||
k1p = k1p.negate();
|
||
if (k2neg)
|
||
k2p = k2p.negate();
|
||
k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
|
||
return k1p.add(k2p);
|
||
}
|
||
/**
|
||
* Constant time multiplication.
|
||
* Uses wNAF method. Windowed method may be 10% faster,
|
||
* but takes 2x longer to generate and consumes 2x memory.
|
||
* Uses precomputes when available.
|
||
* Uses endomorphism for Koblitz curves.
|
||
* @param scalar by which the point would be multiplied
|
||
* @returns New point
|
||
*/
|
||
multiply(scalar) {
|
||
assertGE(scalar);
|
||
let n = scalar;
|
||
let point, fake; // Fake point is used to const-time mult
|
||
const { endo } = CURVE;
|
||
if (endo) {
|
||
const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
|
||
let { p: k1p, f: f1p } = this.wNAF(k1);
|
||
let { p: k2p, f: f2p } = this.wNAF(k2);
|
||
k1p = wnaf.constTimeNegate(k1neg, k1p);
|
||
k2p = wnaf.constTimeNegate(k2neg, k2p);
|
||
k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
|
||
point = k1p.add(k2p);
|
||
fake = f1p.add(f2p);
|
||
}
|
||
else {
|
||
const { p, f } = this.wNAF(n);
|
||
point = p;
|
||
fake = f;
|
||
}
|
||
// Normalize `z` for both points, but return only real one
|
||
return Point.normalizeZ([point, fake])[0];
|
||
}
|
||
/**
|
||
* Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
|
||
* Not using Strauss-Shamir trick: precomputation tables are faster.
|
||
* The trick could be useful if both P and Q are not G (not in our case).
|
||
* @returns non-zero affine point
|
||
*/
|
||
multiplyAndAddUnsafe(Q, a, b) {
|
||
const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes
|
||
const mul = (P, a // Select faster multiply() method
|
||
) => (a === _0n || a === _1n$1 || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));
|
||
const sum = mul(this, a).add(mul(Q, b));
|
||
return sum.is0() ? undefined : sum;
|
||
}
|
||
// Converts Projective point to affine (x, y) coordinates.
|
||
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
||
// (x, y, z) ∋ (x=x/z, y=y/z)
|
||
toAffine(iz) {
|
||
const { px: x, py: y, pz: z } = this;
|
||
const is0 = this.is0();
|
||
// If invZ was 0, we return zero point. However we still want to execute
|
||
// all operations, so we replace invZ with a random number, 1.
|
||
if (iz == null)
|
||
iz = is0 ? Fp.ONE : Fp.inv(z);
|
||
const ax = Fp.mul(x, iz);
|
||
const ay = Fp.mul(y, iz);
|
||
const zz = Fp.mul(z, iz);
|
||
if (is0)
|
||
return { x: Fp.ZERO, y: Fp.ZERO };
|
||
if (!Fp.eql(zz, Fp.ONE))
|
||
throw new Error('invZ was invalid');
|
||
return { x: ax, y: ay };
|
||
}
|
||
isTorsionFree() {
|
||
const { h: cofactor, isTorsionFree } = CURVE;
|
||
if (cofactor === _1n$1)
|
||
return true; // No subgroups, always torsion-free
|
||
if (isTorsionFree)
|
||
return isTorsionFree(Point, this);
|
||
throw new Error('isTorsionFree() has not been declared for the elliptic curve');
|
||
}
|
||
clearCofactor() {
|
||
const { h: cofactor, clearCofactor } = CURVE;
|
||
if (cofactor === _1n$1)
|
||
return this; // Fast-path
|
||
if (clearCofactor)
|
||
return clearCofactor(Point, this);
|
||
return this.multiplyUnsafe(CURVE.h);
|
||
}
|
||
toRawBytes(isCompressed = true) {
|
||
this.assertValidity();
|
||
return toBytes(Point, this, isCompressed);
|
||
}
|
||
toHex(isCompressed = true) {
|
||
return bytesToHex(this.toRawBytes(isCompressed));
|
||
}
|
||
}
|
||
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
||
Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
|
||
const _bits = CURVE.nBitLength;
|
||
const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
|
||
// Validate if generator point is on curve
|
||
return {
|
||
CURVE,
|
||
ProjectivePoint: Point,
|
||
normPrivateKeyToScalar,
|
||
weierstrassEquation,
|
||
isWithinCurveOrder,
|
||
};
|
||
}
|
||
function validateOpts(curve) {
|
||
const opts = validateBasic(curve);
|
||
validateObject(opts, {
|
||
hash: 'hash',
|
||
hmac: 'function',
|
||
randomBytes: 'function',
|
||
}, {
|
||
bits2int: 'function',
|
||
bits2int_modN: 'function',
|
||
lowS: 'boolean',
|
||
});
|
||
return Object.freeze({ lowS: true, ...opts });
|
||
}
|
||
function weierstrass(curveDef) {
|
||
const CURVE = validateOpts(curveDef);
|
||
const { Fp, n: CURVE_ORDER } = CURVE;
|
||
const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
|
||
const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
|
||
function isValidFieldElement(num) {
|
||
return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
|
||
}
|
||
function modN(a) {
|
||
return mod(a, CURVE_ORDER);
|
||
}
|
||
function invN(a) {
|
||
return invert(a, CURVE_ORDER);
|
||
}
|
||
const { ProjectivePoint: Point, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder, } = weierstrassPoints({
|
||
...CURVE,
|
||
toBytes(_c, point, isCompressed) {
|
||
const a = point.toAffine();
|
||
const x = Fp.toBytes(a.x);
|
||
const cat = concatBytes;
|
||
if (isCompressed) {
|
||
return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
|
||
}
|
||
else {
|
||
return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
|
||
}
|
||
},
|
||
fromBytes(bytes) {
|
||
const len = bytes.length;
|
||
const head = bytes[0];
|
||
const tail = bytes.subarray(1);
|
||
// this.assertValidity() is done inside of fromHex
|
||
if (len === compressedLen && (head === 0x02 || head === 0x03)) {
|
||
const x = bytesToNumberBE(tail);
|
||
if (!isValidFieldElement(x))
|
||
throw new Error('Point is not on curve');
|
||
const y2 = weierstrassEquation(x); // y² = x³ + ax + b
|
||
let y;
|
||
try {
|
||
y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
|
||
}
|
||
catch (sqrtError) {
|
||
const suffix = sqrtError instanceof Error ? ': ' + sqrtError.message : '';
|
||
throw new Error('Point is not on curve' + suffix);
|
||
}
|
||
const isYOdd = (y & _1n$1) === _1n$1;
|
||
// ECDSA
|
||
const isHeadOdd = (head & 1) === 1;
|
||
if (isHeadOdd !== isYOdd)
|
||
y = Fp.neg(y);
|
||
return { x, y };
|
||
}
|
||
else if (len === uncompressedLen && head === 0x04) {
|
||
const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
|
||
const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
|
||
return { x, y };
|
||
}
|
||
else {
|
||
throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);
|
||
}
|
||
},
|
||
});
|
||
const numToNByteStr = (num) => bytesToHex(numberToBytesBE(num, CURVE.nByteLength));
|
||
function isBiggerThanHalfOrder(number) {
|
||
const HALF = CURVE_ORDER >> _1n$1;
|
||
return number > HALF;
|
||
}
|
||
function normalizeS(s) {
|
||
return isBiggerThanHalfOrder(s) ? modN(-s) : s;
|
||
}
|
||
// slice bytes num
|
||
const slcNum = (b, from, to) => bytesToNumberBE(b.slice(from, to));
|
||
/**
|
||
* ECDSA signature with its (r, s) properties. Supports DER & compact representations.
|
||
*/
|
||
class Signature {
|
||
constructor(r, s, recovery) {
|
||
this.r = r;
|
||
this.s = s;
|
||
this.recovery = recovery;
|
||
this.assertValidity();
|
||
}
|
||
// pair (bytes of r, bytes of s)
|
||
static fromCompact(hex) {
|
||
const l = CURVE.nByteLength;
|
||
hex = ensureBytes('compactSignature', hex, l * 2);
|
||
return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));
|
||
}
|
||
// DER encoded ECDSA signature
|
||
// https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script
|
||
static fromDER(hex) {
|
||
const { r, s } = DER.toSig(ensureBytes('DER', hex));
|
||
return new Signature(r, s);
|
||
}
|
||
assertValidity() {
|
||
// can use assertGE here
|
||
if (!isWithinCurveOrder(this.r))
|
||
throw new Error('r must be 0 < r < CURVE.n');
|
||
if (!isWithinCurveOrder(this.s))
|
||
throw new Error('s must be 0 < s < CURVE.n');
|
||
}
|
||
addRecoveryBit(recovery) {
|
||
return new Signature(this.r, this.s, recovery);
|
||
}
|
||
recoverPublicKey(msgHash) {
|
||
const { r, s, recovery: rec } = this;
|
||
const h = bits2int_modN(ensureBytes('msgHash', msgHash)); // Truncate hash
|
||
if (rec == null || ![0, 1, 2, 3].includes(rec))
|
||
throw new Error('recovery id invalid');
|
||
const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;
|
||
if (radj >= Fp.ORDER)
|
||
throw new Error('recovery id 2 or 3 invalid');
|
||
const prefix = (rec & 1) === 0 ? '02' : '03';
|
||
const R = Point.fromHex(prefix + numToNByteStr(radj));
|
||
const ir = invN(radj); // r^-1
|
||
const u1 = modN(-h * ir); // -hr^-1
|
||
const u2 = modN(s * ir); // sr^-1
|
||
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
|
||
if (!Q)
|
||
throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
|
||
Q.assertValidity();
|
||
return Q;
|
||
}
|
||
// Signatures should be low-s, to prevent malleability.
|
||
hasHighS() {
|
||
return isBiggerThanHalfOrder(this.s);
|
||
}
|
||
normalizeS() {
|
||
return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
|
||
}
|
||
// DER-encoded
|
||
toDERRawBytes() {
|
||
return hexToBytes(this.toDERHex());
|
||
}
|
||
toDERHex() {
|
||
return DER.hexFromSig({ r: this.r, s: this.s });
|
||
}
|
||
// padded bytes of r, then padded bytes of s
|
||
toCompactRawBytes() {
|
||
return hexToBytes(this.toCompactHex());
|
||
}
|
||
toCompactHex() {
|
||
return numToNByteStr(this.r) + numToNByteStr(this.s);
|
||
}
|
||
}
|
||
const utils = {
|
||
isValidPrivateKey(privateKey) {
|
||
try {
|
||
normPrivateKeyToScalar(privateKey);
|
||
return true;
|
||
}
|
||
catch (error) {
|
||
return false;
|
||
}
|
||
},
|
||
normPrivateKeyToScalar: normPrivateKeyToScalar,
|
||
/**
|
||
* Produces cryptographically secure private key from random of size
|
||
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
||
*/
|
||
randomPrivateKey: () => {
|
||
const length = getMinHashLength(CURVE.n);
|
||
return mapHashToField(CURVE.randomBytes(length), CURVE.n);
|
||
},
|
||
/**
|
||
* Creates precompute table for an arbitrary EC point. Makes point "cached".
|
||
* Allows to massively speed-up `point.multiply(scalar)`.
|
||
* @returns cached point
|
||
* @example
|
||
* const fast = utils.precompute(8, ProjectivePoint.fromHex(someonesPubKey));
|
||
* fast.multiply(privKey); // much faster ECDH now
|
||
*/
|
||
precompute(windowSize = 8, point = Point.BASE) {
|
||
point._setWindowSize(windowSize);
|
||
point.multiply(BigInt(3)); // 3 is arbitrary, just need any number here
|
||
return point;
|
||
},
|
||
};
|
||
/**
|
||
* Computes public key for a private key. Checks for validity of the private key.
|
||
* @param privateKey private key
|
||
* @param isCompressed whether to return compact (default), or full key
|
||
* @returns Public key, full when isCompressed=false; short when isCompressed=true
|
||
*/
|
||
function getPublicKey(privateKey, isCompressed = true) {
|
||
return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
|
||
}
|
||
/**
|
||
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
||
*/
|
||
function isProbPub(item) {
|
||
const arr = isBytes$2(item);
|
||
const str = typeof item === 'string';
|
||
const len = (arr || str) && item.length;
|
||
if (arr)
|
||
return len === compressedLen || len === uncompressedLen;
|
||
if (str)
|
||
return len === 2 * compressedLen || len === 2 * uncompressedLen;
|
||
if (item instanceof Point)
|
||
return true;
|
||
return false;
|
||
}
|
||
/**
|
||
* ECDH (Elliptic Curve Diffie Hellman).
|
||
* Computes shared public key from private key and public key.
|
||
* Checks: 1) private key validity 2) shared key is on-curve.
|
||
* Does NOT hash the result.
|
||
* @param privateA private key
|
||
* @param publicB different public key
|
||
* @param isCompressed whether to return compact (default), or full key
|
||
* @returns shared public key
|
||
*/
|
||
function getSharedSecret(privateA, publicB, isCompressed = true) {
|
||
if (isProbPub(privateA))
|
||
throw new Error('first arg must be private key');
|
||
if (!isProbPub(publicB))
|
||
throw new Error('second arg must be public key');
|
||
const b = Point.fromHex(publicB); // check for being on-curve
|
||
return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed);
|
||
}
|
||
// RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
|
||
// FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
|
||
// bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
|
||
// int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
|
||
const bits2int = CURVE.bits2int ||
|
||
function (bytes) {
|
||
// For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
|
||
// for some cases, since bytes.length * 8 is not actual bitLength.
|
||
const num = bytesToNumberBE(bytes); // check for == u8 done here
|
||
const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
|
||
return delta > 0 ? num >> BigInt(delta) : num;
|
||
};
|
||
const bits2int_modN = CURVE.bits2int_modN ||
|
||
function (bytes) {
|
||
return modN(bits2int(bytes)); // can't use bytesToNumberBE here
|
||
};
|
||
// NOTE: pads output with zero as per spec
|
||
const ORDER_MASK = bitMask(CURVE.nBitLength);
|
||
/**
|
||
* Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
|
||
*/
|
||
function int2octets(num) {
|
||
if (typeof num !== 'bigint')
|
||
throw new Error('bigint expected');
|
||
if (!(_0n <= num && num < ORDER_MASK))
|
||
throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
|
||
// works with order, can have different size than numToField!
|
||
return numberToBytesBE(num, CURVE.nByteLength);
|
||
}
|
||
// Steps A, D of RFC6979 3.2
|
||
// Creates RFC6979 seed; converts msg/privKey to numbers.
|
||
// Used only in sign, not in verify.
|
||
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
|
||
// Also it can be bigger for P224 + SHA256
|
||
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
||
if (['recovered', 'canonical'].some((k) => k in opts))
|
||
throw new Error('sign() legacy options not supported');
|
||
const { hash, randomBytes } = CURVE;
|
||
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
|
||
if (lowS == null)
|
||
lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
|
||
msgHash = ensureBytes('msgHash', msgHash);
|
||
if (prehash)
|
||
msgHash = ensureBytes('prehashed msgHash', hash(msgHash));
|
||
// We can't later call bits2octets, since nested bits2int is broken for curves
|
||
// with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
||
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
||
const h1int = bits2int_modN(msgHash);
|
||
const d = normPrivateKeyToScalar(privateKey); // validate private key, convert to bigint
|
||
const seedArgs = [int2octets(d), int2octets(h1int)];
|
||
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
||
if (ent != null && ent !== false) {
|
||
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
||
const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
|
||
seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes
|
||
}
|
||
const seed = concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
||
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
||
// Converts signature params into point w r/s, checks result for validity.
|
||
function k2sig(kBytes) {
|
||
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
|
||
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
|
||
if (!isWithinCurveOrder(k))
|
||
return; // Important: all mod() calls here must be done over N
|
||
const ik = invN(k); // k^-1 mod n
|
||
const q = Point.BASE.multiply(k).toAffine(); // q = Gk
|
||
const r = modN(q.x); // r = q.x mod n
|
||
if (r === _0n)
|
||
return;
|
||
// Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to
|
||
// https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
|
||
// a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
|
||
const s = modN(ik * modN(m + r * d)); // Not using blinding here
|
||
if (s === _0n)
|
||
return;
|
||
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n$1); // recovery bit (2 or 3, when q.x > n)
|
||
let normS = s;
|
||
if (lowS && isBiggerThanHalfOrder(s)) {
|
||
normS = normalizeS(s); // if lowS was passed, ensure s is always
|
||
recovery ^= 1; // // in the bottom half of N
|
||
}
|
||
return new Signature(r, normS, recovery); // use normS, not s
|
||
}
|
||
return { seed, k2sig };
|
||
}
|
||
const defaultSigOpts = { lowS: CURVE.lowS, prehash: false };
|
||
const defaultVerOpts = { lowS: CURVE.lowS, prehash: false };
|
||
/**
|
||
* Signs message hash with a private key.
|
||
* ```
|
||
* sign(m, d, k) where
|
||
* (x, y) = G × k
|
||
* r = x mod n
|
||
* s = (m + dr)/k mod n
|
||
* ```
|
||
* @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.
|
||
* @param privKey private key
|
||
* @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.
|
||
* @returns signature with recovery param
|
||
*/
|
||
function sign(msgHash, privKey, opts = defaultSigOpts) {
|
||
const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
|
||
const C = CURVE;
|
||
const drbg = createHmacDrbg(C.hash.outputLen, C.nByteLength, C.hmac);
|
||
return drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
||
}
|
||
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
||
Point.BASE._setWindowSize(8);
|
||
// utils.precompute(8, ProjectivePoint.BASE)
|
||
/**
|
||
* Verifies a signature against message hash and public key.
|
||
* Rejects lowS signatures by default: to override,
|
||
* specify option `{lowS: false}`. Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:
|
||
*
|
||
* ```
|
||
* verify(r, s, h, P) where
|
||
* U1 = hs^-1 mod n
|
||
* U2 = rs^-1 mod n
|
||
* R = U1⋅G - U2⋅P
|
||
* mod(R.x, n) == r
|
||
* ```
|
||
*/
|
||
function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {
|
||
const sg = signature;
|
||
msgHash = ensureBytes('msgHash', msgHash);
|
||
publicKey = ensureBytes('publicKey', publicKey);
|
||
if ('strict' in opts)
|
||
throw new Error('options.strict was renamed to lowS');
|
||
const { lowS, prehash } = opts;
|
||
let _sig = undefined;
|
||
let P;
|
||
try {
|
||
if (typeof sg === 'string' || isBytes$2(sg)) {
|
||
// Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
|
||
// Since DER can also be 2*nByteLength bytes, we check for it first.
|
||
try {
|
||
_sig = Signature.fromDER(sg);
|
||
}
|
||
catch (derError) {
|
||
if (!(derError instanceof DER.Err))
|
||
throw derError;
|
||
_sig = Signature.fromCompact(sg);
|
||
}
|
||
}
|
||
else if (typeof sg === 'object' && typeof sg.r === 'bigint' && typeof sg.s === 'bigint') {
|
||
const { r, s } = sg;
|
||
_sig = new Signature(r, s);
|
||
}
|
||
else {
|
||
throw new Error('PARSE');
|
||
}
|
||
P = Point.fromHex(publicKey);
|
||
}
|
||
catch (error) {
|
||
if (error.message === 'PARSE')
|
||
throw new Error(`signature must be Signature instance, Uint8Array or hex string`);
|
||
return false;
|
||
}
|
||
if (lowS && _sig.hasHighS())
|
||
return false;
|
||
if (prehash)
|
||
msgHash = CURVE.hash(msgHash);
|
||
const { r, s } = _sig;
|
||
const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
|
||
const is = invN(s); // s^-1
|
||
const u1 = modN(h * is); // u1 = hs^-1 mod n
|
||
const u2 = modN(r * is); // u2 = rs^-1 mod n
|
||
const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
|
||
if (!R)
|
||
return false;
|
||
const v = modN(R.x);
|
||
return v === r;
|
||
}
|
||
return {
|
||
CURVE,
|
||
getPublicKey,
|
||
getSharedSecret,
|
||
sign,
|
||
verify,
|
||
ProjectivePoint: Point,
|
||
Signature,
|
||
utils,
|
||
};
|
||
}
|
||
|
||
// HMAC (RFC 2104)
|
||
class HMAC extends Hash$1 {
|
||
constructor(hash$1, _key) {
|
||
super();
|
||
this.finished = false;
|
||
this.destroyed = false;
|
||
hash(hash$1);
|
||
const key = toBytes$1(_key);
|
||
this.iHash = hash$1.create();
|
||
if (typeof this.iHash.update !== 'function')
|
||
throw new Error('Expected instance of class which extends utils.Hash');
|
||
this.blockLen = this.iHash.blockLen;
|
||
this.outputLen = this.iHash.outputLen;
|
||
const blockLen = this.blockLen;
|
||
const pad = new Uint8Array(blockLen);
|
||
// blockLen can be bigger than outputLen
|
||
pad.set(key.length > blockLen ? hash$1.create().update(key).digest() : key);
|
||
for (let i = 0; i < pad.length; i++)
|
||
pad[i] ^= 0x36;
|
||
this.iHash.update(pad);
|
||
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
|
||
this.oHash = hash$1.create();
|
||
// Undo internal XOR && apply outer XOR
|
||
for (let i = 0; i < pad.length; i++)
|
||
pad[i] ^= 0x36 ^ 0x5c;
|
||
this.oHash.update(pad);
|
||
pad.fill(0);
|
||
}
|
||
update(buf) {
|
||
exists$1(this);
|
||
this.iHash.update(buf);
|
||
return this;
|
||
}
|
||
digestInto(out) {
|
||
exists$1(this);
|
||
bytes$1(out, this.outputLen);
|
||
this.finished = true;
|
||
this.iHash.digestInto(out);
|
||
this.oHash.update(out);
|
||
this.oHash.digestInto(out);
|
||
this.destroy();
|
||
}
|
||
digest() {
|
||
const out = new Uint8Array(this.oHash.outputLen);
|
||
this.digestInto(out);
|
||
return out;
|
||
}
|
||
_cloneInto(to) {
|
||
// Create new instance without calling constructor since key already in state and we don't know it.
|
||
to || (to = Object.create(Object.getPrototypeOf(this), {}));
|
||
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
||
to = to;
|
||
to.finished = finished;
|
||
to.destroyed = destroyed;
|
||
to.blockLen = blockLen;
|
||
to.outputLen = outputLen;
|
||
to.oHash = oHash._cloneInto(to.oHash);
|
||
to.iHash = iHash._cloneInto(to.iHash);
|
||
return to;
|
||
}
|
||
destroy() {
|
||
this.destroyed = true;
|
||
this.oHash.destroy();
|
||
this.iHash.destroy();
|
||
}
|
||
}
|
||
/**
|
||
* HMAC: RFC2104 message authentication code.
|
||
* @param hash - function that would be used e.g. sha256
|
||
* @param key - message key
|
||
* @param message - message data
|
||
*/
|
||
const hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
|
||
hmac.create = (hash, key) => new HMAC(hash, key);
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
// connects noble-curves to noble-hashes
|
||
function getHash(hash) {
|
||
return {
|
||
hash,
|
||
hmac: (key, ...msgs) => hmac(hash, key, concatBytes$1(...msgs)),
|
||
randomBytes,
|
||
};
|
||
}
|
||
function createCurve(curveDef, defHash) {
|
||
const create = (hash) => weierstrass({ ...curveDef, ...getHash(hash) });
|
||
return Object.freeze({ ...create(defHash), create });
|
||
}
|
||
|
||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||
const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
||
const secp256k1N = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
|
||
const _1n = BigInt(1);
|
||
const _2n = BigInt(2);
|
||
const divNearest = (a, b) => (a + b / _2n) / b;
|
||
/**
|
||
* √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit.
|
||
* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
|
||
*/
|
||
function sqrtMod(y) {
|
||
const P = secp256k1P;
|
||
// prettier-ignore
|
||
const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
|
||
// prettier-ignore
|
||
const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
|
||
const b2 = (y * y * y) % P; // x^3, 11
|
||
const b3 = (b2 * b2 * y) % P; // x^7
|
||
const b6 = (pow2(b3, _3n, P) * b3) % P;
|
||
const b9 = (pow2(b6, _3n, P) * b3) % P;
|
||
const b11 = (pow2(b9, _2n, P) * b2) % P;
|
||
const b22 = (pow2(b11, _11n, P) * b11) % P;
|
||
const b44 = (pow2(b22, _22n, P) * b22) % P;
|
||
const b88 = (pow2(b44, _44n, P) * b44) % P;
|
||
const b176 = (pow2(b88, _88n, P) * b88) % P;
|
||
const b220 = (pow2(b176, _44n, P) * b44) % P;
|
||
const b223 = (pow2(b220, _3n, P) * b3) % P;
|
||
const t1 = (pow2(b223, _23n, P) * b22) % P;
|
||
const t2 = (pow2(t1, _6n, P) * b2) % P;
|
||
const root = pow2(t2, _2n, P);
|
||
if (!Fp.eql(Fp.sqr(root), y))
|
||
throw new Error('Cannot find square root');
|
||
return root;
|
||
}
|
||
const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
|
||
const secp256k1 = createCurve({
|
||
a: BigInt(0), // equation params: a, b
|
||
b: BigInt(7), // Seem to be rigid: bitcointalk.org/index.php?topic=289795.msg3183975#msg3183975
|
||
Fp, // Field's prime: 2n**256n - 2n**32n - 2n**9n - 2n**8n - 2n**7n - 2n**6n - 2n**4n - 1n
|
||
n: secp256k1N, // Curve order, total count of valid points in the field
|
||
// Base point (x, y) aka generator point
|
||
Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
|
||
Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'),
|
||
h: BigInt(1), // Cofactor
|
||
lowS: true, // Allow only low-S signatures by default in sign() and verify()
|
||
/**
|
||
* secp256k1 belongs to Koblitz curves: it has efficiently computable endomorphism.
|
||
* Endomorphism uses 2x less RAM, speeds up precomputation by 2x and ECDH / key recovery by 20%.
|
||
* For precomputed wNAF it trades off 1/2 init time & 1/3 ram for 20% perf hit.
|
||
* Explanation: https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
|
||
*/
|
||
endo: {
|
||
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
|
||
splitScalar: (k) => {
|
||
const n = secp256k1N;
|
||
const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15');
|
||
const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
|
||
const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
|
||
const b2 = a1;
|
||
const POW_2_128 = BigInt('0x100000000000000000000000000000000'); // (2n**128n).toString(16)
|
||
const c1 = divNearest(b2 * k, n);
|
||
const c2 = divNearest(-b1 * k, n);
|
||
let k1 = mod(k - c1 * a1 - c2 * a2, n);
|
||
let k2 = mod(-c1 * b1 - c2 * b2, n);
|
||
const k1neg = k1 > POW_2_128;
|
||
const k2neg = k2 > POW_2_128;
|
||
if (k1neg)
|
||
k1 = n - k1;
|
||
if (k2neg)
|
||
k2 = n - k2;
|
||
if (k1 > POW_2_128 || k2 > POW_2_128) {
|
||
throw new Error('splitScalar: Endomorphism failed, k=' + k);
|
||
}
|
||
return { k1neg, k1, k2neg, k2 };
|
||
},
|
||
},
|
||
}, sha256);
|
||
// Schnorr signatures are superior to ECDSA from above. Below is Schnorr-specific BIP0340 code.
|
||
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
|
||
BigInt(0);
|
||
secp256k1.ProjectivePoint;
|
||
|
||
const ecdsaSign = (msgHash, privKey) => {
|
||
const signature = secp256k1.sign(msgHash, privKey);
|
||
return [signature.toCompactRawBytes(), signature.recovery];
|
||
};
|
||
secp256k1.utils.isValidPrivateKey;
|
||
const publicKeyCreate = secp256k1.getPublicKey;
|
||
|
||
const PRIVATE_KEY_BYTES = 32;
|
||
const ETHEREUM_ADDRESS_BYTES = 20;
|
||
const PUBLIC_KEY_BYTES = 64;
|
||
const SIGNATURE_OFFSETS_SERIALIZED_SIZE = 11;
|
||
|
||
/**
|
||
* Params for creating an secp256k1 instruction using a public key
|
||
*/
|
||
|
||
/**
|
||
* Params for creating an secp256k1 instruction using an Ethereum address
|
||
*/
|
||
|
||
/**
|
||
* Params for creating an secp256k1 instruction using a private key
|
||
*/
|
||
|
||
const SECP256K1_INSTRUCTION_LAYOUT = struct([u8('numSignatures'), u16('signatureOffset'), u8('signatureInstructionIndex'), u16('ethAddressOffset'), u8('ethAddressInstructionIndex'), u16('messageDataOffset'), u16('messageDataSize'), u8('messageInstructionIndex'), blob(20, 'ethAddress'), blob(64, 'signature'), u8('recoveryId')]);
|
||
class Secp256k1Program {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Public key that identifies the secp256k1 program
|
||
*/
|
||
|
||
/**
|
||
* Construct an Ethereum address from a secp256k1 public key buffer.
|
||
* @param {Buffer} publicKey a 64 byte secp256k1 public key buffer
|
||
*/
|
||
static publicKeyToEthAddress(publicKey) {
|
||
assert$1(publicKey.length === PUBLIC_KEY_BYTES, `Public key must be ${PUBLIC_KEY_BYTES} bytes but received ${publicKey.length} bytes`);
|
||
try {
|
||
return buffer.Buffer.from(keccak_256(toBuffer(publicKey))).slice(-ETHEREUM_ADDRESS_BYTES);
|
||
} catch (error) {
|
||
throw new Error(`Error constructing Ethereum address: ${error}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create an secp256k1 instruction with a public key. The public key
|
||
* must be a buffer that is 64 bytes long.
|
||
*/
|
||
static createInstructionWithPublicKey(params) {
|
||
const {
|
||
publicKey,
|
||
message,
|
||
signature,
|
||
recoveryId,
|
||
instructionIndex
|
||
} = params;
|
||
return Secp256k1Program.createInstructionWithEthAddress({
|
||
ethAddress: Secp256k1Program.publicKeyToEthAddress(publicKey),
|
||
message,
|
||
signature,
|
||
recoveryId,
|
||
instructionIndex
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Create an secp256k1 instruction with an Ethereum address. The address
|
||
* must be a hex string or a buffer that is 20 bytes long.
|
||
*/
|
||
static createInstructionWithEthAddress(params) {
|
||
const {
|
||
ethAddress: rawAddress,
|
||
message,
|
||
signature,
|
||
recoveryId,
|
||
instructionIndex = 0
|
||
} = params;
|
||
let ethAddress;
|
||
if (typeof rawAddress === 'string') {
|
||
if (rawAddress.startsWith('0x')) {
|
||
ethAddress = buffer.Buffer.from(rawAddress.substr(2), 'hex');
|
||
} else {
|
||
ethAddress = buffer.Buffer.from(rawAddress, 'hex');
|
||
}
|
||
} else {
|
||
ethAddress = rawAddress;
|
||
}
|
||
assert$1(ethAddress.length === ETHEREUM_ADDRESS_BYTES, `Address must be ${ETHEREUM_ADDRESS_BYTES} bytes but received ${ethAddress.length} bytes`);
|
||
const dataStart = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE;
|
||
const ethAddressOffset = dataStart;
|
||
const signatureOffset = dataStart + ethAddress.length;
|
||
const messageDataOffset = signatureOffset + signature.length + 1;
|
||
const numSignatures = 1;
|
||
const instructionData = buffer.Buffer.alloc(SECP256K1_INSTRUCTION_LAYOUT.span + message.length);
|
||
SECP256K1_INSTRUCTION_LAYOUT.encode({
|
||
numSignatures,
|
||
signatureOffset,
|
||
signatureInstructionIndex: instructionIndex,
|
||
ethAddressOffset,
|
||
ethAddressInstructionIndex: instructionIndex,
|
||
messageDataOffset,
|
||
messageDataSize: message.length,
|
||
messageInstructionIndex: instructionIndex,
|
||
signature: toBuffer(signature),
|
||
ethAddress: toBuffer(ethAddress),
|
||
recoveryId
|
||
}, instructionData);
|
||
instructionData.fill(toBuffer(message), SECP256K1_INSTRUCTION_LAYOUT.span);
|
||
return new TransactionInstruction({
|
||
keys: [],
|
||
programId: Secp256k1Program.programId,
|
||
data: instructionData
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Create an secp256k1 instruction with a private key. The private key
|
||
* must be a buffer that is 32 bytes long.
|
||
*/
|
||
static createInstructionWithPrivateKey(params) {
|
||
const {
|
||
privateKey: pkey,
|
||
message,
|
||
instructionIndex
|
||
} = params;
|
||
assert$1(pkey.length === PRIVATE_KEY_BYTES, `Private key must be ${PRIVATE_KEY_BYTES} bytes but received ${pkey.length} bytes`);
|
||
try {
|
||
const privateKey = toBuffer(pkey);
|
||
const publicKey = publicKeyCreate(privateKey, false /* isCompressed */).slice(1); // throw away leading byte
|
||
const messageHash = buffer.Buffer.from(keccak_256(toBuffer(message)));
|
||
const [signature, recoveryId] = ecdsaSign(messageHash, privateKey);
|
||
return this.createInstructionWithPublicKey({
|
||
publicKey,
|
||
message,
|
||
signature,
|
||
recoveryId,
|
||
instructionIndex
|
||
});
|
||
} catch (error) {
|
||
throw new Error(`Error creating instruction; ${error}`);
|
||
}
|
||
}
|
||
}
|
||
Secp256k1Program.programId = new PublicKey('KeccakSecp256k11111111111111111111111111111');
|
||
|
||
var _class2;
|
||
|
||
/**
|
||
* Address of the stake config account which configures the rate
|
||
* of stake warmup and cooldown as well as the slashing penalty.
|
||
*/
|
||
const STAKE_CONFIG_ID = new PublicKey('StakeConfig11111111111111111111111111111111');
|
||
|
||
/**
|
||
* Stake account authority info
|
||
*/
|
||
class Authorized {
|
||
/**
|
||
* Create a new Authorized object
|
||
* @param staker the stake authority
|
||
* @param withdrawer the withdraw authority
|
||
*/
|
||
constructor(staker, withdrawer) {
|
||
/** stake authority */
|
||
this.staker = void 0;
|
||
/** withdraw authority */
|
||
this.withdrawer = void 0;
|
||
this.staker = staker;
|
||
this.withdrawer = withdrawer;
|
||
}
|
||
}
|
||
/**
|
||
* Stake account lockup info
|
||
*/
|
||
class Lockup {
|
||
/**
|
||
* Create a new Lockup object
|
||
*/
|
||
constructor(unixTimestamp, epoch, custodian) {
|
||
/** Unix timestamp of lockup expiration */
|
||
this.unixTimestamp = void 0;
|
||
/** Epoch of lockup expiration */
|
||
this.epoch = void 0;
|
||
/** Lockup custodian authority */
|
||
this.custodian = void 0;
|
||
this.unixTimestamp = unixTimestamp;
|
||
this.epoch = epoch;
|
||
this.custodian = custodian;
|
||
}
|
||
|
||
/**
|
||
* Default, inactive Lockup value
|
||
*/
|
||
}
|
||
_class2 = Lockup;
|
||
Lockup.default = new _class2(0, 0, PublicKey.default);
|
||
/**
|
||
* Create stake account transaction params
|
||
*/
|
||
/**
|
||
* Create stake account with seed transaction params
|
||
*/
|
||
/**
|
||
* Initialize stake instruction params
|
||
*/
|
||
/**
|
||
* Delegate stake instruction params
|
||
*/
|
||
/**
|
||
* Authorize stake instruction params
|
||
*/
|
||
/**
|
||
* Authorize stake instruction params using a derived key
|
||
*/
|
||
/**
|
||
* Split stake instruction params
|
||
*/
|
||
/**
|
||
* Split with seed transaction params
|
||
*/
|
||
/**
|
||
* Withdraw stake instruction params
|
||
*/
|
||
/**
|
||
* Deactivate stake instruction params
|
||
*/
|
||
/**
|
||
* Merge stake instruction params
|
||
*/
|
||
/**
|
||
* Stake Instruction class
|
||
*/
|
||
class StakeInstruction {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Decode a stake instruction and retrieve the instruction type.
|
||
*/
|
||
static decodeInstructionType(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const instructionTypeLayout = u32('instruction');
|
||
const typeIndex = instructionTypeLayout.decode(instruction.data);
|
||
let type;
|
||
for (const [ixType, layout] of Object.entries(STAKE_INSTRUCTION_LAYOUTS)) {
|
||
if (layout.index == typeIndex) {
|
||
type = ixType;
|
||
break;
|
||
}
|
||
}
|
||
if (!type) {
|
||
throw new Error('Instruction type incorrect; not a StakeInstruction');
|
||
}
|
||
return type;
|
||
}
|
||
|
||
/**
|
||
* Decode a initialize stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeInitialize(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 2);
|
||
const {
|
||
authorized,
|
||
lockup
|
||
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Initialize, instruction.data);
|
||
return {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
authorized: new Authorized(new PublicKey(authorized.staker), new PublicKey(authorized.withdrawer)),
|
||
lockup: new Lockup(lockup.unixTimestamp, lockup.epoch, new PublicKey(lockup.custodian))
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a delegate stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeDelegate(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 6);
|
||
decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Delegate, instruction.data);
|
||
return {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
votePubkey: instruction.keys[1].pubkey,
|
||
authorizedPubkey: instruction.keys[5].pubkey
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode an authorize stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAuthorize(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
const {
|
||
newAuthorized,
|
||
stakeAuthorizationType
|
||
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Authorize, instruction.data);
|
||
const o = {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
authorizedPubkey: instruction.keys[2].pubkey,
|
||
newAuthorizedPubkey: new PublicKey(newAuthorized),
|
||
stakeAuthorizationType: {
|
||
index: stakeAuthorizationType
|
||
}
|
||
};
|
||
if (instruction.keys.length > 3) {
|
||
o.custodianPubkey = instruction.keys[3].pubkey;
|
||
}
|
||
return o;
|
||
}
|
||
|
||
/**
|
||
* Decode an authorize-with-seed stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAuthorizeWithSeed(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 2);
|
||
const {
|
||
newAuthorized,
|
||
stakeAuthorizationType,
|
||
authoritySeed,
|
||
authorityOwner
|
||
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed, instruction.data);
|
||
const o = {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
authorityBase: instruction.keys[1].pubkey,
|
||
authoritySeed: authoritySeed,
|
||
authorityOwner: new PublicKey(authorityOwner),
|
||
newAuthorizedPubkey: new PublicKey(newAuthorized),
|
||
stakeAuthorizationType: {
|
||
index: stakeAuthorizationType
|
||
}
|
||
};
|
||
if (instruction.keys.length > 3) {
|
||
o.custodianPubkey = instruction.keys[3].pubkey;
|
||
}
|
||
return o;
|
||
}
|
||
|
||
/**
|
||
* Decode a split stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeSplit(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
const {
|
||
lamports
|
||
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Split, instruction.data);
|
||
return {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
splitStakePubkey: instruction.keys[1].pubkey,
|
||
authorizedPubkey: instruction.keys[2].pubkey,
|
||
lamports
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a merge stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeMerge(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Merge, instruction.data);
|
||
return {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
sourceStakePubKey: instruction.keys[1].pubkey,
|
||
authorizedPubkey: instruction.keys[4].pubkey
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a withdraw stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeWithdraw(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 5);
|
||
const {
|
||
lamports
|
||
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Withdraw, instruction.data);
|
||
const o = {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
toPubkey: instruction.keys[1].pubkey,
|
||
authorizedPubkey: instruction.keys[4].pubkey,
|
||
lamports
|
||
};
|
||
if (instruction.keys.length > 5) {
|
||
o.custodianPubkey = instruction.keys[5].pubkey;
|
||
}
|
||
return o;
|
||
}
|
||
|
||
/**
|
||
* Decode a deactivate stake instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeDeactivate(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Deactivate, instruction.data);
|
||
return {
|
||
stakePubkey: instruction.keys[0].pubkey,
|
||
authorizedPubkey: instruction.keys[2].pubkey
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkProgramId(programId) {
|
||
if (!programId.equals(StakeProgram.programId)) {
|
||
throw new Error('invalid instruction; programId is not StakeProgram');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkKeyLength(keys, expectedLength) {
|
||
if (keys.length < expectedLength) {
|
||
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* An enumeration of valid StakeInstructionType's
|
||
*/
|
||
|
||
/**
|
||
* An enumeration of valid stake InstructionType's
|
||
* @internal
|
||
*/
|
||
const STAKE_INSTRUCTION_LAYOUTS = Object.freeze({
|
||
Initialize: {
|
||
index: 0,
|
||
layout: struct([u32('instruction'), authorized(), lockup()])
|
||
},
|
||
Authorize: {
|
||
index: 1,
|
||
layout: struct([u32('instruction'), publicKey('newAuthorized'), u32('stakeAuthorizationType')])
|
||
},
|
||
Delegate: {
|
||
index: 2,
|
||
layout: struct([u32('instruction')])
|
||
},
|
||
Split: {
|
||
index: 3,
|
||
layout: struct([u32('instruction'), ns64('lamports')])
|
||
},
|
||
Withdraw: {
|
||
index: 4,
|
||
layout: struct([u32('instruction'), ns64('lamports')])
|
||
},
|
||
Deactivate: {
|
||
index: 5,
|
||
layout: struct([u32('instruction')])
|
||
},
|
||
Merge: {
|
||
index: 7,
|
||
layout: struct([u32('instruction')])
|
||
},
|
||
AuthorizeWithSeed: {
|
||
index: 8,
|
||
layout: struct([u32('instruction'), publicKey('newAuthorized'), u32('stakeAuthorizationType'), rustString('authoritySeed'), publicKey('authorityOwner')])
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Stake authorization type
|
||
*/
|
||
|
||
/**
|
||
* An enumeration of valid StakeAuthorizationLayout's
|
||
*/
|
||
const StakeAuthorizationLayout = Object.freeze({
|
||
Staker: {
|
||
index: 0
|
||
},
|
||
Withdrawer: {
|
||
index: 1
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Factory class for transactions to interact with the Stake program
|
||
*/
|
||
class StakeProgram {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Public key that identifies the Stake program
|
||
*/
|
||
|
||
/**
|
||
* Generate an Initialize instruction to add to a Stake Create transaction
|
||
*/
|
||
static initialize(params) {
|
||
const {
|
||
stakePubkey,
|
||
authorized,
|
||
lockup: maybeLockup
|
||
} = params;
|
||
const lockup = maybeLockup || Lockup.default;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.Initialize;
|
||
const data = encodeData(type, {
|
||
authorized: {
|
||
staker: toBuffer(authorized.staker.toBuffer()),
|
||
withdrawer: toBuffer(authorized.withdrawer.toBuffer())
|
||
},
|
||
lockup: {
|
||
unixTimestamp: lockup.unixTimestamp,
|
||
epoch: lockup.epoch,
|
||
custodian: toBuffer(lockup.custodian.toBuffer())
|
||
}
|
||
});
|
||
const instructionData = {
|
||
keys: [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_RENT_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
};
|
||
return new TransactionInstruction(instructionData);
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that creates a new Stake account at
|
||
* an address generated with `from`, a seed, and the Stake programId
|
||
*/
|
||
static createAccountWithSeed(params) {
|
||
const transaction = new Transaction();
|
||
transaction.add(SystemProgram.createAccountWithSeed({
|
||
fromPubkey: params.fromPubkey,
|
||
newAccountPubkey: params.stakePubkey,
|
||
basePubkey: params.basePubkey,
|
||
seed: params.seed,
|
||
lamports: params.lamports,
|
||
space: this.space,
|
||
programId: this.programId
|
||
}));
|
||
const {
|
||
stakePubkey,
|
||
authorized,
|
||
lockup
|
||
} = params;
|
||
return transaction.add(this.initialize({
|
||
stakePubkey,
|
||
authorized,
|
||
lockup
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that creates a new Stake account
|
||
*/
|
||
static createAccount(params) {
|
||
const transaction = new Transaction();
|
||
transaction.add(SystemProgram.createAccount({
|
||
fromPubkey: params.fromPubkey,
|
||
newAccountPubkey: params.stakePubkey,
|
||
lamports: params.lamports,
|
||
space: this.space,
|
||
programId: this.programId
|
||
}));
|
||
const {
|
||
stakePubkey,
|
||
authorized,
|
||
lockup
|
||
} = params;
|
||
return transaction.add(this.initialize({
|
||
stakePubkey,
|
||
authorized,
|
||
lockup
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that delegates Stake tokens to a validator
|
||
* Vote PublicKey. This transaction can also be used to redelegate Stake
|
||
* to a new validator Vote PublicKey.
|
||
*/
|
||
static delegate(params) {
|
||
const {
|
||
stakePubkey,
|
||
authorizedPubkey,
|
||
votePubkey
|
||
} = params;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.Delegate;
|
||
const data = encodeData(type);
|
||
return new Transaction().add({
|
||
keys: [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: votePubkey,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: STAKE_CONFIG_ID,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that authorizes a new PublicKey as Staker
|
||
* or Withdrawer on the Stake account.
|
||
*/
|
||
static authorize(params) {
|
||
const {
|
||
stakePubkey,
|
||
authorizedPubkey,
|
||
newAuthorizedPubkey,
|
||
stakeAuthorizationType,
|
||
custodianPubkey
|
||
} = params;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.Authorize;
|
||
const data = encodeData(type, {
|
||
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
|
||
stakeAuthorizationType: stakeAuthorizationType.index
|
||
});
|
||
const keys = [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
if (custodianPubkey) {
|
||
keys.push({
|
||
pubkey: custodianPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
});
|
||
}
|
||
return new Transaction().add({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that authorizes a new PublicKey as Staker
|
||
* or Withdrawer on the Stake account.
|
||
*/
|
||
static authorizeWithSeed(params) {
|
||
const {
|
||
stakePubkey,
|
||
authorityBase,
|
||
authoritySeed,
|
||
authorityOwner,
|
||
newAuthorizedPubkey,
|
||
stakeAuthorizationType,
|
||
custodianPubkey
|
||
} = params;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed;
|
||
const data = encodeData(type, {
|
||
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
|
||
stakeAuthorizationType: stakeAuthorizationType.index,
|
||
authoritySeed: authoritySeed,
|
||
authorityOwner: toBuffer(authorityOwner.toBuffer())
|
||
});
|
||
const keys = [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: authorityBase,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}];
|
||
if (custodianPubkey) {
|
||
keys.push({
|
||
pubkey: custodianPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
});
|
||
}
|
||
return new Transaction().add({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static splitInstruction(params) {
|
||
const {
|
||
stakePubkey,
|
||
authorizedPubkey,
|
||
splitStakePubkey,
|
||
lamports
|
||
} = params;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.Split;
|
||
const data = encodeData(type, {
|
||
lamports
|
||
});
|
||
return new TransactionInstruction({
|
||
keys: [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: splitStakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that splits Stake tokens into another stake account
|
||
*/
|
||
static split(params,
|
||
// Compute the cost of allocating the new stake account in lamports
|
||
rentExemptReserve) {
|
||
const transaction = new Transaction();
|
||
transaction.add(SystemProgram.createAccount({
|
||
fromPubkey: params.authorizedPubkey,
|
||
newAccountPubkey: params.splitStakePubkey,
|
||
lamports: rentExemptReserve,
|
||
space: this.space,
|
||
programId: this.programId
|
||
}));
|
||
return transaction.add(this.splitInstruction(params));
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that splits Stake tokens into another account
|
||
* derived from a base public key and seed
|
||
*/
|
||
static splitWithSeed(params,
|
||
// If this stake account is new, compute the cost of allocating it in lamports
|
||
rentExemptReserve) {
|
||
const {
|
||
stakePubkey,
|
||
authorizedPubkey,
|
||
splitStakePubkey,
|
||
basePubkey,
|
||
seed,
|
||
lamports
|
||
} = params;
|
||
const transaction = new Transaction();
|
||
transaction.add(SystemProgram.allocate({
|
||
accountPubkey: splitStakePubkey,
|
||
basePubkey,
|
||
seed,
|
||
space: this.space,
|
||
programId: this.programId
|
||
}));
|
||
if (rentExemptReserve && rentExemptReserve > 0) {
|
||
transaction.add(SystemProgram.transfer({
|
||
fromPubkey: params.authorizedPubkey,
|
||
toPubkey: splitStakePubkey,
|
||
lamports: rentExemptReserve
|
||
}));
|
||
}
|
||
return transaction.add(this.splitInstruction({
|
||
stakePubkey,
|
||
authorizedPubkey,
|
||
splitStakePubkey,
|
||
lamports
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that merges Stake accounts.
|
||
*/
|
||
static merge(params) {
|
||
const {
|
||
stakePubkey,
|
||
sourceStakePubKey,
|
||
authorizedPubkey
|
||
} = params;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.Merge;
|
||
const data = encodeData(type);
|
||
return new Transaction().add({
|
||
keys: [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: sourceStakePubKey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that withdraws deactivated Stake tokens.
|
||
*/
|
||
static withdraw(params) {
|
||
const {
|
||
stakePubkey,
|
||
authorizedPubkey,
|
||
toPubkey,
|
||
lamports,
|
||
custodianPubkey
|
||
} = params;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.Withdraw;
|
||
const data = encodeData(type, {
|
||
lamports
|
||
});
|
||
const keys = [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: toPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
if (custodianPubkey) {
|
||
keys.push({
|
||
pubkey: custodianPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
});
|
||
}
|
||
return new Transaction().add({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a Transaction that deactivates Stake tokens.
|
||
*/
|
||
static deactivate(params) {
|
||
const {
|
||
stakePubkey,
|
||
authorizedPubkey
|
||
} = params;
|
||
const type = STAKE_INSTRUCTION_LAYOUTS.Deactivate;
|
||
const data = encodeData(type);
|
||
return new Transaction().add({
|
||
keys: [{
|
||
pubkey: stakePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
}
|
||
StakeProgram.programId = new PublicKey('Stake11111111111111111111111111111111111111');
|
||
/**
|
||
* Max space of a Stake account
|
||
*
|
||
* This is generated from the solana-stake-program StakeState struct as
|
||
* `StakeStateV2::size_of()`:
|
||
* https://docs.rs/solana-stake-program/latest/solana_stake_program/stake_state/enum.StakeStateV2.html
|
||
*/
|
||
StakeProgram.space = 200;
|
||
|
||
/**
|
||
* Vote account info
|
||
*/
|
||
class VoteInit {
|
||
/** [0, 100] */
|
||
|
||
constructor(nodePubkey, authorizedVoter, authorizedWithdrawer, commission) {
|
||
this.nodePubkey = void 0;
|
||
this.authorizedVoter = void 0;
|
||
this.authorizedWithdrawer = void 0;
|
||
this.commission = void 0;
|
||
this.nodePubkey = nodePubkey;
|
||
this.authorizedVoter = authorizedVoter;
|
||
this.authorizedWithdrawer = authorizedWithdrawer;
|
||
this.commission = commission;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create vote account transaction params
|
||
*/
|
||
|
||
/**
|
||
* InitializeAccount instruction params
|
||
*/
|
||
|
||
/**
|
||
* Authorize instruction params
|
||
*/
|
||
|
||
/**
|
||
* AuthorizeWithSeed instruction params
|
||
*/
|
||
|
||
/**
|
||
* Withdraw from vote account transaction params
|
||
*/
|
||
|
||
/**
|
||
* Update validator identity (node pubkey) vote account instruction params.
|
||
*/
|
||
|
||
/**
|
||
* Vote Instruction class
|
||
*/
|
||
class VoteInstruction {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Decode a vote instruction and retrieve the instruction type.
|
||
*/
|
||
static decodeInstructionType(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
const instructionTypeLayout = u32('instruction');
|
||
const typeIndex = instructionTypeLayout.decode(instruction.data);
|
||
let type;
|
||
for (const [ixType, layout] of Object.entries(VOTE_INSTRUCTION_LAYOUTS)) {
|
||
if (layout.index == typeIndex) {
|
||
type = ixType;
|
||
break;
|
||
}
|
||
}
|
||
if (!type) {
|
||
throw new Error('Instruction type incorrect; not a VoteInstruction');
|
||
}
|
||
return type;
|
||
}
|
||
|
||
/**
|
||
* Decode an initialize vote instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeInitializeAccount(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 4);
|
||
const {
|
||
voteInit
|
||
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.InitializeAccount, instruction.data);
|
||
return {
|
||
votePubkey: instruction.keys[0].pubkey,
|
||
nodePubkey: instruction.keys[3].pubkey,
|
||
voteInit: new VoteInit(new PublicKey(voteInit.nodePubkey), new PublicKey(voteInit.authorizedVoter), new PublicKey(voteInit.authorizedWithdrawer), voteInit.commission)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode an authorize instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAuthorize(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
const {
|
||
newAuthorized,
|
||
voteAuthorizationType
|
||
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.Authorize, instruction.data);
|
||
return {
|
||
votePubkey: instruction.keys[0].pubkey,
|
||
authorizedPubkey: instruction.keys[2].pubkey,
|
||
newAuthorizedPubkey: new PublicKey(newAuthorized),
|
||
voteAuthorizationType: {
|
||
index: voteAuthorizationType
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode an authorize instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeAuthorizeWithSeed(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
const {
|
||
voteAuthorizeWithSeedArgs: {
|
||
currentAuthorityDerivedKeyOwnerPubkey,
|
||
currentAuthorityDerivedKeySeed,
|
||
newAuthorized,
|
||
voteAuthorizationType
|
||
}
|
||
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed, instruction.data);
|
||
return {
|
||
currentAuthorityDerivedKeyBasePubkey: instruction.keys[2].pubkey,
|
||
currentAuthorityDerivedKeyOwnerPubkey: new PublicKey(currentAuthorityDerivedKeyOwnerPubkey),
|
||
currentAuthorityDerivedKeySeed: currentAuthorityDerivedKeySeed,
|
||
newAuthorizedPubkey: new PublicKey(newAuthorized),
|
||
voteAuthorizationType: {
|
||
index: voteAuthorizationType
|
||
},
|
||
votePubkey: instruction.keys[0].pubkey
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Decode a withdraw instruction and retrieve the instruction params.
|
||
*/
|
||
static decodeWithdraw(instruction) {
|
||
this.checkProgramId(instruction.programId);
|
||
this.checkKeyLength(instruction.keys, 3);
|
||
const {
|
||
lamports
|
||
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.Withdraw, instruction.data);
|
||
return {
|
||
votePubkey: instruction.keys[0].pubkey,
|
||
authorizedWithdrawerPubkey: instruction.keys[2].pubkey,
|
||
lamports,
|
||
toPubkey: instruction.keys[1].pubkey
|
||
};
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkProgramId(programId) {
|
||
if (!programId.equals(VoteProgram.programId)) {
|
||
throw new Error('invalid instruction; programId is not VoteProgram');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
static checkKeyLength(keys, expectedLength) {
|
||
if (keys.length < expectedLength) {
|
||
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* An enumeration of valid VoteInstructionType's
|
||
*/
|
||
|
||
/** @internal */
|
||
|
||
const VOTE_INSTRUCTION_LAYOUTS = Object.freeze({
|
||
InitializeAccount: {
|
||
index: 0,
|
||
layout: struct([u32('instruction'), voteInit()])
|
||
},
|
||
Authorize: {
|
||
index: 1,
|
||
layout: struct([u32('instruction'), publicKey('newAuthorized'), u32('voteAuthorizationType')])
|
||
},
|
||
Withdraw: {
|
||
index: 3,
|
||
layout: struct([u32('instruction'), ns64('lamports')])
|
||
},
|
||
UpdateValidatorIdentity: {
|
||
index: 4,
|
||
layout: struct([u32('instruction')])
|
||
},
|
||
AuthorizeWithSeed: {
|
||
index: 10,
|
||
layout: struct([u32('instruction'), voteAuthorizeWithSeedArgs()])
|
||
}
|
||
});
|
||
|
||
/**
|
||
* VoteAuthorize type
|
||
*/
|
||
|
||
/**
|
||
* An enumeration of valid VoteAuthorization layouts.
|
||
*/
|
||
const VoteAuthorizationLayout = Object.freeze({
|
||
Voter: {
|
||
index: 0
|
||
},
|
||
Withdrawer: {
|
||
index: 1
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Factory class for transactions to interact with the Vote program
|
||
*/
|
||
class VoteProgram {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor() {}
|
||
|
||
/**
|
||
* Public key that identifies the Vote program
|
||
*/
|
||
|
||
/**
|
||
* Generate an Initialize instruction.
|
||
*/
|
||
static initializeAccount(params) {
|
||
const {
|
||
votePubkey,
|
||
nodePubkey,
|
||
voteInit
|
||
} = params;
|
||
const type = VOTE_INSTRUCTION_LAYOUTS.InitializeAccount;
|
||
const data = encodeData(type, {
|
||
voteInit: {
|
||
nodePubkey: toBuffer(voteInit.nodePubkey.toBuffer()),
|
||
authorizedVoter: toBuffer(voteInit.authorizedVoter.toBuffer()),
|
||
authorizedWithdrawer: toBuffer(voteInit.authorizedWithdrawer.toBuffer()),
|
||
commission: voteInit.commission
|
||
}
|
||
});
|
||
const instructionData = {
|
||
keys: [{
|
||
pubkey: votePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_RENT_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: nodePubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}],
|
||
programId: this.programId,
|
||
data
|
||
};
|
||
return new TransactionInstruction(instructionData);
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction that creates a new Vote account.
|
||
*/
|
||
static createAccount(params) {
|
||
const transaction = new Transaction();
|
||
transaction.add(SystemProgram.createAccount({
|
||
fromPubkey: params.fromPubkey,
|
||
newAccountPubkey: params.votePubkey,
|
||
lamports: params.lamports,
|
||
space: this.space,
|
||
programId: this.programId
|
||
}));
|
||
return transaction.add(this.initializeAccount({
|
||
votePubkey: params.votePubkey,
|
||
nodePubkey: params.voteInit.nodePubkey,
|
||
voteInit: params.voteInit
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction that authorizes a new Voter or Withdrawer on the Vote account.
|
||
*/
|
||
static authorize(params) {
|
||
const {
|
||
votePubkey,
|
||
authorizedPubkey,
|
||
newAuthorizedPubkey,
|
||
voteAuthorizationType
|
||
} = params;
|
||
const type = VOTE_INSTRUCTION_LAYOUTS.Authorize;
|
||
const data = encodeData(type, {
|
||
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
|
||
voteAuthorizationType: voteAuthorizationType.index
|
||
});
|
||
const keys = [{
|
||
pubkey: votePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: authorizedPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
return new Transaction().add({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction that authorizes a new Voter or Withdrawer on the Vote account
|
||
* where the current Voter or Withdrawer authority is a derived key.
|
||
*/
|
||
static authorizeWithSeed(params) {
|
||
const {
|
||
currentAuthorityDerivedKeyBasePubkey,
|
||
currentAuthorityDerivedKeyOwnerPubkey,
|
||
currentAuthorityDerivedKeySeed,
|
||
newAuthorizedPubkey,
|
||
voteAuthorizationType,
|
||
votePubkey
|
||
} = params;
|
||
const type = VOTE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed;
|
||
const data = encodeData(type, {
|
||
voteAuthorizeWithSeedArgs: {
|
||
currentAuthorityDerivedKeyOwnerPubkey: toBuffer(currentAuthorityDerivedKeyOwnerPubkey.toBuffer()),
|
||
currentAuthorityDerivedKeySeed: currentAuthorityDerivedKeySeed,
|
||
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
|
||
voteAuthorizationType: voteAuthorizationType.index
|
||
}
|
||
});
|
||
const keys = [{
|
||
pubkey: votePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||
isSigner: false,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: currentAuthorityDerivedKeyBasePubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
return new Transaction().add({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction to withdraw from a Vote account.
|
||
*/
|
||
static withdraw(params) {
|
||
const {
|
||
votePubkey,
|
||
authorizedWithdrawerPubkey,
|
||
lamports,
|
||
toPubkey
|
||
} = params;
|
||
const type = VOTE_INSTRUCTION_LAYOUTS.Withdraw;
|
||
const data = encodeData(type, {
|
||
lamports
|
||
});
|
||
const keys = [{
|
||
pubkey: votePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: toPubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: authorizedWithdrawerPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
return new Transaction().add({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction to withdraw safely from a Vote account.
|
||
*
|
||
* This function was created as a safeguard for vote accounts running validators, `safeWithdraw`
|
||
* checks that the withdraw amount will not exceed the specified balance while leaving enough left
|
||
* to cover rent. If you wish to close the vote account by withdrawing the full amount, call the
|
||
* `withdraw` method directly.
|
||
*/
|
||
static safeWithdraw(params, currentVoteAccountBalance, rentExemptMinimum) {
|
||
if (params.lamports > currentVoteAccountBalance - rentExemptMinimum) {
|
||
throw new Error('Withdraw will leave vote account with insufficient funds.');
|
||
}
|
||
return VoteProgram.withdraw(params);
|
||
}
|
||
|
||
/**
|
||
* Generate a transaction to update the validator identity (node pubkey) of a Vote account.
|
||
*/
|
||
static updateValidatorIdentity(params) {
|
||
const {
|
||
votePubkey,
|
||
authorizedWithdrawerPubkey,
|
||
nodePubkey
|
||
} = params;
|
||
const type = VOTE_INSTRUCTION_LAYOUTS.UpdateValidatorIdentity;
|
||
const data = encodeData(type);
|
||
const keys = [{
|
||
pubkey: votePubkey,
|
||
isSigner: false,
|
||
isWritable: true
|
||
}, {
|
||
pubkey: nodePubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}, {
|
||
pubkey: authorizedWithdrawerPubkey,
|
||
isSigner: true,
|
||
isWritable: false
|
||
}];
|
||
return new Transaction().add({
|
||
keys,
|
||
programId: this.programId,
|
||
data
|
||
});
|
||
}
|
||
}
|
||
VoteProgram.programId = new PublicKey('Vote111111111111111111111111111111111111111');
|
||
/**
|
||
* Max space of a Vote account
|
||
*
|
||
* This is generated from the solana-vote-program VoteState struct as
|
||
* `VoteState::size_of()`:
|
||
* https://docs.rs/solana-vote-program/1.9.5/solana_vote_program/vote_state/struct.VoteState.html#method.size_of
|
||
*
|
||
* KEEP IN SYNC WITH `VoteState::size_of()` in https://github.com/solana-labs/solana/blob/a474cb24b9238f5edcc982f65c0b37d4a1046f7e/sdk/program/src/vote/state/mod.rs#L340-L342
|
||
*/
|
||
VoteProgram.space = 3762;
|
||
|
||
const VALIDATOR_INFO_KEY = new PublicKey('Va1idator1nfo111111111111111111111111111111');
|
||
|
||
/**
|
||
* @internal
|
||
*/
|
||
|
||
/**
|
||
* Info used to identity validators.
|
||
*/
|
||
|
||
const InfoString = type({
|
||
name: string(),
|
||
website: optional(string()),
|
||
details: optional(string()),
|
||
keybaseUsername: optional(string())
|
||
});
|
||
|
||
/**
|
||
* ValidatorInfo class
|
||
*/
|
||
class ValidatorInfo {
|
||
/**
|
||
* Construct a valid ValidatorInfo
|
||
*
|
||
* @param key validator public key
|
||
* @param info validator information
|
||
*/
|
||
constructor(key, info) {
|
||
/**
|
||
* validator public key
|
||
*/
|
||
this.key = void 0;
|
||
/**
|
||
* validator information
|
||
*/
|
||
this.info = void 0;
|
||
this.key = key;
|
||
this.info = info;
|
||
}
|
||
|
||
/**
|
||
* Deserialize ValidatorInfo from the config account data. Exactly two config
|
||
* keys are required in the data.
|
||
*
|
||
* @param buffer config account data
|
||
* @return null if info was not found
|
||
*/
|
||
static fromConfigData(buffer$1) {
|
||
let byteArray = [...buffer$1];
|
||
const configKeyCount = decodeLength(byteArray);
|
||
if (configKeyCount !== 2) return null;
|
||
const configKeys = [];
|
||
for (let i = 0; i < 2; i++) {
|
||
const publicKey = new PublicKey(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
|
||
const isSigner = guardedShift(byteArray) === 1;
|
||
configKeys.push({
|
||
publicKey,
|
||
isSigner
|
||
});
|
||
}
|
||
if (configKeys[0].publicKey.equals(VALIDATOR_INFO_KEY)) {
|
||
if (configKeys[1].isSigner) {
|
||
const rawInfo = rustString().decode(buffer.Buffer.from(byteArray));
|
||
const info = JSON.parse(rawInfo);
|
||
assert(info, InfoString);
|
||
return new ValidatorInfo(configKeys[1].publicKey, info);
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
}
|
||
|
||
const VOTE_PROGRAM_ID = new PublicKey('Vote111111111111111111111111111111111111111');
|
||
|
||
/**
|
||
* History of how many credits earned by the end of each epoch
|
||
*/
|
||
|
||
/**
|
||
* See https://github.com/solana-labs/solana/blob/8a12ed029cfa38d4a45400916c2463fb82bbec8c/programs/vote_api/src/vote_state.rs#L68-L88
|
||
*
|
||
* @internal
|
||
*/
|
||
const VoteAccountLayout = struct([publicKey('nodePubkey'), publicKey('authorizedWithdrawer'), u8('commission'), nu64(),
|
||
// votes.length
|
||
seq(struct([nu64('slot'), u32('confirmationCount')]), offset(u32(), -8), 'votes'), u8('rootSlotValid'), nu64('rootSlot'), nu64(),
|
||
// authorizedVoters.length
|
||
seq(struct([nu64('epoch'), publicKey('authorizedVoter')]), offset(u32(), -8), 'authorizedVoters'), struct([seq(struct([publicKey('authorizedPubkey'), nu64('epochOfLastAuthorizedSwitch'), nu64('targetEpoch')]), 32, 'buf'), nu64('idx'), u8('isEmpty')], 'priorVoters'), nu64(),
|
||
// epochCredits.length
|
||
seq(struct([nu64('epoch'), nu64('credits'), nu64('prevCredits')]), offset(u32(), -8), 'epochCredits'), struct([nu64('slot'), nu64('timestamp')], 'lastTimestamp')]);
|
||
/**
|
||
* VoteAccount class
|
||
*/
|
||
class VoteAccount {
|
||
/**
|
||
* @internal
|
||
*/
|
||
constructor(args) {
|
||
this.nodePubkey = void 0;
|
||
this.authorizedWithdrawer = void 0;
|
||
this.commission = void 0;
|
||
this.rootSlot = void 0;
|
||
this.votes = void 0;
|
||
this.authorizedVoters = void 0;
|
||
this.priorVoters = void 0;
|
||
this.epochCredits = void 0;
|
||
this.lastTimestamp = void 0;
|
||
this.nodePubkey = args.nodePubkey;
|
||
this.authorizedWithdrawer = args.authorizedWithdrawer;
|
||
this.commission = args.commission;
|
||
this.rootSlot = args.rootSlot;
|
||
this.votes = args.votes;
|
||
this.authorizedVoters = args.authorizedVoters;
|
||
this.priorVoters = args.priorVoters;
|
||
this.epochCredits = args.epochCredits;
|
||
this.lastTimestamp = args.lastTimestamp;
|
||
}
|
||
|
||
/**
|
||
* Deserialize VoteAccount from the account data.
|
||
*
|
||
* @param buffer account data
|
||
* @return VoteAccount
|
||
*/
|
||
static fromAccountData(buffer) {
|
||
const versionOffset = 4;
|
||
const va = VoteAccountLayout.decode(toBuffer(buffer), versionOffset);
|
||
let rootSlot = va.rootSlot;
|
||
if (!va.rootSlotValid) {
|
||
rootSlot = null;
|
||
}
|
||
return new VoteAccount({
|
||
nodePubkey: new PublicKey(va.nodePubkey),
|
||
authorizedWithdrawer: new PublicKey(va.authorizedWithdrawer),
|
||
commission: va.commission,
|
||
votes: va.votes,
|
||
rootSlot,
|
||
authorizedVoters: va.authorizedVoters.map(parseAuthorizedVoter),
|
||
priorVoters: getPriorVoters(va.priorVoters),
|
||
epochCredits: va.epochCredits,
|
||
lastTimestamp: va.lastTimestamp
|
||
});
|
||
}
|
||
}
|
||
function parseAuthorizedVoter({
|
||
authorizedVoter,
|
||
epoch
|
||
}) {
|
||
return {
|
||
epoch,
|
||
authorizedVoter: new PublicKey(authorizedVoter)
|
||
};
|
||
}
|
||
function parsePriorVoters({
|
||
authorizedPubkey,
|
||
epochOfLastAuthorizedSwitch,
|
||
targetEpoch
|
||
}) {
|
||
return {
|
||
authorizedPubkey: new PublicKey(authorizedPubkey),
|
||
epochOfLastAuthorizedSwitch,
|
||
targetEpoch
|
||
};
|
||
}
|
||
function getPriorVoters({
|
||
buf,
|
||
idx,
|
||
isEmpty
|
||
}) {
|
||
if (isEmpty) {
|
||
return [];
|
||
}
|
||
return [...buf.slice(idx + 1).map(parsePriorVoters), ...buf.slice(0, idx).map(parsePriorVoters)];
|
||
}
|
||
|
||
const endpoint = {
|
||
http: {
|
||
devnet: 'http://api.devnet.solana.com',
|
||
testnet: 'http://api.testnet.solana.com',
|
||
'mainnet-beta': 'http://api.mainnet-beta.solana.com/'
|
||
},
|
||
https: {
|
||
devnet: 'https://api.devnet.solana.com',
|
||
testnet: 'https://api.testnet.solana.com',
|
||
'mainnet-beta': 'https://api.mainnet-beta.solana.com/'
|
||
}
|
||
};
|
||
/**
|
||
* Retrieves the RPC API URL for the specified cluster
|
||
* @param {Cluster} [cluster="devnet"] - The cluster name of the RPC API URL to use. Possible options: 'devnet' | 'testnet' | 'mainnet-beta'
|
||
* @param {boolean} [tls="http"] - Use TLS when connecting to cluster.
|
||
*
|
||
* @returns {string} URL string of the RPC endpoint
|
||
*/
|
||
function clusterApiUrl(cluster, tls) {
|
||
const key = tls === false ? 'http' : 'https';
|
||
if (!cluster) {
|
||
return endpoint[key]['devnet'];
|
||
}
|
||
const url = endpoint[key][cluster];
|
||
if (!url) {
|
||
throw new Error(`Unknown ${key} cluster: ${cluster}`);
|
||
}
|
||
return url;
|
||
}
|
||
|
||
/**
|
||
* Send and confirm a raw transaction
|
||
*
|
||
* If `commitment` option is not specified, defaults to 'max' commitment.
|
||
*
|
||
* @param {Connection} connection
|
||
* @param {Buffer} rawTransaction
|
||
* @param {TransactionConfirmationStrategy} confirmationStrategy
|
||
* @param {ConfirmOptions} [options]
|
||
* @returns {Promise<TransactionSignature>}
|
||
*/
|
||
|
||
/**
|
||
* @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
|
||
* is no longer supported and will be removed in a future version.
|
||
*/
|
||
// eslint-disable-next-line no-redeclare
|
||
|
||
// eslint-disable-next-line no-redeclare
|
||
async function sendAndConfirmRawTransaction(connection, rawTransaction, confirmationStrategyOrConfirmOptions, maybeConfirmOptions) {
|
||
let confirmationStrategy;
|
||
let options;
|
||
if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'lastValidBlockHeight')) {
|
||
confirmationStrategy = confirmationStrategyOrConfirmOptions;
|
||
options = maybeConfirmOptions;
|
||
} else if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'nonceValue')) {
|
||
confirmationStrategy = confirmationStrategyOrConfirmOptions;
|
||
options = maybeConfirmOptions;
|
||
} else {
|
||
options = confirmationStrategyOrConfirmOptions;
|
||
}
|
||
const sendOptions = options && {
|
||
skipPreflight: options.skipPreflight,
|
||
preflightCommitment: options.preflightCommitment || options.commitment,
|
||
minContextSlot: options.minContextSlot
|
||
};
|
||
const signature = await connection.sendRawTransaction(rawTransaction, sendOptions);
|
||
const commitment = options && options.commitment;
|
||
const confirmationPromise = confirmationStrategy ? connection.confirmTransaction(confirmationStrategy, commitment) : connection.confirmTransaction(signature, commitment);
|
||
const status = (await confirmationPromise).value;
|
||
if (status.err) {
|
||
throw new Error(`Raw transaction ${signature} failed (${JSON.stringify(status)})`);
|
||
}
|
||
return signature;
|
||
}
|
||
|
||
/**
|
||
* There are 1-billion lamports in one SOL
|
||
*/
|
||
const LAMPORTS_PER_SOL = 1000000000;
|
||
|
||
exports.Account = Account;
|
||
exports.AddressLookupTableAccount = AddressLookupTableAccount;
|
||
exports.AddressLookupTableInstruction = AddressLookupTableInstruction;
|
||
exports.AddressLookupTableProgram = AddressLookupTableProgram;
|
||
exports.Authorized = Authorized;
|
||
exports.BLOCKHASH_CACHE_TIMEOUT_MS = BLOCKHASH_CACHE_TIMEOUT_MS;
|
||
exports.BPF_LOADER_DEPRECATED_PROGRAM_ID = BPF_LOADER_DEPRECATED_PROGRAM_ID;
|
||
exports.BPF_LOADER_PROGRAM_ID = BPF_LOADER_PROGRAM_ID;
|
||
exports.BpfLoader = BpfLoader;
|
||
exports.COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS;
|
||
exports.ComputeBudgetInstruction = ComputeBudgetInstruction;
|
||
exports.ComputeBudgetProgram = ComputeBudgetProgram;
|
||
exports.Connection = Connection;
|
||
exports.Ed25519Program = Ed25519Program;
|
||
exports.Enum = Enum;
|
||
exports.EpochSchedule = EpochSchedule;
|
||
exports.FeeCalculatorLayout = FeeCalculatorLayout;
|
||
exports.Keypair = Keypair;
|
||
exports.LAMPORTS_PER_SOL = LAMPORTS_PER_SOL;
|
||
exports.LOOKUP_TABLE_INSTRUCTION_LAYOUTS = LOOKUP_TABLE_INSTRUCTION_LAYOUTS;
|
||
exports.Loader = Loader;
|
||
exports.Lockup = Lockup;
|
||
exports.MAX_SEED_LENGTH = MAX_SEED_LENGTH;
|
||
exports.Message = Message;
|
||
exports.MessageAccountKeys = MessageAccountKeys;
|
||
exports.MessageV0 = MessageV0;
|
||
exports.NONCE_ACCOUNT_LENGTH = NONCE_ACCOUNT_LENGTH;
|
||
exports.NonceAccount = NonceAccount;
|
||
exports.PACKET_DATA_SIZE = PACKET_DATA_SIZE;
|
||
exports.PUBLIC_KEY_LENGTH = PUBLIC_KEY_LENGTH;
|
||
exports.PublicKey = PublicKey;
|
||
exports.SIGNATURE_LENGTH_IN_BYTES = SIGNATURE_LENGTH_IN_BYTES;
|
||
exports.SOLANA_SCHEMA = SOLANA_SCHEMA;
|
||
exports.STAKE_CONFIG_ID = STAKE_CONFIG_ID;
|
||
exports.STAKE_INSTRUCTION_LAYOUTS = STAKE_INSTRUCTION_LAYOUTS;
|
||
exports.SYSTEM_INSTRUCTION_LAYOUTS = SYSTEM_INSTRUCTION_LAYOUTS;
|
||
exports.SYSVAR_CLOCK_PUBKEY = SYSVAR_CLOCK_PUBKEY;
|
||
exports.SYSVAR_EPOCH_SCHEDULE_PUBKEY = SYSVAR_EPOCH_SCHEDULE_PUBKEY;
|
||
exports.SYSVAR_INSTRUCTIONS_PUBKEY = SYSVAR_INSTRUCTIONS_PUBKEY;
|
||
exports.SYSVAR_RECENT_BLOCKHASHES_PUBKEY = SYSVAR_RECENT_BLOCKHASHES_PUBKEY;
|
||
exports.SYSVAR_RENT_PUBKEY = SYSVAR_RENT_PUBKEY;
|
||
exports.SYSVAR_REWARDS_PUBKEY = SYSVAR_REWARDS_PUBKEY;
|
||
exports.SYSVAR_SLOT_HASHES_PUBKEY = SYSVAR_SLOT_HASHES_PUBKEY;
|
||
exports.SYSVAR_SLOT_HISTORY_PUBKEY = SYSVAR_SLOT_HISTORY_PUBKEY;
|
||
exports.SYSVAR_STAKE_HISTORY_PUBKEY = SYSVAR_STAKE_HISTORY_PUBKEY;
|
||
exports.Secp256k1Program = Secp256k1Program;
|
||
exports.SendTransactionError = SendTransactionError;
|
||
exports.SolanaJSONRPCError = SolanaJSONRPCError;
|
||
exports.SolanaJSONRPCErrorCode = SolanaJSONRPCErrorCode;
|
||
exports.StakeAuthorizationLayout = StakeAuthorizationLayout;
|
||
exports.StakeInstruction = StakeInstruction;
|
||
exports.StakeProgram = StakeProgram;
|
||
exports.Struct = Struct$1;
|
||
exports.SystemInstruction = SystemInstruction;
|
||
exports.SystemProgram = SystemProgram;
|
||
exports.Transaction = Transaction;
|
||
exports.TransactionExpiredBlockheightExceededError = TransactionExpiredBlockheightExceededError;
|
||
exports.TransactionExpiredNonceInvalidError = TransactionExpiredNonceInvalidError;
|
||
exports.TransactionExpiredTimeoutError = TransactionExpiredTimeoutError;
|
||
exports.TransactionInstruction = TransactionInstruction;
|
||
exports.TransactionMessage = TransactionMessage;
|
||
exports.TransactionStatus = TransactionStatus;
|
||
exports.VALIDATOR_INFO_KEY = VALIDATOR_INFO_KEY;
|
||
exports.VERSION_PREFIX_MASK = VERSION_PREFIX_MASK;
|
||
exports.VOTE_PROGRAM_ID = VOTE_PROGRAM_ID;
|
||
exports.ValidatorInfo = ValidatorInfo;
|
||
exports.VersionedMessage = VersionedMessage;
|
||
exports.VersionedTransaction = VersionedTransaction;
|
||
exports.VoteAccount = VoteAccount;
|
||
exports.VoteAuthorizationLayout = VoteAuthorizationLayout;
|
||
exports.VoteInit = VoteInit;
|
||
exports.VoteInstruction = VoteInstruction;
|
||
exports.VoteProgram = VoteProgram;
|
||
exports.clusterApiUrl = clusterApiUrl;
|
||
exports.sendAndConfirmRawTransaction = sendAndConfirmRawTransaction;
|
||
exports.sendAndConfirmTransaction = sendAndConfirmTransaction;
|
||
|
||
return exports;
|
||
|
||
})({});
|
||
//# sourceMappingURL=index.iife.js.map
|