Skip to content

Commit

Permalink
Merge pull request #8 from gnosis/feat/factory-tests
Browse files Browse the repository at this point in the history
Feat: Factory tests implemented
  • Loading branch information
auryn-macmillan committed Aug 10, 2021
2 parents e24d093 + 21e37dd commit 6b143b8
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 27 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ cache
coverage*
deployments
dist
.DS_Store
.DS_Store
.idea/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ You can check the factory file to see more details, it consists of 4 methods, de

### 3. Get Module

- Interface: `getModule(moduleName, address, provider)`
- Interface: `getModuleInstance(moduleName, address, provider)`
- Arguments:

- `moduleName`: Name of the module to be deployed, note that it needs to exist as a key in the [CONTRACT_ADDRESSES](./src/constants.ts) object
Expand Down
19 changes: 12 additions & 7 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import "@nomiclabs/hardhat-etherscan";
import "hardhat-deploy";
import "solidity-coverage";

const { ETHERSCAN_KEY } = process.env;
const { ETHERSCAN_KEY, ALCHEMY_KEY, ETH_KEY } = process.env;

const INFURA_KEY = process.env.INFURA_KEY || "b76cba91dc954ceebff27244923224b1";
const ETH_KEY =
process.env.ETH_KEY ||
"990b68b61853f6418233b1f502a220a8770bb38849d9bd8fc552ed55f5899365";
const PRIVATE_KEY = ETH_KEY || "990b68b61853f6418233b1f502a220a8770bb38849d9bd8fc552ed55f5899365";
const ALCHEMY_NODE_KEY = ALCHEMY_KEY || "5fdcyEw3_EyCwcUQI0CcuwjNS1C_0k5S";

