Skip to content

Commit

Permalink
Initial refactor to make the code more readable
Browse files Browse the repository at this point in the history
  • Loading branch information
shirren committed Dec 7, 2023
1 parent 98af1a0 commit 4c7ff1a
Show file tree
Hide file tree
Showing 10 changed files with 8,529 additions and 7,945 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ src/artifacts

# Ignore any environmental files with sensitive data
.env
.env.dev
.env.production
.env.devnet
.env.testnet
.env.mainnet
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"printWidth": 130
"printWidth": 80
}
785 changes: 653 additions & 132 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"deploy": "hardhat run utils/deploy-contracts.ts --network",
"deployToDevnet": "npx hardhat run scripts/deploy-wallet-contracts.ts --network devnet",
"deployToTestnet": "npx hardhat run scripts/deploy-wallet-contracts.ts --network testnet",
"deployToMainnet": "npx hardhat run scripts/deploy-wallet-contracts.ts --network mainnet",
"verify": "hardhat verify --network",
"release": "yarn publish src"
},
Expand Down Expand Up @@ -90,5 +91,9 @@
"ganacheGasPrice": "2",
"etherBalance": "100000",
"extra": ""
},
"dependencies": {
"ethereum-private-key-to-public-key": "^0.0.5",
"ethereum-public-key-to-address": "^0.0.5"
}
}
79 changes: 79 additions & 0 deletions scripts/deploy-functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { ethers } from 'ethers';
import { ethers as hardhat } from 'hardhat';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';

export async function deployFactory(
deployer: SignerWithAddress,
adminAddr: string,
deployerAddr: string
): Promise<ethers.Contract> {
const Factory = await hardhat.getContractFactory('Factory');
return await Factory.connect(deployer).deploy(adminAddr, deployerAddr);
}

export async function deployWalletImplLocator(
deployer: SignerWithAddress,
adminAddr: string,
implChangerAddr: string
): Promise<ethers.Contract> {
const LatestWalletImplLocator = await hardhat.getContractFactory(
'LatestWalletImplLocator'
);
return await LatestWalletImplLocator.connect(deployer).deploy(
adminAddr,
implChangerAddr
);
}

export async function deployStartUp(
deployer: SignerWithAddress,
walletImplLocatorAddr: string
): Promise<ethers.Contract> {
const StartupWalletImplImpl = await hardhat.getContractFactory(
'StartupWalletImpl'
);
return await StartupWalletImplImpl.connect(deployer).deploy(
walletImplLocatorAddr
);
}

export async function deployMainModule(
deployer: SignerWithAddress,
factoryAddr: string,
startUpAddr: string
): Promise<ethers.Contract> {
const MainModuleDynamicAuth = await hardhat.getContractFactory(
'MainModuleDynamicAuth'
);
return await MainModuleDynamicAuth.connect(deployer).deploy(
factoryAddr,
startUpAddr
);
}

export async function deployImmutableSigner(
deployer: SignerWithAddress,
rootAdminAddr: string,
signerAdminAddr: string,
signerAddr?: string
): Promise<ethers.Contract> {
const ImmutableSigner = await hardhat.getContractFactory('ImmutableSigner');
return await ImmutableSigner.connect(deployer).deploy(
rootAdminAddr,
signerAdminAddr,
signerAddr
);
}

export async function deployMultiCallDeploy(
deployer: SignerWithAddress,
adminAddr: string,
executorAddr?: string
): Promise<ethers.Contract> {
const MultiCallDeploy = await hardhat.getContractFactory('MultiCallDeploy');
return await MultiCallDeploy.connect(deployer).deploy(
adminAddr,
executorAddr,
{}
);
}
175 changes: 77 additions & 98 deletions scripts/deploy-wallet-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,22 @@ import * as hre from 'hardhat';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import { ethers } from 'ethers';
import { ethers as hardhat } from 'hardhat';
import { expect } from 'chai';

require('dotenv').config();

const outputPath = path.join(__dirname, './deploy_output.json');
let deployer: SignerWithAddress;

