From db9f733e4f4b82f9fd85d2a1285d95ff22519209 Mon Sep 17 00:00:00 2001 From: Trevor Porter Date: Mon, 3 Jun 2024 15:48:33 +0100 Subject: [PATCH] fix: use secret RPC urls in infra, apply environment-specific registry overrides (#3875) ### Description A while back, it seems secret RPC URLs stopped being used by monorepo services (see https://github.com/hyperlane-xyz/hyperlane-monorepo/pull/3179/files#diff-ba3b7bea2b5c046acd88d25ed382df875b49d77e061f2ef8347ffcc741c0353eR34). This adds them back. Some things to note on the approach: - Sadly, due to the way some of the infra config generation works, we're forced to use synchronous interfaces for getting chain metadata in a bunch of places. This is why `getRegistry` returns a `FileSystemRegistry`, which is a `SynchronousRegistry`. - Applying secrets / overrides requires us to do things async for two reasons -- one is just that fetching from GCP secrets is an async operation, the other is that a `MergedRegistry` is not a `SynchronousRegistry`. The approach I've taken is that there are two ways of getting a registry - using `getRegistry` will give the synchronous version that can continue to be used by our sync config generation, but it won't have any environment-specific overrides (tx overrides or secrets). To get an async registry with environment-specific overrides, the `getRegistry` function on the EnvironmentConfig is used. - Overrides are now more succinct as the merging happens later in the pipeline ### Drive-by changes - Started moving away from using the gcloud CLI under the hood for GCP operations and toward using the GCP secret SDK - Updated the mainnet3 key funder to fix an incident, but will follow up with a fresh deploy once this is mergd ### Related issues - These are the code changes for https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3774, but I'll follow up with fresh deploys for the monorepo services ### Backward compatibility ### Testing --------- Co-authored-by: Connor McEwen Co-authored-by: Yorke Rhodes Co-authored-by: J M Rossy --- rust/config/mainnet_config.json | 49 ++- .../config/environments/mainnet3/chains.ts | 28 +- .../config/environments/mainnet3/funding.ts | 2 +- .../config/environments/mainnet3/index.ts | 48 +-- .../infra/config/environments/test/index.ts | 9 +- .../config/environments/testnet4/chains.ts | 15 +- .../config/environments/testnet4/index.ts | 33 +- typescript/infra/config/registry.ts | 39 ++- typescript/infra/package.json | 1 + typescript/infra/scripts/agent-utils.ts | 58 ++-- .../scripts/agents/update-agent-config.ts | 8 +- typescript/infra/scripts/check-rpc-urls.ts | 10 +- .../funding/fund-keys-from-deployer.ts | 4 +- typescript/infra/scripts/helloworld/kathy.ts | 12 +- .../infra/scripts/print-chain-metadatas.ts | 12 +- typescript/infra/scripts/print-gas-prices.ts | 88 +++-- .../infra/scripts/print-token-prices.ts | 12 +- typescript/infra/src/agents/index.ts | 8 +- typescript/infra/src/config/chain.ts | 81 ++++- typescript/infra/src/config/environment.ts | 8 +- typescript/infra/src/utils/gcloud.ts | 30 +- typescript/infra/src/utils/utils.ts | 4 + typescript/sdk/src/metadata/agentConfig.ts | 10 + yarn.lock | 315 +++++++++++++++++- 24 files changed, 722 insertions(+), 162 deletions(-) diff --git a/rust/config/mainnet_config.json b/rust/config/mainnet_config.json index 25bfbb895..00ebf00f0 100644 --- a/rust/config/mainnet_config.json +++ b/rust/config/mainnet_config.json @@ -634,13 +634,19 @@ }, "injective": { "bech32Prefix": "inj", + "blockExplorers": [ + ], "blocks": { + "confirmations": 1, + "estimateBlockTime": 1, "reorgPeriod": 10 }, "canonicalAsset": "inj", "chainId": "injective-1", "contractAddressBytes": 20, - "domainId": "6909546", + "displayName": "Injective", + "domainId": 6909546, + "gasCurrencyCoinGeckoId": "injective-protocol", "gasPrice": { "amount": "700000000", "denom": "inj" @@ -658,12 +664,24 @@ "mailbox": "0x0f7fb53961d70687e352aa55cb329ca76edc0c19", "merkleTreeHook": "0x568ad3638447f07def384969f4ea39fae3802962", "name": "injective", + "nativeToken": { + "decimals": 18, + "denom": "inj", + "name": "Injective", + "symbol": "INJ" + }, "protocol": "cosmos", + "restUrls": [ + { + "http": "https://sentry.lcd.injective.network:443" + } + ], "rpcUrls": [ { - "http": "https://injective-rpc.polkachu.com" + "http": "https://sentry.tm.injective.network:443" } ], + "slip44": 118, "validatorAnnounce": "0x1fb225b2fcfbe75e614a1d627de97ff372242eed" }, "mantapacific": { @@ -837,13 +855,25 @@ }, "neutron": { "bech32Prefix": "neutron", + "blockExplorers": [ + { + "apiUrl": "https://www.mintscan.io/neutron", + "family": "other", + "name": "Mintscan", + "url": "https://www.mintscan.io/neutron" + } + ], "blocks": { + "confirmations": 1, + "estimateBlockTime": 3, "reorgPeriod": 1 }, "canonicalAsset": "untrn", "chainId": "neutron-1", "contractAddressBytes": 32, - "domainId": "1853125230", + "displayName": "Neutron", + "domainId": 1853125230, + "gasCurrencyCoinGeckoId": "neutron-3", "gasPrice": { "amount": "0.0053", "denom": "untrn" @@ -858,10 +888,22 @@ "from": 4000000 }, "interchainGasPaymaster": "0x504ee9ac43ec5814e00c7d21869a90ec52becb489636bdf893b7df9d606b5d67", + "isTestnet": false, "mailbox": "0x848426d50eb2104d5c6381ec63757930b1c14659c40db8b8081e516e7c5238fc", "merkleTreeHook": "0xcd30a0001cc1f436c41ef764a712ebabc5a144140e3fd03eafe64a9a24e4e27c", "name": "neutron", + "nativeToken": { + "decimals": 6, + "denom": "untrn", + "name": "Neutron", + "symbol": "NTRN" + }, "protocol": "cosmos", + "restUrls": [ + { + "http": "https://rest-lb.neutron.org" + } + ], "rpcUrls": [ { "http": "https://rpc-kralum.neutron-1.neutron.org" @@ -872,6 +914,7 @@ "prefix": "neutron", "type": "cosmosKey" }, + "slip44": 118, "validatorAnnounce": "0xf3aa0d652226e21ae35cd9035c492ae41725edc9036edf0d6a48701b153b90a0" }, "optimism": { diff --git a/typescript/infra/config/environments/mainnet3/chains.ts b/typescript/infra/config/environments/mainnet3/chains.ts index 0e5d4144e..c511b72e6 100644 --- a/typescript/infra/config/environments/mainnet3/chains.ts +++ b/typescript/infra/config/environments/mainnet3/chains.ts @@ -1,30 +1,23 @@ import { ChainMap, ChainMetadata } from '@hyperlane-xyz/sdk'; -import { objKeys } from '@hyperlane-xyz/utils'; -import { getChainMetadatas } from '../../../src/config/chain.js'; -import { getChain } from '../../registry.js'; +import { isEthereumProtocolChain } from '../../../src/utils/utils.js'; import { supportedChainNames } from './supportedChainNames.js'; export const environment = 'mainnet3'; -const { - ethereumMetadatas: defaultEthereumMainnetConfigs, - nonEthereumMetadatas: nonEthereumMainnetConfigs, -} = getChainMetadatas(supportedChainNames); +export const ethereumChainNames = supportedChainNames.filter( + isEthereumProtocolChain, +); -export const ethereumMainnetConfigs: ChainMap = { - ...defaultEthereumMainnetConfigs, +export const chainMetadataOverrides: ChainMap> = { bsc: { - ...getChain('bsc'), transactionOverrides: { gasPrice: 3 * 10 ** 9, // 3 gwei }, }, polygon: { - ...getChain('polygon'), blocks: { - ...getChain('polygon').blocks, confirmations: 3, }, transactionOverrides: { @@ -35,9 +28,7 @@ export const ethereumMainnetConfigs: ChainMap = { }, }, ethereum: { - ...getChain('ethereum'), blocks: { - ...getChain('ethereum').blocks, confirmations: 3, }, transactionOverrides: { @@ -46,7 +37,6 @@ export const ethereumMainnetConfigs: ChainMap = { }, }, scroll: { - ...getChain('scroll'), transactionOverrides: { // Scroll doesn't use EIP 1559 and the gas price that's returned is sometimes // too low for the transaction to be included in a reasonable amount of time - @@ -55,17 +45,9 @@ export const ethereumMainnetConfigs: ChainMap = { }, }, moonbeam: { - ...getChain('moonbeam'), transactionOverrides: { maxFeePerGas: 350 * 10 ** 9, // 350 gwei maxPriorityFeePerGas: 50 * 10 ** 9, // 50 gwei }, }, }; - -export const mainnetConfigs: ChainMap = { - ...ethereumMainnetConfigs, - ...nonEthereumMainnetConfigs, -}; - -export const ethereumChainNames = objKeys(ethereumMainnetConfigs); diff --git a/typescript/infra/config/environments/mainnet3/funding.ts b/typescript/infra/config/environments/mainnet3/funding.ts index f9f15f0a8..80c0efc97 100644 --- a/typescript/infra/config/environments/mainnet3/funding.ts +++ b/typescript/infra/config/environments/mainnet3/funding.ts @@ -9,7 +9,7 @@ import { environment } from './chains.js'; export const keyFunderConfig: KeyFunderConfig = { docker: { repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', - tag: 'b22a0f4-20240523-140812', + tag: '7720875-20240531-072251', }, // We're currently using the same deployer/key funder key as mainnet2. // To minimize nonce clobbering we offset the key funder cron diff --git a/typescript/infra/config/environments/mainnet3/index.ts b/typescript/infra/config/environments/mainnet3/index.ts index a8bc14983..6a765693f 100644 --- a/typescript/infra/config/environments/mainnet3/index.ts +++ b/typescript/infra/config/environments/mainnet3/index.ts @@ -1,16 +1,21 @@ -import { ChainMetadata, RpcConsensusType } from '@hyperlane-xyz/sdk'; -import { ProtocolType, objFilter } from '@hyperlane-xyz/utils'; +import { IRegistry } from '@hyperlane-xyz/registry'; +import { RpcConsensusType } from '@hyperlane-xyz/sdk'; import { getKeysForRole, + getMultiProtocolProvider, getMultiProviderForRole, } from '../../../scripts/agent-utils.js'; +import { getRegistryForEnvironment } from '../../../src/config/chain.js'; import { EnvironmentConfig } from '../../../src/config/environment.js'; import { Role } from '../../../src/roles.js'; import { Contexts } from '../../contexts.js'; import { agents } from './agent.js'; -import { environment as environmentName, mainnetConfigs } from './chains.js'; +import { + chainMetadataOverrides, + environment as environmentName, +} from './chains.js'; import { core } from './core.js'; import { keyFunderConfig } from './funding.js'; import { helloWorld } from './helloworld.js'; @@ -18,34 +23,39 @@ import { igp } from './igp.js'; import { infrastructure } from './infrastructure.js'; import { bridgeAdapterConfigs, relayerConfig } from './liquidityLayer.js'; import { owners } from './owners.js'; +import { supportedChainNames } from './supportedChainNames.js'; + +const getRegistry = async (useSecrets = true): Promise => + getRegistryForEnvironment( + environmentName, + supportedChainNames, + chainMetadataOverrides, + useSecrets, + ); export const environment: EnvironmentConfig = { environment: environmentName, - chainMetadataConfigs: mainnetConfigs, - getMultiProvider: ( + supportedChainNames, + getRegistry, + getMultiProtocolProvider: async () => + getMultiProtocolProvider(await getRegistry()), + getMultiProvider: async ( context: Contexts = Contexts.Hyperlane, role: Role = Role.Deployer, - connectionType?: RpcConsensusType, - ) => { - const config = objFilter( - mainnetConfigs, - (_, chainMetadata): chainMetadata is ChainMetadata => - chainMetadata.protocol === ProtocolType.Ethereum, - ); - - return getMultiProviderForRole( - config, + _connectionType?: RpcConsensusType, + useSecrets?: boolean, + ) => + getMultiProviderForRole( environmentName, + await getRegistry(useSecrets), context, role, undefined, - connectionType, - ); - }, + ), getKeys: ( context: Contexts = Contexts.Hyperlane, role: Role = Role.Deployer, - ) => getKeysForRole(mainnetConfigs, environmentName, context, role), + ) => getKeysForRole(environmentName, supportedChainNames, context, role), agents, core, igp, diff --git a/typescript/infra/config/environments/test/index.ts b/typescript/infra/config/environments/test/index.ts index c21e411e5..cdde17fe3 100644 --- a/typescript/infra/config/environments/test/index.ts +++ b/typescript/infra/config/environments/test/index.ts @@ -5,6 +5,7 @@ import { MultiProvider, testChainMetadata } from '@hyperlane-xyz/sdk'; import { EnvironmentConfig } from '../../../src/config/environment.js'; import { agents } from './agent.js'; +import { testChainNames } from './chains.js'; import { core } from './core.js'; import { igp } from './igp.js'; import { infra } from './infra.js'; @@ -12,7 +13,13 @@ import { owners } from './owners.js'; export const environment: EnvironmentConfig = { environment: 'test', - chainMetadataConfigs: testChainMetadata, + supportedChainNames: testChainNames, + getRegistry: () => { + throw new Error('Not implemented'); + }, + getMultiProtocolProvider: () => { + throw new Error('Not implemented'); + }, agents, core, igp, diff --git a/typescript/infra/config/environments/testnet4/chains.ts b/typescript/infra/config/environments/testnet4/chains.ts index 318d67e7b..caa3c1018 100644 --- a/typescript/infra/config/environments/testnet4/chains.ts +++ b/typescript/infra/config/environments/testnet4/chains.ts @@ -1,24 +1,19 @@ import { ChainMap, ChainMetadata } from '@hyperlane-xyz/sdk'; -import { objKeys } from '@hyperlane-xyz/utils'; -import { getChainMetadatas } from '../../../src/config/chain.js'; -import { getChain } from '../../registry.js'; +import { isEthereumProtocolChain } from '../../../src/utils/utils.js'; import { supportedChainNames } from './supportedChainNames.js'; export const environment = 'testnet4'; -const { ethereumMetadatas: defaultEthereumMainnetConfigs } = - getChainMetadatas(supportedChainNames); +export const ethereumChainNames = supportedChainNames.filter( + isEthereumProtocolChain, +); -export const testnetConfigs: ChainMap = { - ...defaultEthereumMainnetConfigs, +export const chainMetadataOverrides: ChainMap> = { bsctestnet: { - ...getChain('bsctestnet'), transactionOverrides: { gasPrice: 8 * 10 ** 9, // 8 gwei }, }, }; - -export const ethereumChainNames = objKeys(defaultEthereumMainnetConfigs); diff --git a/typescript/infra/config/environments/testnet4/index.ts b/typescript/infra/config/environments/testnet4/index.ts index 9eaa66e1c..b93de05c9 100644 --- a/typescript/infra/config/environments/testnet4/index.ts +++ b/typescript/infra/config/environments/testnet4/index.ts @@ -1,15 +1,22 @@ +import { IRegistry } from '@hyperlane-xyz/registry'; import { RpcConsensusType } from '@hyperlane-xyz/sdk'; +import { objMerge } from '@hyperlane-xyz/utils'; import { getKeysForRole, + getMultiProtocolProvider, getMultiProviderForRole, } from '../../../scripts/agent-utils.js'; +import { getRegistryForEnvironment } from '../../../src/config/chain.js'; import { EnvironmentConfig } from '../../../src/config/environment.js'; import { Role } from '../../../src/roles.js'; import { Contexts } from '../../contexts.js'; import { agents } from './agent.js'; -import { environment as environmentName, testnetConfigs } from './chains.js'; +import { + chainMetadataOverrides, + environment as environmentName, +} from './chains.js'; import { core } from './core.js'; import { keyFunderConfig } from './funding.js'; import { helloWorld } from './helloworld.js'; @@ -18,27 +25,39 @@ import { infrastructure } from './infrastructure.js'; import { bridgeAdapterConfigs } from './liquidityLayer.js'; import { liquidityLayerRelayerConfig } from './middleware.js'; import { owners } from './owners.js'; +import { supportedChainNames } from './supportedChainNames.js'; + +const getRegistry = async (useSecrets = true): Promise => + getRegistryForEnvironment( + environmentName, + supportedChainNames, + chainMetadataOverrides, + useSecrets, + ); export const environment: EnvironmentConfig = { environment: environmentName, - chainMetadataConfigs: testnetConfigs, - getMultiProvider: ( + supportedChainNames, + getRegistry, + getMultiProtocolProvider: async () => + getMultiProtocolProvider(await getRegistry()), + getMultiProvider: async ( context: Contexts = Contexts.Hyperlane, role: Role = Role.Deployer, - connectionType?: RpcConsensusType, + _connectionType?: RpcConsensusType, + useSecrets?: boolean, ) => getMultiProviderForRole( - testnetConfigs, environmentName, + await getRegistry(useSecrets), context, role, undefined, - connectionType, ), getKeys: ( context: Contexts = Contexts.Hyperlane, role: Role = Role.Deployer, - ) => getKeysForRole(testnetConfigs, environmentName, context, role), + ) => getKeysForRole(environmentName, supportedChainNames, context, role), agents, core, igp, diff --git a/typescript/infra/config/registry.ts b/typescript/infra/config/registry.ts index a85488014..8c8be46bb 100644 --- a/typescript/infra/config/registry.ts +++ b/typescript/infra/config/registry.ts @@ -1,7 +1,11 @@ import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; -import { ChainAddresses } from '@hyperlane-xyz/registry'; +import { + ChainAddresses, + MergedRegistry, + PartialRegistry, +} from '@hyperlane-xyz/registry'; import { FileSystemRegistry } from '@hyperlane-xyz/registry/fs'; import { ChainMap, @@ -35,10 +39,18 @@ export function setRegistry(reg: FileSystemRegistry) { registry = reg; } +/** + * Gets a FileSystemRegistry whose contents are found at the environment + * variable `REGISTRY_URI`, or `DEFAULT_REGISTRY_URI` if no env var is specified. + * This registry will not have any environment-specific overrides applied, + * and is useful for synchronous registry operations that do not require + * any overrides. + * @returns A FileSystemRegistry. + */ export function getRegistry(): FileSystemRegistry { if (!registry) { const registryUri = process.env.REGISTRY_URI || DEFAULT_REGISTRY_URI; - rootLogger.info('Using registry URI:', registryUri); + rootLogger.info({ registryUri }, 'Using registry URI'); registry = new FileSystemRegistry({ uri: registryUri, logger: rootLogger.child({ module: 'infra-registry' }), @@ -111,3 +123,26 @@ export function getMainnetAddresses(): ChainMap { export function getTestnetAddresses(): ChainMap { return getEnvAddresses('testnet4'); } + +/** + * Gets a registry, applying the provided overrides. The base registry + * that the overrides are applied to is the registry returned by `getRegistry`. + * @param chainMetadataOverrides Chain metadata overrides. + * @param chainAddressesOverrides Chain address overrides. + * @returns A MergedRegistry merging the registry from `getRegistry` and the overrides. + */ +export function getRegistryWithOverrides( + chainMetadataOverrides: ChainMap> = {}, + chainAddressesOverrides: ChainMap> = {}, +): MergedRegistry { + const baseRegistry = getRegistry(); + + const overrideRegistry = new PartialRegistry({ + chainMetadata: chainMetadataOverrides, + chainAddresses: chainAddressesOverrides, + }); + + return new MergedRegistry({ + registries: [baseRegistry, overrideRegistry], + }); +} diff --git a/typescript/infra/package.json b/typescript/infra/package.json index 33f8d6194..67de934c2 100644 --- a/typescript/infra/package.json +++ b/typescript/infra/package.json @@ -12,6 +12,7 @@ "@ethersproject/experimental": "^5.7.0", "@ethersproject/hardware-wallets": "^5.7.0", "@ethersproject/providers": "^5.7.2", + "@google-cloud/secret-manager": "^5.5.0", "@hyperlane-xyz/helloworld": "3.13.0", "@hyperlane-xyz/registry": "1.3.0", "@hyperlane-xyz/sdk": "3.13.0", diff --git a/typescript/infra/scripts/agent-utils.ts b/typescript/infra/scripts/agent-utils.ts index d027d5aad..3ac0f5ebd 100644 --- a/typescript/infra/scripts/agent-utils.ts +++ b/typescript/infra/scripts/agent-utils.ts @@ -1,12 +1,13 @@ import path, { join } from 'path'; import yargs, { Argv } from 'yargs'; -import { ChainAddresses } from '@hyperlane-xyz/registry'; +import { ChainAddresses, IRegistry } from '@hyperlane-xyz/registry'; import { ChainMap, ChainMetadata, ChainName, CoreConfig, + MultiProtocolProvider, MultiProvider, RpcConsensusType, collectValidators, @@ -16,6 +17,7 @@ import { ProtocolType, objFilter, objMap, + objMerge, promiseObjAll, rootLogger, symmetricDifference, @@ -35,7 +37,10 @@ import { getCurrentKubernetesContext } from '../src/agents/index.js'; import { getCloudAgentKey } from '../src/agents/key-utils.js'; import { CloudAgentKey } from '../src/agents/keys.js'; import { RootAgentConfig } from '../src/config/agent/agent.js'; -import { fetchProvider } from '../src/config/chain.js'; +import { + fetchProvider, + getSecretMetadataOverrides, +} from '../src/config/chain.js'; import { AgentEnvironment, DeployEnvironment, @@ -47,6 +52,7 @@ import { assertContext, assertRole, getInfraPath, + inCIMode, readJSONAtPath, writeMergedJSONAtPath, } from '../src/utils/utils.js'; @@ -283,8 +289,8 @@ export function ensureValidatorConfigConsistency(agentConfig: RootAgentConfig) { export function getKeyForRole( environment: DeployEnvironment, context: Contexts, - chain: ChainName, role: Role, + chain?: ChainName, index?: number, ): CloudAgentKey { debugLog(`Getting key for ${role} role`); @@ -292,33 +298,32 @@ export function getKeyForRole( return getCloudAgentKey(agentConfig, role, chain, index); } +export async function getMultiProtocolProvider( + registry: IRegistry, +): Promise { + const chainMetadata = await registry.getMetadata(); + return new MultiProtocolProvider(chainMetadata); +} + export async function getMultiProviderForRole( - txConfigs: ChainMap, environment: DeployEnvironment, + registry: IRegistry, context: Contexts, role: Role, index?: number, - // TODO: rename to consensusType? - connectionType?: RpcConsensusType, ): Promise { + const chainMetadata = await registry.getMetadata(); debugLog(`Getting multiprovider for ${role} role`); - const multiProvider = new MultiProvider(txConfigs); - if (process.env.CI === 'true') { - debugLog('Returning multiprovider with default RPCs in CI'); - // Return the multiProvider with default RPCs + const multiProvider = new MultiProvider(chainMetadata); + if (inCIMode()) { + debugLog('Running in CI, returning multiprovider without secret keys'); return multiProvider; } await promiseObjAll( - objMap(txConfigs, async (chain, _) => { + objMap(chainMetadata, async (chain, _) => { if (multiProvider.getProtocol(chain) === ProtocolType.Ethereum) { - const provider = await fetchProvider( - environment, - chain, - connectionType, - ); - const key = getKeyForRole(environment, context, chain, role, index); - const signer = await key.getSigner(provider); - multiProvider.setProvider(chain, provider); + const key = getKeyForRole(environment, context, role, chain, index); + const signer = await key.getSigner(); multiProvider.setSigner(chain, signer); } }), @@ -330,23 +335,22 @@ export async function getMultiProviderForRole( // Note: this will only work for keystores that allow key's to be extracted. // I.e. GCP will work but AWS HSMs will not. export async function getKeysForRole( - txConfigs: ChainMap, environment: DeployEnvironment, + supportedChainNames: ChainName[], context: Contexts, role: Role, index?: number, ): Promise> { - if (process.env.CI === 'true') { + if (inCIMode()) { debugLog('No keys to return in CI'); return {}; } - const keys = await promiseObjAll( - objMap(txConfigs, async (chain, _) => - getKeyForRole(environment, context, chain, role, index), - ), - ); - return keys; + const keyEntries = supportedChainNames.map((chain) => [ + chain, + getKeyForRole(environment, context, role, chain, index), + ]); + return Object.fromEntries(keyEntries); } export function getEnvironmentDirectory(environment: DeployEnvironment) { diff --git a/typescript/infra/scripts/agents/update-agent-config.ts b/typescript/infra/scripts/agents/update-agent-config.ts index 2ec6431b8..127f4bf16 100644 --- a/typescript/infra/scripts/agents/update-agent-config.ts +++ b/typescript/infra/scripts/agents/update-agent-config.ts @@ -6,7 +6,13 @@ async function main() { const { environment } = await getArgs().argv; const envConfig = getEnvironmentConfig(environment); - let multiProvider = await envConfig.getMultiProvider(); + let multiProvider = await envConfig.getMultiProvider( + undefined, + undefined, + undefined, + // Don't use secrets + false, + ); await writeAgentConfig(multiProvider, environment); } diff --git a/typescript/infra/scripts/check-rpc-urls.ts b/typescript/infra/scripts/check-rpc-urls.ts index 2ab70835b..95ba7ee4c 100644 --- a/typescript/infra/scripts/check-rpc-urls.ts +++ b/typescript/infra/scripts/check-rpc-urls.ts @@ -2,24 +2,22 @@ import { ethers } from 'ethers'; import { rootLogger } from '@hyperlane-xyz/utils'; -import { getSecretRpcEndpoint } from '../src/agents/index.js'; +import { getSecretRpcEndpoints } from '../src/agents/index.js'; import { getArgs } from './agent-utils.js'; import { getEnvironmentConfig } from './core-utils.js'; -// TODO remove this script as part of migration to CLI -// It's redundant with metadata-check.ts in the SDK async function main() { const { environment } = await getArgs().argv; - const config = await getEnvironmentConfig(environment); + const config = getEnvironmentConfig(environment); const multiProvider = await config.getMultiProvider(); const chains = multiProvider.getKnownChainNames(); const providers: [string, ethers.providers.JsonRpcProvider][] = []; for (const chain of chains) { rootLogger.debug(`Building providers for ${chain}`); const rpcData = [ - ...(await getSecretRpcEndpoint(environment, chain, false)), - ...(await getSecretRpcEndpoint(environment, chain, true)), + ...(await getSecretRpcEndpoints(environment, chain, false)), + ...(await getSecretRpcEndpoints(environment, chain, true)), ]; for (const url of rpcData) providers.push([chain, new ethers.providers.StaticJsonRpcProvider(url)]); diff --git a/typescript/infra/scripts/funding/fund-keys-from-deployer.ts b/typescript/infra/scripts/funding/fund-keys-from-deployer.ts index 02b15a978..000034581 100644 --- a/typescript/infra/scripts/funding/fund-keys-from-deployer.ts +++ b/typescript/infra/scripts/funding/fund-keys-from-deployer.ts @@ -381,7 +381,7 @@ class ContextFunder { [Role.Kathy]: '', }; const roleKeysPerChain: ChainMap> = {}; - const chains = getEnvironmentConfig(environment).chainMetadataConfigs; + const { supportedChainNames } = getEnvironmentConfig(environment); for (const role of rolesToFund) { assertFundableRole(role); // only the relayer and kathy are fundable keys const roleAddress = fetchLocalKeyAddresses(role)[environment][context]; @@ -392,7 +392,7 @@ class ContextFunder { } fundableRoleKeys[role] = roleAddress; - for (const chain of Object.keys(chains)) { + for (const chain of supportedChainNames) { if (!roleKeysPerChain[chain as ChainName]) { roleKeysPerChain[chain as ChainName] = { [Role.Relayer]: [], diff --git a/typescript/infra/scripts/helloworld/kathy.ts b/typescript/infra/scripts/helloworld/kathy.ts index 101bd6779..4e39ab14f 100644 --- a/typescript/infra/scripts/helloworld/kathy.ts +++ b/typescript/infra/scripts/helloworld/kathy.ts @@ -20,6 +20,7 @@ import { ProtocolType, ensure0x, objMap, + pick, retryAsync, rootLogger, sleep, @@ -28,7 +29,6 @@ import { } from '@hyperlane-xyz/utils'; import { Contexts } from '../../config/contexts.js'; -import { testnetConfigs } from '../../config/environments/testnet4/chains.js'; import { hyperlaneHelloworld, releaseCandidateHelloworld, @@ -166,7 +166,6 @@ async function main(): Promise { logger.debug('Starting up', { environment }); const coreConfig = getEnvironmentConfig(environment); - // const coreConfig = getCoreConfigStub(environment); const { app, core, igp, multiProvider, keys } = await getHelloWorldMultiProtocolApp( @@ -550,7 +549,14 @@ async function updateWalletBalanceMetricFor( } // Get a core config intended for testing Kathy without secret access -export function getCoreConfigStub(environment: DeployEnvironment) { +export async function getCoreConfigStub(environment: DeployEnvironment) { + const environmentConfig = getEnvironmentConfig(environment); + // Don't fetch any secrets. + const registry = await environmentConfig.getRegistry(false); + const testnetConfigs = pick( + await registry.getMetadata(), + environmentConfig.supportedChainNames, + ); const multiProvider = new MultiProvider({ // Desired chains here. Key must have funds on these chains ...testnetConfigs, diff --git a/typescript/infra/scripts/print-chain-metadatas.ts b/typescript/infra/scripts/print-chain-metadatas.ts index 8653ef908..ff8f771fe 100644 --- a/typescript/infra/scripts/print-chain-metadatas.ts +++ b/typescript/infra/scripts/print-chain-metadatas.ts @@ -1,3 +1,5 @@ +import { pick } from '@hyperlane-xyz/utils'; + import { getArgs } from './agent-utils.js'; import { getEnvironmentConfig } from './core-utils.js'; @@ -9,7 +11,15 @@ async function main() { const environmentConfig = getEnvironmentConfig(args.environment); - console.log(JSON.stringify(environmentConfig.chainMetadataConfigs, null, 2)); + // Intentionally do not include any secrets in the output + const registry = await environmentConfig.getRegistry(false); + const allMetadata = await registry.getMetadata(); + const environmentMetadata = pick( + allMetadata, + environmentConfig.supportedChainNames, + ); + + console.log(JSON.stringify(environmentMetadata, null, 2)); } main().catch((err) => { diff --git a/typescript/infra/scripts/print-gas-prices.ts b/typescript/infra/scripts/print-gas-prices.ts index e06f13421..61126c371 100644 --- a/typescript/infra/scripts/print-gas-prices.ts +++ b/typescript/infra/scripts/print-gas-prices.ts @@ -1,47 +1,67 @@ import { ethers } from 'ethers'; -import { MultiProtocolProvider, ProviderType } from '@hyperlane-xyz/sdk'; -import { objMap, promiseObjAll } from '@hyperlane-xyz/utils'; +import { + ChainMap, + MultiProtocolProvider, + ProviderType, +} from '@hyperlane-xyz/sdk'; -import { mainnetConfigs } from '../config/environments/mainnet3/chains.js'; -import { getCosmosChainGasPrice } from '../src/config/gas-oracle.js'; +import { + GasPriceConfig, + getCosmosChainGasPrice, +} from '../src/config/gas-oracle.js'; + +import { getEnvironmentConfig } from './core-utils.js'; async function main() { - const allMetadatas = mainnetConfigs; - - const mpp = new MultiProtocolProvider(allMetadatas); - - const prices = await promiseObjAll( - objMap(allMetadatas, async (chain, metadata) => { - const provider = mpp.getProvider(chain); - switch (provider.type) { - case ProviderType.EthersV5: { - const gasPrice = await provider.provider.getGasPrice(); - return { - amount: ethers.utils.formatUnits(gasPrice, 'gwei'), - decimals: 9, - }; - } - case ProviderType.CosmJsWasm: { - const { amount } = await getCosmosChainGasPrice(chain); - - return { - amount, - decimals: 1, - }; - } - case ProviderType.SolanaWeb3: - // TODO get a reasonable value - return '0.001'; - default: - throw new Error(`Unsupported provider type: ${provider.type}`); - } - }), + const environmentConfig = getEnvironmentConfig('mainnet3'); + + const mpp = await environmentConfig.getMultiProtocolProvider(); + + const prices: ChainMap = Object.fromEntries( + await Promise.all( + environmentConfig.supportedChainNames.map(async (chain) => [ + chain, + await getGasPrice(mpp, chain), + ]), + ), ); console.log(JSON.stringify(prices, null, 2)); } +async function getGasPrice( + mpp: MultiProtocolProvider, + chain: string, +): Promise { + const provider = mpp.getProvider(chain); + switch (provider.type) { + case ProviderType.EthersV5: { + const gasPrice = await provider.provider.getGasPrice(); + return { + amount: ethers.utils.formatUnits(gasPrice, 'gwei'), + decimals: 9, + }; + } + case ProviderType.CosmJsWasm: { + const { amount } = await getCosmosChainGasPrice(chain); + + return { + amount, + decimals: 1, + }; + } + case ProviderType.SolanaWeb3: + // TODO get a reasonable value + return { + amount: '0.001', + decimals: 9, + }; + default: + throw new Error(`Unsupported provider type: ${provider.type}`); + } +} + main() .then() .catch((err) => { diff --git a/typescript/infra/scripts/print-token-prices.ts b/typescript/infra/scripts/print-token-prices.ts index 35c30fb5b..b125bac95 100644 --- a/typescript/infra/scripts/print-token-prices.ts +++ b/typescript/infra/scripts/print-token-prices.ts @@ -1,11 +1,17 @@ -import { objMap } from '@hyperlane-xyz/utils'; +import { objMap, pick } from '@hyperlane-xyz/utils'; -import { mainnetConfigs } from '../config/environments/mainnet3/chains.js'; +import { getEnvironmentConfig } from './core-utils.js'; const CURRENCY = 'usd'; async function main() { - const metadata = mainnetConfigs; + const environmentConfig = getEnvironmentConfig('mainnet3'); + + const registry = await environmentConfig.getRegistry(); + const metadata = pick( + await registry.getMetadata(), + environmentConfig.supportedChainNames, + ); const ids = objMap( metadata, diff --git a/typescript/infra/src/agents/index.ts b/typescript/infra/src/agents/index.ts index 41eabefae..66a9be195 100644 --- a/typescript/infra/src/agents/index.ts +++ b/typescript/infra/src/agents/index.ts @@ -300,14 +300,14 @@ export async function getSecretAwsCredentials(agentConfig: AgentContextConfig) { }; } -export async function getSecretRpcEndpoint( +export async function getSecretRpcEndpoints( environment: string, chainName: ChainName, - quorum = false, + multipleEndpoints = false, ): Promise { const secret = await fetchGCPSecret( - `${environment}-rpc-endpoint${quorum ? 's' : ''}-${chainName}`, - quorum, + `${environment}-rpc-endpoint${multipleEndpoints ? 's' : ''}-${chainName}`, + multipleEndpoints, ); if (typeof secret != 'string' && !Array.isArray(secret)) { throw Error(`Expected secret for ${chainName} rpc endpoint`); diff --git a/typescript/infra/src/config/chain.ts b/typescript/infra/src/config/chain.ts index b64035b2b..414ca34bd 100644 --- a/typescript/infra/src/config/chain.ts +++ b/typescript/infra/src/config/chain.ts @@ -1,16 +1,21 @@ +import { SecretManagerServiceClient } from '@google-cloud/secret-manager'; import { providers } from 'ethers'; +import { IRegistry } from '@hyperlane-xyz/registry'; import { + ChainMap, ChainMetadata, ChainName, HyperlaneSmartProvider, ProviderRetryOptions, RpcConsensusType, + RpcUrl, } from '@hyperlane-xyz/sdk'; -import { ProtocolType, objFilter } from '@hyperlane-xyz/utils'; +import { ProtocolType, objFilter, objMerge } from '@hyperlane-xyz/utils'; -import { getChain } from '../../config/registry.js'; -import { getSecretRpcEndpoint } from '../agents/index.js'; +import { getChain, getRegistryWithOverrides } from '../../config/registry.js'; +import { getSecretRpcEndpoints } from '../agents/index.js'; +import { inCIMode } from '../utils/utils.js'; import { DeployEnvironment } from './environment.js'; @@ -20,7 +25,6 @@ export const defaultRetry: ProviderRetryOptions = { }; export async function fetchProvider( - environment: DeployEnvironment, chainName: ChainName, connectionType: RpcConsensusType = RpcConsensusType.Single, ): Promise { @@ -29,10 +33,9 @@ export async function fetchProvider( throw Error(`Unsupported chain: ${chainName}`); } const chainId = chainMetadata.chainId; - const single = connectionType === RpcConsensusType.Single; let rpcData = chainMetadata.rpcUrls.map((url) => url.http); if (rpcData.length === 0) { - rpcData = await getSecretRpcEndpoint(environment, chainName, !single); + throw Error(`No RPC URLs found for chain: ${chainName}`); } if (connectionType === RpcConsensusType.Single) { @@ -73,3 +76,69 @@ export function getChainMetadatas(chains: Array) { return { ethereumMetadatas, nonEthereumMetadatas }; } + +/** + * Gets the registry for the given environment, with optional overrides and + * the ability to get overrides from secrets. + * @param deployEnv The deploy environment. + * @param chains The chains to get metadata for. + * @param defaultChainMetadataOverrides The default chain metadata overrides. If + * secret overrides are used, the secret overrides will be merged with these and + * take precedence. + * @param useSecrets Whether to fetch metadata overrides from secrets. + * @returns A registry with overrides for the given environment. + */ +export async function getRegistryForEnvironment( + deployEnv: DeployEnvironment, + chains: ChainName[], + defaultChainMetadataOverrides: ChainMap> = {}, + useSecrets: boolean = true, +): Promise { + let overrides = defaultChainMetadataOverrides; + if (useSecrets && !inCIMode()) { + overrides = objMerge( + overrides, + await getSecretMetadataOverrides(deployEnv, chains), + ); + } + const registry = getRegistryWithOverrides(overrides); + return registry; +} + +/** + * Gets chain metadata overrides from GCP secrets. + * @param deployEnv The deploy environment. + * @param chains The chains to get metadata overrides for. + * @returns A partial chain metadata map with the secret overrides. + */ +export async function getSecretMetadataOverrides( + deployEnv: DeployEnvironment, + chains: string[], +): Promise>> { + const chainMetadataOverrides: ChainMap> = {}; + + const secretRpcUrls = await Promise.all( + chains.map(async (chain) => { + const rpcUrls = await getSecretRpcEndpoints(deployEnv, chain, true); + return { + chain, + rpcUrls, + }; + }), + ); + + for (const { chain, rpcUrls } of secretRpcUrls) { + if (rpcUrls.length === 0) { + throw Error(`No secret RPC URLs found for chain: ${chain}`); + } + // Need explicit casting here because Zod expects a non-empty array. + const metadataRpcUrls = rpcUrls.map((rpcUrl: string) => ({ + http: rpcUrl, + })) as ChainMetadata['rpcUrls']; + chainMetadataOverrides[chain] = { + rpcUrls: metadataRpcUrls, + }; + } + + return chainMetadataOverrides; +} diff --git a/typescript/infra/src/config/environment.ts b/typescript/infra/src/config/environment.ts index fbb9b74c7..72e30f6d9 100644 --- a/typescript/infra/src/config/environment.ts +++ b/typescript/infra/src/config/environment.ts @@ -1,3 +1,4 @@ +import { IRegistry } from '@hyperlane-xyz/registry'; import { BridgeAdapterConfig, ChainMap, @@ -5,6 +6,7 @@ import { ChainName, CoreConfig, IgpConfig, + MultiProtocolProvider, MultiProvider, OwnableConfig, RpcConsensusType, @@ -39,17 +41,21 @@ export const envNameToAgentEnv: Record = { export type EnvironmentConfig = { environment: DeployEnvironment; - chainMetadataConfigs: ChainMap; + supportedChainNames: ChainName[]; + // Get the registry with or without environment-specific secrets. + getRegistry: (useSecrets?: boolean) => Promise; // Each AgentConfig, keyed by the context agents: Partial>; core: ChainMap; igp: ChainMap; owners: ChainMap; infra: InfrastructureConfig; + getMultiProtocolProvider: () => Promise; getMultiProvider: ( context?: Contexts, role?: Role, connectionType?: RpcConsensusType, + useSecrets?: boolean, ) => Promise; getKeys: ( context?: Contexts, diff --git a/typescript/infra/src/utils/gcloud.ts b/typescript/infra/src/utils/gcloud.ts index 0ce5e21f3..cc4fd2d62 100644 --- a/typescript/infra/src/utils/gcloud.ts +++ b/typescript/infra/src/utils/gcloud.ts @@ -1,3 +1,4 @@ +import { SecretManagerServiceClient } from '@google-cloud/secret-manager'; import fs from 'fs'; import { rootLogger } from '@hyperlane-xyz/utils'; @@ -6,6 +7,8 @@ import { rm, writeFile } from 'fs/promises'; import { execCmd, execCmdAndParseJson } from './utils.js'; +export const GCP_PROJECT_ID = 'abacus-labs-dev'; + interface IamCondition { title: string; expression: string; @@ -32,9 +35,7 @@ export async function fetchGCPSecret( ); output = envVarOverride; } else { - [output] = await execCmd( - `gcloud secrets versions access latest --secret ${secretName}`, - ); + output = await fetchLatestGCPSecret(secretName); } if (parseJson) { @@ -43,6 +44,29 @@ export async function fetchGCPSecret( return output; } +export async function fetchLatestGCPSecret(secretName: string) { + const client = new SecretManagerServiceClient({ + projectId: GCP_PROJECT_ID, + }); + const [secretVersion] = await client.accessSecretVersion({ + name: `projects/${GCP_PROJECT_ID}/secrets/${secretName}/versions/latest`, + }); + const secretData = secretVersion.payload?.data; + if (!secretData) { + throw new Error(`Secret ${secretName} missing payload`); + } + + // Handle both string and Uint8Array + let dataStr: string; + if (typeof secretData === 'string') { + dataStr = secretData; + } else { + dataStr = new TextDecoder().decode(secretData); + } + + return dataStr; +} + // If the environment variable GCP_SECRET_OVERRIDES_ENABLED is `true`, // this will attempt to find an environment variable of the form: // `GCP_SECRET_OVERRIDE_${gcpSecretName.replaceAll('-', '_').toUpperCase()}` diff --git a/typescript/infra/src/utils/utils.ts b/typescript/infra/src/utils/utils.ts index 476fe3913..d3a8075ff 100644 --- a/typescript/infra/src/utils/utils.ts +++ b/typescript/infra/src/utils/utils.ts @@ -269,3 +269,7 @@ export function isEthereumProtocolChain(chainName: ChainName) { export function getInfraPath() { return join(dirname(fileURLToPath(import.meta.url)), '../../'); } + +export function inCIMode() { + return process.env.CI === 'true'; +} diff --git a/typescript/sdk/src/metadata/agentConfig.ts b/typescript/sdk/src/metadata/agentConfig.ts index 0885a3e4a..49f05e883 100644 --- a/typescript/sdk/src/metadata/agentConfig.ts +++ b/typescript/sdk/src/metadata/agentConfig.ts @@ -399,6 +399,16 @@ export function buildAgentConfig( const chainConfigs: ChainMap = {}; for (const chain of [...chains].sort()) { const metadata = multiProvider.tryGetChainMetadata(chain); + if (metadata?.protocol === ProtocolType.Cosmos) { + // Note: the gRPC URL format in the registry lacks a correct http:// or https:// prefix at the moment, + // which is expected by the agents. For now, we intentionally skip this. + delete metadata.grpcUrls; + + // The agents expect gasPrice.amount and gasPrice.denom and ignore the transaction overrides. + // To reduce confusion when looking at the config, we remove the transaction overrides. + delete metadata.transactionOverrides; + } + const chainConfig: AgentChainMetadata = { ...metadata, ...addresses[chain], diff --git a/yarn.lock b/yarn.lock index 9fc2aab50..8b293bfc7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5608,6 +5608,39 @@ __metadata: languageName: node linkType: hard +"@google-cloud/secret-manager@npm:^5.5.0": + version: 5.5.0 + resolution: "@google-cloud/secret-manager@npm:5.5.0" + dependencies: + google-gax: "npm:^4.0.3" + checksum: 487267dab1e260a0da79012194bb61c85f8b02b642330fdec32cac1fe37900f0fd6709ff4928fe631ab227b0d758bd3e59b1e3dc1d0682de566a64ef4fb42bba + languageName: node + linkType: hard + +"@grpc/grpc-js@npm:~1.10.3": + version: 1.10.8 + resolution: "@grpc/grpc-js@npm:1.10.8" + dependencies: + "@grpc/proto-loader": "npm:^0.7.13" + "@js-sdsl/ordered-map": "npm:^4.4.2" + checksum: cb7903e93db38a86bd2ddffb84313de78144454ad988801ede90f0c794d6a5f666a1b24f50e950b50d633b4bacc7416c7cabf4a6791b91c4fa89c001122edba8 + languageName: node + linkType: hard + +"@grpc/proto-loader@npm:^0.7.0, @grpc/proto-loader@npm:^0.7.13": + version: 0.7.13 + resolution: "@grpc/proto-loader@npm:0.7.13" + dependencies: + lodash.camelcase: "npm:^4.3.0" + long: "npm:^5.0.0" + protobufjs: "npm:^7.2.5" + yargs: "npm:^17.7.2" + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 7e2d842c2061cbaf6450c71da0077263be3bab165454d5c8a3e1ae4d3c6d2915f02fd27da63ff01f05e127b1221acd40705273f5d29303901e60514e852992f4 + languageName: node + linkType: hard + "@headlessui/react@npm:^1.7.17": version: 1.7.18 resolution: "@headlessui/react@npm:1.7.18" @@ -5824,6 +5857,7 @@ __metadata: "@ethersproject/experimental": "npm:^5.7.0" "@ethersproject/hardware-wallets": "npm:^5.7.0" "@ethersproject/providers": "npm:^5.7.2" + "@google-cloud/secret-manager": "npm:^5.5.0" "@hyperlane-xyz/helloworld": "npm:3.13.0" "@hyperlane-xyz/registry": "npm:1.3.0" "@hyperlane-xyz/sdk": "npm:3.13.0" @@ -6501,6 +6535,13 @@ __metadata: languageName: node linkType: hard +"@js-sdsl/ordered-map@npm:^4.4.2": + version: 4.4.2 + resolution: "@js-sdsl/ordered-map@npm:4.4.2" + checksum: ac64e3f0615ecc015461c9f527f124d2edaa9e68de153c1e270c627e01e83d046522d7e872692fd57a8c514578b539afceff75831c0d8b2a9a7a347fbed35af4 + languageName: node + linkType: hard + "@layerzerolabs/lz-evm-messagelib-v2@npm:^2.0.2": version: 2.0.6 resolution: "@layerzerolabs/lz-evm-messagelib-v2@npm:2.0.6" @@ -9439,6 +9480,13 @@ __metadata: languageName: node linkType: hard +"@types/caseless@npm:*": + version: 0.12.5 + resolution: "@types/caseless@npm:0.12.5" + checksum: f6a3628add76d27005495914c9c3873a93536957edaa5b69c63b46fe10b4649a6fecf16b676c1695f46aab851da47ec6047dcf3570fa8d9b6883492ff6d074e0 + languageName: node + linkType: hard + "@types/chai@npm:*, @types/chai@npm:^4.2.21": version: 4.3.1 resolution: "@types/chai@npm:4.3.1" @@ -9607,7 +9655,7 @@ __metadata: languageName: node linkType: hard -"@types/long@npm:^4.0.1": +"@types/long@npm:^4.0.0, @types/long@npm:^4.0.1": version: 4.0.2 resolution: "@types/long@npm:4.0.2" checksum: 68afa05fb20949d88345876148a76f6ccff5433310e720db51ac5ca21cb8cc6714286dbe04713840ddbd25a8b56b7a23aa87d08472fabf06463a6f2ed4967707 @@ -9814,6 +9862,18 @@ __metadata: languageName: node linkType: hard +"@types/request@npm:^2.48.8": + version: 2.48.12 + resolution: "@types/request@npm:2.48.12" + dependencies: + "@types/caseless": "npm:*" + "@types/node": "npm:*" + "@types/tough-cookie": "npm:*" + form-data: "npm:^2.5.0" + checksum: a7b3f9f14cacc18fe235bb8e57eff1232a04bd3fa3dad29371f24a5d96db2cd295a0c8b6b34ed7efa3efbbcff845febb02c9635cd68c54811c947ea66ae22090 + languageName: node + linkType: hard + "@types/resolve@npm:^0.0.8": version: 0.0.8 resolution: "@types/resolve@npm:0.0.8" @@ -9904,6 +9964,13 @@ __metadata: languageName: node linkType: hard +"@types/tough-cookie@npm:*": + version: 4.0.5 + resolution: "@types/tough-cookie@npm:4.0.5" + checksum: 01fd82efc8202670865928629697b62fe9bf0c0dcbc5b1c115831caeb073a2c0abb871ff393d7df1ae94ea41e256cb87d2a5a91fd03cdb1b0b4384e08d4ee482 + languageName: node + linkType: hard + "@types/trusted-types@npm:^2.0.2": version: 2.0.7 resolution: "@types/trusted-types@npm:2.0.7" @@ -10902,6 +10969,15 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:^7.0.2": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" + dependencies: + debug: "npm:^4.3.4" + checksum: c478fec8f79953f118704d007a38f2a185458853f5c45579b9669372bd0e12602e88dc2ad0233077831504f7cd6fcc8251c383375bba5eaaf563b102938bda26 + languageName: node + linkType: hard + "agentkeepalive@npm:^4.2.1": version: 4.2.1 resolution: "agentkeepalive@npm:4.2.1" @@ -11956,6 +12032,13 @@ __metadata: languageName: node linkType: hard +"buffer-equal-constant-time@npm:1.0.1": + version: 1.0.1 + resolution: "buffer-equal-constant-time@npm:1.0.1" + checksum: 80bb945f5d782a56f374b292770901065bad21420e34936ecbe949e57724b4a13874f735850dd1cc61f078773c4fb5493a41391e7bda40d1fa388d6bd80daaab + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -13651,6 +13734,18 @@ __metadata: languageName: node linkType: hard +"duplexify@npm:^4.0.0": + version: 4.1.3 + resolution: "duplexify@npm:4.1.3" + dependencies: + end-of-stream: "npm:^1.4.1" + inherits: "npm:^2.0.3" + readable-stream: "npm:^3.1.1" + stream-shift: "npm:^1.0.2" + checksum: b44b98ba0ffac3a658b4b1bf877219e996db288c5ae6f3dc55ca9b2cbef7df60c10eabfdd947f3d73a623eb9975a74a66d6d61e6f26bff90155315adb362aa77 + languageName: node + linkType: hard + "duplexify@npm:^4.1.2": version: 4.1.2 resolution: "duplexify@npm:4.1.2" @@ -13680,6 +13775,15 @@ __metadata: languageName: node linkType: hard +"ecdsa-sig-formatter@npm:1.0.11, ecdsa-sig-formatter@npm:^1.0.11": + version: 1.0.11 + resolution: "ecdsa-sig-formatter@npm:1.0.11" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 878e1aab8a42773320bc04c6de420bee21aebd71810e40b1799880a8a1c4594bcd6adc3d4213a0fb8147d4c3f529d8f9a618d7f59ad5a9a41b142058aceda23f + languageName: node + linkType: hard + "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -14912,7 +15016,7 @@ __metadata: languageName: node linkType: hard -"extend@npm:~3.0.2": +"extend@npm:^3.0.2, extend@npm:~3.0.2": version: 3.0.2 resolution: "extend@npm:3.0.2" checksum: 59e89e2dc798ec0f54b36d82f32a27d5f6472c53974f61ca098db5d4648430b725387b53449a34df38fd0392045434426b012f302b3cc049a6500ccf82877e4e @@ -15303,7 +15407,7 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^2.2.0": +"form-data@npm:^2.2.0, form-data@npm:^2.5.0": version: 2.5.1 resolution: "form-data@npm:2.5.1" dependencies: @@ -15666,6 +15770,29 @@ __metadata: languageName: node linkType: hard +"gaxios@npm:^6.0.0, gaxios@npm:^6.1.1": + version: 6.6.0 + resolution: "gaxios@npm:6.6.0" + dependencies: + extend: "npm:^3.0.2" + https-proxy-agent: "npm:^7.0.1" + is-stream: "npm:^2.0.0" + node-fetch: "npm:^2.6.9" + uuid: "npm:^9.0.1" + checksum: 9f035590374fd168e7bb3ddda369fc8bd487f16a2308fde18284ccc0f685d0af4ac5e3e38d680a8c6342a9000fbf9d77ce691ee110dbed2feebb659e729c640a + languageName: node + linkType: hard + +"gcp-metadata@npm:^6.1.0": + version: 6.1.0 + resolution: "gcp-metadata@npm:6.1.0" + dependencies: + gaxios: "npm:^6.0.0" + json-bigint: "npm:^1.0.0" + checksum: a0d12a9cb7499fdb9de0fff5406aa220310c1326b80056be8d9b747aae26414f99d14bd795c0ec52ef7d0473eef9d61bb657b8cd3d8186c8a84c4ddbff025fe9 + languageName: node + linkType: hard + "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -16034,6 +16161,40 @@ __metadata: languageName: node linkType: hard +"google-auth-library@npm:^9.3.0": + version: 9.10.0 + resolution: "google-auth-library@npm:9.10.0" + dependencies: + base64-js: "npm:^1.3.0" + ecdsa-sig-formatter: "npm:^1.0.11" + gaxios: "npm:^6.1.1" + gcp-metadata: "npm:^6.1.0" + gtoken: "npm:^7.0.0" + jws: "npm:^4.0.0" + checksum: 10d5863493f9426107b0f6c4df244b1413a2cacff9589076f906924336d894fe8bc4153d4a3756cebec8a58784ff1a3900c621924f75f004908611fa46d3caa6 + languageName: node + linkType: hard + +"google-gax@npm:^4.0.3": + version: 4.3.3 + resolution: "google-gax@npm:4.3.3" + dependencies: + "@grpc/grpc-js": "npm:~1.10.3" + "@grpc/proto-loader": "npm:^0.7.0" + "@types/long": "npm:^4.0.0" + abort-controller: "npm:^3.0.0" + duplexify: "npm:^4.0.0" + google-auth-library: "npm:^9.3.0" + node-fetch: "npm:^2.6.1" + object-hash: "npm:^3.0.0" + proto3-json-serializer: "npm:^2.0.0" + protobufjs: "npm:7.2.6" + retry-request: "npm:^7.0.0" + uuid: "npm:^9.0.1" + checksum: 63335724e741737b90689e43f8ea5804d82b8f4eaa013ba07166bf6119ef7474d06682d580d72f6b708d6c55251204b1f05db615c3cd84abf2f8f295c50882ec + languageName: node + linkType: hard + "gopd@npm:^1.0.1": version: 1.0.1 resolution: "gopd@npm:1.0.1" @@ -16166,6 +16327,16 @@ __metadata: languageName: node linkType: hard +"gtoken@npm:^7.0.0": + version: 7.1.0 + resolution: "gtoken@npm:7.1.0" + dependencies: + gaxios: "npm:^6.0.0" + jws: "npm:^4.0.0" + checksum: 640392261e55c9242137a81a4af8feb053b57061762cedddcbb6a0d62c2314316161808ac2529eea67d06d69fdc56d82361af50f2d840a04a87ea29e124d7382 + languageName: node + linkType: hard + "h3@npm:^1.10.1, h3@npm:^1.8.2": version: 1.10.2 resolution: "h3@npm:1.10.2" @@ -16725,6 +16896,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.1": + version: 7.0.4 + resolution: "https-proxy-agent@npm:7.0.4" + dependencies: + agent-base: "npm:^7.0.2" + debug: "npm:4" + checksum: 405fe582bba461bfe5c7e2f8d752b384036854488b828ae6df6a587c654299cbb2c50df38c4b6ab303502c3c5e029a793fbaac965d1e86ee0be03faceb554d63 + languageName: node + linkType: hard + "human-id@npm:^1.0.2": version: 1.0.2 resolution: "human-id@npm:1.0.2" @@ -18336,6 +18517,27 @@ __metadata: languageName: node linkType: hard +"jwa@npm:^2.0.0": + version: 2.0.0 + resolution: "jwa@npm:2.0.0" + dependencies: + buffer-equal-constant-time: "npm:1.0.1" + ecdsa-sig-formatter: "npm:1.0.11" + safe-buffer: "npm:^5.0.1" + checksum: ab983f6685d99d13ddfbffef9b1c66309a536362a8412d49ba6e687d834a1240ce39290f30ac7dbe241e0ab6c76fee7ff795776ce534e11d148158c9b7193498 + languageName: node + linkType: hard + +"jws@npm:^4.0.0": + version: 4.0.0 + resolution: "jws@npm:4.0.0" + dependencies: + jwa: "npm:^2.0.0" + safe-buffer: "npm:^5.0.1" + checksum: 1d15f4cdea376c6bd6a81002bd2cb0bf3d51d83da8f0727947b5ba3e10cf366721b8c0d099bf8c1eb99eb036e2c55e5fd5efd378ccff75a2b4e0bd10002348b9 + languageName: node + linkType: hard + "keccak@npm:3.0.1": version: 3.0.1 resolution: "keccak@npm:3.0.1" @@ -18918,6 +19120,13 @@ __metadata: languageName: node linkType: hard +"long@npm:^5.0.0": + version: 5.2.3 + resolution: "long@npm:5.2.3" + checksum: 9167ec6947a825b827c30da169a7384eec6c0c9ec2f0b9c74da2e93d81159bbe39fb09c3f13dae9721d4b807ccfa09797a7dd1012f5d478e3e33ca3c78b608e6 + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -20113,7 +20322,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.12": +"node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.9": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: @@ -20422,6 +20631,13 @@ __metadata: languageName: node linkType: hard +"object-hash@npm:^3.0.0": + version: 3.0.0 + resolution: "object-hash@npm:3.0.0" + checksum: f498d456a20512ba7be500cef4cf7b3c183cc72c65372a549c9a0e6dd78ce26f375e9b1315c07592d3fde8f10d5019986eba35970570d477ed9a2a702514432a + languageName: node + linkType: hard + "object-inspect@npm:^1.12.0, object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": version: 1.12.2 resolution: "object-inspect@npm:1.12.2" @@ -21344,6 +21560,35 @@ __metadata: languageName: node linkType: hard +"proto3-json-serializer@npm:^2.0.0": + version: 2.0.1 + resolution: "proto3-json-serializer@npm:2.0.1" + dependencies: + protobufjs: "npm:^7.2.5" + checksum: dc4319c90e2412b9647f13dd1df2a6338ee3a07e2fd693c5ce4d1728c3730d913ebdb6d656f400ae4214a70bf0791ca0bc04d53b2cbdd75394bf0b175898443b + languageName: node + linkType: hard + +"protobufjs@npm:7.2.6": + version: 7.2.6 + resolution: "protobufjs@npm:7.2.6" + dependencies: + "@protobufjs/aspromise": "npm:^1.1.2" + "@protobufjs/base64": "npm:^1.1.2" + "@protobufjs/codegen": "npm:^2.0.4" + "@protobufjs/eventemitter": "npm:^1.1.0" + "@protobufjs/fetch": "npm:^1.1.0" + "@protobufjs/float": "npm:^1.0.2" + "@protobufjs/inquire": "npm:^1.1.0" + "@protobufjs/path": "npm:^1.1.2" + "@protobufjs/pool": "npm:^1.1.0" + "@protobufjs/utf8": "npm:^1.1.0" + "@types/node": "npm:>=13.7.0" + long: "npm:^5.0.0" + checksum: 81ab853d28c71998d056d6b34f83c4bc5be40cb0b416585f99ed618aed833d64b2cf89359bad7474d345302f2b5e236c4519165f8483d7ece7fd5b0d9ac13f8b + languageName: node + linkType: hard + "protobufjs@npm:^6.8.8, protobufjs@npm:~6.11.2, protobufjs@npm:~6.11.3": version: 6.11.4 resolution: "protobufjs@npm:6.11.4" @@ -21368,6 +21613,26 @@ __metadata: languageName: node linkType: hard +"protobufjs@npm:^7.2.5": + version: 7.3.0 + resolution: "protobufjs@npm:7.3.0" + dependencies: + "@protobufjs/aspromise": "npm:^1.1.2" + "@protobufjs/base64": "npm:^1.1.2" + "@protobufjs/codegen": "npm:^2.0.4" + "@protobufjs/eventemitter": "npm:^1.1.0" + "@protobufjs/fetch": "npm:^1.1.0" + "@protobufjs/float": "npm:^1.0.2" + "@protobufjs/inquire": "npm:^1.1.0" + "@protobufjs/path": "npm:^1.1.2" + "@protobufjs/pool": "npm:^1.1.0" + "@protobufjs/utf8": "npm:^1.1.0" + "@types/node": "npm:>=13.7.0" + long: "npm:^5.0.0" + checksum: aff4aa2a3a2f011accb51e23fcae122acbee35cb761abe51f799675a61ab39ad9a506911f307e0fdb9a1703bed1f522cfbdaafaeefd2b3aaca2ddc18f03029d9 + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -22253,6 +22518,17 @@ __metadata: languageName: node linkType: hard +"retry-request@npm:^7.0.0": + version: 7.0.2 + resolution: "retry-request@npm:7.0.2" + dependencies: + "@types/request": "npm:^2.48.8" + extend: "npm:^3.0.2" + teeny-request: "npm:^9.0.0" + checksum: 8f4c927d41dd575fc460aad7b762fb0a33542097201c3c1a31529ad17fa8af3ac0d2a45bf4a2024d079913e9c2dd431566070fe33321c667ac87ebb400de5917 + languageName: node + linkType: hard + "retry@npm:0.13.1": version: 0.13.1 resolution: "retry@npm:0.13.1" @@ -23390,7 +23666,16 @@ __metadata: languageName: node linkType: hard -"stream-shift@npm:^1.0.0": +"stream-events@npm:^1.0.5": + version: 1.0.5 + resolution: "stream-events@npm:1.0.5" + dependencies: + stubs: "npm:^3.0.0" + checksum: 969ce82e34bfbef5734629cc06f9d7f3705a9ceb8fcd6a526332f9159f1f8bbfdb1a453f3ced0b728083454f7706adbbe8428bceb788a0287ca48ba2642dc3fc + languageName: node + linkType: hard + +"stream-shift@npm:^1.0.0, stream-shift@npm:^1.0.2": version: 1.0.3 resolution: "stream-shift@npm:1.0.3" checksum: a24c0a3f66a8f9024bd1d579a533a53be283b4475d4e6b4b3211b964031447bdf6532dd1f3c2b0ad66752554391b7c62bd7ca4559193381f766534e723d50242 @@ -23690,6 +23975,13 @@ __metadata: languageName: node linkType: hard +"stubs@npm:^3.0.0": + version: 3.0.0 + resolution: "stubs@npm:3.0.0" + checksum: dec7b82186e3743317616235c59bfb53284acc312cb9f4c3e97e2205c67a5c158b0ca89db5927e52351582e90a2672822eeaec9db396e23e56893d2a8676e024 + languageName: node + linkType: hard + "styled-jsx@npm:5.1.1": version: 5.1.1 resolution: "styled-jsx@npm:5.1.1" @@ -23943,6 +24235,19 @@ __metadata: languageName: node linkType: hard +"teeny-request@npm:^9.0.0": + version: 9.0.0 + resolution: "teeny-request@npm:9.0.0" + dependencies: + http-proxy-agent: "npm:^5.0.0" + https-proxy-agent: "npm:^5.0.0" + node-fetch: "npm:^2.6.9" + stream-events: "npm:^1.0.5" + uuid: "npm:^9.0.0" + checksum: 44daabb6c2e239c3daed0218ebdafb50c7141c16d7257a6cfef786dbff56d7853c2c02c97934f7ed57818ce5861ac16c5f52f3a16fa292bd4caf53483d386443 + languageName: node + linkType: hard + "term-size@npm:^2.1.0": version: 2.2.1 resolution: "term-size@npm:2.2.1"