diff --git a/packages/indexer-cli/src/actions.ts b/packages/indexer-cli/src/actions.ts index 7b5790271..c70e42d90 100644 --- a/packages/indexer-cli/src/actions.ts +++ b/packages/indexer-cli/src/actions.ts @@ -10,7 +10,7 @@ import { nullPassThrough, OrderDirection, parseBoolean, - validateNetworkIdentifier, + validateSupportedNetworkIdentifier, } from '@graphprotocol/indexer-common' import { validatePOI, validateRequiredParams } from './command-helpers' import gql from 'graphql-tag' @@ -215,7 +215,7 @@ const ACTION_PARAMS_PARSERS: Record any> type: x => validateActionType(x), status: x => validateActionStatus(x), reason: nullPassThrough, - protocolNetwork: x => validateNetworkIdentifier(x), + protocolNetwork: x => validateSupportedNetworkIdentifier(x), } /** diff --git a/packages/indexer-cli/src/command-helpers.ts b/packages/indexer-cli/src/command-helpers.ts index 2d8b1aef8..0b6d0a48b 100644 --- a/packages/indexer-cli/src/command-helpers.ts +++ b/packages/indexer-cli/src/command-helpers.ts @@ -36,7 +36,10 @@ export enum OutputFormat { import yaml from 'yaml' import { GluegunParameters, GluegunPrint } from 'gluegun' import { utils } from 'ethers' -import { validateNetworkIdentifier } from '@graphprotocol/indexer-common' +import { + validateNetworkIdentifier, + validateSupportedNetworkIdentifier, +} from '@graphprotocol/indexer-common' export const fixParameters = ( parameters: GluegunParameters, @@ -237,7 +240,7 @@ export function extractProtocolNetworkOption( const input = (network ?? n) as string try { - return validateNetworkIdentifier(input) + return validateSupportedNetworkIdentifier(input) } catch (parseError) { throw new Error(`Invalid value for the option '--network'. ${parseError}`) } @@ -251,3 +254,37 @@ export function requireProtocolNetworkOption(options: { [key: string]: any }): s } return protocolNetwork } + +export function extractSyncingNetworkOption( + options: { + [key: string]: any + }, + required = false, +): string | undefined { + const { s, syncing } = options + + // Tries to extract the --network option from Gluegun options. + // Throws if required is set to true and the option is not found. + if (!s && !syncing) { + if (required) { + throw new Error("The option '--syncing' is required") + } else { + return undefined + } + } + + // Check for invalid usage + const allowedUsages = + (s === undefined && typeof syncing === 'string') || + (syncing === undefined && typeof s === 'string') + if (!allowedUsages) { + throw new Error("Invalid usage of the option '--network'") + } + const input = (syncing ?? s) as string + + try { + return validateNetworkIdentifier(input) + } catch (parseError) { + throw new Error(`Invalid value for the option '--syncing'. ${parseError}`) + } +} diff --git a/packages/indexer-cli/src/commands/indexer/actions/get.ts b/packages/indexer-cli/src/commands/indexer/actions/get.ts index ce73d2740..1b8e0fb24 100644 --- a/packages/indexer-cli/src/commands/indexer/actions/get.ts +++ b/packages/indexer-cli/src/commands/indexer/actions/get.ts @@ -14,6 +14,7 @@ import { fixParameters, printObjectOrArray, extractProtocolNetworkOption, + extractSyncingNetworkOption, } from '../../../command-helpers' import { fetchAction, fetchActions } from '../../../actions' @@ -23,6 +24,7 @@ ${chalk.dim('Options:')} -h, --help Show usage information -n, --network Filter by protocol network (mainnet, arbitrum-one, sepolia, arbitrum-sepolia) + -s, --syncing Filter by the syncing network (see https://thegraph.com/networks/ for supported networks) --type allocate|unallocate|reallocate|collect Filter by type --status queued|approved|pending|success|failed|canceled Filter by status --source Fetch only actions queued by a specific source @@ -37,6 +39,7 @@ ${chalk.dim('Options:')} const actionFields: (keyof Action)[] = [ 'id', 'protocolNetwork', + 'syncingNetwork', 'type', 'deploymentID', 'allocationID', @@ -51,7 +54,7 @@ const actionFields: (keyof Action)[] = [ 'reason', ] -/// Validates input for the `--fieds` option. +/// Validates input for the `--fields` option. function validateFields(fields: string | undefined): (keyof Action)[] { if (fields === undefined) { return [] @@ -95,10 +98,8 @@ module.exports = { let orderByParam = ActionParams.ID let orderDirectionValue = OrderDirection.DESC const outputFormat = o || output || 'table' - - const protocolNetwork: string | undefined = extractProtocolNetworkOption( - parameters.options, - ) + let protocolNetwork: string | undefined = undefined + let syncingNetwork: string | undefined = undefined if (help || h) { inputSpinner.stopAndPersist({ symbol: '💁', text: HELP }) @@ -106,6 +107,10 @@ module.exports = { } let selectedFields: (keyof Action)[] try { + protocolNetwork = extractProtocolNetworkOption(parameters.options) + + syncingNetwork = extractSyncingNetworkOption(parameters.options) + if (!['json', 'yaml', 'table'].includes(outputFormat)) { throw Error( `Invalid output format "${outputFormat}" must be one of ['json', 'yaml' or 'table']`, @@ -195,6 +200,7 @@ module.exports = { source, reason, protocolNetwork, + syncingNetwork, }, first, orderByParam, @@ -213,9 +219,10 @@ module.exports = { ) // Format Actions 'protocolNetwork' field to display human-friendly chain aliases instead of CAIP2-IDs - actions.forEach( - action => (action.protocolNetwork = resolveChainAlias(action.protocolNetwork)), - ) + actions.forEach(action => { + action.protocolNetwork = resolveChainAlias(action.protocolNetwork) + action.syncingNetwork = resolveChainAlias(action.syncingNetwork) + }) printObjectOrArray(print, outputFormat, actions, displayProperties) } catch (error) { diff --git a/packages/indexer-cli/src/commands/indexer/allocations/close.ts b/packages/indexer-cli/src/commands/indexer/allocations/close.ts index 796493939..06b5a93d4 100644 --- a/packages/indexer-cli/src/commands/indexer/allocations/close.ts +++ b/packages/indexer-cli/src/commands/indexer/allocations/close.ts @@ -5,7 +5,7 @@ import { loadValidatedConfig } from '../../../config' import { createIndexerManagementClient } from '../../../client' import { closeAllocation } from '../../../allocations' import { validatePOI, printObjectOrArray } from '../../../command-helpers' -import { validateNetworkIdentifier } from '@graphprotocol/indexer-common' +import { validateSupportedNetworkIdentifier } from '@graphprotocol/indexer-common' const HELP = ` ${chalk.bold('graph indexer allocations close')} [options] @@ -63,7 +63,7 @@ module.exports = { return } else { try { - protocolNetwork = validateNetworkIdentifier(network) + protocolNetwork = validateSupportedNetworkIdentifier(network) } catch (error) { spinner.fail(`Invalid value for argument 'network': '${network}' `) process.exitCode = 1 diff --git a/packages/indexer-cli/src/commands/indexer/allocations/collect.ts b/packages/indexer-cli/src/commands/indexer/allocations/collect.ts index 4730988d2..6a95015dc 100644 --- a/packages/indexer-cli/src/commands/indexer/allocations/collect.ts +++ b/packages/indexer-cli/src/commands/indexer/allocations/collect.ts @@ -4,7 +4,7 @@ import chalk from 'chalk' import { loadValidatedConfig } from '../../../config' import { createIndexerManagementClient } from '../../../client' import { submitCollectReceiptsJob } from '../../../allocations' -import { validateNetworkIdentifier } from '@graphprotocol/indexer-common' +import { validateSupportedNetworkIdentifier } from '@graphprotocol/indexer-common' const HELP = ` ${chalk.bold('graph indexer allocations collect')} [options] @@ -60,7 +60,7 @@ module.exports = { return } else { try { - protocolNetwork = validateNetworkIdentifier(network) + protocolNetwork = validateSupportedNetworkIdentifier(network) } catch (error) { spinner.fail(`Invalid value for argument 'network': '${network}' `) process.exitCode = 1 diff --git a/packages/indexer-cli/src/commands/indexer/allocations/create.ts b/packages/indexer-cli/src/commands/indexer/allocations/create.ts index 6986bfbe2..659ce2393 100644 --- a/packages/indexer-cli/src/commands/indexer/allocations/create.ts +++ b/packages/indexer-cli/src/commands/indexer/allocations/create.ts @@ -8,7 +8,7 @@ import { createAllocation } from '../../../allocations' import { processIdentifier, SubgraphIdentifierType, - validateNetworkIdentifier, + validateSupportedNetworkIdentifier, } from '@graphprotocol/indexer-common' import { printObjectOrArray } from '../../../command-helpers' @@ -64,7 +64,7 @@ module.exports = { // This nested try block is necessary to complement the parsing error with the 'network' field. try { - validateNetworkIdentifier(protocolNetwork) + validateSupportedNetworkIdentifier(protocolNetwork) } catch (parsingError) { throw new Error(`Invalid 'network' provided. ${parsingError}`) } diff --git a/packages/indexer-common/src/parsers/basic-types.ts b/packages/indexer-common/src/parsers/basic-types.ts index 68b945b5e..15b43e0c2 100644 --- a/packages/indexer-common/src/parsers/basic-types.ts +++ b/packages/indexer-common/src/parsers/basic-types.ts @@ -20,14 +20,18 @@ export const url = P.regex(/^https?:.*/) // Source: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md export const caip2IdRegex = /^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}$/ -const caip2Id = P.regex(caip2IdRegex).chain(validateNetworkIdentifier) +const caip2Id = P.regex(caip2IdRegex) +const supportedCaip2Id = P.regex(caip2IdRegex).chain(validateNetworkIdentifier) // A valid human friendly network name / alias. -const networkAlias = P.regex(/[a-z-]+/).chain(validateNetworkIdentifier) +const networkAlias = P.regex(/[a-z-]+/) +const supportedNetworkAlias = P.regex(/[a-z-]+/).chain(validateNetworkIdentifier) // Either a CAIP-2 or an alias. export const networkIdentifier = P.alt(caip2Id, networkAlias) +export const supportedNetworkIdentifier = P.alt(supportedCaip2Id, supportedNetworkAlias) + // A basic `base58btc` parser for CIDv0 (IPFS Hashes) export const base58 = P.regex(/^Qm[1-9A-HJ-NP-Za-km-z]{44,}$/).desc( 'An IPFS Content Identifer (Qm...)', diff --git a/packages/indexer-common/src/parsers/validators.ts b/packages/indexer-common/src/parsers/validators.ts index cf81e70a2..718fd0b58 100644 --- a/packages/indexer-common/src/parsers/validators.ts +++ b/packages/indexer-common/src/parsers/validators.ts @@ -3,7 +3,7 @@ import P from 'parsimmon' -import { networkIdentifier, base58 } from './basic-types' +import { base58, networkIdentifier, supportedNetworkIdentifier } from './basic-types' export { caip2IdRegex } from './basic-types' // Generic function that takes a parser of type T and attempts to parse it from a string. If it @@ -21,10 +21,15 @@ function parse(parser: P.Parser, input: string): T { `Failed to parse "${input}". Expected: ${expected}. Parsed up to: "${parsed}". Remaining: "${remaining}"`, ) } + export function validateNetworkIdentifier(input: string): string { return parse(networkIdentifier, input) } +export function validateSupportedNetworkIdentifier(input: string): string { + return parse(supportedNetworkIdentifier, input) +} + export function validateIpfsHash(input: string): string { return parse(base58, input) }