UNPKG

ccxt

Version:

A cryptocurrency trading API with more than 100 exchanges in JavaScript / TypeScript / Python / C# / PHP / Go

633 lines (626 loc) • 23.1 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); require('./utils/base58.js'); var errors = require('./utils/errors.js'); var properties = require('./utils/properties.js'); require('./utils/fixednumber.js'); var maths = require('./utils/maths.js'); require('./utils/utf8.js'); require('../../base/functions/platform.js'); require('../../base/functions/encode.js'); require('../../base/functions/crypto.js'); require('../../base/functions/io.js'); require('@noble/hashes/sha3.js'); require('@noble/hashes/sha2.js'); // ---------------------------------------------------------------------------- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code // EDIT THE CORRESPONDENT .ts FILE INSTEAD /** * A fragment is a single item from an ABI, which may represent any of: * * - [Functions](FunctionFragment) * - [Events](EventFragment) * - [Constructors](ConstructorFragment) * - Custom [Errors](ErrorFragment) * - [Fallback or Receive](FallbackFragment) functions * * @_subsection api/abi/abi-coder:Fragments [about-fragments] */ var _a; // [ "a", "b" ] => { "a": 1, "b": 1 } function setify(items) { const result = new Set(); items.forEach((k) => result.add(k)); return Object.freeze(result); } const _kwVisibDeploy = "external public payable"; setify(_kwVisibDeploy.split(" ")); // Visibility Keywords const _kwVisib = "constant external internal payable private public pure view"; setify(_kwVisib.split(" ")); const _kwTypes = "constructor error event fallback function receive struct"; setify(_kwTypes.split(" ")); const _kwModifiers = "calldata memory storage payable indexed"; const KwModifiers = setify(_kwModifiers.split(" ")); const _kwOther = "tuple returns"; // All Keywords const _keywords = [_kwTypes, _kwModifiers, _kwOther, _kwVisib].join(" "); const Keywords = setify(_keywords.split(" ")); // Single character tokens const SimpleTokens = { "(": "OPEN_PAREN", ")": "CLOSE_PAREN", "[": "OPEN_BRACKET", "]": "CLOSE_BRACKET", ",": "COMMA", "@": "AT" }; // Parser regexes to consume the next token const regexWhitespacePrefix = new RegExp("^(\\s*)"); const regexNumberPrefix = new RegExp("^([0-9]+)"); const regexIdPrefix = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)"); // Parser regexs to check validity const regexId = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)$"); const regexType = new RegExp("^(address|bool|bytes([0-9]*)|string|u?int([0-9]*))$"); class TokenString { #offset; #tokens; get offset() { return this.#offset; } get length() { return this.#tokens.length - this.#offset; } constructor(tokens) { this.#offset = 0; this.#tokens = tokens.slice(); } clone() { return new _a(this.#tokens); } reset() { this.#offset = 0; } #subTokenString(from = 0, to = 0) { return new _a(this.#tokens.slice(from, to).map((t) => { return Object.freeze(Object.assign({}, t, { match: (t.match - from), linkBack: (t.linkBack - from), linkNext: (t.linkNext - from), })); })); } // Pops and returns the value of the next token, if it is a keyword in allowed; throws if out of tokens popKeyword(allowed) { const top = this.peek(); if (top.type !== "KEYWORD" || !allowed.has(top.text)) { throw new Error(`expected keyword ${top.text}`); } return this.pop().text; } // Pops and returns the value of the next token if it is `type`; throws if out of tokens popType(type) { if (this.peek().type !== type) { throw new Error(`expected ${type}; got ${JSON.stringify(this.peek())}`); } return this.pop().text; } // Pops and returns a "(" TOKENS ")" popParen() { const top = this.peek(); if (top.type !== "OPEN_PAREN") { throw new Error("bad start"); } const result = this.#subTokenString(this.#offset + 1, top.match + 1); this.#offset = top.match + 1; return result; } // Pops and returns the items within "(" ITEM1 "," ITEM2 "," ... ")" popParams() { const top = this.peek(); if (top.type !== "OPEN_PAREN") { throw new Error("bad start"); } const result = []; while (this.#offset < top.match - 1) { const link = this.peek().linkNext; result.push(this.#subTokenString(this.#offset + 1, link)); this.#offset = link; } this.#offset = top.match + 1; return result; } // Returns the top Token, throwing if out of tokens peek() { if (this.#offset >= this.#tokens.length) { throw new Error("out-of-bounds"); } return this.#tokens[this.#offset]; } // Returns the next value, if it is a keyword in `allowed` peekKeyword(allowed) { const top = this.peekType("KEYWORD"); return (top != null && allowed.has(top)) ? top : null; } // Returns the value of the next token if it is `type` peekType(type) { if (this.length === 0) { return null; } const top = this.peek(); return (top.type === type) ? top.text : null; } // Returns the next token; throws if out of tokens pop() { const result = this.peek(); this.#offset++; return result; } toString() { const tokens = []; for (let i = this.#offset; i < this.#tokens.length; i++) { const token = this.#tokens[i]; tokens.push(`${token.type}:${token.text}`); } return `<TokenString ${tokens.join(" ")}>`; } } _a = TokenString; function lex(text) { const tokens = []; const throwError = (message) => { const token = (offset < text.length) ? JSON.stringify(text[offset]) : "$EOI"; throw new Error(`invalid token ${token} at ${offset}: ${message}`); }; let brackets = []; let commas = []; let offset = 0; while (offset < text.length) { // Strip off any leading whitespace let cur = text.substring(offset); let match = cur.match(regexWhitespacePrefix); if (match) { offset += match[1].length; cur = text.substring(offset); } const token = { depth: brackets.length, linkBack: -1, linkNext: -1, match: -1, type: "", text: "", offset, value: -1 }; tokens.push(token); let type = (SimpleTokens[cur[0]] || ""); if (type) { token.type = type; token.text = cur[0]; offset++; if (type === "OPEN_PAREN") { brackets.push(tokens.length - 1); commas.push(tokens.length - 1); } else if (type == "CLOSE_PAREN") { if (brackets.length === 0) { throwError("no matching open bracket"); } token.match = brackets.pop(); (tokens[token.match]).match = tokens.length - 1; token.depth--; token.linkBack = commas.pop(); (tokens[token.linkBack]).linkNext = tokens.length - 1; } else if (type === "COMMA") { token.linkBack = commas.pop(); (tokens[token.linkBack]).linkNext = tokens.length - 1; commas.push(tokens.length - 1); } else if (type === "OPEN_BRACKET") { token.type = "BRACKET"; } else if (type === "CLOSE_BRACKET") { // Remove the CLOSE_BRACKET let suffix = tokens.pop().text; if (tokens.length > 0 && tokens[tokens.length - 1].type === "NUMBER") { const value = tokens.pop().text; suffix = value + suffix; (tokens[tokens.length - 1]).value = maths.getNumber(value); } if (tokens.length === 0 || tokens[tokens.length - 1].type !== "BRACKET") { throw new Error("missing opening bracket"); } (tokens[tokens.length - 1]).text += suffix; } continue; } match = cur.match(regexIdPrefix); if (match) { token.text = match[1]; offset += token.text.length; if (Keywords.has(token.text)) { token.type = "KEYWORD"; continue; } if (token.text.match(regexType)) { token.type = "TYPE"; continue; } token.type = "ID"; continue; } match = cur.match(regexNumberPrefix); if (match) { token.text = match[1]; token.type = "NUMBER"; offset += token.text.length; continue; } throw new Error(`unexpected token ${JSON.stringify(cur[0])} at position ${offset}`); } return new TokenString(tokens.map((t) => Object.freeze(t))); } // ...all keywords matching allowed, returning the keywords function consumeKeywords(tokens, allowed) { const keywords = new Set(); while (true) { const keyword = tokens.peekType("KEYWORD"); if (keyword == null || (allowed && !allowed.has(keyword))) { break; } tokens.pop(); if (keywords.has(keyword)) { throw new Error(`duplicate keywords: ${JSON.stringify(keyword)}`); } keywords.add(keyword); } return Object.freeze(keywords); } const regexArrayType = new RegExp(/^(.*)\[([0-9]*)\]$/); function verifyBasicType(type) { const match = type.match(regexType); errors.assertArgument(match, "invalid type", "type", type); if (type === "uint") { return "uint256"; } if (type === "int") { return "int256"; } if (match[2]) { // bytesXX const length = parseInt(match[2]); errors.assertArgument(length !== 0 && length <= 32, "invalid bytes length", "type", type); } else if (match[3]) { // intXX or uintXX const size = parseInt(match[3]); errors.assertArgument(size !== 0 && size <= 256 && (size % 8) === 0, "invalid numeric width", "type", type); } return type; } // Make the Fragment constructors effectively private const _guard = {}; const internal = Symbol.for("_ethers_internal"); const ParamTypeInternal = "_ParamTypeInternal"; /** * Each input and output of a [[Fragment]] is an Array of **ParamType**. */ class ParamType { /** * @private */ constructor(guard, name, type, baseType, indexed, components, arrayLength, arrayChildren) { errors.assertPrivate(guard, _guard, "ParamType"); Object.defineProperty(this, internal, { value: ParamTypeInternal }); if (components) { components = Object.freeze(components.slice()); } if (baseType === "array") { if (arrayLength == null || arrayChildren == null) { throw new Error(""); } } else if (arrayLength != null || arrayChildren != null) { throw new Error(""); } if (baseType === "tuple") { if (components == null) { throw new Error(""); } } else if (components != null) { throw new Error(""); } properties.defineProperties(this, { name, type, baseType, indexed, components, arrayLength, arrayChildren }); } /** * Return a string representation of this type. * * For example, * * ``sighash" => "(uint256,address)"`` * * ``"minimal" => "tuple(uint256,address) indexed"`` * * ``"full" => "tuple(uint256 foo, address bar) indexed baz"`` */ format(format) { if (format == null) { format = "sighash"; } if (format === "json") { const name = this.name || ""; if (this.isArray()) { if (this.arrayChildren == null) { throw new Error("missing array children"); } const result = JSON.parse(this.arrayChildren.format("json")); result.name = name; const arrayLength = this.arrayLength; result.type += `[${((arrayLength == null || arrayLength < 0) ? "" : String(arrayLength))}]`; return JSON.stringify(result); } const result = { type: ((this.baseType === "tuple") ? "tuple" : this.type), name }; if (typeof (this.indexed) === "boolean") { result.indexed = this.indexed; } if (this.isTuple()) { if (this.components == null) { throw new Error("missing components"); } result.components = this.components.map((c) => JSON.parse(c.format(format))); } return JSON.stringify(result); } let result = ""; // Array if (this.isArray()) { if (this.arrayChildren == null) { throw new Error("missing array children"); } result += this.arrayChildren.format(format); const arrayLength = this.arrayLength; result += `[${((arrayLength == null || arrayLength < 0) ? "" : String(arrayLength))}]`; } else { if (this.isTuple()) { if (this.components == null) { throw new Error("missing components"); } result += "(" + this.components.map((comp) => comp.format(format)).join((format === "full") ? ", " : ",") + ")"; } else { result += this.type; } } if (format !== "sighash") { if (this.indexed === true) { result += " indexed"; } if (format === "full" && this.name) { result += " " + this.name; } } return result; } /** * Returns true if %%this%% is an Array type. * * This provides a type gaurd ensuring that [[arrayChildren]] * and [[arrayLength]] are non-null. */ isArray() { return (this.baseType === "array"); } /** * Returns true if %%this%% is a Tuple type. * * This provides a type gaurd ensuring that [[components]] * is non-null. */ isTuple() { return (this.baseType === "tuple"); } /** * Returns true if %%this%% is an Indexable type. * * This provides a type gaurd ensuring that [[indexed]] * is non-null. */ isIndexable() { return (this.indexed != null); } /** * Walks the **ParamType** with %%value%%, calling %%process%% * on each type, destructing the %%value%% recursively. */ walk(value, process) { if (this.isArray()) { if (!Array.isArray(value)) { throw new Error("invalid array value"); } if (this.arrayLength !== -1 && value.length !== this.arrayLength) { throw new Error("array is wrong length"); } const arrayChildren = this.arrayChildren; if (arrayChildren == null) { throw new Error("missing array children"); } return value.map((v) => (arrayChildren.walk(v, process))); } if (this.isTuple()) { if (!Array.isArray(value)) { throw new Error("invalid tuple value"); } const components = this.components; if (components == null) { throw new Error("missing components"); } if (value.length !== components.length) { throw new Error("array is wrong length"); } return value.map((v, i) => (components[i].walk(v, process))); } return process(this.type, value); } #walkAsync(promises, value, process, setValue) { if (this.isArray()) { if (!Array.isArray(value)) { throw new Error("invalid array value"); } if (this.arrayLength !== -1 && value.length !== this.arrayLength) { throw new Error("array is wrong length"); } const childType = this.arrayChildren; if (childType == null) { throw new Error("missing array children"); } const result = value.slice(); result.forEach((value, index) => { childType.#walkAsync(promises, value, process, (value) => { result[index] = value; }); }); setValue(result); return; } if (this.isTuple()) { const components = this.components; if (components == null) { throw new Error("missing components"); } // Convert the object into an array let result; if (Array.isArray(value)) { result = value.slice(); } else { if (value == null || typeof (value) !== "object") { throw new Error("invalid tuple value"); } result = components.map((param) => { if (!param.name) { throw new Error("cannot use object value with unnamed components"); } if (!(param.name in value)) { throw new Error(`missing value for component ${param.name}`); } return value[param.name]; }); } if (result.length !== components.length) { throw new Error("array is wrong length"); } result.forEach((value, index) => { components[index].#walkAsync(promises, value, process, (value) => { result[index] = value; }); }); setValue(result); return; } const result = process(this.type, value); if (result.then) { promises.push((async function () { setValue(await result); })()); } else { setValue(result); } } /** * Walks the **ParamType** with %%value%%, asynchronously calling * %%process%% on each type, destructing the %%value%% recursively. * * This can be used to resolve ENS naes by walking and resolving each * ``"address"`` type. */ async walkAsync(value, process) { const promises = []; const result = [value]; this.#walkAsync(promises, value, process, (value) => { result[0] = value; }); if (promises.length) { await Promise.all(promises); } return result[0]; } /** * Creates a new **ParamType** for %%obj%%. * * If %%allowIndexed%% then the ``indexed`` keyword is permitted, * otherwise the ``indexed`` keyword will throw an error. */ static from(obj, allowIndexed) { if (ParamType.isParamType(obj)) { return obj; } if (typeof (obj) === "string") { try { return ParamType.from(lex(obj), allowIndexed); } catch (error) { errors.assertArgument(false, "invalid param type", "obj", obj); } } else if (obj instanceof TokenString) { let type = "", baseType = ""; let comps = null; if (consumeKeywords(obj, setify(["tuple"])).has("tuple") || obj.peekType("OPEN_PAREN")) { // Tuple baseType = "tuple"; comps = obj.popParams().map((t) => ParamType.from(t)); type = `tuple(${comps.map((c) => c.format()).join(",")})`; } else { // Normal type = verifyBasicType(obj.popType("TYPE")); baseType = type; } // Check for Array let arrayChildren = null; let arrayLength = null; while (obj.length && obj.peekType("BRACKET")) { const bracket = obj.pop(); //arrays[i]; arrayChildren = new ParamType(_guard, "", type, baseType, null, comps, arrayLength, arrayChildren); arrayLength = bracket.value; type += bracket.text; baseType = "array"; comps = null; } let indexed = null; const keywords = consumeKeywords(obj, KwModifiers); if (keywords.has("indexed")) { if (!allowIndexed) { throw new Error(""); } indexed = true; } const name = (obj.peekType("ID") ? obj.pop().text : ""); if (obj.length) { throw new Error("leftover tokens"); } return new ParamType(_guard, name, type, baseType, indexed, comps, arrayLength, arrayChildren); } const name = obj.name; errors.assertArgument(!name || (typeof (name) === "string" && name.match(regexId)), "invalid name", "obj.name", name); let indexed = obj.indexed; if (indexed != null) { errors.assertArgument(allowIndexed, "parameter cannot be indexed", "obj.indexed", obj.indexed); indexed = !!indexed; } let type = obj.type; let arrayMatch = type.match(regexArrayType); if (arrayMatch) { const arrayLength = parseInt(arrayMatch[2] || "-1"); const arrayChildren = ParamType.from({ type: arrayMatch[1], components: obj.components }); return new ParamType(_guard, name || "", type, "array", indexed, null, arrayLength, arrayChildren); } if (type === "tuple" || type.startsWith("tuple(" /* fix: ) */) || type.startsWith("(" /* fix: ) */)) { const comps = (obj.components != null) ? obj.components.map((c) => ParamType.from(c)) : null; const tuple = new ParamType(_guard, name || "", type, "tuple", indexed, comps, null, null); // @TODO: use lexer to validate and normalize type return tuple; } type = verifyBasicType(obj.type); return new ParamType(_guard, name || "", type, type, indexed, null, null, null); } /** * Returns true if %%value%% is a **ParamType**. */ static isParamType(value) { return (value && value[internal] === ParamTypeInternal); } } exports.ParamType = ParamType;