feat(infra): strongly type keyfunder config (#4093)

resolves https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3732

- strongly type the keyfunder config
- new chains added to an environment's supported chains list must be
configured
- opens up the path to strongly type more of the env config down the
line

missing 1 chain:
<img width="336" alt="image"
src="https://github.com/hyperlane-xyz/hyperlane-monorepo/assets/10051819/698ef9db-c50a-4a49-bc11-d33a44f186bf">

missing multiple chains:
<img width="350" alt="image"
src="https://github.com/hyperlane-xyz/hyperlane-monorepo/assets/10051819/2f9e4e6c-5c36-4239-9c00-5951eca91589">
pull/4077/head
Paul Balaji 5 months ago committed by GitHub
parent 46652c62a8
commit 94e6ca21ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 17
      typescript/infra/config/environments/mainnet3/funding.ts
  2. 2
      typescript/infra/config/environments/mainnet3/igp.ts
  3. 6
      typescript/infra/config/environments/mainnet3/supportedChainNames.ts
  4. 15
      typescript/infra/config/environments/testnet4/funding.ts
  5. 1
      typescript/infra/config/environments/testnet4/index.ts
  6. 7
      typescript/infra/config/environments/testnet4/supportedChainNames.ts
  7. 6
      typescript/infra/config/registry.ts
  8. 36
      typescript/infra/scripts/funding/fund-keys-from-deployer.ts
  9. 10
      typescript/infra/scripts/print-token-prices.ts
  10. 3
      typescript/infra/src/config/environment.ts
  11. 10
      typescript/infra/src/config/funding.ts
  12. 6
      typescript/infra/src/funding/key-funder.ts

@ -3,8 +3,11 @@ import { Role } from '../../../src/roles.js';
import { Contexts } from '../../contexts.js';
import { environment } from './chains.js';
import { mainnet3SupportedChainNames } from './supportedChainNames.js';
export const keyFunderConfig: KeyFunderConfig = {
export const keyFunderConfig: KeyFunderConfig<
typeof mainnet3SupportedChainNames
> = {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: '1b5e4d4-20240702-152903',
@ -49,6 +52,10 @@ export const keyFunderConfig: KeyFunderConfig = {
taiko: '0.2',
viction: '3',
zetachain: '20',
// ignore cosmos chains
injective: '0',
neutron: '0',
osmosis: '0',
},
desiredKathyBalancePerChain: {
arbitrum: '0.1',
@ -77,6 +84,10 @@ export const keyFunderConfig: KeyFunderConfig = {
taiko: '0',
viction: '0.05',
zetachain: '0',
// ignore cosmos chains
injective: '0',
neutron: '0',
osmosis: '0',
},
igpClaimThresholdPerChain: {
arbitrum: '0.1',
@ -105,5 +116,9 @@ export const keyFunderConfig: KeyFunderConfig = {
taiko: '0.1',
viction: '2',
zetachain: '20',
// ignore cosmos chains
injective: '0',
neutron: '0',
osmosis: '0',
},
};

@ -28,7 +28,7 @@ const tokenPrices: ChainMap<string> = rawTokenPrices;
const FOREIGN_DEFAULT_OVERHEAD = 600_000; // cosmwasm warp route somewhat arbitrarily chosen
const remoteOverhead = (remote: ChainName) =>
ethereumChainNames.includes(remote)
ethereumChainNames.includes(remote as any)
? multisigIsmVerificationCost(
defaultMultisigConfigs[remote].threshold,
defaultMultisigConfigs[remote].validators.length,

@ -1,6 +1,6 @@
// These chains may be any protocol type.
// Placing them here instead of adjacent chains file to avoid circular dep
export const supportedChainNames = [
export const mainnet3SupportedChainNames = [
'arbitrum',
'ancient8',
'avalanche',
@ -30,4 +30,6 @@ export const supportedChainNames = [
'taiko',
'viction',
'zetachain',
];
] as const;
export const supportedChainNames = [...mainnet3SupportedChainNames];

@ -3,8 +3,11 @@ import { Role } from '../../../src/roles.js';
import { Contexts } from '../../contexts.js';
import { environment } from './chains.js';
import { testnet4SupportedChainNames } from './supportedChainNames.js';
export const keyFunderConfig: KeyFunderConfig = {
export const keyFunderConfig: KeyFunderConfig<
typeof testnet4SupportedChainNames
> = {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: 'efa9025-20240605-091304',
@ -31,14 +34,21 @@ export const keyFunderConfig: KeyFunderConfig = {
// Funder boosts itself upto 5x balance on L2 before dispersing funds
scrollsepolia: '1',
sepolia: '5',
// no funding for solana
eclipsetestnet: '0',
solanatestnet: '0',
},
desiredKathyBalancePerChain: {
alfajores: '1',
bsctestnet: '1',
fuji: '1',
holesky: '0',
plumetestnet: '0.05',
scrollsepolia: '1',
sepolia: '1',
// no funding for solana
eclipsetestnet: '0',
solanatestnet: '0',
},
igpClaimThresholdPerChain: {
alfajores: '1',
@ -48,5 +58,8 @@ export const keyFunderConfig: KeyFunderConfig = {
plumetestnet: '0.1',
scrollsepolia: '0.1',
sepolia: '1',
// no funding for solana
eclipsetestnet: '0',
solanatestnet: '0',
},
};

@ -1,5 +1,4 @@
import { IRegistry } from '@hyperlane-xyz/registry';
import { objMerge } from '@hyperlane-xyz/utils';
import {
getKeysForRole,

@ -1,6 +1,5 @@
// These chains may be any protocol type.
// Placing them here instead of adjacent chains file to avoid circular dep
export const supportedChainNames = [
export const testnet4SupportedChainNames = [
'alfajores',
'bsctestnet',
'eclipsetestnet',
@ -10,4 +9,6 @@ export const supportedChainNames = [
'scrollsepolia',
'sepolia',
'solanatestnet',
];
] as const;
export const supportedChainNames = [...testnet4SupportedChainNames];

@ -109,10 +109,8 @@ export function getEnvAddresses(
env: DeployEnvironment,
): ChainMap<ChainAddresses> {
const envChains = getEnvChains(env);
return objFilter(
getChainAddresses(),
(chain, addresses): addresses is ChainAddresses =>
getEnvChains(env).includes(chain),
return objFilter(getChainAddresses(), (chain, _): _ is ChainAddresses =>
envChains.includes(chain),
);
}

@ -225,9 +225,15 @@ class ContextFunder {
public readonly context: Contexts,
public readonly rolesToFund: FundableRole[],
public readonly skipIgpClaim: boolean,
public readonly desiredBalancePerChain: KeyFunderConfig['desiredBalancePerChain'],
public readonly desiredKathyBalancePerChain: KeyFunderConfig['desiredKathyBalancePerChain'],
public readonly igpClaimThresholdPerChain: KeyFunderConfig['igpClaimThresholdPerChain'],
public readonly desiredBalancePerChain: KeyFunderConfig<
ChainName[]
>['desiredBalancePerChain'],
public readonly desiredKathyBalancePerChain: KeyFunderConfig<
ChainName[]
>['desiredKathyBalancePerChain'],
public readonly igpClaimThresholdPerChain: KeyFunderConfig<
ChainName[]
>['igpClaimThresholdPerChain'],
) {
// At the moment, only blessed EVM chains are supported
roleKeysPerChain = objFilter(
@ -266,9 +272,15 @@ class ContextFunder {
multiProvider: MultiProvider,
contextsAndRolesToFund: ContextAndRolesMap,
skipIgpClaim: boolean,
desiredBalancePerChain: KeyFunderConfig['desiredBalancePerChain'],
desiredKathyBalancePerChain: KeyFunderConfig['desiredKathyBalancePerChain'],
igpClaimThresholdPerChain: KeyFunderConfig['igpClaimThresholdPerChain'],
desiredBalancePerChain: KeyFunderConfig<
ChainName[]
>['desiredBalancePerChain'],
desiredKathyBalancePerChain: KeyFunderConfig<
ChainName[]
>['desiredKathyBalancePerChain'],
igpClaimThresholdPerChain: KeyFunderConfig<
ChainName[]
>['igpClaimThresholdPerChain'],
filePath: string,
) {
logger.info({ filePath }, 'Reading identifiers and addresses from file');
@ -348,9 +360,15 @@ class ContextFunder {
context: Contexts,
rolesToFund: FundableRole[],
skipIgpClaim: boolean,
desiredBalancePerChain: KeyFunderConfig['desiredBalancePerChain'],
desiredKathyBalancePerChain: KeyFunderConfig['desiredKathyBalancePerChain'],
igpClaimThresholdPerChain: KeyFunderConfig['igpClaimThresholdPerChain'],
desiredBalancePerChain: KeyFunderConfig<
ChainName[]
>['desiredBalancePerChain'],
desiredKathyBalancePerChain: KeyFunderConfig<
ChainName[]
>['desiredKathyBalancePerChain'],
igpClaimThresholdPerChain: KeyFunderConfig<
ChainName[]
>['igpClaimThresholdPerChain'],
) {
// only roles that are fundable keys ie. relayer and kathy
const fundableRoleKeys: Record<FundableRole, Address> = {

@ -1,9 +1,10 @@
import { ChainMetadata } from '@hyperlane-xyz/sdk';
import { objMap, pick } from '@hyperlane-xyz/utils';
// Intentionally circumvent `mainnet3/index.ts` and `getEnvironmentConfig('mainnet3')`
// to avoid circular dependencies.
import { getRegistry as getMainnet3Registry } from '../config/environments/mainnet3/chains.js';
import { supportedChainNames as mainnet3SupportedChainNames } from '../config/environments/mainnet3/supportedChainNames.js';
import { mainnet3SupportedChainNames } from '../config/environments/mainnet3/supportedChainNames.js';
const CURRENCY = 'usd';
@ -11,8 +12,11 @@ async function main() {
const registry = await getMainnet3Registry();
const chainMetadata = await registry.getMetadata();
const metadata = pick(
await registry.getMetadata(),
mainnet3SupportedChainNames,
chainMetadata as Record<
(typeof mainnet3SupportedChainNames)[number],
ChainMetadata
>,
[...mainnet3SupportedChainNames],
);
const ids = objMap(

@ -2,7 +2,6 @@ import { IRegistry } from '@hyperlane-xyz/registry';
import {
BridgeAdapterConfig,
ChainMap,
ChainMetadata,
ChainName,
CoreConfig,
IgpConfig,
@ -60,7 +59,7 @@ export type EnvironmentConfig = {
role?: Role,
) => Promise<ChainMap<CloudAgentKey>>;
helloWorld?: Partial<Record<Contexts, HelloWorldConfig>>;
keyFunderConfig?: KeyFunderConfig;
keyFunderConfig?: KeyFunderConfig<string[]>;
liquidityLayerConfig?: {
bridgeAdapters: ChainMap<BridgeAdapterConfig>;
relayer: LiquidityLayerRelayerConfig;

@ -1,4 +1,4 @@
import { ChainMap } from '@hyperlane-xyz/sdk';
import { ChainName } from '@hyperlane-xyz/sdk';
import { Contexts } from '../../config/contexts.js';
import { FundableRole, Role } from '../roles.js';
@ -12,7 +12,7 @@ export interface ContextAndRoles {
export type ContextAndRolesMap = Partial<Record<Contexts, FundableRole[]>>;
export interface KeyFunderConfig {
export interface KeyFunderConfig<SupportedChains extends readonly ChainName[]> {
docker: DockerConfig;
cronSchedule: string;
namespace: string;
@ -20,7 +20,7 @@ export interface KeyFunderConfig {
contextsAndRolesToFund: ContextAndRolesMap;
cyclesBetweenEthereumMessages?: number;
prometheusPushGateway: string;
desiredBalancePerChain: ChainMap<string>;
desiredKathyBalancePerChain: ChainMap<string>;
igpClaimThresholdPerChain: ChainMap<string>;
desiredBalancePerChain: Record<SupportedChains[number], string>;
desiredKathyBalancePerChain: Record<SupportedChains[number], string>;
igpClaimThresholdPerChain: Record<SupportedChains[number], string>;
}

@ -7,7 +7,7 @@ import { execCmd } from '../utils/utils.js';
export async function runKeyFunderHelmCommand(
helmCommand: HelmCommand,
agentConfig: AgentContextConfig,
keyFunderConfig: KeyFunderConfig,
keyFunderConfig: KeyFunderConfig<string[]>,
) {
const values = getKeyFunderHelmValues(agentConfig, keyFunderConfig);
if (helmCommand === HelmCommand.InstallOrUpgrade) {
@ -36,7 +36,7 @@ export async function runKeyFunderHelmCommand(
function getKeyFunderHelmValues(
agentConfig: AgentContextConfig,
keyFunderConfig: KeyFunderConfig,
keyFunderConfig: KeyFunderConfig<string[]>,
) {
const values = {
cronjob: {
@ -65,7 +65,7 @@ function getKeyFunderHelmValues(
export function getKeyFunderConfig(
coreConfig: EnvironmentConfig,
): KeyFunderConfig {
): KeyFunderConfig<string[]> {
const keyFunderConfig = coreConfig.keyFunderConfig;
if (!keyFunderConfig) {
throw new Error(

Loading…
Cancel
Save