Skip to content

Commit

Permalink
Merge branch 'main' into dan/fix-cosmos-balance-parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-savu authored Dec 7, 2023
2 parents daef58d + 313a2ab commit 2cd538d
Show file tree
Hide file tree
Showing 14 changed files with 390 additions and 266 deletions.
2 changes: 1 addition & 1 deletion solidity/test/isms/DomainRoutingIsm.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ contract DomainRoutingIsmTest is Test {
_domains[i] = domain - i;
_isms[i] = deployTestIsm(bytes32(0));
}
ism = factory.deploy(_domains, _isms);
ism = factory.deploy(address(this), _domains, _isms);
for (uint256 i = 0; i < count; ++i) {
assertEq(address(ism.module(_domains[i])), address(_isms[i]));
}
Expand Down
8 changes: 2 additions & 6 deletions typescript/cli/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#! /usr/bin/env node
import figlet from 'figlet';
import chalk from 'chalk';
import yargs from 'yargs';

import { errorRed } from './logger.js';
Expand All @@ -13,11 +13,7 @@ import { VERSION } from './src/version.js';
// From yargs code:
const MISSING_PARAMS_ERROR = 'Not enough non-option arguments';

console.log(
figlet.textSync('Hyperlane', {
font: 'ANSI Shadow',
}),
);
console.log(chalk.blue('Hyperlane'), chalk.magentaBright('CLI'));

