* Alpha7

* Checker

* Move AbacusCoreChecker to deploy
pull/597/head v0.2.1
Nam Chu Hoai 2 years ago committed by GitHub
parent 630e20bbc2
commit 55c9750cd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      package.json
  2. 2
      solidity/app/contracts/AbacusConnectionClient.sol
  3. 12
      solidity/app/contracts/Router.sol
  4. 11
      solidity/app/contracts/test/TestRouter.sol
  5. 1
      solidity/app/hardhat.config.ts
  6. 7
      solidity/app/package.json
  7. 260
      solidity/app/test/router.test.ts
  8. 2
      solidity/app/tsconfig.json
  9. 6
      solidity/core/contracts/Inbox.sol
  10. 2
      solidity/core/contracts/MerkleTreeManager.sol
  11. 6
      solidity/core/contracts/Outbox.sol
  12. 0
      solidity/core/contracts/libs/Merkle.sol
  13. 0
      solidity/core/contracts/libs/Message.sol
  14. 0
      solidity/core/contracts/libs/TypeCasts.sol
  15. 2
      solidity/core/contracts/test/TestMessage.sol
  16. 2
      solidity/core/contracts/test/TestOutbox.sol
  17. 2
      solidity/core/contracts/test/TestSendReceiver.sol
  18. 2
      solidity/core/contracts/validator-manager/OutboxValidatorManager.sol
  19. 18
      solidity/core/hardhat.config.ts
  20. 7
      solidity/core/package.json
  21. 2
      solidity/core/tsconfig.json
  22. 9
      typescript/deploy/package.json
  23. 2
      typescript/deploy/src/check.ts
  24. 23
      typescript/deploy/src/core/check.ts
  25. 7
      typescript/deploy/src/core/deploy.ts
  26. 6
      typescript/deploy/src/deploy.ts
  27. 1
      typescript/deploy/src/index.ts
  28. 24
      typescript/deploy/src/router/check.ts
  29. 39
      typescript/deploy/src/router/deploy.ts
  30. 1
      typescript/deploy/src/router/types.ts
  31. 10
      typescript/deploy/src/utils.ts
  32. 10
      typescript/hardhat/package.json
  33. 8
      typescript/infra/package.json
  34. 3
      typescript/infra/scripts/check-deploy.ts
  35. 1
      typescript/infra/src/core/index.ts
  36. 10
      typescript/infra/src/utils/utils.ts
  37. 7
      typescript/infra/test/core.test.ts
  38. 6
      typescript/sdk/package.json
  39. 4
      typescript/sdk/src/app.ts
  40. 13
      typescript/sdk/src/core/app.ts
  41. 26
      typescript/sdk/src/core/contracts.ts
  42. 4
      typescript/sdk/src/core/events.ts
  43. 4
      typescript/sdk/src/index.ts
  44. 26
      typescript/sdk/src/router.ts
  45. 1
      typescript/sdk/src/utils.ts
  46. 2
      typescript/utils/package.json
  47. 41
      yarn.lock

