UNPKG

@ganache/ethereum-options

Version:
276 lines (261 loc) 11.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ForkOptions = exports.KNOWN_NETWORKS = void 0; const helpers_1 = require("./helpers"); const ethereum_utils_1 = require("@ganache/ethereum-utils"); const url_1 = require("url"); const version = process.env.VERSION || "DEV"; // we aren't going to treat block numbers as a bigint, so we don't want to // accept block numbers we can't add to const MAX_BLOCK_NUMBER = Math.floor(Number.MAX_SAFE_INTEGER / 2); exports.KNOWN_NETWORKS = [ "mainnet", "goerli", "görli", "sepolia" ]; const reColonSplit = /:\s?(?:.+)/; function coerceHeaders(headers, input) { // split *1* time on the first colon, this also ignores leading whitespace // from the value per RFC7230 const [name, value] = input.split(reColonSplit); headers.push({ name, value }); return headers; } const ALLOWED_PROTOCOLS = ["ws:", "wss:", "http:", "https:"]; const arrayToOxfordList = (arr, conjunction = "and") => { const last = arr.pop(); switch (arr.length) { case 0: return ""; case 1: return last; case 2: return arr[0] + ` ${conjunction} ` + last; default: return arr.join(", ") + `, ${conjunction} ` + last; } }; exports.ForkOptions = { // url's definition _must_ come before blockNumber, username, and password // as the defaults are processed in order, and they rely on the `fork.url` url: { normalize: rawInput => { // because `url` is an alias of `fork`, along with `provider` and // `network` the runtime type isn't always going to be `"string"` if (typeof rawInput !== "string" || exports.KNOWN_NETWORKS.includes(rawInput)) { // if the string matches a network name ignore it return; } let url = new url_1.URL(rawInput); const path = url.pathname + url.search; const lastIndex = path.lastIndexOf("@"); // pull the blockNumber out of the URL if (lastIndex !== -1) { // remove everything after the last @ url = new url_1.URL(path.substr(0, lastIndex), url); const blockNumber = path.substr(lastIndex + 1); if (blockNumber && blockNumber !== ethereum_utils_1.Tag.latest) { // don't use parseInt because strings like `"123abc"` parse // to `123`, and there is probably an error on the user's side we'd // want to uncover. const asNum = blockNumber - 0; // don't allow invalid, negative, or decimals if (isNaN(asNum) || asNum < 0 || (asNum | 0) !== asNum || asNum > MAX_BLOCK_NUMBER) { console.warn(`Ignoring invalid block number in fork url: "${blockNumber}". Block number must be an integer from [0 - ${MAX_BLOCK_NUMBER}].`); } else { url._blockNumber = asNum; } } if (!ALLOWED_PROTOCOLS.includes(url.protocol)) { throw new Error(`Invalid protocol for fork url: ${url.protocol}. Supported protocols are: ${arrayToOxfordList(ALLOWED_PROTOCOLS)}.`); } } return url; }, cliDescription: `Fork from another currently running Ethereum client at a given block. Input should be the URL of the node, e.g. \`"http://localhost:1337"\`. You can optionally specify the block to fork from using an @ sign: \`"http://localhost:1337@8675309"\`. You can specify Basic Authentication credentials in the URL as well. e.g., \`"wss://user:password@example.com/"\`. If you need to use an Infura Project Secret, you would use it like this: \`"wss://:{YOUR-PROJECT-SECRET}@mainnet.infura.com/..."\` Alternatively, you can use the \`fork.username\` and \`fork.password\` options.`, legacyName: "fork", cliAliases: ["f", "fork"], conflicts: ["provider", "network"] }, provider: { normalize: rawInput => { // because `provider` is an alias of `fork`, along with `network` and // `url` the runtime type isn't always going to match the TypeScript type. // if rawInput is a string it will be handled by the `url` or `network` // handlers. if (typeof rawInput === "string" || // like `--fork http://url` (url shorthand) (typeof rawInput === "object" && (typeof rawInput.url === "string" || // like `--fork.url http://url` typeof rawInput.url === "boolean" || // like `--fork` (implied "mainnet" network shorthand) typeof rawInput.network === "string" || // like `--fork.network mainnet` typeof rawInput.network === "boolean")) // like `--fork.network true` ) { return; } else { return rawInput; } }, cliDescription: "Specify an EIP-1193 provider to use instead of a url.", disableInCLI: true, legacyName: "fork", conflicts: ["url", "network"] }, network: { normalize: rawInput => { // because `network` is an alias of `fork`, along with `provider` and // `url` the runtime type isn't always going to be `"string"` if (typeof rawInput === "string" && exports.KNOWN_NETWORKS.includes(rawInput)) return rawInput; if ( // handle `ganache --fork` case, which gets weird because both url // and network can use the `--fork` flag (the `url` handler ignores // non-strings, like `true` and strings that match our known networks) typeof rawInput === "object" && "url" in rawInput) { const { url } = rawInput; if (url === true) { return "mainnet"; } else if (exports.KNOWN_NETWORKS.includes(url)) { return rawInput.url; } } }, cliDescription: `A network name to fork from; uses Infura's archive nodes. Use the shorthand command \`ganache --fork\` to automatically fork from Mainnet at the latest block. `, cliChoices: exports.KNOWN_NETWORKS, legacyName: "fork", conflicts: ["url", "provider"] }, blockNumber: { normalize: helpers_1.normalize, cliDescription: "Block number the provider should fork from.", legacyName: "fork_block_number", default: ({ url, provider, network }) => { if (url) { // use the url's _blockNumber, if present, otherwise use "latest" if (url._blockNumber) { return url._blockNumber; } else { return ethereum_utils_1.Tag.latest; } } else if (provider || network) { return ethereum_utils_1.Tag.latest; } else { return; } }, defaultDescription: `Latest block number` //implies: ["url"] }, preLatestConfirmations: { normalize: helpers_1.normalize, cliDescription: 'When the `fork.blockNumber` is set to "latest" (default), the number of blocks before the remote node\'s "latest" block to fork from.', default: () => 5, defaultDescription: "5", cliType: "number" }, username: { normalize: helpers_1.normalize, cliDescription: `Username to use for Basic Authentication. Does not require setting \`fork.password\`. When combined with \`fork.password\`, is shorthand for \`fork: { headers: { "Authorization": "Basic {ENCODED-BASIC-HEADER}" } }\` If the \`fork.headers\` option specifies an "Authorization" header, it will be be inserted _after_ this Basic token.`, default: ({ url }) => { // use the url's username, if present if (url) { if (url.username) { return url.username; } } }, defaultDescription: "" //implies: ["url"] }, password: { normalize: helpers_1.normalize, cliDescription: `Password to use for Basic Authentication. Does not require setting \`fork.username\`. When combined with \`fork.username\`, is shorthand for \`fork: { headers: { "Authorization": "Basic {ENCODED-BASIC-HEADER}" } }\` If the \`fork.headers\` option specifies an "Authorization" header, it will be be inserted _after_ this Basic token.`, default: ({ url }) => { // use the url's password, if present if (url) { if (url.password) { return url.password; } } }, defaultDescription: "" //implies: ["url"] }, jwt: { normalize: helpers_1.normalize, cliDescription: `_Encoded_ JSON Web Token (JWT) used for authenticating to some servers. Shorthand for \`fork: { headers: { "Authorization": "Bearer {YOUR-ENCODED-JWT}" } }\` If the \`fork.headers\` option specifies an "Authorization" header, it will be be inserted _after_ the JWT Bearer token.` //implies: ["url"] }, userAgent: { normalize: helpers_1.normalize, cliDescription: `The User-Agent header sent to the fork on each request. Sent as Api-User-Agent when used in the browser. Will be overridden by a \`"User-Agent"\` defined in the \`fork.headers\` option, if provided.`, default: () => { return `Ganache/${version} (https://www.trufflesuite.com/ganache; ganache<at>trufflesuite.com)`; } // implies: ["url"] }, origin: { normalize: helpers_1.normalize, cliDescription: `The Origin header sent to the fork on each request. Ignored in the browser. Will be overridden by an \`"Origin"\` value defined in the \`fork.headers\` option, if provided.` //implies: ["url"] }, headers: { normalize: helpers_1.normalize, cliDescription: `Headers to supply on each request to the forked provider. Headers set here override headers set by other options, unless otherwise specified. Defaults to: \`["User-Agent: Ganache/VERSION (https://www.trufflesuite.com/ganache; ganache<at>trufflesuite.com)"]\``, cliType: "array:string", implies: ["url"], cliCoerce: rawInput => rawInput.reduce(coerceHeaders, []) }, requestsPerSecond: { normalize(rawValue) { if (rawValue < 0) { throw new Error(`fork.requestsPerSecond is invalid: "${rawValue}"; must be a positive number`); } return rawValue; }, default: () => 0, cliDescription: "Restrict the number of requests per second sent to the fork provider. `0` means no limit is applied.", cliType: "number" //implies: ["url"] }, disableCache: { normalize: helpers_1.normalize, default: () => false, cliDescription: "Disables caching of all forking requests.", cliType: "boolean" }, deleteCache: { normalize: helpers_1.normalize, default: () => false, cliDescription: "Deletes the persistent cache before starting.", cliType: "boolean" } }; //# sourceMappingURL=fork-options.js.map