try {
await yargs(process.argv.slice(2))
Expand Down
2 changes: 0 additions & 2 deletions typescript/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@
"bignumber.js": "^9.1.1",
"chalk": "^5.3.0",
"ethers": "^5.7.2",
"figlet": "^1.7.0",
"terminal-link": "^3.0.0",
"yaml": "^2.3.1",
"yargs": "^17.7.2",
"zod": "^3.21.2"
},
"devDependencies": {
"@types/figlet": "^1",
"@types/mocha": "^10.0.1",
"@types/node": "^18.14.5",
"@types/yargs": "^17.0.24",
Expand Down
2 changes: 1 addition & 1 deletion typescript/infra/config/environments/mainnet3/funding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { environment } from './chains';
export const keyFunderConfig: KeyFunderConfig = {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: '4a3e6ee-20231025-192258',
tag: 'b86ebc1-20231207-123951',
},
// We're currently using the same deployer key as mainnet.
// To minimize nonce clobbering we offset the key funder cron
Expand Down
7 changes: 4 additions & 3 deletions typescript/infra/config/environments/mainnet3/helloworld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const hyperlane: HelloWorldConfig = {
kathy: {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: 'e21e020-20231201-111649',
tag: 'e152268-20231205-122327',
},
chainsToSkip: [],
runEnv: environment,
Expand All @@ -34,7 +34,7 @@ export const releaseCandidate: HelloWorldConfig = {
kathy: {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: 'e21e020-20231201-111649',
tag: 'e152268-20231205-122327',
},
chainsToSkip: [],
runEnv: environment,
Expand All @@ -50,5 +50,6 @@ export const releaseCandidate: HelloWorldConfig = {

export const helloWorld = {
[Contexts.Hyperlane]: hyperlane,
// [Contexts.ReleaseCandidate]: releaseCandidate,
[Contexts.ReleaseCandidate]: releaseCandidate,
[Contexts.Neutron]: undefined,
};
2 changes: 1 addition & 1 deletion typescript/infra/config/environments/testnet4/funding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { environment } from './chains';
export const keyFunderConfig: KeyFunderConfig = {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: 'cfaf553-20231009-174629',
tag: 'b86ebc1-20231207-123951',
},
// We're currently using the same deployer key as testnet2.
// To minimize nonce clobbering we offset the key funder cron
Expand Down
4 changes: 2 additions & 2 deletions typescript/infra/config/environments/testnet4/helloworld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const hyperlaneHelloworld: HelloWorldConfig = {
kathy: {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: 'e21e020-20231201-111649',
tag: 'e152268-20231205-122327',
},
chainsToSkip: [],
runEnv: environment,
Expand All @@ -33,7 +33,7 @@ export const releaseCandidateHelloworld: HelloWorldConfig = {
kathy: {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: 'e21e020-20231201-111649',
tag: 'e152268-20231205-122327',
},
chainsToSkip: [],
runEnv: environment,
Expand Down
186 changes: 106 additions & 80 deletions typescript/infra/scripts/funding/fund-keys-from-deployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,39 @@ import { Gauge, Registry } from 'prom-client';
import { format } from 'util';

import {
AllChains,
ChainMap,
ChainName,
Chains,
HyperlaneIgp,
MultiProvider,
RpcConsensusType,
} from '@hyperlane-xyz/sdk';
import { Address, error, log, warn } from '@hyperlane-xyz/utils';
import {
Address,
error,
log,
objFilter,
objMap,
promiseObjAll,
warn,
} from '@hyperlane-xyz/utils';

import { Contexts } from '../../config/contexts';
import { parseKeyIdentifier } from '../../src/agents/agent';
import { getAllCloudAgentKeys } from '../../src/agents/key-utils';
import { KeyAsAddress, getRoleKeysPerChain } from '../../src/agents/key-utils';
import {
BaseCloudAgentKey,
ReadOnlyCloudAgentKey,
} from '../../src/agents/keys';
import { DeployEnvironment } from '../../src/config';
import { deployEnvToSdkEnv } from '../../src/config/environment';
import { ContextAndRoles, ContextAndRolesMap } from '../../src/config/funding';
import { ALL_AGENT_ROLES, AgentRole, Role } from '../../src/roles';
import { Role } from '../../src/roles';
import { submitMetrics } from '../../src/utils/metrics';
import {
assertContext,
assertRole,
isEthereumProtocolChain,
readJSONAtPath,
} from '../../src/utils/utils';
import { getAgentConfig, getArgs, getEnvironmentConfig } from '../utils';
Expand Down Expand Up @@ -256,9 +264,9 @@ async function main() {
ContextFunder.fromSerializedAddressFile(
environment,
multiProvider,
path,
argv.contextsAndRoles,
argv.skipIgpClaim,
path,
),
);
} else {
Expand Down Expand Up @@ -293,78 +301,116 @@ async function main() {
class ContextFunder {
igp: HyperlaneIgp;

keysToFundPerChain: ChainMap<BaseCloudAgentKey[]>;

constructor(
public readonly environment: DeployEnvironment,
public readonly multiProvider: MultiProvider,
public readonly keys: BaseCloudAgentKey[],
roleKeysPerChain: ChainMap<Record<Role, BaseCloudAgentKey[]>>,
public readonly context: Contexts,
public readonly rolesToFund: Role[],
public readonly skipIgpClaim: boolean,
) {
// At the moment, only blessed EVM chains are supported
roleKeysPerChain = objFilter(
roleKeysPerChain,
(chain, _roleKeys): _roleKeys is Record<Role, BaseCloudAgentKey[]> => {
const valid =
isEthereumProtocolChain(chain) &&
multiProvider.tryGetChainName(chain) !== null;
if (!valid) {
warn('Skipping funding for non-blessed or non-Ethereum chain', {
chain,
});
}
return valid;
},
);

this.igp = HyperlaneIgp.fromEnvironment(
deployEnvToSdkEnv[this.environment],
multiProvider,
);
this.keysToFundPerChain = objMap(roleKeysPerChain, (_chain, roleKeys) => {
return Object.keys(roleKeys).reduce((agg, roleStr) => {
const role = roleStr as Role;
if (this.rolesToFund.includes(role)) {
return [...agg, ...roleKeys[role]];
}
return agg;
}, [] as BaseCloudAgentKey[]);
});
}

static fromSerializedAddressFile(
environment: DeployEnvironment,
multiProvider: MultiProvider,
path: string,
contextsAndRolesToFund: ContextAndRolesMap,
skipIgpClaim: boolean,
filePath: string,
) {
log('Reading identifiers and addresses from file', {
path,
filePath,
});
const idsAndAddresses = readJSONAtPath(path);
const keys: BaseCloudAgentKey[] = idsAndAddresses
.filter((idAndAddress: any) => {
const parsed = parseKeyIdentifier(idAndAddress.identifier);
// Filter out any invalid chain names. This can happen if we're running an old
// version of this script but the list of identifiers (expected to be stored in GCP secrets)
// references newer chains.
return (
parsed.chainName === undefined ||
(AllChains as string[]).includes(parsed.chainName)
);
})
.map((idAndAddress: any) =>
ReadOnlyCloudAgentKey.fromSerializedAddress(
idAndAddress.identifier,
idAndAddress.address,
),
);

const context = keys[0].context;
// Ensure all keys have the same context, just to be safe
for (const key of keys) {
if (key.context !== context) {
throw Error(
`Expected all keys at path ${path} to have context ${context}, found ${key.context}`,
);
}
// A big array of KeyAsAddress, including keys that we may not care about.
const allIdsAndAddresses: KeyAsAddress[] = readJSONAtPath(filePath);
if (!allIdsAndAddresses.length) {
throw Error(`Expected at least one key in file ${filePath}`);
}

const rolesToFund = contextsAndRolesToFund[context];
if (!rolesToFund) {
throw Error(
`Expected context ${context} to be defined in contextsAndRolesToFund`,
);
}
// Arbitrarily pick the first key to get the context
const firstKey = allIdsAndAddresses[0];
const context = ReadOnlyCloudAgentKey.fromSerializedAddress(
firstKey.identifier,
firstKey.address,
).context;

// Indexed by the identifier for quicker lookup
const idsAndAddresses: Record<string, KeyAsAddress> =
allIdsAndAddresses.reduce((agg, idAndAddress) => {
agg[idAndAddress.identifier] = idAndAddress;
return agg;
}, {} as Record<string, KeyAsAddress>);

log('Read keys for context from file', {
path,
keyCount: keys.length,
const agentConfig = getAgentConfig(context, environment);
// Unfetched keys per chain and role, so we know which keys
// we need. We'll use this to create a corresponding object
// of ReadOnlyCloudAgentKeys using addresses found in the
// serialized address file.
const roleKeysPerChain = getRoleKeysPerChain(agentConfig);

const readOnlyKeysPerChain = objMap(
roleKeysPerChain,
(_chain, roleKeys) => {
return objMap(roleKeys, (_role, keys) => {
return keys.map((key) => {
const idAndAddress = idsAndAddresses[key.identifier];
if (!idAndAddress) {
throw Error(
`Expected key identifier ${key.identifier} to be in file ${filePath}`,
);
}
return ReadOnlyCloudAgentKey.fromSerializedAddress(
idAndAddress.identifier,
idAndAddress.address,
);
});
});
},
);

log('Successfully read keys for context from file', {
filePath,
readOnlyKeysPerChain,
context,
});

return new ContextFunder(
environment,
multiProvider,
keys,
readOnlyKeysPerChain,
context,
rolesToFund,
contextsAndRolesToFund[context]!,
skipIgpClaim,
);
}
Expand All @@ -380,12 +426,22 @@ class ContextFunder {
skipIgpClaim: boolean,
) {
const agentConfig = getAgentConfig(context, environment);
const keys = getAllCloudAgentKeys(agentConfig);
await Promise.all(keys.map((key) => key.fetch()));
const roleKeysPerChain = getRoleKeysPerChain(agentConfig);
// Fetch all the keys
await promiseObjAll(
objMap(roleKeysPerChain, (_chain, roleKeys) => {
return promiseObjAll(
objMap(roleKeys, (_role, keys) => {
return Promise.all(keys.map((key) => key.fetch()));
}),
);
}),
);

return new ContextFunder(
environment,
multiProvider,
keys,
roleKeysPerChain,
context,
rolesToFund,
skipIgpClaim,
Expand All @@ -395,8 +451,7 @@ class ContextFunder {
// Funds all the roles in this.rolesToFund
// Returns whether a failure occurred.
async fund(): Promise<boolean> {
const chainKeys = this.getChainKeys();
const chainKeyEntries = Object.entries(chainKeys);
const chainKeyEntries = Object.entries(this.keysToFundPerChain);
const promises = chainKeyEntries.map(async ([chain, keys]) => {
let failureOccurred = false;
if (keys.length > 0) {
Expand Down Expand Up @@ -441,31 +496,6 @@ class ContextFunder {
return failureOccurred;
}

private getChainKeys() {
const chainKeys: ChainMap<BaseCloudAgentKey[]> = Object.fromEntries(
// init with empty arrays
AllChains.map((c) => [c, []]),
);
for (const role of this.rolesToFund) {
const keys = this.getKeysWithRole(role);
for (const key of keys) {
const chains = getAgentConfig(
key.context,
key.environment,
).contextChainNames;
// If the role is not a relayer, we need to look up the chains for Kathy, so we'll fallback to the relayer
const roleToLookup = ALL_AGENT_ROLES.includes(role as AgentRole)
? role
: Role.Relayer;
const chainsPicked = chains[roleToLookup as AgentRole];
for (const chain of chainsPicked) {
chainKeys[chain].push(key);
}
}
}
return chainKeys;
}

private async attemptToFundKey(
key: BaseCloudAgentKey,
chain: ChainName,
Expand Down Expand Up @@ -788,10 +818,6 @@ class ContextFunder {
),
);
}

private getKeysWithRole(role: Role) {
return this.keys.filter((k) => k.role === role);
}
}

async function getAddressInfo(
Expand Down
Loading

0 comments on commit 2cd538d

Please sign in to comment.