@ -16,6 +16,7 @@
"private": true,
"scripts": {
"build": "yarn workspaces foreach --verbose --parallel --topological run build",
"publish": "yarn workspaces foreach --no-private --verbose --topological npm publish --access public",
"postinstall": "husky install",
"prettier": "yarn workspaces foreach --verbose --parallel run prettier",
"lint-ts": "eslint . --ext .ts",

@ -48,7 +48,7 @@ abstract contract AbacusConnectionClient is OwnableUpgradeable {
function __AbacusConnectionClient_initialize(
address _abacusConnectionManager
) internal {
) internal onlyInitializing {
_setAbacusConnectionManager(_abacusConnectionManager);
__Ownable_init();
}

@ -35,8 +35,18 @@ abstract contract Router is AbacusConnectionClient, IMessageRecipient {
}
// ======== Initializer =========
function initialize(address _abacusConnectionManager)
external
virtual
initializer
{
__Router_initialize(_abacusConnectionManager);
}
function __Router_initialize(address _abacusConnectionManager) internal {
function __Router_initialize(address _abacusConnectionManager)
internal
onlyInitializing
{
__AbacusConnectionClient_initialize(_abacusConnectionManager);
}

@ -4,8 +4,15 @@ pragma solidity >=0.6.11;
import "../Router.sol";
contract TestRouter is Router {
function initialize(address _abacusConnectionManager) external initializer {
__Router_initialize(_abacusConnectionManager);
event InitializeOverload();
function initialize(address abacusConnectionManager)
external
override
initializer
{
__Router_initialize(abacusConnectionManager);
emit InitializeOverload();
}
function _handle(

@ -29,6 +29,5 @@ module.exports = {
typechain: {
outDir: './types',
target: 'ethers-v5',
alwaysGenerateOverloads: false, // should overloads with full signatures like deposit(uint256) be generated always, even if there are no overloads?
},
};

@ -1,10 +1,10 @@
{
"name": "@abacus-network/app",
"description": "Solidity contracts for Abacus apps",
"version": "0.2.1-alpha3",
"version": "0.2.1",
"dependencies": {
"@abacus-network/core": "^0.2.1-alpha3",
"@abacus-network/utils": "^0.2.1-alpha3",
"@abacus-network/core": "^0.2.1",
"@abacus-network/utils": "^0.2.1",
"@openzeppelin/contracts-upgradeable": "^4.5.0"
},
"devDependencies": {
@ -45,6 +45,7 @@
"repository": "https://github.com/abacus-network/abacus-monorepo",
"scripts": {
"build": "hardhat compile && tsc",
"clean": "hardhat clean",
"coverage": "hardhat coverage",
"prettier": "prettier --write ./contracts ./test",
"test": "hardhat test"

@ -49,138 +49,172 @@ describe('Router', async () => {
);
await connectionManager.setOutbox(outbox.address);
const routerFactory = new TestRouter__factory(signer);
router = await routerFactory.deploy();
await router.initialize(connectionManager.address);
router = await new TestRouter__factory(signer).deploy();
});
it('Cannot be initialized twice', async () => {
await expect(
router.initialize(ethers.constants.AddressZero),
).to.be.revertedWith('Initializable: contract is already initialized');
});
describe('#initialize', () => {
it('should set the abacus connection manager', async () => {
await router.initialize(connectionManager.address);
expect(await router.abacusConnectionManager()).to.equal(
connectionManager.address,
);
});
it('accepts message from enrolled inbox and router', async () => {
await connectionManager.enrollInbox(origin, signer.address);
const remote = utils.addressToBytes32(nonOwner.address);
await router.enrollRemoteRouter(origin, remote);
// Does not revert.
await router.handle(origin, remote, message);
});
it('should transfer owner to deployer', async () => {
await router.initialize(connectionManager.address);
expect(await router.owner()).to.equal(signer.address);
});
it('rejects message from unenrolled inbox', async () => {
await expect(
router.handle(origin, utils.addressToBytes32(nonOwner.address), message),
).to.be.revertedWith('!inbox');
});
it('should use overloaded initialize', async () => {
await expect(router.initialize(connectionManager.address)).to.emit(
router,
'InitializeOverload',
);
});
it('rejects message from unenrolled router', async () => {
await connectionManager.enrollInbox(origin, signer.address);
await expect(
router.handle(origin, utils.addressToBytes32(nonOwner.address), message),
).to.be.revertedWith('!router');
it('cannot be initialized twice', async () => {
await router.initialize(ethers.constants.AddressZero);
await expect(
router.initialize(ethers.constants.AddressZero),
).to.be.revertedWith('Initializable: contract is already initialized');
});
});
it('owner can enroll remote router', async () => {
const remote = nonOwner.address;
const remoteBytes = utils.addressToBytes32(nonOwner.address);
expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(false);
await expect(router.mustHaveRemoteRouter(origin)).to.be.revertedWith(
'!router',
);
await expect(
router.enrollRemoteRouter(origin, utils.addressToBytes32(remote)),
).to.emit(router, 'RemoteRouterEnrolled');
expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(true);
expect(await router.mustHaveRemoteRouter(origin)).to.equal(remoteBytes);
});
describe('when initialized', () => {
beforeEach(async () => {
await router.initialize(connectionManager.address);
});
it('non-owner cannot enroll remote router', async () => {
await expect(
router
.connect(nonOwner)
.enrollRemoteRouter(origin, utils.addressToBytes32(nonOwner.address)),
).to.be.revertedWith(ONLY_OWNER_REVERT_MSG);
});
it('accepts message from enrolled inbox and router', async () => {
await connectionManager.enrollInbox(origin, signer.address);
const remote = utils.addressToBytes32(nonOwner.address);
await router.enrollRemoteRouter(origin, remote);
// Does not revert.
await router.handle(origin, remote, message);
});
describe('dispatch functions', () => {
let interchainGasPaymaster: InterchainGasPaymaster;
beforeEach(async () => {
const interchainGasPaymasterFactory = new InterchainGasPaymaster__factory(
signer,
);
interchainGasPaymaster = await interchainGasPaymasterFactory.deploy();
await router.setInterchainGasPaymaster(interchainGasPaymaster.address);
// Enroll a remote router on the destination domain.
// The address is arbitrary because no messages will actually be processed.
await router.enrollRemoteRouter(
destination,
utils.addressToBytes32(nonOwner.address),
it('rejects message from unenrolled inbox', async () => {
await expect(
router.handle(
origin,
utils.addressToBytes32(nonOwner.address),
message,
),
).to.be.revertedWith('!inbox');
});
it('rejects message from unenrolled router', async () => {
await connectionManager.enrollInbox(origin, signer.address);
await expect(
router.handle(
origin,
utils.addressToBytes32(nonOwner.address),
message,
),
).to.be.revertedWith('!router');
});
it('owner can enroll remote router', async () => {
const remote = nonOwner.address;
const remoteBytes = utils.addressToBytes32(nonOwner.address);
expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(false);
await expect(router.mustHaveRemoteRouter(origin)).to.be.revertedWith(
'!router',
);
await router.enrollRemoteRouter(origin, utils.addressToBytes32(remote));
expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(true);
expect(await router.mustHaveRemoteRouter(origin)).to.equal(remoteBytes);
});
// Helper for testing different variations of dispatch functions
const runDispatchFunctionTests = async (
dispatchFunction: (
destinationDomain: number,
interchainGasPayment?: number,
) => Promise<ContractTransaction>,
expectGasPayment: boolean,
) => {
// Allows a Chai Assertion to be programmatically negated
const expectAssertion = (
assertion: Chai.Assertion,
expected: boolean,
) => {
return expected ? assertion : assertion.not;
};
it('non-owner cannot enroll remote router', async () => {
await expect(
router
.connect(nonOwner)
.enrollRemoteRouter(origin, utils.addressToBytes32(nonOwner.address)),
).to.be.revertedWith(ONLY_OWNER_REVERT_MSG);
});
it('dispatches a message', async () => {
await expect(dispatchFunction(destination)).to.emit(outbox, 'Dispatch');
describe('dispatch functions', () => {
let interchainGasPaymaster: InterchainGasPaymaster;
beforeEach(async () => {
const interchainGasPaymasterFactory =
new InterchainGasPaymaster__factory(signer);
interchainGasPaymaster = await interchainGasPaymasterFactory.deploy();
await router.setInterchainGasPaymaster(interchainGasPaymaster.address);
// Enroll a remote router on the destination domain.
// The address is arbitrary because no messages will actually be processed.
await router.enrollRemoteRouter(
destination,
utils.addressToBytes32(nonOwner.address),
);
});
it(`${
expectGasPayment ? 'pays' : 'does not pay'
} interchain gas`, async () => {
const testInterchainGasPayment = 1234;
const leafIndex = await outbox.count();
const assertion = expectAssertion(
expect(dispatchFunction(destination, testInterchainGasPayment)).to,
expectGasPayment,
// Helper for testing different variations of dispatch functions
const runDispatchFunctionTests = async (
dispatchFunction: (
destinationDomain: number,
interchainGasPayment?: number,
) => Promise<ContractTransaction>,
expectGasPayment: boolean,
) => {
// Allows a Chai Assertion to be programmatically negated
const expectAssertion = (
assertion: Chai.Assertion,
expected: boolean,
) => {
return expected ? assertion : assertion.not;
};
it('dispatches a message', async () => {
await expect(dispatchFunction(destination)).to.emit(
outbox,
'Dispatch',
);
});
it(`${
expectGasPayment ? 'pays' : 'does not pay'
} interchain gas`, async () => {
const testInterchainGasPayment = 1234;
const leafIndex = await outbox.count();
const assertion = expectAssertion(
expect(dispatchFunction(destination, testInterchainGasPayment)).to,
expectGasPayment,
);
await assertion
.emit(interchainGasPaymaster, 'GasPayment')
.withArgs(outbox.address, leafIndex, testInterchainGasPayment);
});
it('reverts when dispatching a message to an unenrolled remote router', async () => {
await expect(
dispatchFunction(destinationWithoutRouter),
).to.be.revertedWith('!router');
});
};
describe('#dispatch', () => {
runDispatchFunctionTests(
(destinationDomain) => router.dispatch(destinationDomain, '0x'),
false,
);
await assertion
.emit(interchainGasPaymaster, 'GasPayment')
.withArgs(outbox.address, leafIndex, testInterchainGasPayment);
});
it('reverts when dispatching a message to an unenrolled remote router', async () => {
await expect(
dispatchFunction(destinationWithoutRouter),
).to.be.revertedWith('!router');
describe('#dispatchWithGas', () => {
runDispatchFunctionTests(
(destinationDomain, interchainGasPayment = 0) =>
router.dispatchWithGas(
destinationDomain,
'0x',
interchainGasPayment,
{
value: interchainGasPayment,
},
),
true,
);
});
};
describe('#dispatch', () => {
runDispatchFunctionTests(
(destinationDomain) => router.dispatch(destinationDomain, '0x'),
false,
);
});
describe('#dispatchWithGas', () => {
runDispatchFunctionTests(
(destinationDomain, interchainGasPayment = 0) =>
router.dispatchWithGas(
destinationDomain,
'0x',
interchainGasPayment,
{
value: interchainGasPayment,
},
),
true,
);
});
});
});

@ -5,5 +5,5 @@
},
"exclude": ["./node_modules/", "./dist/", "./types/hardhat.d.ts"],
"extends": "../../tsconfig.json",
"include": ["./types/*.ts", "./types/factories/*.ts"]
"include": ["./types/**/*.ts"]
}

@ -4,9 +4,9 @@ pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {Version0} from "./Version0.sol";
import {Mailbox} from "./Mailbox.sol";
import {MerkleLib} from "../libs/Merkle.sol";
import {Message} from "../libs/Message.sol";
import {TypeCasts} from "../libs/TypeCasts.sol";
import {MerkleLib} from "./libs/Merkle.sol";
import {Message} from "./libs/Message.sol";
import {TypeCasts} from "./libs/TypeCasts.sol";
import {IMessageRecipient} from "../interfaces/IMessageRecipient.sol";
import {IInbox} from "../interfaces/IInbox.sol";

@ -2,7 +2,7 @@
pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {MerkleLib} from "../libs/Merkle.sol";
import {MerkleLib} from "./libs/Merkle.sol";
/**
* @title MerkleTreeManager

@ -4,9 +4,9 @@ pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {Version0} from "./Version0.sol";
import {Mailbox} from "./Mailbox.sol";
import {MerkleLib} from "../libs/Merkle.sol";
import {Message} from "../libs/Message.sol";
import {TypeCasts} from "../libs/TypeCasts.sol";
import {MerkleLib} from "./libs/Merkle.sol";
import {Message} from "./libs/Message.sol";
import {TypeCasts} from "./libs/TypeCasts.sol";
import {MerkleTreeManager} from "./MerkleTreeManager.sol";
import {IOutbox} from "../interfaces/IOutbox.sol";

@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
import {Message} from "../../libs/Message.sol";
import {Message} from "../libs/Message.sol";
contract TestMessage {
using Message for bytes;

@ -3,7 +3,7 @@ pragma solidity >=0.8.0;
// ============ Internal Imports ============
import "../Outbox.sol";
import {MerkleLib} from "../../libs/Merkle.sol";
import {MerkleLib} from "../libs/Merkle.sol";
contract TestOutbox is Outbox {
constructor(uint32 _localDomain) Outbox(_localDomain) {} // solhint-disable-line no-empty-blocks

@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
import {TypeCasts} from "../../libs/TypeCasts.sol";
import {TypeCasts} from "../libs/TypeCasts.sol";
import {IInterchainGasPaymaster} from "../../interfaces/IInterchainGasPaymaster.sol";
import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol";

@ -4,7 +4,7 @@ pragma abicoder v2;
// ============ Internal Imports ============
import {IOutbox} from "../../interfaces/IOutbox.sol";
import {MerkleLib} from "../../libs/Merkle.sol";
import {MerkleLib} from "../libs/Merkle.sol";
import {MultisigValidatorManager} from "./MultisigValidatorManager.sol";
/**

@ -1,8 +1,8 @@
import "solidity-coverage";
import "@typechain/hardhat";
import "@nomiclabs/hardhat-ethers";
import "@nomiclabs/hardhat-waffle";
import "hardhat-gas-reporter";
import '@nomiclabs/hardhat-ethers';
import '@nomiclabs/hardhat-waffle';
import '@typechain/hardhat';
import 'hardhat-gas-reporter';
import 'solidity-coverage';
/**
* @type import('hardhat/config').HardhatUserConfig
@ -18,12 +18,12 @@ module.exports = {
},
},
gasReporter: {
currency: "USD",
currency: 'USD',
},
typechain: {
outDir: "./types",
target: "ethers-v5",
alwaysGenerateOverloads: false, // should overloads with full signatures like deposit(uint256) be generated always, even if there are no overloads?
outDir: './types',
target: 'ethers-v5',
alwaysGenerateOverloads: true,
},
mocha: {
bail: true,

@ -1,9 +1,9 @@
{
"name": "@abacus-network/core",
"description": "Core solidity contracts for Abacus",
"version": "0.2.1-alpha3",
"version": "0.2.1",
"dependencies": {
"@abacus-network/utils": "^0.2.1-alpha3",
"@abacus-network/utils": "^0.2.1",
"@openzeppelin/contracts": "^4.6.0",
"@openzeppelin/contracts-upgradeable": "^4.6.0",
"@summa-tx/memview-sol": "^2.0.0"
@ -45,8 +45,9 @@
"repository": "https://github.com/abacus-network/abacus-monorepo",
"scripts": {
"build": "hardhat compile && tsc",
"clean": "hardhat clean",
"coverage": "hardhat coverage",
"prettier": "prettier --write ./contracts ./libs ./test",
"prettier": "prettier --write ./contracts ./interfaces ./test",
"test": "hardhat test"
},
"types": "dist/index.d.ts"

@ -6,5 +6,5 @@
},
"exclude": ["./node_modules/", "./dist/", "./types/hardhat.d.ts"],
"extends": "../../tsconfig.json",
"include": ["./types/*.ts", "./types/factories/*.ts"]
"include": ["./types/**/*.ts"]
}

@ -1,11 +1,12 @@
{
"name": "@abacus-network/deploy",
"description": "Deploy tools for the Abacus network",
"version": "0.2.1-alpha3",
"version": "0.2.1",
"dependencies": {
"@abacus-network/core": "^0.2.1-alpha3",
"@abacus-network/sdk": "^0.2.1-alpha3",
"@abacus-network/utils": "^0.2.1-alpha3",
"@abacus-network/app": "^0.2.1",
"@abacus-network/core": "^0.2.1",
"@abacus-network/sdk": "^0.2.1",
"@abacus-network/utils": "^0.2.1",
"@types/debug": "^4.1.7",
"@types/yargs": "^17.0.10",
"axios": "^0.21.3",

@ -58,7 +58,7 @@ export abstract class AbacusAppChecker<
) {
const dc = this.multiProvider.getChainConnection(chain);
const implementation = await upgradeBeaconImplementation(
dc.provider!,
dc.provider,
proxiedAddress.beacon,
);
if (implementation !== proxiedAddress.implementation) {

@ -1,21 +1,21 @@
import { expect } from 'chai';
import { MultisigValidatorManager } from '@abacus-network/core';
import {
AbacusAppChecker,
CheckerViolation,
CoreConfig,
} from '@abacus-network/deploy';
import {
AbacusCore,
BeaconProxyAddresses,
ChainName,
ChainNameToDomainId,
chainMetadata,
objMap,
promiseObjAll,
} from '@abacus-network/sdk';
import { setDifference } from '../utils/utils';
import { AbacusAppChecker } from '../check';
import { CheckerViolation } from '../config';
import { setDifference } from '../utils';
import { CoreConfig } from './deploy';
export enum CoreViolationType {
ValidatorManager = 'ValidatorManager',
@ -182,6 +182,17 @@ export class AbacusCoreChecker<
}),
);
await promiseObjAll(
objMap(coreContracts.inboxes, async (remoteChain, inbox) => {
// check that the inbox has the right local domain
const actualLocalDomain = await inbox.inbox.contract.localDomain();
expect(actualLocalDomain).to.equal(ChainNameToDomainId[chain]);
const actualRemoteDomain = await inbox.inbox.contract.remoteDomain();
expect(actualRemoteDomain).to.equal(ChainNameToDomainId[remoteChain]);
}),
);
// Check that all inboxes on this chain share the same implementation and
// UpgradeBeacon.
const coreAddresses = this.app.getAddresses(chain);

@ -24,6 +24,8 @@ import { types } from '@abacus-network/utils';
import { AbacusDeployer } from '../deploy';
import debug = require('debug');
export type ValidatorManagerConfig = {
validators: Array<types.Address>;
threshold: number;
@ -46,10 +48,13 @@ export class AbacusCoreDeployer<Chain extends ChainName> extends AbacusDeployer<
configMap: ChainMap<Chain, CoreConfig>,
factoriesOverride = coreFactories,
) {
super(multiProvider, configMap, factoriesOverride);
super(multiProvider, configMap, factoriesOverride, {
logger: debug('abacus:CoreDeployer'),
});
this.startingBlockNumbers = objMap(configMap, () => undefined);
}
// override return type for inboxes shape derived from chain
async deploy(): Promise<CoreContractsMap<Chain>> {
return super.deploy() as Promise<CoreContractsMap<Chain>>;
}

@ -96,13 +96,14 @@ export abstract class AbacusDeployer<
ubcAddress: types.Address,
initArgs: Parameters<C['initialize']>,
): Promise<ProxiedContract<C, BeaconProxyAddresses>> {
const chainConnection = this.multiProvider.getChainConnection(chain);
const signer = chainConnection.signer;
const implementation = await this.deployContract<K>(
chain,
contractName,
deployArgs,
);
this.logger(`Proxy ${contractName.toString()} on ${chain}`);
const chainConnection = this.multiProvider.getChainConnection(chain);
const signer = chainConnection.signer;
const beacon = await new UpgradeBeacon__factory(signer).deploy(
implementation.address,
ubcAddress,
@ -138,6 +139,7 @@ export abstract class AbacusDeployer<
proxy: ProxiedContract<C, BeaconProxyAddresses>,
initArgs: Parameters<C['initialize']>,
): Promise<ProxiedContract<C, BeaconProxyAddresses>> {
this.logger(`Duplicate Proxy on ${chain}`);
const signer = this.multiProvider.getChainConnection(chain).signer!;
const initData = proxy.contract.interface.encodeFunctionData(
'initialize',

@ -5,6 +5,7 @@ export {
CoreConfig,
ValidatorManagerConfig,
} from './core/deploy';
export { AbacusCoreChecker } from './core/check';
export { AbacusDeployer } from './deploy';
export { UpgradeBeaconViolation } from './proxy';
export {

@ -14,7 +14,8 @@ import { RouterConfig } from './types';
export class AbacusRouterChecker<
Chain extends ChainName,
App extends AbacusApp<RouterContracts, Chain>,
Contracts extends RouterContracts,
App extends AbacusApp<Contracts, Chain>,
Config extends RouterConfig,
> extends AbacusAppChecker<Chain, App, Config> {
checkOwnership(chain: Chain) {
@ -26,7 +27,6 @@ export class AbacusRouterChecker<
async checkChain(chain: Chain): Promise<void> {
await this.checkEnrolledRouters(chain);
await this.checkOwnership(chain);
await this.checkAbacusConnectionManager(chain);
}
async checkEnrolledRouters(chain: Chain): Promise<void> {
@ -44,24 +44,6 @@ export class AbacusRouterChecker<
}
ownables(chain: Chain): Ownable[] {
const contracts = this.app.getContracts(chain);
const ownables: Ownable[] = [contracts.router];
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 && contracts.abacusConnectionManager) {
ownables.push(contracts.abacusConnectionManager);
}
return ownables;
}
async checkAbacusConnectionManager(chain: Chain): Promise<void> {
const config = this.configMap[chain];
const contracts = this.app.getContracts(chain);
if (!config.abacusConnectionManager || !contracts.abacusConnectionManager) {
return;
}
const actual = contracts.abacusConnectionManager.address;
expect(actual).to.equal(config.abacusConnectionManager);
return [this.app.getContracts(chain).router];
}
}

@ -4,6 +4,7 @@ import {
ChainMap,
ChainName,
MultiProvider,
Router,
RouterContracts,
RouterFactories,
chainMetadata,
@ -18,9 +19,9 @@ import { RouterConfig } from './types';
export abstract class AbacusRouterDeployer<
Chain extends ChainName,
Config extends RouterConfig,
Factories extends RouterFactories,
Contracts extends RouterContracts,
Factories extends RouterFactories,
Config extends RouterConfig,
> extends AbacusDeployer<Chain, Config, Factories, Contracts> {
constructor(
multiProvider: MultiProvider<Chain>,
@ -32,9 +33,20 @@ export abstract class AbacusRouterDeployer<
super(multiProvider, configMap, factories, { ...options, logger });
}
async deploy() {
const contractsMap = await super.deploy();
// for use in implementations of deployContracts
async deployRouter<RouterContract extends Router>(
chain: Chain,
deployParams: Parameters<Factories['router']['deploy']>,
initParams: Parameters<RouterContract['initialize']>,
): Promise<Contracts['router']> {
const router = await this.deployContract(chain, 'router', deployParams);
this.logger(`Initializing ${chain}'s router with ${initParams}`);
// @ts-ignore spread operator
await router.initialize(...initParams);
return router;
}
async enrollRemoteRouters(contractsMap: ChainMap<Chain, Contracts>) {
this.logger(`Enrolling deployed routers with each other...`);
// Make all routers aware of eachother.
await promiseObjAll(
@ -48,6 +60,25 @@ export abstract class AbacusRouterDeployer<
}
}),
);
}
async transferOwnership(contractsMap: ChainMap<Chain, Contracts>) {
// TODO: check for initialization before transferring ownership
this.logger(`Transferring ownership of routers...`);
await promiseObjAll(
objMap(contractsMap, async (chain, contracts) => {
const owner = this.configMap[chain].owner;
this.logger(`Transfer ownership of ${chain}'s router to ${owner}`);
await contracts.router.transferOwnership(owner);
}),
);
}
async deploy() {
const contractsMap = await super.deploy();
await this.enrollRemoteRouters(contractsMap);
await this.transferOwnership(contractsMap);
return contractsMap;
}

@ -1,6 +1,5 @@
import { types } from '@abacus-network/utils';
export type RouterConfig = {
abacusConnectionManager: types.Address;
owner: types.Address;
};

@ -29,3 +29,13 @@ export const getMultiProviderFromConfigAndSigner = <Chain extends ChainName>(
}));
return new MultiProvider(chainProviders);
};
// Returns a \ b
// Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#implementing_basic_set_operations
export function setDifference<T>(a: Set<T>, b: Set<T>) {
const diff = new Set(a);
for (const element of b) {
diff.delete(element);
}
return diff;
}

@ -1,12 +1,12 @@
{
"name": "@abacus-network/hardhat",
"description": "Hardhat related tools for the Abacus network",
"version": "0.2.1-alpha3",
"version": "0.2.1",
"dependencies": {
"@abacus-network/core": "^0.2.1-alpha3",
"@abacus-network/deploy": "^0.2.1-alpha3",
"@abacus-network/sdk": "^0.2.1-alpha3",
"@abacus-network/utils": "^0.2.1-alpha3",
"@abacus-network/core": "^0.2.1",
"@abacus-network/deploy": "^0.2.1",
"@abacus-network/sdk": "^0.2.1",
"@abacus-network/utils": "^0.2.1",
"@nomiclabs/hardhat-ethers": "^2.0.5",
"@nomiclabs/hardhat-waffle": "^2.0.2",
"ethereum-waffle": "^3.2.2",

@ -1,11 +1,11 @@
{
"name": "@abacus-network/infra",
"description": "Infrastructure utilities for the Abacus Network",
"version": "0.2.1-alpha3",
"version": "0.2.1",
"dependencies": {
"@abacus-network/core": "^0.2.1-alpha3",
"@abacus-network/deploy": "^0.2.1-alpha3",
"@abacus-network/sdk": "^0.2.1-alpha3",
"@abacus-network/core": "^0.2.1",
"@abacus-network/deploy": "^0.2.1",
"@abacus-network/sdk": "^0.2.1",
"@aws-sdk/client-iam": "^3.74.0",
"@aws-sdk/client-kms": "3.48.0",
"@aws-sdk/client-s3": "^3.74.0",

@ -1,7 +1,6 @@
import { AbacusCoreChecker } from '@abacus-network/deploy';
import { AbacusCore } from '@abacus-network/sdk';
import { AbacusCoreChecker } from '../src/core';
import { getCoreEnvironmentConfig, getEnvironment } from './utils';
async function check() {

@ -1 +0,0 @@
export { AbacusCoreChecker, CoreViolationType } from './check';

@ -160,13 +160,3 @@ export function writeJSON(directory: string, filename: string, obj: any) {
JSON.stringify(obj, null, 2),
);
}
// Returns a \ b
// Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#implementing_basic_set_operations
export function setDifference<T>(a: Set<T>, b: Set<T>) {
const diff = new Set(a);
for (const element of b) {
diff.delete(element);
}
return diff;
}

@ -2,7 +2,11 @@ import '@nomiclabs/hardhat-waffle';
import { ethers } from 'hardhat';
import path from 'path';
import { AbacusCoreDeployer, CoreConfig } from '@abacus-network/deploy';
import {
AbacusCoreChecker,
AbacusCoreDeployer,
CoreConfig,
} from '@abacus-network/deploy';
import { getMultiProviderFromConfigAndSigner } from '@abacus-network/deploy/dist/src/utils';
import {
AbacusCore,
@ -15,7 +19,6 @@ import {
import { environment as testConfig } from '../config/environments/test';
import { TestChains } from '../config/environments/test/chains';
import { AbacusCoreChecker } from '../src/core';
import { AbacusCoreInfraDeployer } from '../src/core/deploy';
import { writeJSON } from '../src/utils/utils';

@ -1,10 +1,10 @@
{
"name": "@abacus-network/sdk",
"description": "The official SDK for the Abacus Network",
"version": "0.2.1-alpha3",
"version": "0.2.1",
"dependencies": {
"@abacus-network/core": "^0.2.1-alpha3",
"@abacus-network/utils": "^0.2.1-alpha3",
"@abacus-network/core": "^0.2.1",
"@abacus-network/utils": "^0.2.1",
"@ethersproject/bignumber": "^5.5.0",
"@ethersproject/bytes": "^5.5.0",
"celo-ethers-provider": "^0.0.0",

@ -13,8 +13,8 @@ export class AbacusApp<
Chain extends ChainName = ChainName,
> extends MultiGeneric<Chain, Contracts> {
constructor(
public contractsMap: ChainMap<Chain, Contracts>,
multiProvider: MultiProvider<Chain>,
public readonly contractsMap: ChainMap<Chain, Contracts>,
public readonly multiProvider: MultiProvider<Chain>,
) {
const connectedContractsMap = objMap(contractsMap, (chain, contracts) =>
connectContracts(

@ -3,7 +3,8 @@ import { Inbox, Outbox } from '@abacus-network/core';
import { AbacusApp } from '../app';
import { buildContracts } from '../contracts';
import { MultiProvider } from '../provider';
import { ChainName, Remotes } from '../types';
import { ChainMap, ChainName, Remotes } from '../types';
import { objMap } from '../utils';
import { CoreContracts, coreFactories } from './contracts';
import { environments } from './environments';
@ -45,6 +46,16 @@ export class AbacusCore<Chain extends ChainName = ChainName> extends AbacusApp<
return super.getContracts(chain) as CoreContracts<Chain, Local>;
}
extendWithConnectionManagers<T>(
config: ChainMap<Chain, T>,
): ChainMap<Chain, T & { abacusConnectionManager: string }> {
return objMap(config, (chain, config) => ({
...config,
abacusConnectionManager:
this.getContracts(chain).abacusConnectionManager.address,
}));
}
getMailboxPair<Local extends Chain>(
origin: Remotes<Chain, Local>,
destination: Local,

@ -21,29 +21,29 @@ export type InboxContracts = {
inboxValidatorManager: InboxValidatorManager;
};
const inboxFactories = {
inbox: new Inbox__factory(),
inboxValidatorManager: new InboxValidatorManager__factory(),
};
export type OutboxContracts = {
outbox: ProxiedContract<Outbox, BeaconProxyAddresses>;
outboxValidatorManager: OutboxValidatorManager;
};
const outboxFactories = {
outbox: new Outbox__factory(),
outboxValidatorManager: new OutboxValidatorManager__factory(),
};
export type CoreContracts<
Networks extends ChainName,
Local extends Networks,
> = {
> = OutboxContracts & {
inboxes: RemoteChainMap<Networks, Local, InboxContracts>;
abacusConnectionManager: AbacusConnectionManager;
upgradeBeaconController: UpgradeBeaconController;
inboxes: RemoteChainMap<Networks, Local, InboxContracts>;
} & OutboxContracts;
};
const inboxFactories = {
inbox: new Inbox__factory(),
inboxValidatorManager: new InboxValidatorManager__factory(),
};
const outboxFactories = {
outbox: new Outbox__factory(),
outboxValidatorManager: new OutboxValidatorManager__factory(),
};
export const coreFactories = {
abacusConnectionManager: new AbacusConnectionManager__factory(),

@ -1,5 +1,5 @@
import type { ProcessEvent } from '@abacus-network/core/types/contracts/Inbox';
import type { DispatchEvent } from '@abacus-network/core/types/contracts/Outbox';
import type { ProcessEvent } from '@abacus-network/core/dist/contracts/Inbox';
import type { DispatchEvent } from '@abacus-network/core/dist/contracts/Outbox';
import { Annotated } from '../events';

@ -27,6 +27,7 @@ export {
resolveId,
resolveNetworks,
} from './core';
export { RetryJsonRpcProvider, RetryProvider } from './ethers';
export {
Annotated,
getEvents,
@ -40,7 +41,7 @@ export {
} from './gas';
export { ChainConnection, IChainConnection, MultiProvider } from './provider';
export { BeaconProxyAddresses, ProxiedContract, ProxyAddresses } from './proxy';
export { RouterContracts, RouterFactories } from './router';
export { Router, RouterContracts, RouterFactories } from './router';
export {
AllChains,
ChainMap,
@ -56,4 +57,3 @@ export {
TestChainNames,
} from './types';
export { objMap, objMapEntries, promiseObjAll, utils } from './utils';
export { RetryProvider, RetryJsonRpcProvider } from './ethers';

@ -1,20 +1,22 @@
import { Router, Router__factory } from '@abacus-network/app';
import {
AbacusConnectionManager,
AbacusConnectionManager__factory,
} from '@abacus-network/core';
import { ethers } from 'ethers';
import { Router } from '@abacus-network/app';
import { AbacusContracts, AbacusFactories } from './contracts';
export type RouterContracts<RouterContract extends Router = Router> =
AbacusContracts & {
router: RouterContract;
abacusConnectionManager: AbacusConnectionManager;
};
export type RouterFactories<
RouterFactory extends Router__factory = Router__factory,
> = AbacusFactories & {
router: RouterFactory;
abacusConnectionManager: AbacusConnectionManager__factory;
};
type RouterFactory<RouterContract extends Router = Router> =
ethers.ContractFactory & {
deploy: (...args: any[]) => Promise<RouterContract>;
};
export type RouterFactories<RouterContract extends Router = Router> =
AbacusFactories & {
router: RouterFactory<RouterContract>;
};
export { Router } from '@abacus-network/app';

@ -112,6 +112,7 @@ export function objMapEntries<K extends string, I = any, O = any>(
return Object.entries<I>(obj).map(([k, v]) => [k as K, func(k as K, v)]);
}
// Map over the values of the object
export function objMap<K extends string, I = any, O = any>(
obj: Record<K, I>,
func: (k: K, _: I) => O,

@ -1,7 +1,7 @@
{
"name": "@abacus-network/utils",
"description": "General utilities for the Abacus network",
"version": "0.2.1-alpha3",
"version": "0.2.1",
"dependencies": {
"chai": "^4.3.0",
"ethers": "^5.4.7"

@ -5,12 +5,12 @@ __metadata:
version: 6
cacheKey: 8
"@abacus-network/app@workspace:solidity/app":
"@abacus-network/app@^0.2.1, @abacus-network/app@workspace:solidity/app":
version: 0.0.0-use.local
resolution: "@abacus-network/app@workspace:solidity/app"
dependencies:
"@abacus-network/core": ^0.2.1-alpha3
"@abacus-network/utils": ^0.2.1-alpha3
"@abacus-network/core": ^0.2.1
"@abacus-network/utils": ^0.2.1
"@nomiclabs/hardhat-ethers": ^2.0.1
"@nomiclabs/hardhat-waffle": ^2.0.1
"@openzeppelin/contracts-upgradeable": ^4.5.0
@ -33,11 +33,11 @@ __metadata:
languageName: unknown
linkType: soft
"@abacus-network/core@^0.2.1-alpha3, @abacus-network/core@workspace:solidity/core":
"@abacus-network/core@^0.2.1, @abacus-network/core@workspace:solidity/core":
version: 0.0.0-use.local
resolution: "@abacus-network/core@workspace:solidity/core"
dependencies:
"@abacus-network/utils": ^0.2.1-alpha3
"@abacus-network/utils": ^0.2.1
"@nomiclabs/hardhat-ethers": ^2.0.1
"@nomiclabs/hardhat-waffle": ^2.0.1
"@openzeppelin/contracts": ^4.6.0
@ -61,13 +61,14 @@ __metadata:
languageName: unknown
linkType: soft
"@abacus-network/deploy@^0.2.1-alpha3, @abacus-network/deploy@workspace:typescript/deploy":
"@abacus-network/deploy@^0.2.1, @abacus-network/deploy@workspace:typescript/deploy":
version: 0.0.0-use.local
resolution: "@abacus-network/deploy@workspace:typescript/deploy"
dependencies:
"@abacus-network/core": ^0.2.1-alpha3
"@abacus-network/sdk": ^0.2.1-alpha3
"@abacus-network/utils": ^0.2.1-alpha3
"@abacus-network/app": ^0.2.1
"@abacus-network/core": ^0.2.1
"@abacus-network/sdk": ^0.2.1
"@abacus-network/utils": ^0.2.1
"@types/debug": ^4.1.7
"@types/node": ^16.9.1
"@types/yargs": ^17.0.10
@ -85,10 +86,10 @@ __metadata:
version: 0.0.0-use.local
resolution: "@abacus-network/hardhat@workspace:typescript/hardhat"
dependencies:
"@abacus-network/core": ^0.2.1-alpha3
"@abacus-network/deploy": ^0.2.1-alpha3
"@abacus-network/sdk": ^0.2.1-alpha3
"@abacus-network/utils": ^0.2.1-alpha3
"@abacus-network/core": ^0.2.1
"@abacus-network/deploy": ^0.2.1
"@abacus-network/sdk": ^0.2.1
"@abacus-network/utils": ^0.2.1
"@nomiclabs/hardhat-ethers": ^2.0.5
"@nomiclabs/hardhat-waffle": ^2.0.2
ethereum-waffle: ^3.2.2
@ -104,9 +105,9 @@ __metadata:
version: 0.0.0-use.local
resolution: "@abacus-network/infra@workspace:typescript/infra"
dependencies:
"@abacus-network/core": ^0.2.1-alpha3
"@abacus-network/deploy": ^0.2.1-alpha3
"@abacus-network/sdk": ^0.2.1-alpha3
"@abacus-network/core": ^0.2.1
"@abacus-network/deploy": ^0.2.1
"@abacus-network/sdk": ^0.2.1
"@aws-sdk/client-iam": ^3.74.0
"@aws-sdk/client-kms": 3.48.0
"@aws-sdk/client-s3": ^3.74.0
@ -147,12 +148,12 @@ __metadata:
languageName: unknown
linkType: soft
"@abacus-network/sdk@^0.2.1-alpha3, @abacus-network/sdk@workspace:typescript/sdk":
"@abacus-network/sdk@^0.2.1, @abacus-network/sdk@workspace:typescript/sdk":
version: 0.0.0-use.local
resolution: "@abacus-network/sdk@workspace:typescript/sdk"
dependencies:
"@abacus-network/core": ^0.2.1-alpha3
"@abacus-network/utils": ^0.2.1-alpha3
"@abacus-network/core": ^0.2.1
"@abacus-network/utils": ^0.2.1
"@ethersproject/bignumber": ^5.5.0
"@ethersproject/bytes": ^5.5.0
"@types/node": ^16.9.1
@ -168,7 +169,7 @@ __metadata:
languageName: unknown
linkType: soft
"@abacus-network/utils@^0.2.1-alpha3, @abacus-network/utils@workspace:typescript/utils":
"@abacus-network/utils@^0.2.1, @abacus-network/utils@workspace:typescript/utils":
version: 0.0.0-use.local
resolution: "@abacus-network/utils@workspace:typescript/utils"
dependencies:

Loading…
Cancel
Save