const config: HardhatUserConfig = {
paths: {
Expand All @@ -24,10 +22,17 @@ const config: HardhatUserConfig = {
namedAccounts: {
deployer: 0,
},
defaultNetwork: "hardhat",
networks: {
hardhat: {
forking: {
url: `https://eth-rinkeby.alchemyapi.io/v2/${ALCHEMY_NODE_KEY}`,
blockNumber: 8450000,
},
},
rinkeby: {
url: `https://rinkeby.infura.io/v3/${INFURA_KEY}`,
accounts: [`0x${ETH_KEY}`],
url: `https://eth-rinkeby.alchemyapi.io/v2/${ALCHEMY_NODE_KEY}`,
accounts: [`0x${PRIVATE_KEY}`],
},
},
mocha: {
Expand Down
21 changes: 17 additions & 4 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@ export const CONTRACT_ADDRESSES: Record<number, ContractAddresses> = {
4: {
dao: "0x0049B9A81E602C846807873026C20CC56038E571",
amb: "0x399E5e6424DF1448dB19fccFbc9E3DCef95c9f34",
delay: "0xC67cE465f76eAa84bb7560d19F7339D1aEdA201a",
factory: "0xE9E80739Af9D0DD8AaE6255c96a1266c059469ba",
delay: "0x09492F397d823bcD6dEf7f4782DC2a7990C49907",
factory: "0x569F2e024D0aD6bBfBd8135097DFa7D0641Ae79b",
},
// for testing purposes
31337: {
dao: "0xe40e0F913ABf3C561aE39A72b6D4dDdB9b943793",
amb: "0x781c968c88EF6eFCBe13d174b876dc9dc0c3A99b",
delay: "0x3cc7aBD1908906e2102D302249c82d083975e1EF",
factory: "0x569F2e024D0aD6bBfBd8135097DFa7D0641Ae79b",
},
};

Expand Down Expand Up @@ -48,15 +55,21 @@ export const CONTRACT_ABIS = {
`function setTxCooldown(uint256 cooldown) public`,
`function setTxExpiration(uint256 expiration) public`,
`function setUp(
Executor _executor,
address _executor,
uint256 cooldown,
uint256 expiration
) public`,
`function enableModule(address module) public`,
`function txCooldown() public view returns (uint256)`,
`function txExpiration() public view returns (uint256)`,
`function getModulesPaginated(address start, uint256 pageSize) external
view returns (address[] memory array, address next)`,
],
factory: [
`function deployModule(
address masterCopy,
bytes memory initializer
bytes memory initializer,
uint256 saltNonce
) public returns (address proxy)`,
],
};
38 changes: 25 additions & 13 deletions src/factory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ethers, Contract, Signer } from "ethers";
import { JsonRpcProvider } from "@ethersproject/providers";
import { CONTRACT_ADDRESSES, CONTRACT_ABIS } from "./constants";
import { KnownModules } from "./types";
import { Contract, ethers, Signer } from "ethers";

import { CONTRACT_ABIS, CONTRACT_ADDRESSES } from "./constants";
import { ContractAddresses, KnownModules } from "./types";

export const deployAndSetUpModule = async (
moduleName: keyof KnownModules,
Expand All @@ -10,14 +11,14 @@ export const deployAndSetUpModule = async (
chainId: number,
saltNonce: string
) => {
const { factory, module } = await getFactoryAndMasterCopy(
const { factory, module } = getFactoryAndMasterCopy(
moduleName,
provider,
chainId
);
const moduleSetupData = module.interface.encodeFunctionData("setUp", args);

const expectedModuleAddress = await calculateProxyAddress(
const expectedModuleAddress = calculateProxyAddress(
factory,
module.address,
moduleSetupData,
Expand All @@ -27,6 +28,7 @@ export const deployAndSetUpModule = async (
const deployData = factory.interface.encodeFunctionData("deployModule", [
module.address,
moduleSetupData,
saltNonce,
]);
const transaction = {
data: deployData,
Expand All @@ -39,7 +41,7 @@ export const deployAndSetUpModule = async (
};
};

export const calculateProxyAddress = async (
export const calculateProxyAddress = (
factory: Contract,
masterCopy: string,
initData: string,
Expand All @@ -63,7 +65,7 @@ export const calculateProxyAddress = async (
);
};

export const getModule = (
export const getModuleInstance = (
moduleName: keyof KnownModules,
address: string,
provider: JsonRpcProvider | Signer
Expand All @@ -72,18 +74,28 @@ export const getModule = (
if (moduleIsNotSupported) {
throw new Error("Module " + moduleName + " not supported");
}
const module = new Contract(address, CONTRACT_ABIS[moduleName], provider);
return module;
return new Contract(address, CONTRACT_ABIS[moduleName], provider);
};

export const getModuleContractAddress = (
chainId: number,
module: keyof ContractAddresses
): string => {
return CONTRACT_ADDRESSES[chainId][module];
};

export const getFactoryContractAddress = (chainId: number): string => {
return CONTRACT_ADDRESSES[chainId].factory;
};

export const getFactoryAndMasterCopy = async (
export const getFactoryAndMasterCopy = (
moduleName: keyof KnownModules,
provider: JsonRpcProvider,
chainId: number
) => {
const masterCopyAddress = CONTRACT_ADDRESSES[chainId][moduleName];
const factoryAddress = CONTRACT_ADDRESSES[chainId].factory;
const module = getModule(moduleName, masterCopyAddress, provider);
const masterCopyAddress = getModuleContractAddress(chainId, moduleName);
const factoryAddress = getFactoryContractAddress(chainId);
const module = getModuleInstance(moduleName, masterCopyAddress, provider);
const factory = new Contract(factoryAddress, CONTRACT_ABIS.factory, provider);

return {
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ export {
deployAndSetUpModule,
calculateProxyAddress,
getFactoryAndMasterCopy,
getModule,
getModuleInstance,
getModuleContractAddress,
getFactoryContractAddress,
} from "./factory";
export { KnownContracts, ContractAddresses, KnownModules } from "./types";
export { CONTRACT_ADDRESSES, CONTRACT_ABIS } from "./constants";
74 changes: 74 additions & 0 deletions test/factory.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { JsonRpcProvider } from "@ethersproject/providers";
import { expect } from "chai";
import { Contract } from "ethers";
import { ethers } from "hardhat";

import {
deployAndSetUpModule,
getModuleInstance,
getFactoryAndMasterCopy,
} from "../src";

import "@nomiclabs/hardhat-ethers";

const PROVIDER = new JsonRpcProvider(
`https://rinkeby.infura.io/v3/${process.env.INFURA_KEY}`
);

describe("Factory JS functions ", () => {
describe("deployAndSetUpModule", () => {
it("should execute transaction and retrieve expected address ", async () => {
const network = await ethers.provider.getNetwork();
const [signer] = await ethers.getSigners();
const { transaction: deployTx, expectedModuleAddress } =
await deployAndSetUpModule(
"dao",
[
"0x38063380d21F2d7A2f093cF4FCedBf6A552A1f76",
"0x3D00D77ee771405628a4bA4913175EcC095538da",
100,
180,
2000,
100000000,
1,
],
PROVIDER,
network.chainId,
Date.now().toString()
);

const transaction = await signer.sendTransaction({
data: deployTx.data,
to: deployTx.to,
});
const receipt = await transaction.wait();
expect(receipt.transactionHash).to.be.a("string");
expect(receipt.status).to.be.eq(1);
expect(expectedModuleAddress).to.a("string");
});
});

describe("getModuleInstance", () => {
it("should retreive module instance", async () => {
const module = await getModuleInstance(
"dao",
"0x327F67C24D1F24fcE614ae8a6D7309bf8736C8B3",
PROVIDER
);
expect(module).to.be.instanceOf(Contract);
});
});

describe("getFactoryAndMasterCopy", () => {
it("should retreive factory and module instance", async () => {
const network = await ethers.provider.getNetwork();
const { module, factory } = await getFactoryAndMasterCopy(
"dao",
PROVIDER,
network.chainId
);
expect(module).to.be.instanceOf(Contract);
expect(factory).to.be.instanceOf(Contract);
});
});
});

0 comments on commit 6b143b8

Please sign in to comment.