async function deploy() {
// TODO: We should obtain an API key for blockscout and uncomment
// the following lines before a mainnet deployment
// if (typeof process.env.ETHERSCAN_API_KEY === 'undefined') {
// throw new Error('Etherscan API KEY has not been defined');
// }

// /dev/imx-evm-relayer/EOA_SUBMITTER
let relayerSubmitterEOAPubKey = '0xBC52cE84FceFd2D941D1127608D6Cf598f9633d3';
// /dev/imx-evm-relayer/IMMUTABLE_SIGNER_CONTRACT
let immutableSignerPubKey = '0x1cE50560686b1297B6311F36B47dbe5d6E04D0f8';
import { UnknownEnvironmentError } from './errors';
import {
deployMultiCallDeploy,
deployFactory,
deployWalletImplLocator,
deployStartUp,
deployMainModule,
deployImmutableSigner
} from './deploy-functions';
import dotenv from 'dotenv';
import { loadEnvironmentInfo } from './environment';

async function main() {
const environment = loadEnvironmentInfo(hre.network.name);
console.log(environment);
return;

// Administration accounts
let multiCallAdminPubKey = '0x575be326c482a487add43974e0eaf232e3366e13';
Expand All @@ -33,68 +31,104 @@ async function deploy() {
// Required private keys:
// 1. Deployer
// 2. walletImplLocatorChanger
const [contractDeployer, walletImplLocatorImplChanger] = await hardhat.getSigners();
deployer = contractDeployer;
const [contractDeployer, walletImplLocatorImplChanger] =
await hardhat.getSigners();

// TOTAL deployment cost = 0.009766773 GWEI = 0.000000000009766773 ETHER
// Deployments with esimated gas costs (GWEI)
console.log('Deploying contracts...');

// 1. Deploy multi call deploy
// EST gas cost: 0.001561956
const multiCallDeploy = await deployMultiCallDeploy(multiCallAdminPubKey, relayerSubmitterEOAPubKey);
const multiCallDeploy = await deployMultiCallDeploy(
contractDeployer,
multiCallAdminPubKey,
environment.submitterAddress
);
await multiCallDeploy.deployTransaction.wait();
console.log('Multi Call Deploy deployed to: ', multiCallDeploy.address);

// 2. Deploy factory with multi call deploy address as deployer role EST
// EST gas cost: 0.001239658
const factory = await deployFactory(factoryAdminPubKey, multiCallDeploy.address);
const factory = await deployFactory(
contractDeployer,
factoryAdminPubKey,
multiCallDeploy.address
);
await factory.deployTransaction.wait();
console.log(`Factory deployed to: ${factory.address} with hash ${factory.deployTransaction.hash}`);
console.log(
`Factory deployed to: ${factory.address} with hash ${factory.deployTransaction.hash}`
);

// 3. Deploy wallet impl locator
// EST gas cost: 0.001021586
const walletImplLocator = await deployWalletImplLocator(walletImplLocatorAdmin, walletImplLocatorImplChanger.address);
const walletImplLocator = await deployWalletImplLocator(
contractDeployer,
walletImplLocatorAdmin,
walletImplLocatorImplChanger.address
);
await walletImplLocator.deployTransaction.wait();
console.log(
`Wallet Implementation Locator deployed to: ${walletImplLocator.address} with hash ${walletImplLocator.deployTransaction.hash}`
);

// 4. Deploy startup wallet impl
// EST gas cost: 0.000175659
const startupWalletImpl = await deployStartUp(walletImplLocator.address);
const startupWalletImpl = await deployStartUp(
contractDeployer,
walletImplLocator.address
);
await startupWalletImpl.deployTransaction.wait();
console.log(
`Startup Wallet Impl deployed to: ${startupWalletImpl.address} with hash ${startupWalletImpl.deployTransaction.hash}`
);

// 5. Deploy main module dynamic auth
// EST gas cost: 0.003911813
const mainModule = await deployMainModule(factory.address, startupWalletImpl.address);
const mainModule = await deployMainModule(
contractDeployer,
factory.address,
startupWalletImpl.address
);
await mainModule.deployTransaction.wait();
console.log(`Main Module Dynamic Auth deployed to: ${mainModule.address} with hash ${mainModule.deployTransaction.hash}`);
console.log(
`Main Module Dynamic Auth deployed to: ${mainModule.address} with hash ${mainModule.deployTransaction.hash}`
);

// 6. Deploy immutable signer
// EST gas cost: 0.001856101
const immutableSigner = await deployImmutableSigner(signerRootAdminPubKey, signerAdminPubKey, immutableSignerPubKey);
const immutableSigner = await deployImmutableSigner(
contractDeployer,
signerRootAdminPubKey,
signerAdminPubKey,
environment.signerAddress
);
await immutableSigner.deployTransaction.wait();
console.log('Finished deploying contracts');

// Fund the implementation changer
// WARNING: If the deployment fails at this step, DO NOT RERUN without commenting out the code a prior which deploys
// the contracts.
// TODO: Code below can be improved by calculating the amount that is required to be transferred.
const fundingTx = await deployer.sendTransaction({
const fundingTx = await contractDeployer.sendTransaction({
to: await walletImplLocatorImplChanger.getAddress(),
value: ethers.utils.parseEther('10')
});
await fundingTx.wait();

console.log(`Transfered funds to the wallet locator implementer changer with hash ${fundingTx.hash}`);
console.log(
`Transfered funds to the wallet locator implementer changer with hash ${fundingTx.hash}`
);

// Set implementation address on impl locator to dyanmic module auth addr
const tx = await walletImplLocator.connect(walletImplLocatorImplChanger).changeWalletImplementation(mainModule.address);
const tx = await walletImplLocator
.connect(walletImplLocatorImplChanger)
.changeWalletImplementation(mainModule.address);
await tx.wait();
console.log('Wallet Implentation Locator implementation changed to: ', mainModule.address);
console.log(
'Wallet Implentation Locator implementation changed to: ',
mainModule.address
);

// Output JSON file with addresses and role addresses
const JSONOutput = {
Expand All @@ -104,18 +138,19 @@ async function deploy() {
MainModuleDynamicAuthAddress: mainModule.address,
ImmutableSignerContractAddress: immutableSigner.address,
MultiCallDeployAddress: multiCallDeploy.address,
DeployerAddress: deployer.address,
DeployerAddress: contractDeployer.address,
FactoryAdminAddress: factoryAdminPubKey,
FactoryDeployerAddress: relayerSubmitterEOAPubKey,
FactoryDeployerAddress: environment.submitterAddress,
WalletImplLocatorAdminAddress: walletImplLocatorAdmin,
WalletImplLocatorImplChangerAddress: walletImplLocatorImplChanger.address,
SignerRootAdminAddress: signerRootAdminPubKey,
SignerAdminAddress: signerAdminPubKey,
ImmutableSignerAddress: immutableSignerPubKey,
ImmutableSignerAddress: environment.signerAddress,
MultiCallAdminAddress: multiCallAdminPubKey,
MultiCallExecutorAddress: relayerSubmitterEOAPubKey
MultiCallExecutorAddress: environment.submitterAddress
};
fs.writeFileSync(outputPath, JSON.stringify(JSONOutput, null, 1));

fs.writeFileSync(environment.outputPath, JSON.stringify(JSONOutput, null, 1));

// Verify contracts on etherscan
// console.log("Verifying contracts on etherscan...");
Expand All @@ -125,68 +160,12 @@ async function deploy() {
// await verifyContract(startupWalletImpl.address, [walletImplLocator.address]);
// await verifyContract(mainModule.address, [factory.address, startupWalletImpl.address], true, "contracts/modules/MainModuleDynamicAuth.sol:MainModuleDynamicAuth");
// await verifyContract(immutableSigner.address, [signerRootAdminPubKey, signerAdminPubKey, relayerSubmitterEOAPubKey]);
console.log('Skipping contract verification... (Etherscan not available on Immutable zkEVM)');
}

async function deployFactory(adminAddr: string, deployerAddr: string): Promise<ethers.Contract> {
const Factory = await hardhat.getContractFactory('Factory');
return await Factory.connect(deployer).deploy(adminAddr, deployerAddr);
}

async function deployWalletImplLocator(adminAddr: string, implChangerAddr: string): Promise<ethers.Contract> {
const LatestWalletImplLocator = await hardhat.getContractFactory('LatestWalletImplLocator');
return await LatestWalletImplLocator.connect(deployer).deploy(adminAddr, implChangerAddr);
}

async function deployStartUp(walletImplLocatorAddr: string): Promise<ethers.Contract> {
const StartupWalletImplImpl = await hardhat.getContractFactory('StartupWalletImpl');
return await StartupWalletImplImpl.connect(deployer).deploy(walletImplLocatorAddr);
}

async function deployMainModule(factoryAddr: string, startUpAddr: string): Promise<ethers.Contract> {
const MainModuleDynamicAuth = await hardhat.getContractFactory('MainModuleDynamicAuth');
return await MainModuleDynamicAuth.connect(deployer).deploy(factoryAddr, startUpAddr);
}

async function deployImmutableSigner(
rootAdminAddr: string,
signerAdminAddr: string,
signerAddr: string
): Promise<ethers.Contract> {
const ImmutableSigner = await hardhat.getContractFactory('ImmutableSigner');
return await ImmutableSigner.connect(deployer).deploy(rootAdminAddr, signerAdminAddr, signerAddr);
}

async function deployMultiCallDeploy(adminAddr: string, executorAddr: string): Promise<ethers.Contract> {
const MultiCallDeploy = await hardhat.getContractFactory('MultiCallDeploy');
return await MultiCallDeploy.connect(deployer).deploy(adminAddr, executorAddr, {});
}

async function verifyContract(
contractAddr: string,
constructorArgs: any[],
requiesContractPath: boolean = false,
contractPath: string = ''
) {
try {
if (requiesContractPath) {
await hre.run('verify:verify', {
contract: contractPath,
address: contractAddr,
constructorArguments: constructorArgs
});
} else {
await hre.run('verify:verify', {
address: contractAddr,
constructorArguments: constructorArgs
});
}
} catch (error) {
expect(error.message.toLowerCase().includes('already verified')).to.be.equal(true);
}
console.log(
'Skipping contract verification... (Etherscan not available on Immutable zkEVM)'
);
}

deploy().catch(error => {
console.error(error);
main().catch(err => {
console.error(err);
process.exitCode = 1;
});
Loading

0 comments on commit 4c7ff1a

Please sign in to comment.