Rename domain to chain in typescript (#446)

* Rename domain to chain in typescript

* Update typescript/sdk/CHANGELOG.md

Co-authored-by: Yorke Rhodes <yorke@useabacus.network>

* Rename Network to Chain (#448)

* Rename Network to Chain

* PR review

Co-authored-by: Yorke Rhodes <yorke@useabacus.network>
pull/455/head
Nam Chu Hoai 3 years ago committed by GitHub
parent ac808a8641
commit 2934288f4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      typescript/deploy/src/check.ts
  2. 6
      typescript/deploy/src/config.ts
  3. 85
      typescript/deploy/src/core/deploy.ts
  4. 60
      typescript/deploy/src/deploy.ts
  5. 6
      typescript/deploy/src/proxy.ts
  6. 46
      typescript/deploy/src/router/check.ts
  7. 34
      typescript/deploy/src/router/deploy.ts
  8. 32
      typescript/deploy/src/utils.ts
  9. 40
      typescript/deploy/src/verify/ContractVerifier.ts
  10. 6
      typescript/infra/config/environments/dev/agent.ts
  11. 4
      typescript/infra/config/environments/dev/chains.ts
  12. 4
      typescript/infra/config/environments/dev/controller.ts
  13. 4
      typescript/infra/config/environments/dev/core.ts
  14. 4
      typescript/infra/config/environments/dev/index.ts
  15. 4
      typescript/infra/config/environments/dev/validators.ts
  16. 6
      typescript/infra/config/environments/test/agent.ts
  17. 4
      typescript/infra/config/environments/test/chains.ts
  18. 4
      typescript/infra/config/environments/test/controller.ts
  19. 4
      typescript/infra/config/environments/test/core.ts
  20. 4
      typescript/infra/config/environments/test/index.ts
  21. 4
      typescript/infra/config/environments/test/validators.ts
  22. 6
      typescript/infra/config/environments/testnet/agent.ts
  23. 4
      typescript/infra/config/environments/testnet/chains.ts
  24. 4
      typescript/infra/config/environments/testnet/core.ts
  25. 4
      typescript/infra/config/environments/testnet/index.ts
  26. 4
      typescript/infra/config/environments/testnet/validators.ts
  27. 27
      typescript/infra/hardhat.config.ts
  28. 2
      typescript/infra/scripts/deploy-agents.ts
  29. 13
      typescript/infra/scripts/set-validator.ts
  30. 4
      typescript/infra/scripts/update-agents-diff.ts
  31. 12
      typescript/infra/scripts/utils.ts
  32. 6
      typescript/infra/src/agents/aws/user.ts
  33. 8
      typescript/infra/src/agents/aws/validator-user.ts
  34. 36
      typescript/infra/src/agents/index.ts
  35. 22
      typescript/infra/src/agents/key-utils.ts
  36. 66
      typescript/infra/src/config/agent.ts
  37. 14
      typescript/infra/src/config/environment.ts
  38. 44
      typescript/infra/src/controller/check.ts
  39. 22
      typescript/infra/src/controller/deploy.ts
  40. 82
      typescript/infra/src/core/check.ts
  41. 52
      typescript/infra/src/core/control.ts
  42. 28
      typescript/infra/src/core/deploy.ts
  43. 8
      typescript/infra/src/verify.ts
  44. 10
      typescript/infra/test/controller.test.ts
  45. 21
      typescript/infra/test/core.test.ts
  46. 3
      typescript/sdk/CHANGELOG.md
  47. 28
      typescript/sdk/src/app.ts
  48. 49
      typescript/sdk/src/chain-metadata.ts
  49. 4
      typescript/sdk/src/chains.ts
  50. 44
      typescript/sdk/src/controller/app.ts
  51. 41
      typescript/sdk/src/core/app.ts
  52. 4
      typescript/sdk/src/core/message.ts
  53. 38
      typescript/sdk/src/events.ts
  54. 76
      typescript/sdk/src/gas/calculator.ts
  55. 4
      typescript/sdk/src/gas/token-prices.ts
  56. 2
      typescript/sdk/src/index.ts
  57. 22
      typescript/sdk/src/provider.ts
  58. 28
      typescript/sdk/src/types.ts
  59. 46
      typescript/sdk/src/utils.ts
  60. 2
      typescript/sdk/test/gas/calculator.test.ts
  61. 8
      typescript/sdk/test/utils.ts

@ -17,19 +17,19 @@ export interface Ownable {
}
export abstract class AbacusAppChecker<
Networks extends ChainName,
App extends AbacusApp<any, Networks>,
Chain extends ChainName,
App extends AbacusApp<any, Chain>,
Config,
> {
readonly multiProvider: MultiProvider<Networks>;
readonly multiProvider: MultiProvider<Chain>;
readonly app: App;
readonly configMap: ChainMap<Networks, Config>;
readonly configMap: ChainMap<Chain, Config>;
readonly violations: CheckerViolation[];
constructor(
multiProvider: MultiProvider<Networks>,
multiProvider: MultiProvider<Chain>,
app: App,
configMap: ChainMap<Networks, Config>,
configMap: ChainMap<Chain, Config>,
) {
this.multiProvider = multiProvider;
this.app = app;
@ -37,11 +37,11 @@ export abstract class AbacusAppChecker<
this.configMap = configMap;
}
abstract checkDomain(network: Networks): Promise<void>;
abstract checkChain(chain: Chain): Promise<void>;
async check() {
return Promise.all(
this.app.networks().map((network) => this.checkDomain(network)),
this.app.chains().map((chain) => this.checkChain(chain)),
);
}
@ -52,18 +52,18 @@ export abstract class AbacusAppChecker<
}
async checkUpgradeBeacon(
network: Networks,
chain: Chain,
name: string,
proxiedAddress: ProxiedAddress,
) {
const dc = this.multiProvider.getChainConnection(network);
const dc = this.multiProvider.getChainConnection(chain);
const implementation = await upgradeBeaconImplementation(
dc.provider!,
proxiedAddress.beacon,
);
if (implementation !== proxiedAddress.implementation) {
this.addViolation(
upgradeBeaconViolation(network, name, proxiedAddress, implementation),
upgradeBeaconViolation(chain, name, proxiedAddress, implementation),
);
}
}
@ -80,7 +80,7 @@ export abstract class AbacusAppChecker<
const duplicates = this.violations.filter(
(v) =>
violation.type === v.type &&
violation.network === v.network &&
violation.chain === v.chain &&
violation.actual === v.actual &&
violation.expected === v.expected,
);

@ -3,7 +3,7 @@ import { ethers } from 'ethers';
import { ChainMap, ChainName } from '@abacus-network/sdk';
export interface CheckerViolation {
network: ChainName;
chain: ChainName;
type: string;
expected: any;
actual: any;
@ -18,7 +18,7 @@ export type TransactionConfig = {
signer?: ethers.Signer;
};
export type EnvironmentConfig<Networks extends ChainName> = ChainMap<
Networks,
export type EnvironmentConfig<Chain extends ChainName> = ChainMap<
Chain,
TransactionConfig
>;

@ -22,7 +22,7 @@ import {
MultiProvider,
RemoteChainMap,
Remotes,
domains,
chainMetadata,
objMap,
promiseObjAll,
} from '@abacus-network/sdk';
@ -43,49 +43,49 @@ export type CoreConfig = {
type FactoryBuilder = (signer: ethers.Signer) => ethers.ContractFactory;
export class AbacusCoreDeployer<
Networks extends ChainName,
Chain extends ChainName,
> extends AbacusAppDeployer<
Networks,
Chain,
CoreConfig,
CoreContractAddresses<Networks, any>
CoreContractAddresses<Chain, any>
> {
inboxFactoryBuilder: FactoryBuilder = (signer: ethers.Signer) =>
new Inbox__factory(signer);
outboxFactoryBuilder: FactoryBuilder = (signer: ethers.Signer) =>
new Outbox__factory(signer);
startingBlockNumbers: ChainMap<Networks, number | undefined>;
startingBlockNumbers: ChainMap<Chain, number | undefined>;
constructor(
multiProvider: MultiProvider<Networks>,
configMap: ChainMap<Networks, CoreConfig>,
multiProvider: MultiProvider<Chain>,
configMap: ChainMap<Chain, CoreConfig>,
) {
super(multiProvider, configMap);
this.startingBlockNumbers = objMap(configMap, () => undefined);
}
async deployContracts<Local extends Networks>(
network: Local,
async deployContracts<LocalChain extends Chain>(
chain: LocalChain,
config: CoreConfig,
): Promise<CoreContractAddresses<Networks, Local>> {
const dc = this.multiProvider.getChainConnection(network);
): Promise<CoreContractAddresses<Chain, LocalChain>> {
const dc = this.multiProvider.getChainConnection(chain);
const signer = dc.signer!;
const provider = dc.provider!;
const startingBlockNumber = await provider.getBlockNumber();
this.startingBlockNumbers[network] = startingBlockNumber;
this.startingBlockNumbers[chain] = startingBlockNumber;
const upgradeBeaconController = await this.deployContract(
network,
chain,
'UpgradeBeaconController',
new UpgradeBeaconController__factory(signer),
[],
);
const outboxValidatorManagerConfig = config.validatorManager;
const domain = domains[network].id;
const domain = chainMetadata[chain].id;
const outboxValidatorManager = await this.deployContract(
network,
chain,
'OutboxValidatorManager',
new OutboxValidatorManager__factory(signer),
[
@ -96,7 +96,7 @@ export class AbacusCoreDeployer<
);
const outbox = await this.deployProxiedContract(
network,
chain,
'Outbox',
this.outboxFactoryBuilder(signer),
[domain],
@ -105,14 +105,14 @@ export class AbacusCoreDeployer<
);
const interchainGasPaymaster = await this.deployContract(
network,
chain,
'InterchainGasPaymaster',
new InterchainGasPaymaster__factory(signer),
[],
);
const abacusConnectionManager = await this.deployContract(
network,
chain,
'AbacusConnectionManager',
new AbacusConnectionManager__factory(signer),
[],
@ -127,31 +127,35 @@ export class AbacusCoreDeployer<
);
const remotes = Object.keys(this.configMap).filter(
(k) => k !== network,
) as Remotes<Networks, Local>[];
(k) => k !== chain,
) as Remotes<Chain, LocalChain>[];
const deployValidatorManager = async (
remote: Remotes<Networks, Local>,
remote: Remotes<Chain, LocalChain>,
): Promise<InboxValidatorManager> => {
const remoteConfig = this.configMap[remote].validatorManager;
return this.deployContract(
network,
chain,
'InboxValidatorManager',
new InboxValidatorManager__factory(signer),
[domains[remote].id, remoteConfig.validators, remoteConfig.threshold],
[
chainMetadata[remote].id,
remoteConfig.validators,
remoteConfig.threshold,
],
);
};
const [firstRemote, ...trailingRemotes] = remotes;
const firstValidatorManager = await deployValidatorManager(firstRemote);
const firstInbox = await this.deployProxiedContract(
network,
chain,
'Inbox',
this.inboxFactoryBuilder(signer),
[domain],
upgradeBeaconController.address,
[
domains[firstRemote].id,
chainMetadata[firstRemote].id,
firstValidatorManager.address,
ethers.constants.HashZero,
0,
@ -166,7 +170,7 @@ export class AbacusCoreDeployer<
validatorManager: validatorManager.address,
});
type RemoteMailboxEntry = [Remotes<Networks, Local>, MailboxAddresses];
type RemoteMailboxEntry = [Remotes<Chain, LocalChain>, MailboxAddresses];
const firstInboxAddresses: RemoteMailboxEntry = [
firstRemote,
@ -177,11 +181,11 @@ export class AbacusCoreDeployer<
trailingRemotes.map(async (remote): Promise<RemoteMailboxEntry> => {
const validatorManager = await deployValidatorManager(remote);
const inbox = await this.duplicateProxiedContract(
network,
chain,
'Inbox',
firstInbox,
[
domains[remote].id,
chainMetadata[remote].id,
validatorManager.address,
ethers.constants.HashZero,
0,
@ -196,7 +200,10 @@ export class AbacusCoreDeployer<
await Promise.all(
inboxAddresses.map(([remote, mailbox]) =>
abacusConnectionManager.enrollInbox(domains[remote].id, mailbox.proxy),
abacusConnectionManager.enrollInbox(
chainMetadata[remote].id,
mailbox.proxy,
),
),
);
@ -206,8 +213,8 @@ export class AbacusCoreDeployer<
interchainGasPaymaster: interchainGasPaymaster.address,
outbox: getMailbox(outboxValidatorManager, outbox),
inboxes: Object.fromEntries(inboxAddresses) as RemoteChainMap<
Networks,
Local,
Chain,
LocalChain,
MailboxAddresses
>,
};
@ -219,10 +226,10 @@ export class AbacusCoreDeployer<
multiProvider: MultiProvider<CoreNetworks>,
) {
return promiseObjAll(
objMap(core.contractsMap, async (network, coreContracts) => {
const owner = owners[network];
const chainConnection = multiProvider.getChainConnection(network);
return AbacusCoreDeployer.transferOwnershipOfDomain(
objMap(core.contractsMap, async (chain, coreContracts) => {
const owner = owners[chain];
const chainConnection = multiProvider.getChainConnection(chain);
return AbacusCoreDeployer.transferOwnershipOfChain(
coreContracts,
owner,
chainConnection,
@ -231,11 +238,11 @@ export class AbacusCoreDeployer<
);
}
static async transferOwnershipOfDomain<
CoreNetworks extends ChainName,
Local extends CoreNetworks,
static async transferOwnershipOfChain<
Chain extends ChainName,
Local extends Chain,
>(
core: CoreContracts<CoreNetworks, Local>,
core: CoreContracts<Chain, Local>,
owner: types.Address,
chainConnection: ChainConnection,
): Promise<ethers.ContractReceipt> {

@ -21,40 +21,37 @@ import {
} from './verify';
// TODO: Make AppDeployer generic on AbacusApp and return instance from deploy()
export abstract class AbacusAppDeployer<Networks extends ChainName, C, A> {
verificationInputs: ChainMap<Networks, ContractVerificationInput[]>;
export abstract class AbacusAppDeployer<Chain extends ChainName, C, A> {
verificationInputs: ChainMap<Chain, ContractVerificationInput[]>;
constructor(
protected readonly multiProvider: MultiProvider<Networks>,
protected readonly configMap: ChainMap<Networks, C>,
protected readonly multiProvider: MultiProvider<Chain>,
protected readonly configMap: ChainMap<Chain, C>,
) {
this.verificationInputs = objMap(configMap, () => []);
}
abstract deployContracts(network: Networks, config: C): Promise<A>;
abstract deployContracts(chain: Chain, config: C): Promise<A>;
async deploy() {
this.verificationInputs = objMap(this.configMap, () => []);
const networks = Object.keys(this.configMap) as Networks[];
const entries: [Networks, A][] = [];
for (const network of networks) {
console.log(`Deploying to ${network}...`);
const result = await this.deployContracts(
network,
this.configMap[network],
);
entries.push([network, result]);
const chains = Object.keys(this.configMap) as Chain[];
const entries: [Chain, A][] = [];
for (const chain of chains) {
console.log(`Deploying to ${chain}...`);
const result = await this.deployContracts(chain, this.configMap[chain]);
entries.push([chain, result]);
}
return Object.fromEntries(entries) as Record<Networks, A>;
return Object.fromEntries(entries) as Record<Chain, A>;
}
async deployContract<F extends ethers.ContractFactory>(
network: Networks,
chain: Chain,
contractName: string,
factory: F,
args: Parameters<F['deploy']>,
): Promise<ReturnType<F['deploy']>> {
const chainConnection = this.multiProvider.getChainConnection(network);
const chainConnection = this.multiProvider.getChainConnection(chain);
const contract = await factory.deploy(...args, chainConnection.overrides);
await contract.deployTransaction.wait(chainConnection.confirmations);
const verificationInput = getContractVerificationInput(
@ -62,7 +59,7 @@ export abstract class AbacusAppDeployer<Networks extends ChainName, C, A> {
contract,
factory.bytecode,
);
this.verificationInputs[network].push(verificationInput);
this.verificationInputs[chain].push(verificationInput);
return contract;
}
@ -74,23 +71,23 @@ export abstract class AbacusAppDeployer<Networks extends ChainName, C, A> {
F extends ethers.ContractFactory,
C extends ethers.Contract = Awaited<ReturnType<F['deploy']>>,
>(
network: Networks,
chain: Chain,
contractName: string,
factory: F,
deployArgs: Parameters<F['deploy']>,
ubcAddress: types.Address,
initArgs: Parameters<C['initialize']>,
) {
const chainConnection = this.multiProvider.getChainConnection(network);
const chainConnection = this.multiProvider.getChainConnection(chain);
const signer = chainConnection.signer;
const implementation = await this.deployContract(
network,
chain,
`${contractName} Implementation`,
factory,
deployArgs,
);
const beacon = await this.deployContract(
network,
chain,
`${contractName} UpgradeBeacon`,
new UpgradeBeacon__factory(signer),
[implementation.address, ubcAddress],
@ -101,7 +98,7 @@ export abstract class AbacusAppDeployer<Networks extends ChainName, C, A> {
initArgs,
);
const proxy = await this.deployContract(
network,
chain,
`${contractName} Proxy`,
new UpgradeBeaconProxy__factory(signer),
[beacon.address, initData],
@ -120,18 +117,18 @@ export abstract class AbacusAppDeployer<Networks extends ChainName, C, A> {
*
*/
async duplicateProxiedContract<C extends ethers.Contract>(
network: Networks,
chain: Chain,
contractName: string,
proxy: ProxiedContract<C>,
initArgs: Parameters<C['initialize']>,
) {
const chainConnection = this.multiProvider.getChainConnection(network);
const chainConnection = this.multiProvider.getChainConnection(chain);
const initData = proxy.contract.interface.encodeFunctionData(
'initialize',
initArgs,
);
const newProxy = await this.deployContract(
network,
chain,
`${contractName} Proxy`,
new UpgradeBeaconProxy__factory(chainConnection.signer!),
[proxy.addresses.beacon, initData],
@ -147,12 +144,12 @@ export abstract class AbacusAppDeployer<Networks extends ChainName, C, A> {
return newProxiedContract;
}
writeOutput(directory: string, addresses: ChainMap<Networks, A>) {
writeOutput(directory: string, addresses: ChainMap<Chain, A>) {
this.writeContracts(addresses, path.join(directory, 'addresses.ts'));
this.writeVerification(path.join(directory, 'verification'));
}
writeContracts(addresses: ChainMap<Networks, A>, filepath: string) {
writeContracts(addresses: ChainMap<Chain, A>, filepath: string) {
const contents = `export const addresses = ${AbacusAppDeployer.stringify(
addresses,
)}`;
@ -160,11 +157,8 @@ export abstract class AbacusAppDeployer<Networks extends ChainName, C, A> {
}
writeVerification(directory: string) {
objMap(this.verificationInputs, (network, input) => {
AbacusAppDeployer.writeJson(
path.join(directory, `${network}.json`),
input,
);
objMap(this.verificationInputs, (chain, input) => {
AbacusAppDeployer.writeJson(path.join(directory, `${chain}.json`), input);
});
}

@ -39,14 +39,14 @@ export async function upgradeBeaconImplementation(
return ethers.utils.getAddress(storageValue.slice(26));
}
export function upgradeBeaconViolation<Networks extends ChainName>(
network: Networks,
export function upgradeBeaconViolation<Chain extends ChainName>(
chain: Chain,
name: string,
proxiedAddress: ProxiedAddress,
actual: types.Address,
): UpgradeBeaconViolation {
return {
network,
chain,
type: ProxyViolationType.UpgradeBeacon,
actual,
expected: proxiedAddress.implementation,

@ -1,6 +1,6 @@
import { expect } from 'chai';
import { AbacusApp, ChainName, domains } from '@abacus-network/sdk';
import { AbacusApp, ChainName, chainMetadata } from '@abacus-network/sdk';
import { types, utils } from '@abacus-network/utils';
import { AbacusAppChecker, Ownable } from '../check';
@ -8,33 +8,33 @@ import { AbacusAppChecker, Ownable } from '../check';
import { Router, RouterConfig } from './types';
export abstract class AbacusRouterChecker<
Networks extends ChainName,
App extends AbacusApp<any, Networks>,
Chain extends ChainName,
App extends AbacusApp<any, Chain>,
Config extends RouterConfig & {
owner: types.Address;
},
> extends AbacusAppChecker<Networks, App, Config> {
abstract mustGetRouter(network: Networks): Router; // TODO: implement on AbacusRouterApp
> extends AbacusAppChecker<Chain, App, Config> {
abstract mustGetRouter(chain: Chain): Router; // TODO: implement on AbacusRouterApp
checkOwnership(network: Networks) {
const owner = this.configMap[network].owner;
const ownables = this.ownables(network);
checkOwnership(chain: Chain) {
const owner = this.configMap[chain].owner;
const ownables = this.ownables(chain);
return AbacusAppChecker.checkOwnership(owner, ownables);
}
async checkDomain(network: Networks): Promise<void> {
await this.checkEnrolledRouters(network);
await this.checkOwnership(network);
await this.checkAbacusConnectionManager(network);
async checkChain(chain: Chain): Promise<void> {
await this.checkEnrolledRouters(chain);
await this.checkOwnership(chain);
await this.checkAbacusConnectionManager(chain);
}
async checkEnrolledRouters(network: Networks): Promise<void> {
const router = this.mustGetRouter(network);
async checkEnrolledRouters(chain: Chain): Promise<void> {
const router = this.mustGetRouter(chain);
await Promise.all(
this.app.remotes(network).map(async (remoteNetwork) => {
this.app.remoteChains(chain).map(async (remoteNetwork) => {
const remoteRouter = this.mustGetRouter(remoteNetwork);
const remoteChainId = domains[remoteNetwork].id;
const remoteChainId = chainMetadata[remoteNetwork].id;
expect(await router.routers(remoteChainId)).to.equal(
utils.addressToBytes32(remoteRouter.address),
);
@ -42,24 +42,24 @@ export abstract class AbacusRouterChecker<
);
}
ownables(network: Networks): Ownable[] {
const ownables: Ownable[] = [this.mustGetRouter(network)];
const config = this.configMap[network];
ownables(chain: Chain): Ownable[] {
const ownables: Ownable[] = [this.mustGetRouter(chain)];
const config = this.configMap[chain];
// If the config specifies that an abacusConnectionManager should have been deployed,
// it should be owned by the owner.
if (config.abacusConnectionManager) {
const contracts: any = this.app.getContracts(network);
const contracts: any = this.app.getContracts(chain);
ownables.push(contracts.abacusConnectionManager);
}
return ownables;
}
async checkAbacusConnectionManager(network: Networks): Promise<void> {
const config = this.configMap[network];
async checkAbacusConnectionManager(chain: Chain): Promise<void> {
const config = this.configMap[chain];
if (!config.abacusConnectionManager) {
return;
}
const actual = await this.mustGetRouter(network).abacusConnectionManager();
const actual = await this.mustGetRouter(chain).abacusConnectionManager();
expect(actual).to.equal(config.abacusConnectionManager);
}
}

@ -7,7 +7,7 @@ import {
ChainMap,
ChainName,
MultiProvider,
domains,
chainMetadata,
objMap,
promiseObjAll,
} from '@abacus-network/sdk';
@ -18,18 +18,18 @@ import { AbacusAppDeployer } from '../deploy';
import { Router, RouterConfig } from './types';
export abstract class AbacusRouterDeployer<
Networks extends ChainName,
Chain extends ChainName,
Config extends RouterConfig,
Addresses,
> extends AbacusAppDeployer<Networks, Config, Addresses> {
protected core?: AbacusCore<Networks>;
> extends AbacusAppDeployer<Chain, Config, Addresses> {
protected core?: AbacusCore<Chain>;
abstract mustGetRouter(network: Networks, addresses: Addresses): Router;
abstract mustGetRouter(chain: Chain, addresses: Addresses): Router;
constructor(
multiProvider: MultiProvider<Networks>,
configMap: ChainMap<Networks, Config>,
core?: AbacusCore<Networks>,
multiProvider: MultiProvider<Chain>,
configMap: ChainMap<Chain, Config>,
core?: AbacusCore<Chain>,
) {
super(multiProvider, configMap);
this.core = core;
@ -42,13 +42,13 @@ export abstract class AbacusRouterDeployer<
await promiseObjAll(
objMap(deploymentOutput, async (local, addresses) => {
const localRouter = this.mustGetRouter(local, addresses);
for (const remote of this.multiProvider.remotes(local)) {
for (const remote of this.multiProvider.remoteChains(local)) {
const remoteRouter = this.mustGetRouter(
remote,
deploymentOutput[remote],
);
await localRouter.enrollRemoteRouter(
domains[remote].id,
chainMetadata[remote].id,
utils.addressToBytes32(remoteRouter.address),
);
}
@ -59,11 +59,11 @@ export abstract class AbacusRouterDeployer<
}
async deployConnectionManagerIfNotConfigured(
network: Networks,
chain: Chain,
): Promise<AbacusConnectionManager> {
const dc = this.multiProvider.getChainConnection(network);
const dc = this.multiProvider.getChainConnection(chain);
const signer = dc.signer!;
const config = this.configMap[network];
const config = this.configMap[chain];
if (config.abacusConnectionManager) {
return AbacusConnectionManager__factory.connect(
config.abacusConnectionManager,
@ -72,7 +72,7 @@ export abstract class AbacusRouterDeployer<
}
const abacusConnectionManager = await this.deployContract(
network,
chain,
'AbacusConnectionManager',
new AbacusConnectionManager__factory(signer),
[],
@ -80,14 +80,14 @@ export abstract class AbacusRouterDeployer<
const overrides = dc.overrides;
if (!this.core)
throw new Error('must set core or configure abacusConnectionManager');
const localCore = this.core.getContracts(network);
const localCore = this.core.getContracts(chain);
await abacusConnectionManager.setOutbox(
localCore.outbox.outbox.address,
overrides,
);
for (const remote of this.core.remotes(network)) {
for (const remote of this.core.remoteChains(chain)) {
await abacusConnectionManager.enrollInbox(
domains[remote].id,
chainMetadata[remote].id,
localCore.inboxes[remote].inbox.address,
overrides,
);

@ -50,12 +50,12 @@ function fixOverrides(config: TransactionConfig): ethers.Overrides {
}
}
export const registerEnvironment = <Networks extends ChainName>(
multiProvider: MultiProvider<Networks>,
environmentConfig: EnvironmentConfig<Networks>,
export const registerEnvironment = <Chain extends ChainName>(
multiProvider: MultiProvider<Chain>,
environmentConfig: EnvironmentConfig<Chain>,
) => {
multiProvider.apply((network, dc) => {
const txConfig = environmentConfig[network];
multiProvider.apply((chain, dc) => {
const txConfig = environmentConfig[chain];
dc.registerOverrides(fixOverrides(txConfig));
if (txConfig.confirmations) {
dc.registerConfirmations(txConfig.confirmations);
@ -66,28 +66,28 @@ export const registerEnvironment = <Networks extends ChainName>(
});
};
export const registerSigners = <Networks extends ChainName>(
export const registerSigners = <Chain extends ChainName>(
multiProvider: MultiProvider,
signers: ChainMap<Networks, ethers.Signer>,
signers: ChainMap<Chain, ethers.Signer>,
) =>
objMap(signers, (network, signer) =>
multiProvider.getChainConnection(network).registerSigner(signer),
objMap(signers, (chain, signer) =>
multiProvider.getChainConnection(chain).registerSigner(signer),
);
export const registerSigner = <Networks extends ChainName>(
multiProvider: MultiProvider<Networks>,
export const registerSigner = <Chain extends ChainName>(
multiProvider: MultiProvider<Chain>,
signer: ethers.Signer,
) => multiProvider.apply((_, dc) => dc.registerSigner(signer));
export const getMultiProviderFromConfigAndSigner = <Networks extends ChainName>(
environmentConfig: EnvironmentConfig<Networks>,
export const getMultiProviderFromConfigAndSigner = <Chain extends ChainName>(
environmentConfig: EnvironmentConfig<Chain>,
signer: ethers.Signer,
): MultiProvider<Networks> => {
const networkProviders = objMap(environmentConfig, () => ({
): MultiProvider<Chain> => {
const chainProviders = objMap(environmentConfig, () => ({
provider: signer.provider!,
signer,
}));
const multiProvider = new MultiProvider(networkProviders);
const multiProvider = new MultiProvider(chainProviders);
registerEnvironment(multiProvider, environmentConfig);
return multiProvider;
};

@ -17,49 +17,47 @@ const etherscanChains = [
export abstract class ContractVerifier {
constructor(public readonly key: string) {}
abstract networks: ChainName[];
abstract getVerificationInput(network: ChainName): VerificationInput;
abstract chainNames: ChainName[];
abstract getVerificationInput(chain: ChainName): VerificationInput;
static etherscanLink(network: ChainName, address: types.Address) {
if (network === 'polygon') {
static etherscanLink(chain: ChainName, address: types.Address) {
if (chain === 'polygon') {
return `https://polygonscan.com/address/${address}`;
}
const prefix = network === 'ethereum' ? '' : `${network}.`;
const prefix = chain === 'ethereum' ? '' : `${chain}.`;
return `https://${prefix}etherscan.io/address/${address}`;
}
async verify(hre: any) {
let network = hre.network.name;
let chain = hre.network.name;
if (network === 'mainnet') {
network = 'ethereum';
if (chain === 'mainnet') {
chain = 'ethereum';
}
const envError = (network: string) =>
`pass --network tag to hardhat task (current network=${network})`;
// assert that network from .env is supported by Etherscan
if (!etherscanChains.includes(network)) {
throw new Error(
`Network not supported by Etherscan; ${envError(network)}`,
);
if (!etherscanChains.includes(chain)) {
throw new Error(`Network not supported by Etherscan; ${envError(chain)}`);
}
// get the JSON verification inputs for the given network
// from the latest contract deploy; throw if not found
const verificationInputs = this.getVerificationInput(network);
const verificationInputs = this.getVerificationInput(chain);
// loop through each verification input for each contract in the file
for (const verificationInput of verificationInputs) {
// attempt to verify contract on etherscan
// (await one-by-one so that Etherscan doesn't rate limit)
await this.verifyContract(network, verificationInput, hre);
await this.verifyContract(chain, verificationInput, hre);
}
}
async verifyContract(
network: ChainName,
chain: ChainName,
input: ContractVerificationInput,
hre: any,
) {
@ -67,10 +65,10 @@ export abstract class ContractVerifier {
console.log(
` Attempt to verify ${
input.name
} - ${ContractVerifier.etherscanLink(network, input.address)}`,
} - ${ContractVerifier.etherscanLink(chain, input.address)}`,
);
await hre.run('verify:verify', {
network,
chain,
address: input.address,
constructorArguments: input.constructorArguments,
});
@ -78,7 +76,7 @@ export abstract class ContractVerifier {
if (input.isProxy) {
console.log(` Attempt to verify as proxy`);
await this.verifyProxy(network, input.address);
await this.verifyProxy(chain, input.address);
console.log(` SUCCESS submitting proxy verification`);
}
} catch (e) {
@ -88,10 +86,10 @@ export abstract class ContractVerifier {
console.log('\n\n'); // add space after each attempt
}
async verifyProxy(network: ChainName, address: types.Address) {
const suffix = network === 'ethereum' ? '' : `-${network}`;
async verifyProxy(chain: ChainName, address: types.Address) {
const suffix = chain === 'ethereum' ? '' : `-${chain}`;
console.log(` Submit ${address} for proxy verification on ${network}`);
console.log(` Submit ${address} for proxy verification on ${chain}`);
// Submit contract for verification
const verifyResponse = await axios.post(
`https://api${suffix}.etherscan.io/api`,

@ -1,9 +1,9 @@
import { AgentConfig } from '../../../src/config';
import { DevNetworks, domainNames } from './domains';
import { DevChains, chainNames } from './chains';
import { validators } from './validators';
export const agent: AgentConfig<DevNetworks> = {
export const agent: AgentConfig<DevChains> = {
environment: 'dev',
namespace: 'dev',
runEnv: 'dev',
@ -11,7 +11,7 @@ export const agent: AgentConfig<DevNetworks> = {
repo: 'gcr.io/abacus-labs-dev/abacus-agent',
tag: 'sha-3c312d7',
},
domainNames,
chainNames,
validatorSets: validators,
validator: {
default: {

@ -5,5 +5,5 @@ export const devConfigs = {
kovan: configs.kovan,
};
export type DevNetworks = keyof typeof devConfigs;
export const domainNames = Object.keys(devConfigs) as DevNetworks[];
export type DevChains = keyof typeof devConfigs;
export const chainNames = Object.keys(devConfigs) as DevChains[];

@ -2,7 +2,7 @@ import { ChainMap } from '@abacus-network/sdk';
import { ControllerConfig } from '../../../src/controller';
import { DevNetworks } from './domains';
import { DevChains } from './chains';
const defaultControllerConfig = {
recoveryManager: '0x3909CFACD7a568634716CbCE635F76b9Cf37364B',
@ -17,4 +17,4 @@ const addresses = {
kovan: defaultControllerConfig,
};
export const controller: ChainMap<DevNetworks, ControllerConfig> = addresses;
export const controller: ChainMap<DevChains, ControllerConfig> = addresses;

@ -1,9 +1,9 @@
import { CoreConfig } from '@abacus-network/deploy';
import { ChainMap } from '@abacus-network/sdk';
import { DevNetworks } from './domains';
import { DevChains } from './chains';
export const core: ChainMap<DevNetworks, CoreConfig> = {
export const core: ChainMap<DevChains, CoreConfig> = {
alfajores: {
validatorManager: {
validators: [

@ -2,12 +2,12 @@ import { getMultiProviderFromGCP } from '../../../scripts/utils';
import { CoreEnvironmentConfig } from '../../../src/config';
import { agent } from './agent';
import { DevChains, devConfigs } from './chains';
import { controller } from './controller';
import { core } from './core';
import { DevNetworks, devConfigs } from './domains';
import { infrastructure } from './infrastructure';
export const environment: CoreEnvironmentConfig<DevNetworks> = {
export const environment: CoreEnvironmentConfig<DevChains> = {
transactionConfigs: devConfigs,
getMultiProvider: () => getMultiProviderFromGCP(devConfigs, 'dev'),
agent,

@ -5,14 +5,14 @@ import {
CheckpointSyncerType,
} from '../../../src/config/agent';
import { DevNetworks } from './domains';
import { DevChains } from './chains';
const s3BucketRegion = 'us-east-1';
const s3BucketName = (chainName: ChainName, index: number) =>
`abacus-dev-${chainName}-validator-${index}`;
export const validators: ChainValidatorSets<DevNetworks> = {
export const validators: ChainValidatorSets<DevChains> = {
alfajores: {
threshold: 2,
validators: [

@ -1,9 +1,9 @@
import { AgentConfig } from '../../../src/config';
import { TestNetworks, domainNames } from './domains';
import { TestChains, chainNames } from './chains';
import { validators } from './validators';
export const agent: AgentConfig<TestNetworks> = {
export const agent: AgentConfig<TestChains> = {
environment: 'test',
namespace: 'test',
runEnv: 'test',
@ -11,7 +11,7 @@ export const agent: AgentConfig<TestNetworks> = {
repo: 'gcr.io/abacus-labs-dev/abacus-agent',
tag: '8852db3d88e87549269487da6da4ea5d67fdbfed',
},
domainNames,
chainNames,
validatorSets: validators,
validator: {
default: {

@ -6,5 +6,5 @@ export const testConfigs = {
test3: configs.test3,
};
export type TestNetworks = keyof typeof testConfigs;
export const domainNames = Object.keys(testConfigs) as TestNetworks[];
export type TestChains = keyof typeof testConfigs;
export const chainNames = Object.keys(testConfigs) as TestChains[];

@ -2,7 +2,7 @@ import { ChainMap } from '@abacus-network/sdk';
import { ControllerConfig } from '../../../src/controller';
import { TestNetworks } from './domains';
import { TestChains } from './chains';
const defaultControllerConfig: ControllerConfig = {
recoveryManager: '0x4FbBB2b0820CF0cF027BbB58DC7F7f760BC0c57e',
@ -18,4 +18,4 @@ const addresses = {
test3: defaultControllerConfig,
};
export const controller: ChainMap<TestNetworks, ControllerConfig> = addresses;
export const controller: ChainMap<TestChains, ControllerConfig> = addresses;

@ -1,9 +1,9 @@
import { CoreConfig } from '@abacus-network/deploy';
import { ChainMap } from '@abacus-network/sdk';
import { TestNetworks } from './domains';
import { TestChains } from './chains';
export const core: ChainMap<TestNetworks, CoreConfig> = {
export const core: ChainMap<TestChains, CoreConfig> = {
// Hardhat accounts 1-4
test1: {
validatorManager: {

@ -3,12 +3,12 @@ import { utils } from '@abacus-network/deploy';
import { CoreEnvironmentConfig } from '../../../src/config';
import { agent } from './agent';
import { TestChains, testConfigs } from './chains';
import { controller } from './controller';
import { core } from './core';
import { TestNetworks, testConfigs } from './domains';
import { infra } from './infra';
export const environment: CoreEnvironmentConfig<TestNetworks> = {
export const environment: CoreEnvironmentConfig<TestChains> = {
transactionConfigs: testConfigs,
agent,
core,

@ -5,12 +5,12 @@ import {
CheckpointSyncerType,
} from '../../../src/config/agent';
import { TestNetworks } from './domains';
import { TestChains } from './chains';
const localStoragePath = (chainName: ChainName) =>
`/tmp/abacus-test-${chainName}-validator`;
export const validators: ChainValidatorSets<TestNetworks> = {
export const validators: ChainValidatorSets<TestChains> = {
test1: {
threshold: 1,
validators: [

@ -1,9 +1,9 @@
import { AgentConfig } from '../../../src/config';
import { TestnetNetworks, domainNames } from './domains';
import { TestnetChains, chainNames } from './chains';
import { validators } from './validators';
export const agent: AgentConfig<TestnetNetworks> = {
export const agent: AgentConfig<TestnetChains> = {
environment: 'testnet',
namespace: 'testnet',
runEnv: 'testnet',
@ -14,7 +14,7 @@ export const agent: AgentConfig<TestnetNetworks> = {
aws: {
region: 'us-east-1',
},
domainNames,
chainNames: chainNames,
validatorSets: validators,
validator: {
default: {

@ -10,5 +10,5 @@ export const testnetConfigs = {
optimismkovan: configs.optimismkovan,
};
export type TestnetNetworks = keyof typeof testnetConfigs;
export const domainNames = Object.keys(testnetConfigs) as TestnetNetworks[];
export type TestnetChains = keyof typeof testnetConfigs;
export const chainNames = Object.keys(testnetConfigs) as TestnetChains[];

@ -1,9 +1,9 @@
import { CoreConfig } from '@abacus-network/deploy';
import { ChainMap } from '@abacus-network/sdk';
import { TestnetNetworks } from './domains';
import { TestnetChains } from './chains';
export const core: ChainMap<TestnetNetworks, CoreConfig> = {
export const core: ChainMap<TestnetChains, CoreConfig> = {
alfajores: {
validatorManager: {
validators: [

@ -2,12 +2,12 @@ import { getMultiProviderFromGCP } from '../../../scripts/utils';
import { CoreEnvironmentConfig } from '../../../src/config';
import { agent } from './agent';
import { TestnetChains, testnetConfigs } from './chains';
import { controller } from './controller';
import { core } from './core';
import { TestnetNetworks, testnetConfigs } from './domains';
import { infrastructure } from './infrastructure';
export const environment: CoreEnvironmentConfig<TestnetNetworks> = {
export const environment: CoreEnvironmentConfig<TestnetChains> = {
transactionConfigs: testnetConfigs,
getMultiProvider: () => getMultiProviderFromGCP(testnetConfigs, 'testnet'),
agent,

@ -5,14 +5,14 @@ import {
CheckpointSyncerType,
} from '../../../src/config/agent';
import { TestnetNetworks } from './domains';
import { TestnetChains } from './chains';
const s3BucketRegion = 'us-east-1';
const s3BucketName = (chainName: ChainName, index: number) =>
`abacus-testnet-${chainName}-validator-${index}`;
export const validators: ChainValidatorSets<TestnetNetworks> = {
export const validators: ChainValidatorSets<TestnetChains> = {
alfajores: {
threshold: 2,
validators: [

@ -22,25 +22,24 @@ import { AbacusCoreInfraDeployer } from './src/core/deploy';
import { sleep } from './src/utils/utils';
import { AbacusContractVerifier } from './src/verify';
const domainSummary = async <Networks extends ChainName>(
core: AbacusCore<Networks>,
network: Networks,
const chainSummary = async <Chain extends ChainName>(
core: AbacusCore<Chain>,
chain: Chain,
) => {
const coreContracts = core.getContracts(network);
const coreContracts = core.getContracts(chain);
const outbox = coreContracts.outbox.outbox;
const [outboxCheckpointRoot, outboxCheckpointIndex] =
await outbox.latestCheckpoint();
const count = (await outbox.tree()).toNumber();
const inboxSummary = async (remote: Networks) => {
const inbox =
coreContracts.inboxes[remote as Exclude<Networks, Networks>].inbox;
const inboxSummary = async (remote: Chain) => {
const inbox = coreContracts.inboxes[remote as Exclude<Chain, Chain>].inbox;
const [inboxCheckpointRoot, inboxCheckpointIndex] =
await inbox.latestCheckpoint();
const processFilter = inbox.filters.Process();
const processes = await inbox.queryFilter(processFilter);
return {
network: remote,
chain: remote,
processed: processes.length,
root: inboxCheckpointRoot,
index: inboxCheckpointIndex.toNumber(),
@ -48,7 +47,7 @@ const domainSummary = async <Networks extends ChainName>(
};
const summary = {
network,
chain,
outbox: {
count,
checkpoint: {
@ -57,7 +56,7 @@ const domainSummary = async <Networks extends ChainName>(
},
},
inboxes: await Promise.all(
core.remotes(network).map((remote) => inboxSummary(remote)),
core.remoteChains(chain).map((remote) => inboxSummary(remote)),
),
};
return summary;
@ -115,12 +114,12 @@ task('kathy', 'Dispatches random abacus messages').setAction(
// Generate artificial traffic
while (true) {
const local = core.networks()[0];
const remote: ChainName = randomElement(core.remotes(local));
const local = core.chains()[0];
const remote: ChainName = randomElement(core.remoteChains(local));
const remoteId = ChainNameToDomainId[remote];
const coreContracts = core.getContracts(local);
const outbox = coreContracts.outbox.outbox;
// Send a batch of messages to the remote domain to test
// Send a batch of messages to the destination chain to test
// the relayer submitting only greedily
for (let i = 0; i < 10; i++) {
await outbox.dispatch(
@ -136,7 +135,7 @@ task('kathy', 'Dispatches random abacus messages').setAction(
(await outbox.count()).toNumber() - 1
}`,
);
console.log(await domainSummary(core, local));
console.log(await chainSummary(core, local));
await sleep(5000);
}
}

@ -25,7 +25,7 @@ async function deploy() {
// While this function still has these side effects, the workaround is to just
// run the create-keys script first.
await Promise.all(
config.agent.domainNames.map((name: any) =>
config.agent.chainNames.map((name: any) =>
runAgentHelmCommand(HelmCommand.InstallOrUpgrade, config.agent, name),
),
);

@ -24,20 +24,17 @@ async function main() {
config.core,
);
await checker.check();
// Sanity check: for each domain, expect one validator violation.
// Sanity check: for each chain, expect one validator violation.
checker.expectViolations(
[CoreViolationType.Validator],
[core.networks().length],
);
// Sanity check: for each domain, expect one call to set the validator.
checker.expectCalls(
core.networks(),
new Array(core.networks().length).fill(1),
[core.chains().length],
);
// Sanity check: for each chain, expect one call to set the validator.
checker.expectCalls(core.chains(), new Array(core.chains().length).fill(1));
// Change to `batch.execute` in order to run.
const controllerActor = await controllerApp.controller();
const provider = multiProvider.getChainConnection(controllerActor.network)
const provider = multiProvider.getChainConnection(controllerActor.chain)
.provider!;
const receipts = await checker.controllerApp.estimateGas(provider);
console.log(receipts);

@ -6,8 +6,8 @@ import { getCoreEnvironmentConfig, getEnvironment } from './utils';
async function deploy() {
const environment = await getEnvironment();
const config = await getCoreEnvironmentConfig(environment);
for (const network of config.agent.domainNames) {
await runAgentHelmCommand(HelmCommand.UpgradeDiff, config.agent, network);
for (const chain of config.agent.chainNames) {
await runAgentHelmCommand(HelmCommand.UpgradeDiff, config.agent, chain);
}
}

@ -38,14 +38,14 @@ export async function getEnvironmentConfig() {
return getCoreEnvironmentConfig(await getEnvironment());
}
export async function getMultiProviderFromGCP<Networks extends ChainName>(
txConfigs: ChainMap<Networks, TransactionConfig>,
export async function getMultiProviderFromGCP<Chain extends ChainName>(
txConfigs: ChainMap<Chain, TransactionConfig>,
environment: DeployEnvironment,
) {
const connections = await promiseObjAll(
objMap(txConfigs, async (domain, config) => {
const provider = await fetchProvider(environment, domain);
const signer = await fetchSigner(environment, domain, provider);
objMap(txConfigs, async (chain, config) => {
const provider = await fetchProvider(environment, chain);
const signer = await fetchSigner(environment, chain, provider);
return {
provider,
signer,
@ -54,7 +54,7 @@ export async function getMultiProviderFromGCP<Networks extends ChainName>(
};
}),
);
return new MultiProvider<Networks>(connections);
return new MultiProvider<Chain>(connections);
}
function getContractsSdkFilepath(mod: string, environment: DeployEnvironment) {

@ -18,14 +18,14 @@ import { KEY_ROLE_ENUM } from '../roles';
import { AgentAwsKey } from './key';
export class AgentAwsUser<Networks extends ChainName> {
export class AgentAwsUser<Chain extends ChainName> {
private adminIamClient: IAMClient;
private _arn: string | undefined;
constructor(
public readonly environment: string,
public readonly chainName: Networks,
public readonly chainName: Chain,
public readonly role: KEY_ROLE_ENUM,
public readonly region: string,
) {
@ -107,7 +107,7 @@ export class AgentAwsUser<Networks extends ChainName> {
return new AgentAwsKey(agentConfig, this.role, this.chainName);
}
async createKeyIfNotExists(agentConfig: AgentConfig<Networks>) {
async createKeyIfNotExists(agentConfig: AgentConfig<Chain>) {
const key = this.key(agentConfig);
await key.createIfNotExists();
await key.putKeyPolicy(this.arn);

@ -14,13 +14,13 @@ import { AgentAwsKey } from './key';
import { AgentAwsUser } from './user';
export class ValidatorAgentAwsUser<
Networks extends ChainName,
> extends AgentAwsUser<Networks> {
Chain extends ChainName,
> extends AgentAwsUser<Chain> {
private adminS3Client: S3Client;
constructor(
environment: string,
chainName: Networks,
chainName: Chain,
public readonly index: number,
region: string,
public readonly bucket: string,
@ -83,7 +83,7 @@ export class ValidatorAgentAwsUser<
await this.adminS3Client.send(cmd);
}
key(agentConfig: AgentConfig<Networks>): AgentAwsKey {
key(agentConfig: AgentConfig<Chain>): AgentAwsKey {
return new AgentAwsKey(agentConfig, this.role, this.chainName, this.index);
}

@ -14,9 +14,9 @@ import { AgentGCPKey } from './gcp';
import { fetchKeysForChain } from './key-utils';
import { KEY_ROLES, KEY_ROLE_ENUM } from './roles';
async function helmValuesForChain<Networks extends ChainName>(
chainName: Networks,
agentConfig: AgentConfig<Networks>,
async function helmValuesForChain<Chain extends ChainName>(
chainName: Chain,
agentConfig: AgentConfig<Chain>,
) {
const chainAgentConfig = new ChainAgentConfig(agentConfig, chainName);
@ -32,7 +32,7 @@ async function helmValuesForChain<Networks extends ChainName>(
name: chainName,
},
aws: !!agentConfig.aws,
inboxChains: agentConfig.domainNames
inboxChains: agentConfig.chainNames
.filter((name) => name !== chainName)
.map((remoteChainName) => {
return {
@ -65,13 +65,13 @@ async function helmValuesForChain<Networks extends ChainName>(
};
}
export async function getAgentEnvVars<Networks extends ChainName>(
outboxChainName: Networks,
export async function getAgentEnvVars<Chain extends ChainName>(
outboxChainName: Chain,
role: KEY_ROLE_ENUM,
agentConfig: AgentConfig<Networks>,
agentConfig: AgentConfig<Chain>,
index?: number,
) {
const chainNames = agentConfig.domainNames;
const chainNames = agentConfig.chainNames;
if (role === KEY_ROLE_ENUM.Validator && index === undefined) {
throw Error('Expected index for validator role');
}
@ -132,7 +132,7 @@ export async function getAgentEnvVars<Networks extends ChainName>(
} else {
// AWS keys
let user: AgentAwsUser<Networks>;
let user: AgentAwsUser<Chain>;
if (role === KEY_ROLE_ENUM.Validator) {
const checkpointSyncer =
@ -250,8 +250,8 @@ function configEnvVars(
return envVars;
}
export async function getSecretAwsCredentials<Networks extends ChainName>(
agentConfig: AgentConfig<Networks>,
export async function getSecretAwsCredentials<Chain extends ChainName>(
agentConfig: AgentConfig<Chain>,
) {
return {
accessKeyId: await fetchGCPSecret(
@ -281,12 +281,12 @@ export async function getSecretDeployerKey(
return key.privateKey;
}
async function getSecretRpcEndpoints<Networks extends ChainName>(
agentConfig: AgentConfig<Networks>,
async function getSecretRpcEndpoints<Chain extends ChainName>(
agentConfig: AgentConfig<Chain>,
) {
const environment = agentConfig.runEnv;
return getSecretForEachChain(
agentConfig.domainNames,
agentConfig.chainNames,
(name: ChainName) => `${environment}-rpc-endpoint-${name}`,
false,
);
@ -311,10 +311,10 @@ async function getSecretForEachChain(
);
}
export async function runAgentHelmCommand<Networks extends ChainName>(
export async function runAgentHelmCommand<Chain extends ChainName>(
action: HelmCommand,
agentConfig: AgentConfig<Networks>,
outboxChainName: Networks,
agentConfig: AgentConfig<Chain>,
outboxChainName: Chain,
) {
const valueDict = await helmValuesForChain(outboxChainName, agentConfig);
const values = helmifyValues(valueDict);
@ -338,7 +338,7 @@ export async function runKeymasterHelmCommand(
action: HelmCommand,
agentConfig: AgentConfig<any>,
) {
const chainNames = agentConfig.domainNames;
const chainNames = agentConfig.chainNames;
// It's ok to use pick an arbitrary chain here since we are only grabbing the signers
const chainName = chainNames[0];
const gcpKeys = (await fetchKeysForChain(agentConfig, chainName)) as Record<

@ -14,10 +14,10 @@ interface KeyAsAddress {
address: string;
}
export function getKey<Networks extends ChainName>(
agentConfig: AgentConfig<Networks>,
export function getKey<Chain extends ChainName>(
agentConfig: AgentConfig<Chain>,
role: KEY_ROLE_ENUM,
chainName?: Networks,
chainName?: Chain,
index?: number,
): AgentKey {
if (agentConfig.aws) {
@ -31,7 +31,7 @@ export function getAllKeys(agentConfig: AgentConfig<any>): Array<AgentKey> {
return KEY_ROLES.flatMap((role) => {
if (role === KEY_ROLE_ENUM.Validator) {
// For each chainName, create validatorCount keys
return agentConfig.domainNames.flatMap((chainName) =>
return agentConfig.chainNames.flatMap((chainName) =>
[
...Array(
agentConfig.validatorSets[chainName].validators.length,
@ -39,7 +39,7 @@ export function getAllKeys(agentConfig: AgentConfig<any>): Array<AgentKey> {
].map((index) => getKey(agentConfig, role, chainName, index)),
);
} else if (role === KEY_ROLE_ENUM.Relayer) {
return agentConfig.domainNames.map((chainName) =>
return agentConfig.chainNames.map((chainName) =>
getKey(agentConfig, role, chainName),
);
} else {
@ -75,10 +75,10 @@ export async function createAgentKeysIfNotExists(
);
}
export async function rotateKey<Networks extends ChainName>(
agentConfig: AgentConfig<Networks>,
export async function rotateKey<Chain extends ChainName>(
agentConfig: AgentConfig<Chain>,
role: KEY_ROLE_ENUM,
chainName: Networks,
chainName: Chain,
) {
const key = getKey(agentConfig, role, chainName);
await key.update();
@ -99,9 +99,9 @@ async function persistAddresses(environment: string, keys: KeyAsAddress[]) {
}
// This function returns all keys for a given outbox chain in a dictionary where the key is the identifier
export async function fetchKeysForChain<Networks extends ChainName>(
agentConfig: AgentConfig<Networks>,
chainName: Networks,
export async function fetchKeysForChain<Chain extends ChainName>(
agentConfig: AgentConfig<Chain>,
chainName: Chain,
): Promise<Record<string, AgentKey>> {
// Get all keys for the chainName. Include keys where chainName is undefined,
// which are keys that are not chain-specific but should still be included

@ -10,16 +10,16 @@ import { KEY_ROLE_ENUM } from '../agents/roles';
import { DeployEnvironment } from './environment';
// Allows a "default" config to be specified and any per-network overrides.
interface ChainOverridableConfig<Networks extends ChainName, T> {
// Allows a "default" config to be specified and any per-chain overrides.
interface ChainOverridableConfig<Chain extends ChainName, T> {
default: T;
chainOverrides?: Partial<ChainMap<Networks, T>>;
chainOverrides?: Partial<ChainMap<Chain, T>>;
}
// Returns the default config with any overriden values specified for the provided chain.
export function getChainOverriddenConfig<Networks extends ChainName, T>(
overridableConfig: ChainOverridableConfig<Networks, T>,
chain: Networks,
export function getChainOverriddenConfig<Chain extends ChainName, T>(
overridableConfig: ChainOverridableConfig<Chain, T>,
chain: Chain,
): T {
return {
...overridableConfig.default,
@ -75,9 +75,9 @@ interface Validator {
checkpointSyncer: CheckpointSyncerConfig;
}
// Validator sets for each network
export type ChainValidatorSets<Networks extends ChainName> = ChainMap<
Networks,
// Validator sets for each chain
export type ChainValidatorSets<Chain extends ChainName> = ChainMap<
Chain,
ValidatorSet
>;
@ -98,8 +98,8 @@ interface BaseRelayerConfig {
}
// Per-chain relayer agent configs
type ChainRelayerConfigs<Networks extends ChainName> = ChainOverridableConfig<
Networks,
type ChainRelayerConfigs<Chain extends ChainName> = ChainOverridableConfig<
Chain,
BaseRelayerConfig
>;
@ -121,8 +121,8 @@ interface BaseValidatorConfig {
}
// Per-chain validator agent configs
type ChainValidatorConfigs<Networks extends ChainName> = ChainOverridableConfig<
Networks,
type ChainValidatorConfigs<Chain extends ChainName> = ChainOverridableConfig<
Chain,
BaseValidatorConfig
>;
@ -145,8 +145,10 @@ interface CheckpointerConfig {
}
// Per-chain checkpointer agent configs
type ChainCheckpointerConfigs<Networks extends ChainName> =
ChainOverridableConfig<Networks, CheckpointerConfig>;
type ChainCheckpointerConfigs<Chain extends ChainName> = ChainOverridableConfig<
Chain,
CheckpointerConfig
>;
// ===============================
// ===== Kathy Agent =====
@ -159,8 +161,8 @@ interface KathyConfig {
}
// Per-chain kathy agent configs
type ChainKathyConfigs<Networks extends ChainName> = ChainOverridableConfig<
Networks,
type ChainKathyConfigs<Chain extends ChainName> = ChainOverridableConfig<
Chain,
KathyConfig
>;
@ -199,19 +201,19 @@ export interface DockerConfig {
tag: string;
}
export interface AgentConfig<Networks extends ChainName> {
export interface AgentConfig<Chain extends ChainName> {
environment: string;
namespace: string;
runEnv: string;
docker: DockerConfig;
index?: IndexingConfig;
aws?: AwsConfig;
domainNames: Networks[];
validatorSets: ChainValidatorSets<Networks>;
validator: ChainValidatorConfigs<Networks>;
relayer: ChainRelayerConfigs<Networks>;
checkpointer?: ChainCheckpointerConfigs<Networks>;
kathy?: ChainKathyConfigs<Networks>;
chainNames: Chain[];
validatorSets: ChainValidatorSets<Chain>;
validator: ChainValidatorConfigs<Chain>;
relayer: ChainRelayerConfigs<Chain>;
checkpointer?: ChainCheckpointerConfigs<Chain>;
kathy?: ChainKathyConfigs<Chain>;
}
export type RustSigner = {
@ -241,11 +243,11 @@ export type InboxAddresses = {
validatorManager: types.Address;
};
export type RustConfig<Networks extends ChainName> = {
export type RustConfig<Chain extends ChainName> = {
environment: DeployEnvironment;
index?: { from: string };
signers: Partial<ChainMap<Networks, RustSigner>>;
inboxes: RemoteChainMap<Networks, any, RustContractBlock<InboxAddresses>>;
signers: Partial<ChainMap<Chain, RustSigner>>;
inboxes: RemoteChainMap<Chain, any, RustContractBlock<InboxAddresses>>;
outbox: RustContractBlock<OutboxAddresses>;
tracing: {
level: string;
@ -255,10 +257,10 @@ export type RustConfig<Networks extends ChainName> = {
};
// Helper to get chain-specific agent configurations
export class ChainAgentConfig<Networks extends ChainName> {
export class ChainAgentConfig<Chain extends ChainName> {
constructor(
public readonly agentConfig: AgentConfig<Networks>,
public readonly chainName: Networks,
public readonly agentConfig: AgentConfig<Chain>,
public readonly chainName: Chain,
) {}
// Credentials are only needed if AWS keys are needed -- otherwise, the
@ -274,7 +276,7 @@ export class ChainAgentConfig<Networks extends ChainName> {
}
signers(role: KEY_ROLE_ENUM) {
return this.agentConfig.domainNames.map((name) => ({
return this.agentConfig.chainNames.map((name) => ({
name,
keyConfig: this.keyConfig(role),
}));
@ -365,7 +367,7 @@ export class ChainAgentConfig<Networks extends ChainName> {
);
await awsUser.createIfNotExists();
const key = await awsUser.createKeyIfNotExists(this.agentConfig);
return this.agentConfig.domainNames.map((name) => ({
return this.agentConfig.chainNames.map((name) => ({
name,
keyConfig: key.keyConfig,
}));

@ -9,16 +9,16 @@ import { InfrastructureConfig } from './infrastructure';
export const EnvironmentNames = Object.keys(environments);
export type DeployEnvironment = keyof typeof environments;
export type EnvironmentNetworks<E extends DeployEnvironment> = Extract<
export type EnvironmentChain<E extends DeployEnvironment> = Extract<
keyof typeof environments[E],
ChainName
>;
export type CoreEnvironmentConfig<Networks extends ChainName> = {
transactionConfigs: EnvironmentConfig<Networks>;
agent: AgentConfig<Networks>;
core: ChainMap<Networks, CoreConfig>;
controller: ChainMap<Networks, ControllerConfig>;
export type CoreEnvironmentConfig<Chain extends ChainName> = {
transactionConfigs: EnvironmentConfig<Chain>;
agent: AgentConfig<Chain>;
core: ChainMap<Chain, CoreConfig>;
controller: ChainMap<Chain, ControllerConfig>;
infra: InfrastructureConfig;
getMultiProvider: () => Promise<MultiProvider<Networks>>;
getMultiProvider: () => Promise<MultiProvider<Chain>>;
};

@ -14,18 +14,18 @@ import { types } from '@abacus-network/utils';
import { ControllerConfig } from './types';
export class ControllerChecker<
Networks extends ChainName,
Chain extends ChainName,
> extends AbacusRouterChecker<
Networks,
ControllerApp<Networks>,
Chain,
ControllerApp<Chain>,
ControllerConfig & {
owner: types.Address;
}
> {
constructor(
multiProvider: MultiProvider<any>,
app: ControllerApp<Networks>,
configMap: ChainMap<Networks, ControllerConfig>,
app: ControllerApp<Chain>,
configMap: ChainMap<Chain, ControllerConfig>,
) {
const joinedConfig = objMap(configMap, (_, config) => ({
...config,
@ -35,41 +35,37 @@ export class ControllerChecker<
}
// ControllerRouter's owner is 0x0 on all chains except the controlling chain as setup in the constructor
async checkOwnership(network: Networks): Promise<void> {
const contracts = this.app.getContracts(network);
async checkOwnership(chain: Chain): Promise<void> {
const contracts = this.app.getContracts(chain);
// check router's owner with the config
const routerOwner = await contracts.router.owner();
expect(routerOwner).to.equal(this.configMap[network].owner);
expect(routerOwner).to.equal(this.configMap[chain].owner);
// check ubc is owned by local router
const ubcOwner = await contracts.upgradeBeaconController.owner();
expect(ubcOwner).to.equal(contracts.router.address);
}
async checkDomain(network: Networks): Promise<void> {
await super.checkDomain(network);
await this.checkProxiedContracts(network);
await this.checkRecoveryManager(network);
async checkChain(chain: Chain): Promise<void> {
await super.checkChain(chain);
await this.checkProxiedContracts(chain);
await this.checkRecoveryManager(chain);
}
async checkProxiedContracts(network: Networks): Promise<void> {
const addresses = this.app.getAddresses(network);
async checkProxiedContracts(chain: Chain): Promise<void> {
const addresses = this.app.getAddresses(chain);
// Outbox upgrade setup contracts are defined
await this.checkUpgradeBeacon(
network,
'ControllerRouter',
addresses.router,
);
await this.checkUpgradeBeacon(chain, 'ControllerRouter', addresses.router);
}
async checkRecoveryManager(network: Networks): Promise<void> {
const actual = await this.mustGetRouter(network).recoveryManager();
const config = this.configMap[network];
async checkRecoveryManager(chain: Chain): Promise<void> {
const actual = await this.mustGetRouter(chain).recoveryManager();
const config = this.configMap[chain];
expect(actual).to.equal(config.recoveryManager);
}
mustGetRouter(network: Networks) {
return this.app.getContracts(network).router;
mustGetRouter(chain: Chain) {
return this.app.getContracts(chain).router;
}
}

@ -13,31 +13,27 @@ import {
import { ControllerConfig } from './types';
export class ControllerDeployer<
Networks extends ChainName,
> extends AbacusRouterDeployer<
Networks,
ControllerConfig,
ControllerAddresses
> {
Chain extends ChainName,
> extends AbacusRouterDeployer<Chain, ControllerConfig, ControllerAddresses> {
async deployContracts(
network: Networks,
chain: Chain,
config: ControllerConfig,
): Promise<ControllerAddresses> {
const dc = this.multiProvider.getChainConnection(network);
const dc = this.multiProvider.getChainConnection(chain);
const signer = dc.signer!;
const abacusConnectionManager =
await this.deployConnectionManagerIfNotConfigured(network);
await this.deployConnectionManagerIfNotConfigured(chain);
const upgradeBeaconController = await this.deployContract(
network,
chain,
'UpgradeBeaconController',
new UpgradeBeaconController__factory(signer),
[],
);
const router = await this.deployProxiedContract(
network,
chain,
'ControllerRouter',
new ControllerRouter__factory(signer),
[config.recoveryTimelock],
@ -82,10 +78,10 @@ export class ControllerDeployer<
return deploymentOutput;
}
mustGetRouter(network: Networks, addresses: ControllerAddresses) {
mustGetRouter(chain: Chain, addresses: ControllerAddresses) {
return ControllerRouter__factory.connect(
addresses.router.proxy,
this.multiProvider.getChainConnection(network).signer!,
this.multiProvider.getChainConnection(chain).signer!,
);
}
}

@ -10,7 +10,7 @@ import {
AbacusCore,
ChainName,
MailboxAddresses,
domains,
chainMetadata,
objMap,
promiseObjAll,
} from '@abacus-network/sdk';
@ -42,26 +42,26 @@ export interface ValidatorViolation extends CheckerViolation {
}
export class AbacusCoreChecker<
Networks extends ChainName,
Chain extends ChainName,
> extends AbacusAppChecker<
Networks,
AbacusCore<Networks>,
Chain,
AbacusCore<Chain>,
CoreConfig & {
owner: types.Address;
}
> {
async checkDomain(network: Networks): Promise<void> {
await this.checkDomainOwnership(network);
await this.checkProxiedContracts(network);
await this.checkOutbox(network);
await this.checkInboxes(network);
await this.checkAbacusConnectionManager(network);
await this.checkValidatorManagers(network);
async checkChain(chain: Chain): Promise<void> {
await this.checkDomainOwnership(chain);
await this.checkProxiedContracts(chain);
await this.checkOutbox(chain);
await this.checkInboxes(chain);
await this.checkAbacusConnectionManager(chain);
await this.checkValidatorManagers(chain);
}
async checkDomainOwnership(network: Networks): Promise<void> {
const config = this.configMap[network];
const contracts = this.app.getContracts(network);
async checkDomainOwnership(chain: Chain): Promise<void> {
const config = this.configMap[chain];
const contracts = this.app.getContracts(chain);
const ownables = [
contracts.abacusConnectionManager,
contracts.upgradeBeaconController,
@ -74,13 +74,13 @@ export class AbacusCoreChecker<
return AbacusAppChecker.checkOwnership(config.owner, ownables);
}
async checkOutbox(network: Networks): Promise<void> {
const contracts = this.app.getContracts(network);
async checkOutbox(chain: Chain): Promise<void> {
const contracts = this.app.getContracts(chain);
const actualManager = await contracts.outbox.outbox.validatorManager();
const expectedManager = contracts.outbox.validatorManager.address;
if (actualManager !== expectedManager) {
const violation: ValidatorManagerViolation = {
network,
chain,
type: CoreViolationType.ValidatorManager,
actual: actualManager,
expected: expectedManager,
@ -90,17 +90,17 @@ export class AbacusCoreChecker<
}
// Checks validator sets of the OutboxValidatorManager and all
// InboxValidatorManagers on the domain.
async checkValidatorManagers(network: Networks) {
const coreContracts = this.app.getContracts(network);
// InboxValidatorManagers on the chain.
async checkValidatorManagers(chain: Chain) {
const coreContracts = this.app.getContracts(chain);
await this.checkValidatorManager(
network,
network,
chain,
chain,
coreContracts.outbox.validatorManager,
);
return promiseObjAll(
objMap(coreContracts.inboxes, (remote, inbox) =>
this.checkValidatorManager(network, remote, inbox.validatorManager),
this.checkValidatorManager(chain, remote, inbox.validatorManager),
),
);
}
@ -110,8 +110,8 @@ export class AbacusCoreChecker<
// If localDomain == outboxDomain, this checks the OutboxValidatorManager, otherwise
// it checks an InboxValidatorManager.
async checkValidatorManager(
local: Networks,
remote: Networks,
local: Chain,
remote: Chain,
validatorManager: MultisigValidatorManager,
): Promise<void> {
const config = this.configMap[remote];
@ -128,7 +128,7 @@ export class AbacusCoreChecker<
// Validators that should be enrolled
for (const validatorToEnroll of toEnroll) {
const violation: ValidatorViolation = {
network: local,
chain: local,
type: CoreViolationType.Validator,
actual: undefined,
expected: validatorToEnroll,
@ -143,7 +143,7 @@ export class AbacusCoreChecker<
// Validators that should be unenrolled
for (const validatorToUnenroll of toUnenroll) {
const violation: ValidatorViolation = {
network: local,
chain: local,
type: CoreViolationType.Validator,
actual: validatorToUnenroll,
expected: undefined,
@ -162,7 +162,7 @@ export class AbacusCoreChecker<
if (expectedThreshold !== actualThreshold.toNumber()) {
const violation: ValidatorViolation = {
network: local,
chain: local,
type: CoreViolationType.Validator,
actual: actualThreshold,
expected: expectedThreshold,
@ -175,10 +175,10 @@ export class AbacusCoreChecker<
}
}
async checkInboxes(network: Networks): Promise<void> {
const coreContracts = this.app.getContracts(network);
async checkInboxes(chain: Chain): Promise<void> {
const coreContracts = this.app.getContracts(chain);
// Check that all inboxes on this domain are pointed to the right validator
// Check that all inboxes on this chain are pointed to the right validator
// manager.
await promiseObjAll(
objMap(coreContracts.inboxes, async (_, inbox) => {
@ -188,9 +188,9 @@ export class AbacusCoreChecker<
}),
);
// Check that all inboxes on this domain share the same implementation and
// Check that all inboxes on this chain share the same implementation and
// UpgradeBeacon.
const coreAddresses = this.app.getAddresses(network);
const coreAddresses = this.app.getAddresses(chain);
const inboxes: MailboxAddresses[] = Object.values(coreAddresses.inboxes);
const implementations = inboxes.map((r) => r.implementation);
const identical = (a: any, b: any) => (a === b ? a : false);
@ -199,11 +199,11 @@ export class AbacusCoreChecker<
expect(upgradeBeacons.reduce(identical)).to.not.be.false;
}
async checkAbacusConnectionManager(network: Networks): Promise<void> {
const coreContracts = this.app.getContracts(network);
async checkAbacusConnectionManager(chain: Chain): Promise<void> {
const coreContracts = this.app.getContracts(chain);
await promiseObjAll(
objMap(coreContracts.inboxes, async (remote, inbox) => {
const remoteDomain = domains[remote as ChainName].id;
const remoteDomain = chainMetadata[remote].id;
// inbox is enrolled in abacusConnectionManager
const enrolledInboxes =
await coreContracts.abacusConnectionManager.getInboxes(remoteDomain);
@ -216,13 +216,13 @@ export class AbacusCoreChecker<
expect(outbox).to.equal(coreContracts.outbox.outbox.address);
}
async checkProxiedContracts(network: Networks): Promise<void> {
async checkProxiedContracts(chain: Chain): Promise<void> {
// Outbox upgrade setup contracts are defined
const addresses = this.app.getAddresses(network);
await this.checkUpgradeBeacon(network, 'Outbox', addresses.outbox);
const addresses = this.app.getAddresses(chain);
await this.checkUpgradeBeacon(chain, 'Outbox', addresses.outbox);
await promiseObjAll(
objMap(addresses.inboxes, (network, inbox) =>
this.checkUpgradeBeacon(network, 'Inbox', inbox),
objMap(addresses.inboxes, (chain, inbox) =>
this.checkUpgradeBeacon(chain, 'Inbox', inbox),
),
);
}

@ -25,27 +25,27 @@ import {
ValidatorViolationType,
} from './check';
interface DomainedCall {
network: ChainName;
interface CallWithTarget {
chain: ChainName;
call: Call;
}
export class AbacusCoreControllerChecker<
Networks extends ChainName,
> extends AbacusCoreChecker<Networks> {
readonly controllerApp: ControllerApp<Networks>;
Chain extends ChainName,
> extends AbacusCoreChecker<Chain> {
readonly controllerApp: ControllerApp<Chain>;
constructor(
multiProvider: MultiProvider<Networks>,
app: AbacusCore<Networks>,
controllerApp: ControllerApp<Networks>,
config: ChainMap<Networks, CoreConfig>,
multiProvider: MultiProvider<Chain>,
app: AbacusCore<Chain>,
controllerApp: ControllerApp<Chain>,
config: ChainMap<Chain, CoreConfig>,
) {
const owners = controllerApp.routerAddresses();
const joinedConfigMap = objMap(config, (network, coreConfig) => {
const joinedConfigMap = objMap(config, (chain, coreConfig) => {
return {
...coreConfig,
owner: owners[network],
owner: owners[chain],
};
});
super(multiProvider, app, joinedConfigMap);
@ -58,12 +58,12 @@ export class AbacusCoreControllerChecker<
this.violations.map((v) => this.handleViolation(v)),
);
txs.map((call) =>
this.controllerApp.pushCall(call.network as Networks, call.call),
this.controllerApp.pushCall(call.chain as Chain, call.call),
);
return [];
}
handleViolation(v: CheckerViolation): Promise<DomainedCall> {
handleViolation(v: CheckerViolation): Promise<CallWithTarget> {
switch (v.type) {
case ProxyViolationType.UpgradeBeacon:
return this.handleUpgradeBeaconViolation(v as UpgradeBeaconViolation);
@ -76,26 +76,22 @@ export class AbacusCoreControllerChecker<
async handleUpgradeBeaconViolation(
violation: UpgradeBeaconViolation,
): Promise<DomainedCall> {
const network = violation.network;
const ubc = this.app.getContracts(
network as Networks,
).upgradeBeaconController;
): Promise<CallWithTarget> {
const chain = violation.chain;
const ubc = this.app.getContracts(chain as Chain).upgradeBeaconController;
if (ubc === undefined) throw new Error('Undefined ubc');
const tx = await ubc.populateTransaction.upgrade(
violation.data.proxiedAddress.beacon,
violation.expected,
);
if (tx.to === undefined) throw new Error('undefined tx.to');
return { network, call: tx as Call };
return { chain, call: tx as Call };
}
async handleValidatorViolation(
violation: ValidatorViolation,
): Promise<DomainedCall> {
const dc = this.multiProvider.getChainConnection(
violation.network as Networks,
);
): Promise<CallWithTarget> {
const dc = this.multiProvider.getChainConnection(violation.chain as Chain);
const provider = dc.provider!;
const validatorManager = MultisigValidatorManager__factory.connect(
@ -130,13 +126,13 @@ export class AbacusCoreControllerChecker<
}
if (tx.to === undefined) throw new Error('undefined tx.to');
return { network: violation.network, call: tx as Call };
return { chain: violation.chain, call: tx as Call };
}
expectCalls(networks: Networks[], count: number[]) {
expect(networks).to.have.lengthOf(count.length);
networks.forEach((network, i) => {
expect(this.controllerApp.getCalls(network)).to.have.lengthOf(count[i]);
expectCalls(chains: Chain[], count: number[]) {
expect(chains).to.have.lengthOf(count.length);
chains.forEach((chain, i) => {
expect(this.controllerApp.getCalls(chain)).to.have.lengthOf(count[i]);
});
}
}

@ -1,30 +1,28 @@
import path from 'path';
import { AbacusAppDeployer, AbacusCoreDeployer } from '@abacus-network/deploy';
import { ChainName, domains, objMap } from '@abacus-network/sdk';
import { ChainName, chainMetadata, objMap } from '@abacus-network/sdk';
import { DeployEnvironment, RustConfig } from '../config';
export class AbacusCoreInfraDeployer<
Networks extends ChainName,
> extends AbacusCoreDeployer<Networks> {
Chain extends ChainName,
> extends AbacusCoreDeployer<Chain> {
writeRustConfigs(
environment: DeployEnvironment,
directory: string,
networkAddresses: Awaited<
ReturnType<AbacusCoreDeployer<Networks>['deploy']>
>,
contractAddresses: Awaited<ReturnType<AbacusCoreDeployer<Chain>['deploy']>>,
) {
objMap(this.configMap, (network) => {
const filepath = path.join(directory, `${network}_config.json`);
const addresses = networkAddresses[network];
objMap(this.configMap, (chain) => {
const filepath = path.join(directory, `${chain}_config.json`);
const addresses = contractAddresses[chain];
const outbox = {
addresses: {
outbox: addresses.outbox.proxy,
},
domain: domains[network].id.toString(),
name: network,
domain: chainMetadata[chain].id.toString(),
name: chain,
rpcStyle: 'ethereum',
connection: {
type: 'http',
@ -32,7 +30,7 @@ export class AbacusCoreInfraDeployer<
},
};
const rustConfig: RustConfig<Networks> = {
const rustConfig: RustConfig<Chain> = {
environment,
signers: {},
inboxes: {},
@ -44,17 +42,17 @@ export class AbacusCoreInfraDeployer<
db: 'db_path',
};
const startingBlockNumber = this.startingBlockNumbers[network];
const startingBlockNumber = this.startingBlockNumbers[chain];
if (startingBlockNumber) {
rustConfig.index = { from: startingBlockNumber.toString() };
}
this.multiProvider.remotes(network).forEach((remote) => {
this.multiProvider.remoteChains(chain).forEach((remote) => {
const inboxAddresses = addresses.inboxes[remote];
const inbox = {
domain: domains[remote].id.toString(),
domain: chainMetadata[remote].id.toString(),
name: remote,
rpcStyle: 'ethereum',
connection: {

@ -25,7 +25,7 @@ export class AbacusContractVerifier extends ContractVerifier {
);
}
get networks(): ChainName[] {
get chainNames(): ChainName[] {
const filenames = fs
.readdirSync(this.verificationDir, { withFileTypes: true })
.map((dirEntry: fs.Dirent) => dirEntry.name);
@ -33,12 +33,12 @@ export class AbacusContractVerifier extends ContractVerifier {
return filenames.map((name) => name.split('.')[0] as ChainName);
}
getVerificationInput(network: ChainName): VerificationInput {
const filename = `${network}.json`;
getVerificationInput(chain: ChainName): VerificationInput {
const filename = `${chain}.json`;
const filepath = path.join(this.verificationDir, filename);
if (!fs.existsSync(filepath)) {
throw new Error(
`No ${filename} files found for ${network} at ${this.verificationDir}`,
`No ${filename} files found for ${chain} at ${this.verificationDir}`,
);
}

@ -9,7 +9,7 @@ import {
MultiProvider,
} from '@abacus-network/sdk';
import { TestNetworks } from '../config/environments/test/domains';
import { TestChains } from '../config/environments/test/chains';
import { getCoreEnvironmentConfig } from '../scripts/utils';
import {
ControllerChecker,
@ -20,10 +20,10 @@ import {
describe('controller', async () => {
const environment = 'test';
let multiProvider: MultiProvider<TestNetworks>;
let deployer: ControllerDeployer<TestNetworks>;
let addresses: ChainMap<TestNetworks, ControllerAddresses>;
let controllerConfig: ChainMap<TestNetworks, ControllerConfig>;
let multiProvider: MultiProvider<TestChains>;
let deployer: ControllerDeployer<TestChains>;
let addresses: ChainMap<TestChains, ControllerAddresses>;
let controllerConfig: ChainMap<TestChains, ControllerConfig>;
before(async () => {
const config = getCoreEnvironmentConfig(environment);

@ -11,7 +11,7 @@ import {
objMap,
} from '@abacus-network/sdk';
import { TestNetworks } from '../config/environments/test/domains';
import { TestChains } from '../config/environments/test/chains';
import { getCoreEnvironmentConfig } from '../scripts/utils';
import { AbacusCoreChecker } from '../src/core';
import { AbacusCoreInfraDeployer } from '../src/core/deploy';
@ -19,16 +19,13 @@ import { AbacusCoreInfraDeployer } from '../src/core/deploy';
describe('core', async () => {
const environment = 'test';
let multiProvider: MultiProvider<TestNetworks>;
let deployer: AbacusCoreInfraDeployer<TestNetworks>;
let core: AbacusCore<TestNetworks>;
let addresses: ChainMap<
TestNetworks,
CoreContractAddresses<TestNetworks, any>
>;
let coreConfig: ChainMap<TestNetworks, CoreConfig>;
let multiProvider: MultiProvider<TestChains>;
let deployer: AbacusCoreInfraDeployer<TestChains>;
let core: AbacusCore<TestChains>;
let addresses: ChainMap<TestChains, CoreContractAddresses<TestChains, any>>;
let coreConfig: ChainMap<TestChains, CoreConfig>;
let owners: ChainMap<TestNetworks, string>;
let owners: ChainMap<TestChains, string>;
before(async () => {
const config = getCoreEnvironmentConfig(environment);
multiProvider = await config.getMultiProvider();
@ -55,9 +52,9 @@ describe('core', async () => {
});
it('checks', async () => {
const joinedConfig = objMap(coreConfig, (network, config) => ({
const joinedConfig = objMap(coreConfig, (chain, config) => ({
...config,
owner: owners[network],
owner: owners[chain],
}));
const checker = new AbacusCoreChecker(multiProvider, core, joinedConfig);
await checker.check();

@ -3,6 +3,9 @@
## Unreleased
- [Strongly type InterchainGasCalculator](https://github.com/abacus-network/abacus-monorepo/pull/433): Adds type guards and uses chainNames instead of domain IDs in `InterchainGasCalculator`
- Renamed `MultiProvider`'s `getDomainConnection` to `getChainConnection`
- Renamed `MultiGeneric`'s `domainMap` to `chainMap`
- Rename the mapping from chain names to domain IDs from `domains` to `chainMetadata`
## 0.1.1

@ -5,40 +5,40 @@ import { MultiGeneric, objMap } from './utils';
export class AbacusApp<
Contracts extends IAbacusContracts<any, any>,
Networks extends ChainName = ChainName,
> extends MultiGeneric<Networks, Contracts> {
Chain extends ChainName = ChainName,
> extends MultiGeneric<Chain, Contracts> {
constructor(
builder: ContractsBuilder<any, Contracts>,
networkAddresses: ChainMap<Networks, any>,
multiProvider: MultiProvider<Networks>,
contractAddresses: ChainMap<Chain, any>,
multiProvider: MultiProvider<Chain>,
) {
super(
objMap(
networkAddresses,
(network, addresses) =>
contractAddresses,
(chain, addresses) =>
new builder(
addresses,
multiProvider.getChainConnection(network).getConnection()!,
multiProvider.getChainConnection(chain).getConnection()!,
),
),
);
}
public contractsMap = this.domainMap;
public contractsMap = this.chainMap;
getContracts(
network: Networks,
chain: Chain,
): Contracts extends IAbacusContracts<any, infer C> ? C : never {
return this.get(network).contracts;
return this.get(chain).contracts;
}
getAddresses(
network: Networks,
chain: Chain,
): Contracts extends IAbacusContracts<infer A, any> ? A : never {
return this.get(network).addresses;
return this.get(chain).addresses;
}
reconnect(network: Networks, connection: Connection) {
this.get(network).reconnect(connection);
reconnect(chain: Chain, connection: Connection) {
this.get(chain).reconnect(connection);
}
}

@ -1,4 +1,4 @@
import { CompleteChainMap, Domain } from './types';
import { ChainMetadata, CompleteChainMap } from './types';
// IDs can be generated in many ways-- for example, in JS:
// > Array.from('celo').map((c, i) => c.charCodeAt(0).toString(16).padStart(2, '0')).join('')
@ -7,15 +7,15 @@ import { CompleteChainMap, Domain } from './types';
/**
* Mainnets
*/
export const celo: Domain = {
export const celo: ChainMetadata = {
id: 0x63656c6f, // b'celo' interpreted as an int
};
export const ethereum: Domain = {
export const ethereum: ChainMetadata = {
id: 0x657468, // b'eth' interpreted as an int
};
export const avalanche: Domain = {
export const avalanche: ChainMetadata = {
id: 0x61766178, // b'avax' interpreted as an int
paginate: {
// Needs to be low to avoid RPC timeouts
@ -24,7 +24,7 @@ export const avalanche: Domain = {
},
};
export const polygon: Domain = {
export const polygon: ChainMetadata = {
id: 0x706f6c79, // b'poly' interpreted as an int
paginate: {
// Needs to be low to avoid RPC timeouts
@ -36,23 +36,23 @@ export const polygon: Domain = {
/**
* Testnets
*/
export const alfajores: Domain = {
export const alfajores: ChainMetadata = {
id: 1000,
};
export const fuji: Domain = {
export const fuji: ChainMetadata = {
id: 43113,
};
export const goerli: Domain = {
export const goerli: ChainMetadata = {
id: 5,
};
export const kovan: Domain = {
export const kovan: ChainMetadata = {
id: 3000,
};
export const mumbai: Domain = {
export const mumbai: ChainMetadata = {
id: 80001,
paginate: {
// eth_getLogs and eth_newFilter are limited to a 10,000 blocks range
@ -61,19 +61,7 @@ export const mumbai: Domain = {
},
};
export const rinkarby: Domain = {
id: 4000,
};
export const rinkeby: Domain = {
id: 2000,
};
export const ropsten: Domain = {
id: 3,
};
const testDomains = {
const testChains = {
test1: {
id: 13371,
},
@ -85,23 +73,23 @@ const testDomains = {
},
};
export const bsctestnet: Domain = {
export const bsctestnet: ChainMetadata = {
id: 0x62732d74, // b'bs-t' interpreted as an int
};
export const arbitrumrinkeby: Domain = {
export const arbitrumrinkeby: ChainMetadata = {
id: 0x61722d72, // b'ar-r' interpreted as an int
};
export const optimismkovan: Domain = {
export const optimismkovan: ChainMetadata = {
id: 0x6f702d6b, // b'op-k' interpreted as an int
};
export const auroratestnet: Domain = {
export const auroratestnet: ChainMetadata = {
id: 0x61752d74, // b'au-t' interpreted as an int
};
export const domains: CompleteChainMap<Domain> = {
export const chainMetadata: CompleteChainMap<ChainMetadata> = {
celo,
ethereum,
avalanche,
@ -110,13 +98,10 @@ export const domains: CompleteChainMap<Domain> = {
fuji,
goerli,
mumbai,
rinkeby,
rinkarby,
ropsten,
kovan,
bsctestnet,
arbitrumrinkeby,
optimismkovan,
auroratestnet,
...testDomains,
...testChains,
};

@ -98,8 +98,8 @@ const _configs = {
};
export const addSignerToConnection =
<Networks extends ChainName>(signer: ethers.Signer) =>
(_chain: Networks, connection: IChainConnection) => ({
<Chain extends ChainName>(signer: ethers.Signer) =>
(_chain: Chain, connection: IChainConnection) => ({
...connection,
signer,
});

@ -21,13 +21,13 @@ export type Controller = {
};
export class ControllerApp<
Networks extends ChainName = ChainName,
> extends AbacusApp<ControllerContracts, Networks> {
Chain extends ChainName = ChainName,
> extends AbacusApp<ControllerContracts, Chain> {
constructor(
networkAddresses: ChainMap<Networks, ControllerAddresses>,
multiProvider: MultiProvider<Networks>,
addresses: ChainMap<Chain, ControllerAddresses>,
multiProvider: MultiProvider<Chain>,
) {
super(ControllerContracts, networkAddresses, multiProvider);
super(ControllerContracts, addresses, multiProvider);
}
static fromEnvironment(
@ -37,56 +37,56 @@ export class ControllerApp<
return new ControllerApp(environments[name], multiProvider);
}
pushCall(network: Networks, call: Call) {
this.get(network).push(call);
pushCall(chain: Chain, call: Call) {
this.get(chain).push(call);
}
getCalls(network: Networks) {
return this.get(network).calls;
getCalls(chain: Chain) {
return this.get(chain).calls;
}
networkCalls = () =>
chainCalls = () =>
Object.fromEntries(
this.networks().map((network) => [network, this.getCalls(network)]),
) as ChainMap<Networks, Call[]>;
this.chains().map((chain) => [chain, this.getCalls(chain)]),
) as ChainMap<Chain, Call[]>;
routers = () => objMap(this.contractsMap, (_, d) => d.contracts.router);
routerAddresses = () => objMap(this.routers(), (_, r) => r.address);
controller = async (): Promise<{
network: Networks;
chain: Chain;
address: types.Address;
}> => {
const controllers = await promiseObjAll(
objMap(this.routers(), (network, router) => router.controller()),
objMap(this.routers(), (_chain, router) => router.controller()),
);
const match = Object.entries(controllers).find(
([_, controller]) => controller !== ethers.constants.AddressZero,
) as [Networks, types.Address] | undefined;
) as [Chain, types.Address] | undefined;
if (match) {
return { network: match[0], address: match[1] };
return { chain: match[0], address: match[1] };
}
throw new Error('No controller found');
};
build = async (): Promise<ethers.PopulatedTransaction[]> => {
const controller = await this.controller();
const controllerRouter = this.routers()[controller.network];
const controllerRouter = this.routers()[controller.chain];
const networkTransactions = await promiseObjAll(
objMap(this.networkCalls(), (network, calls) => {
if (network === controller.network) {
const chainTransactions = await promiseObjAll(
objMap(this.chainCalls(), (chain, calls) => {
if (chain === controller.chain) {
return controllerRouter.populateTransaction.call(calls);
} else {
return controllerRouter.populateTransaction.callRemote(
ChainNameToDomainId[network],
ChainNameToDomainId[chain],
calls,
);
}
}),
);
return Object.values(networkTransactions);
return Object.values(chainTransactions);
};
execute = async (signer: ethers.Signer) => {

@ -11,21 +11,22 @@ import { environments } from './environments';
export const CoreEnvironments = Object.keys(environments);
export type CoreEnvironment = keyof typeof environments;
export type CoreEnvironmentNetworks<E extends CoreEnvironment> = Extract<
export type CoreEnvironmentChain<E extends CoreEnvironment> = Extract<
keyof typeof environments[E],
ChainName
>;
export class AbacusCore<
Networks extends ChainName = ChainName,
> extends AbacusApp<CoreContracts<Networks>, Networks> {
export class AbacusCore<Chain extends ChainName = ChainName> extends AbacusApp<
CoreContracts<Chain>,
Chain
> {
constructor(
networkAddresses: {
[local in Networks]: CoreContractAddresses<Networks, local>;
addresses: {
[local in Chain]: CoreContractAddresses<Chain, local>;
},
multiProvider: MultiProvider<Networks>,
multiProvider: MultiProvider<Chain>,
) {
super(CoreContracts, networkAddresses, multiProvider);
super(CoreContracts, addresses, multiProvider);
}
static fromEnvironment<E extends CoreEnvironment>(
@ -35,22 +36,22 @@ export class AbacusCore<
return new AbacusCore(environments[name], multiProvider);
}
// override type to be derived from network key
getContracts<Local extends Networks>(
network: Local,
): CoreContractSchema<Networks, Local> {
return super.getContracts(network) as any;
// override type to be derived from chain key
getContracts<Local extends Chain>(
chain: Local,
): CoreContractSchema<Chain, Local> {
return super.getContracts(chain) as any;
}
// override type to be derived from network key
getAddresses<Local extends Networks>(
network: Local,
): CoreContractAddresses<Networks, Local> {
return super.getAddresses(network) as any;
// override type to be derived from chain key
getAddresses<Local extends Chain>(
chain: Local,
): CoreContractAddresses<Chain, Local> {
return super.getAddresses(chain) as any;
}
getMailboxPair<Local extends Networks>(
origin: Remotes<Networks, Local>,
getMailboxPair<Local extends Chain>(
origin: Remotes<Chain, Local>,
destination: Local,
) {
const outbox = this.getContracts(origin).outbox.outbox;

@ -154,8 +154,8 @@ export class AbacusMessage {
): AbacusMessage[] {
const messages: AbacusMessage[] = [];
const outbox = new Outbox__factory().interface;
const network = resolveDomain(nameOrDomain);
const provider = multiProvider.getChainConnection(network).provider!;
const chain = resolveDomain(nameOrDomain);
const provider = multiProvider.getChainConnection(chain).provider!;
for (const log of receipt.logs) {
try {

@ -6,7 +6,7 @@ import {
TypedEventFilter,
} from '@abacus-network/core/dist/commons';
import { domains } from './domains';
import { chainMetadata } from './chain-metadata';
import { MultiProvider } from './provider';
import { ChainName } from './types';
@ -82,7 +82,7 @@ export interface TSContract<T extends Result, U> {
export async function queryAnnotatedEvents<T extends Result, U>(
multiprovider: MultiProvider<any>,
network: ChainName,
chain: ChainName,
contract: TSContract<T, U>,
filter: TypedEventFilter<T, U>,
startBlock?: number,
@ -90,45 +90,45 @@ export async function queryAnnotatedEvents<T extends Result, U>(
): Promise<Array<Annotated<T, TypedEvent<T & U>>>> {
const events = await getEvents(
multiprovider,
network,
chain,
contract,
filter,
startBlock,
endBlock,
);
return Annotated.fromEvents(domains[network].id, events);
return Annotated.fromEvents(chainMetadata[chain].id, events);
}
export async function findAnnotatedSingleEvent<T extends Result, U>(
multiprovider: MultiProvider<any>,
network: ChainName,
chain: ChainName,
contract: TSContract<T, U>,
filter: TypedEventFilter<T, U>,
startBlock?: number,
): Promise<Array<Annotated<T, TypedEvent<T & U>>>> {
const events = await findEvent(
multiprovider,
network,
chain,
contract,
filter,
startBlock,
);
return Annotated.fromEvents(domains[network].id, events);
return Annotated.fromEvents(chainMetadata[chain].id, events);
}
export async function getEvents<T extends Result, U>(
multiprovider: MultiProvider<any>,
network: ChainName,
chain: ChainName,
contract: TSContract<T, U>,
filter: TypedEventFilter<T, U>,
startBlock?: number,
endBlock?: number,
): Promise<Array<TypedEvent<T & U>>> {
const domain = domains[network];
const domain = chainMetadata[chain];
if (domain.paginate) {
return getPaginatedEvents(
multiprovider,
network,
chain,
contract,
filter,
startBlock,
@ -140,16 +140,16 @@ export async function getEvents<T extends Result, U>(
export async function findEvent<T extends Result, U>(
multiprovider: MultiProvider<any>,
network: ChainName,
chain: ChainName,
contract: TSContract<T, U>,
filter: TypedEventFilter<T, U>,
startBlock?: number,
): Promise<Array<TypedEvent<T & U>>> {
const domain = domains[network];
const domain = chainMetadata[chain];
if (domain.paginate) {
return findFromPaginatedEvents(
multiprovider,
network,
chain,
contract,
filter,
startBlock,
@ -160,13 +160,13 @@ export async function findEvent<T extends Result, U>(
async function getPaginatedEvents<T extends Result, U>(
multiprovider: MultiProvider<any>,
network: ChainName,
chain: ChainName,
contract: TSContract<T, U>,
filter: TypedEventFilter<T, U>,
startBlock?: number,
endBlock?: number,
): Promise<Array<TypedEvent<T & U>>> {
const domain = domains[network];
const domain = chainMetadata[chain];
if (!domain.paginate) {
throw new Error('Domain need not be paginated');
}
@ -179,7 +179,7 @@ async function getPaginatedEvents<T extends Result, U>(
// or current block number
let lastBlock;
if (!endBlock) {
const provider = multiprovider.getChainConnection(network).provider!;
const provider = multiprovider.getChainConnection(chain).provider!;
lastBlock = await provider.getBlockNumber();
} else {
lastBlock = endBlock;
@ -207,13 +207,13 @@ async function getPaginatedEvents<T extends Result, U>(
async function findFromPaginatedEvents<T extends Result, U>(
multiprovider: MultiProvider<any>,
network: ChainName,
chain: ChainName,
contract: TSContract<T, U>,
filter: TypedEventFilter<T, U>,
startBlock?: number,
endBlock?: number,
): Promise<Array<TypedEvent<T & U>>> {
const domain = domains[network];
const domain = chainMetadata[chain];
if (!domain.paginate) {
throw new Error('Domain need not be paginated');
}
@ -226,7 +226,7 @@ async function findFromPaginatedEvents<T extends Result, U>(
// or current block number
let lastBlock;
if (!endBlock) {
const provider = multiprovider.getChainConnection(network).provider!;
const provider = multiprovider.getChainConnection(chain).provider!;
lastBlock = await provider.getBlockNumber();
} else {
lastBlock = endBlock;

@ -1,4 +1,4 @@
import { AbacusCore, MultiProvider, domains } from '..';
import { AbacusCore, MultiProvider, chainMetadata } from '..';
import { BigNumber, FixedNumber, ethers } from 'ethers';
import { utils } from '@abacus-network/utils';
@ -21,7 +21,7 @@ import { convertDecimalValue, mulBigAndFixed } from './utils';
* estimating amounts.
*/
// If a domain doesn't specify how many decimals their native token has, 18 is used.
// If a chain doesn't specify how many decimals their native token has, 18 is used.
const DEFAULT_TOKEN_DECIMALS = 18;
// A generous estimation of the overhead gas amount when processing a message. This
@ -36,7 +36,7 @@ const DEFAULT_TOKEN_DECIMALS = 18;
const INBOX_PROCESS_OVERHEAD_GAS = 130_000;
// Intrinsic gas for a transaction. Does not consider calldata costs or differences in
// intrinsic gas or different networks.
// intrinsic gas or different chains.
const BASE_INTRINSIC_GAS = 21_000;
// The gas used if the quorum threshold of a signed checkpoint is zero.
@ -74,10 +74,10 @@ export interface InterchainGasCalculatorConfig {
}
export type ParsedMessage<
Networks extends ChainName,
Destination extends Networks,
Chain extends ChainName,
Destination extends Chain,
> = {
origin: Exclude<Networks, Destination>;
origin: Exclude<Chain, Destination>;
sender: string;
destination: Destination;
recipient: string;
@ -87,9 +87,9 @@ export type ParsedMessage<
/**
* Calculates interchain gas payments.
*/
export class InterchainGasCalculator<Networks extends ChainName> {
core: AbacusCore<Networks>;
multiProvider: MultiProvider<Networks>;
export class InterchainGasCalculator<Chain extends ChainName> {
core: AbacusCore<Chain>;
multiProvider: MultiProvider<Chain>;
tokenPriceGetter: TokenPriceGetter;
@ -97,8 +97,8 @@ export class InterchainGasCalculator<Networks extends ChainName> {
messageGasEstimateBuffer: ethers.BigNumber;
constructor(
multiProvider: MultiProvider<Networks>,
core: AbacusCore<Networks>,
multiProvider: MultiProvider<Chain>,
core: AbacusCore<Chain>,
config?: InterchainGasCalculatorConfig,
) {
this.multiProvider = multiProvider;
@ -130,8 +130,8 @@ export class InterchainGasCalculator<Networks extends ChainName> {
* @returns An estimated amount of origin chain tokens to cover gas costs of the
* message on the destination chain.
*/
async estimatePaymentForHandleGasAmount<Destination extends Networks>(
origin: Exclude<Networks, Destination>,
async estimatePaymentForHandleGasAmount<Destination extends Chain>(
origin: Exclude<Chain, Destination>,
destination: Destination,
destinationHandleGas: BigNumber,
): Promise<BigNumber> {
@ -147,7 +147,7 @@ export class InterchainGasCalculator<Networks extends ChainName> {
.add(destinationHandleGas);
const destinationCostWei = totalDestinationGas.mul(destinationGasPrice);
// Convert from destination domain native tokens to origin domain native tokens.
// Convert from destination chain native tokens to origin chain native tokens.
const originCostWei = await this.convertBetweenNativeTokens(
destination,
origin,
@ -172,8 +172,8 @@ export class InterchainGasCalculator<Networks extends ChainName> {
* @returns An estimated amount of origin chain tokens to cover gas costs of the
* message on the destination chain.
*/
async estimatePaymentForMessage<Destination extends Networks>(
message: ParsedMessage<Networks, Destination>,
async estimatePaymentForMessage<Destination extends Chain>(
message: ParsedMessage<Chain, Destination>,
) {
const destinationGas = await this.estimateHandleGasForMessage(message);
return this.estimatePaymentForHandleGasAmount(
@ -187,15 +187,15 @@ export class InterchainGasCalculator<Networks extends ChainName> {
* Using the exchange rates provided by tokenPriceGetter, returns the amount of
* `toChain` native tokens equivalent in value to the provided `fromAmount` of
* `fromChain` native tokens. Accounts for differences in the decimals of the tokens.
* @param fromChain The domain whose native token is being converted from.
* @param toChain The domain whose native token is being converted into.
* @param fromChain The chain whose native token is being converted from.
* @param toChain The chain whose native token is being converted into.
* @param fromAmount The amount of `fromChain` native tokens to convert from.
* @returns The amount of `toChain` native tokens whose value is equivalent to
* `fromAmount` of `fromChain` native tokens.
*/
async convertBetweenNativeTokens(
fromChain: Networks,
toChain: Networks,
fromChain: Chain,
toChain: Chain,
fromAmount: BigNumber,
): Promise<BigNumber> {
// A FixedNumber that doesn't care what the decimals of the from/to
@ -220,15 +220,15 @@ export class InterchainGasCalculator<Networks extends ChainName> {
}
/**
* @param baseChain The domain whose native token is the base asset.
* @param quoteChain The domain whose native token is the quote asset.
* @param baseChain The chain whose native token is the base asset.
* @param quoteChain The chain whose native token is the quote asset.
* @returns The exchange rate of the native tokens of the baseChain and the quoteChain.
* I.e. the number of whole quote tokens a single whole base token is equivalent
* in value to.
*/
async getExchangeRate(
baseChain: Networks,
quoteChain: Networks,
baseChain: Chain,
quoteChain: Chain,
): Promise<FixedNumber> {
const baseUsd = await this.tokenPriceGetter.getNativeTokenUsdPrice(
baseChain,
@ -248,11 +248,11 @@ export class InterchainGasCalculator<Networks extends ChainName> {
}
/**
* Gets a suggested gas price for a domain.
* Gets a suggested gas price for a chain.
* @param chainName The name of the chain to get the gas price for
* @returns The suggested gas price in wei on the destination chain.
*/
async suggestedGasPrice(chainName: Networks): Promise<BigNumber> {
async suggestedGasPrice(chainName: Chain): Promise<BigNumber> {
const provider = this.multiProvider.getChainConnection(chainName).provider!;
return provider.getGasPrice();
}
@ -262,14 +262,14 @@ export class InterchainGasCalculator<Networks extends ChainName> {
* @param chain The chain.
* @returns The number of decimals of `chain`'s native token.
*/
nativeTokenDecimals(chain: Networks) {
return domains[chain].nativeTokenDecimals ?? DEFAULT_TOKEN_DECIMALS;
nativeTokenDecimals(chain: Chain) {
return chainMetadata[chain].nativeTokenDecimals ?? DEFAULT_TOKEN_DECIMALS;
}
/**
* Estimates the amount of gas used by message's recipient `handle` function
* on its destination chain. This does not assume the Inbox of the destination
* domain has a checkpoint that the message is included in, and does not
* chain has a checkpoint that the message is included in, and does not
* consider intrinsic gas or any "overhead" gas incurred by Inbox.process.
* The estimated gas returned is the sum of:
* 1. The estimated gas consumption of a direct call to the `handle`
@ -280,13 +280,13 @@ export class InterchainGasCalculator<Networks extends ChainName> {
* @returns The estimated gas required by the message's recipient handle function
* on the destination chain.
*/
async estimateHandleGasForMessage<Local extends Networks>(
message: ParsedMessage<Networks, Local>,
async estimateHandleGasForMessage<LocalChain extends Chain>(
message: ParsedMessage<Chain, LocalChain>,
): Promise<BigNumber> {
const provider = this.multiProvider.getChainConnection(message.destination)
.provider!;
const { inbox } = this.core.getMailboxPair<Local>(
const { inbox } = this.core.getMailboxPair<LocalChain>(
message.origin,
message.destination,
);
@ -320,13 +320,13 @@ export class InterchainGasCalculator<Networks extends ChainName> {
* @param origin The name of the origin chain.
* @param destination The name of the destination chain.
* @returns An estimated gas amount a relayer will spend when submitting a signed
* checkpoint to the destination domain.
* checkpoint to the destination chain.
*/
async checkpointRelayGas<Destination extends Networks>(
origin: Remotes<Networks, Destination>,
async checkpointRelayGas<Destination extends Chain>(
origin: Remotes<Chain, Destination>,
destination: Destination,
): Promise<BigNumber> {
const inboxes: RemoteChainMap<Networks, Destination, InboxContracts> =
const inboxes: RemoteChainMap<Chain, Destination, InboxContracts> =
this.core.getContracts(destination).inboxes;
const inboxValidatorManager = inboxes[origin].validatorManager;
const threshold = await inboxValidatorManager.threshold();
@ -344,8 +344,8 @@ export class InterchainGasCalculator<Networks extends ChainName> {
* estimate sovereign consensus costs, and we'd like to keep the interface consistent.
*/
inboxProcessOverheadGas(): Promise<BigNumber> {
// This does not consider that different domains can possibly have different gas costs.
// Consider this being configurable for each domain, or investigate ways to estimate
// This does not consider that different chains can possibly have different gas costs.
// Consider this being configurable for each chain, or investigate ways to estimate
// this over RPC.
// Also does not consider gas usage that may scale with message size, e.g. calldata
// costs.

@ -3,12 +3,12 @@ import { FixedNumber } from 'ethers';
import { NameOrDomain } from '../types';
export interface TokenPriceGetter {
getNativeTokenUsdPrice(domain: NameOrDomain): Promise<FixedNumber>;
getNativeTokenUsdPrice(chain: NameOrDomain): Promise<FixedNumber>;
}
// TODO implement in following PR
export class DefaultTokenPriceGetter implements TokenPriceGetter {
getNativeTokenUsdPrice(_domain: NameOrDomain): Promise<FixedNumber> {
getNativeTokenUsdPrice(_chain: NameOrDomain): Promise<FixedNumber> {
return Promise.resolve(FixedNumber.from('12.34'));
}
}

@ -25,7 +25,7 @@ export {
resolveId,
resolveNetworks,
} from './core';
export { domains } from './domains';
export { chainMetadata } from './chain-metadata';
export {
Annotated,
getEvents,

@ -56,20 +56,22 @@ export class ChainConnection {
}
export class MultiProvider<
Networks extends ChainName = ChainName,
> extends MultiGeneric<Networks, ChainConnection> {
constructor(networks: ChainMap<Networks, IChainConnection> | Networks[]) {
const params = Array.isArray(networks)
? networks.map((v) => [v, {}])
: (Object.entries(networks) as [Networks, IChainConnection][]);
const providerEntries = params.map(([network, v]) => [
network,
Chain extends ChainName = ChainName,
> extends MultiGeneric<Chain, ChainConnection> {
constructor(
chainConnectionConfigs: ChainMap<Chain, IChainConnection> | Chain[],
) {
const params = Array.isArray(chainConnectionConfigs)
? chainConnectionConfigs.map((v) => [v, {}])
: (Object.entries(chainConnectionConfigs) as [Chain, IChainConnection][]);
const providerEntries = params.map(([chain, v]) => [
chain,
new ChainConnection(v),
]);
super(Object.fromEntries(providerEntries));
}
getChainConnection(network: Networks) {
return this.get(network);
getChainConnection(chain: Chain) {
return this.get(chain);
}
// This doesn't work on hardhat providers so we skip for now
// ready() {

@ -2,7 +2,7 @@ import { ethers } from 'ethers';
import { types } from '@abacus-network/utils';
import { domains } from './domains';
import { chainMetadata } from './chain-metadata';
/**
* RPC Pagination information for Polygon
@ -21,9 +21,6 @@ export enum Chains { // must be string type to be used with Object.keys
kovan = 'kovan',
goerli = 'goerli',
fuji = 'fuji',
rinkarby = 'rinkarby',
rinkeby = 'rinkeby',
ropsten = 'ropsten',
celo = 'celo',
ethereum = 'ethereum',
avalanche = 'avalanche',
@ -38,37 +35,34 @@ export enum Chains { // must be string type to be used with Object.keys
}
export type ChainName = keyof typeof Chains;
export type CompleteChainMap<Value> = Record<ChainName, Value>;
export type ChainMap<Networks extends ChainName, Value> = Record<
Networks,
Value
>;
export type ChainMap<Chain extends ChainName, Value> = Record<Chain, Value>;
export type TestChainNames = 'test1' | 'test2' | 'test3';
export const AllChains = Object.keys(Chains) as ChainName[];
export const DomainIdToChainName = Object.fromEntries(
AllChains.map((chain) => [domains[chain].id, chain]),
AllChains.map((chain) => [chainMetadata[chain].id, chain]),
);
export const ChainNameToDomainId = Object.fromEntries(
AllChains.map((chain) => [chain, domains[chain].id]),
AllChains.map((chain) => [chain, chainMetadata[chain].id]),
) as CompleteChainMap<number>;
export type NameOrDomain = ChainName | number;
export type Remotes<
Networks extends ChainName,
Local extends Networks,
> = Exclude<Networks, Local>;
Chain extends ChainName,
LocalChain extends Chain,
> = Exclude<Chain, LocalChain>;
export type RemoteChainMap<
Networks extends ChainName,
Local extends Networks,
Chain extends ChainName,
LocalChain extends Chain,
Value,
> = Record<Remotes<Networks, Local>, Value>;
> = Record<Remotes<Chain, LocalChain>, Value>;
/**
* A Domain (and its characteristics)
*/
export type Domain = {
export type ChainMetadata = {
id: number;
nativeTokenDecimals?: number;
paginate?: Pagination;

@ -55,46 +55,46 @@ export function delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export class MultiGeneric<Networks extends ChainName, Value> {
constructor(protected readonly domainMap: ChainMap<Networks, Value>) {}
export class MultiGeneric<Chain extends ChainName, Value> {
constructor(protected readonly chainMap: ChainMap<Chain, Value>) {}
protected get = (network: Networks) => this.domainMap[network];
protected get = (chain: Chain) => this.chainMap[chain];
networks = () => Object.keys(this.domainMap) as Networks[];
chains = () => Object.keys(this.chainMap) as Chain[];
apply(fn: (n: Networks, dc: Value) => void) {
for (const network of this.networks()) {
fn(network, this.domainMap[network]);
apply(fn: (n: Chain, dc: Value) => void) {
for (const chain of this.chains()) {
fn(chain, this.chainMap[chain]);
}
}
map<Output>(fn: (n: Networks, dc: Value) => Output) {
let entries: [Networks, Output][] = [];
const networks = this.networks();
for (const network of networks) {
entries.push([network, fn(network, this.domainMap[network])]);
map<Output>(fn: (n: Chain, dc: Value) => Output) {
let entries: [Chain, Output][] = [];
const chains = this.chains();
for (const chain of chains) {
entries.push([chain, fn(chain, this.chainMap[chain])]);
}
return Object.fromEntries(entries) as Record<Networks, Output>;
return Object.fromEntries(entries) as Record<Chain, Output>;
}
remotes = <Name extends Networks>(name: Name) =>
this.networks().filter((key) => key !== name) as Remotes<Networks, Name>[];
remoteChains = <LocalChain extends Chain>(name: LocalChain) =>
this.chains().filter((key) => key !== name) as Remotes<Chain, LocalChain>[];
extendWithDomain = <New extends Remotes<ChainName, Networks>>(
network: New,
extendWithChain = <New extends Remotes<ChainName, Chain>>(
chain: New,
value: Value,
) =>
new MultiGeneric<New & Networks, Value>({
...this.domainMap,
[network]: value,
new MultiGeneric<New & Chain, Value>({
...this.chainMap,
[chain]: value,
});
knownDomain = (network: ChainName) => network in this.domainMap;
knownChain = (chain: ChainName) => chain in this.chainMap;
}
export function inferChainMap<M>(map: M) {
return map as M extends ChainMap<infer Networks, infer Value>
? Record<Networks, Value>
return map as M extends ChainMap<infer Chain, infer Value>
? Record<Chain, Value>
: never;
}

@ -25,7 +25,7 @@ describe('InterchainGasCalculator', () => {
// This is because InterchainGasCalculator isn't very strongly typed,
// which is because ParsedMessage isn't very strongly typed. This results
// in InterchainGasCalculator expecting a multiprovider with providers for
// every network.
// every chain.
const multiProvider = new MultiProvider({
test1: { provider },
test2: { provider },

@ -41,14 +41,14 @@ export class MockProvider extends ethers.providers.BaseProvider {
}
// A mock TokenPriceGetter intended to be used by tests when mocking token prices
export class MockTokenPriceGetter<Networks extends ChainName> {
private tokenPrices: Partial<ChainMap<Networks, FixedNumber>>;
export class MockTokenPriceGetter<Chain extends ChainName> {
private tokenPrices: Partial<ChainMap<Chain, FixedNumber>>;
constructor() {
this.tokenPrices = {};
}
getNativeTokenUsdPrice(chain: Networks): Promise<FixedNumber> {
getNativeTokenUsdPrice(chain: Chain): Promise<FixedNumber> {
const price = this.tokenPrices[chain];
if (price) {
// TS compiler somehow can't deduce the check above
@ -57,7 +57,7 @@ export class MockTokenPriceGetter<Networks extends ChainName> {
throw Error(`No price for chain ${chain}`);
}
setTokenPrice(chain: Networks, price: string | number) {
setTokenPrice(chain: Chain, price: string | number) {
this.tokenPrices[chain] = FixedNumber.from(price);
}
}

Loading…
Cancel
Save