Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion contract_manager/scripts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { Contract } from "web3-eth-contract";
import { InferredOptionType } from "yargs";
import { PrivateKey, getDefaultDeploymentConfig } from "../src/core/base";
import { EvmChain } from "../src/core/chains";
import { EvmEntropyContract, EvmWormholeContract } from "../src/core/contracts";
import {
EvmEntropyContract,
EvmExecutorContract,
EvmWormholeContract,
} from "../src/core/contracts";

export interface BaseDeployConfig {
gasMultiplier: number;
Expand Down Expand Up @@ -237,6 +241,27 @@ export function findWormholeContract(
}
}

/**
* Finds the executor contract for a given EVM chain.
* @param {EvmChain} chain The EVM chain to find the executor contract for.
* @returns If found, the executor contract for the given EVM chain. Else, undefined
*/
export function findExecutorContract(
chain: EvmChain,
): EvmExecutorContract | undefined {
for (const contract of Object.values(DefaultStore.executor_contracts)) {
if (
contract instanceof EvmExecutorContract &&
contract.chain.getId() === chain.getId()
) {
console.log(
`Found executor contract for ${chain.getId()} at ${contract.address}`,
);
return contract;
}
}
}

export interface DeployWormholeReceiverContractsConfig
extends BaseDeployConfig {
saveContract: boolean;
Expand Down
44 changes: 3 additions & 41 deletions contract_manager/scripts/deploy_evm_entropy_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
} from "../src/core/contracts/evm";
import {
DeploymentType,
getDefaultDeploymentConfig,
toDeploymentType,
toPrivateKey,
} from "../src/core/base";
Expand All @@ -22,6 +21,7 @@ import {
topupAccountsIfNecessary,
DefaultAddresses,
} from "./common";
import { getOrDeployExecutorContract } from "./deploy_evm_executor";

interface DeploymentConfig extends BaseDeployConfig {
type: DeploymentType;
Expand All @@ -44,44 +44,6 @@ const parser = yargs(hideBin(process.argv))
},
});

async function deployExecutorContracts(
chain: EvmChain,
config: DeploymentConfig,
wormholeAddr: string,
): Promise<string> {
const executorImplAddr = await deployIfNotCached(
CACHE_FILE,
chain,
config,
"ExecutorUpgradable",
[],
);

// Craft the init data for the proxy contract
const { governanceDataSource } = getDefaultDeploymentConfig(config.type);

const executorImplContract = getWeb3Contract(
config.jsonOutputDir,
"ExecutorUpgradable",
executorImplAddr,
);

const executorInitData = executorImplContract.methods
.initialize(
wormholeAddr,
0, // lastExecutedSequence,
chain.getWormholeChainId(),
governanceDataSource.emitterChain,
`0x${governanceDataSource.emitterAddress}`,
)
.encodeABI();

return await deployIfNotCached(CACHE_FILE, chain, config, "ERC1967Proxy", [
executorImplAddr,
executorInitData,
]);
}

async function deployEntropyContracts(
chain: EvmChain,
config: DeploymentConfig,
Expand Down Expand Up @@ -166,15 +128,15 @@ async function main() {

console.log(`Deploying entropy contracts on ${chain.getId()}...`);

const executorAddr = await deployExecutorContracts(
const executorContract = await getOrDeployExecutorContract(
chain,
deploymentConfig,
wormholeContract.address,
);
const entropyAddr = await deployEntropyContracts(
chain,
deploymentConfig,
executorAddr,
executorContract.address,
);

if (deploymentConfig.saveContract) {
Expand Down
147 changes: 147 additions & 0 deletions contract_manager/scripts/deploy_evm_executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { EvmChain } from "../src/core/chains";
import {
BaseDeployConfig,
COMMON_DEPLOY_OPTIONS,
deployIfNotCached,
findExecutorContract,
getOrDeployWormholeContract,
getWeb3Contract,
} from "./common";
import {
DeploymentType,
getDefaultDeploymentConfig,
toDeploymentType,
toPrivateKey,
} from "../src/core/base";
import { DefaultStore } from "../src/node/utils/store";
import { EvmExecutorContract } from "../src/core/contracts/evm";

const CACHE_FILE = ".cache-deploy-evm-executor";

const parser = yargs(hideBin(process.argv))
.scriptName("deploy_evm_executor.ts")
.usage(
"Usage: $0 --std-output-dir <path/to/std-output-dir/> --private-key <private-key> --chain <chain>",
)
.options({
...COMMON_DEPLOY_OPTIONS,
chain: {
type: "string",
demandOption: true,
desc: "Chain to upload the contract on. Can be one of the evm chains available in the store",
},
});

interface DeploymentConfig extends BaseDeployConfig {
type: DeploymentType;
saveContract: boolean;
}

export async function getOrDeployExecutorContract(
chain: EvmChain,
config: DeploymentConfig,
wormholeAddr: string,
): Promise<EvmExecutorContract> {
return (
findExecutorContract(chain) ??
(await deployExecutorContracts(chain, config, wormholeAddr))
);
}

/**
* Deploys the executor contracts for a given EVM chain.
* @param {EvmChain} chain The EVM chain to deploy the executor contracts for.
* @param {DeploymentConfig} config The deployment configuration.
* @param {string} wormholeAddr The address of the wormhole contract.
* @returns {Promise<string>} The address of the deployed executor contract.
*/
export async function deployExecutorContracts(
chain: EvmChain,
config: DeploymentConfig,
wormholeAddr: string,
): Promise<EvmExecutorContract> {
const executorImplAddr = await deployIfNotCached(
CACHE_FILE,
chain,
config,
"ExecutorUpgradable",
[],
);

// Craft the init data for the proxy contract
const { governanceDataSource } = getDefaultDeploymentConfig(config.type);

const executorImplContract = getWeb3Contract(
config.jsonOutputDir,
"ExecutorUpgradable",
executorImplAddr,
);

const executorInitData = executorImplContract.methods
.initialize(
wormholeAddr,
0, // lastExecutedSequence,
chain.getWormholeChainId(),
governanceDataSource.emitterChain,
`0x${governanceDataSource.emitterAddress}`,
)
.encodeABI();

const executorAddr = await deployIfNotCached(
CACHE_FILE,
chain,
config,
"ERC1967Proxy",
[executorImplAddr, executorInitData],
);

return new EvmExecutorContract(chain, executorAddr);
}

export async function main() {
const argv = await parser.argv;

const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain);

const deploymentConfig: DeploymentConfig = {
type: toDeploymentType(argv.deploymentType),
gasMultiplier: argv.gasMultiplier,
gasPriceMultiplier: argv.gasPriceMultiplier,
privateKey: toPrivateKey(argv.privateKey),
jsonOutputDir: argv.stdOutputDir,
saveContract: argv.saveContract,
};

const wormholeContract = await getOrDeployWormholeContract(
chain,
deploymentConfig,
CACHE_FILE,
);

console.log(
`Deployment config: ${JSON.stringify(deploymentConfig, null, 2)}\n`,
);

console.log(`Deploying executor contracts on ${chain.getId()}...`);

const executorContract = await getOrDeployExecutorContract(
chain,
deploymentConfig,
wormholeContract.address,
);

if (deploymentConfig.saveContract) {
console.log("Saving the contract in the store...");
DefaultStore.executor_contracts[executorContract.getId()] =
executorContract;
DefaultStore.saveAllContracts();
}

console.log(
`✅ Executor contract on ${chain.getId()} at ${executorContract.address}\n\n`,
);
}

main();
31 changes: 29 additions & 2 deletions contract_manager/src/core/contracts/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,16 +412,32 @@ export class EvmEntropyContract extends Storable {
}
}

export class EvmExecutorContract {
export class EvmExecutorContract extends Storable {
static type = "EvmExecutorContract";

constructor(
public chain: EvmChain,
public address: string,
) {}
) {
super();
}

getId(): string {
return `${this.chain.getId()}_${this.address}`;
}

getType(): string {
return EvmExecutorContract.type;
}

toJson() {
return {
chain: this.chain.getId(),
address: this.address,
type: EvmExecutorContract.type,
};
}

async getWormholeContract(): Promise<EvmWormholeContract> {
const web3 = this.chain.getWeb3();
//Unfortunately, there is no public method to get the wormhole address
Expand All @@ -431,6 +447,17 @@ export class EvmExecutorContract {
return new EvmWormholeContract(this.chain, address);
}

static fromJson(
chain: Chain,
parsed: { type: string; address: string },
): EvmExecutorContract {
if (parsed.type !== EvmExecutorContract.type)
throw new Error("Invalid type");
if (!(chain instanceof EvmChain))
throw new Error(`Wrong chain type ${chain}`);
return new EvmExecutorContract(chain, parsed.address);
}

getContract() {
const web3 = this.chain.getWeb3();
return new web3.eth.Contract(EXECUTOR_ABI, this.address);
Expand Down
9 changes: 8 additions & 1 deletion contract_manager/src/node/utils/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
IotaWormholeContract,
IotaPriceFeedContract,
EvmPulseContract,
EvmExecutorContract,
} from "../../core/contracts";
import { Token } from "../../core/token";
import { PriceFeedContract, Storable } from "../../core/base";
Expand All @@ -46,6 +47,7 @@ import {
export class Store {
public chains: Record<string, Chain> = { global: new GlobalChain() };
public contracts: Record<string, PriceFeedContract> = {};
public executor_contracts: Record<string, EvmExecutorContract> = {};
public entropy_contracts: Record<string, EvmEntropyContract> = {};
public pulse_contracts: Record<string, EvmPulseContract> = {};
public wormhole_contracts: Record<string, WormholeContract> = {};
Expand Down Expand Up @@ -118,6 +120,7 @@ export class Store {
const contracts: Storable[] = Object.values(this.contracts);
contracts.push(...Object.values(this.entropy_contracts));
contracts.push(...Object.values(this.wormhole_contracts));
contracts.push(...Object.values(this.executor_contracts));
for (const contract of contracts) {
if (!contractsByType[contract.getType()]) {
contractsByType[contract.getType()] = [];
Expand Down Expand Up @@ -167,6 +170,7 @@ export class Store {
[AptosWormholeContract.type]: AptosWormholeContract,
[EvmEntropyContract.type]: EvmEntropyContract,
[EvmWormholeContract.type]: EvmWormholeContract,
[EvmExecutorContract.type]: EvmExecutorContract,
[FuelPriceFeedContract.type]: FuelPriceFeedContract,
[FuelWormholeContract.type]: FuelWormholeContract,
[StarknetPriceFeedContract.type]: StarknetPriceFeedContract,
Expand All @@ -192,7 +196,8 @@ export class Store {
if (
this.contracts[chainContract.getId()] ||
this.entropy_contracts[chainContract.getId()] ||
this.wormhole_contracts[chainContract.getId()]
this.wormhole_contracts[chainContract.getId()] ||
this.executor_contracts[chainContract.getId()]
)
throw new Error(
`Multiple contracts with id ${chainContract.getId()} found`,
Expand All @@ -201,6 +206,8 @@ export class Store {
this.entropy_contracts[chainContract.getId()] = chainContract;
} else if (chainContract instanceof WormholeContract) {
this.wormhole_contracts[chainContract.getId()] = chainContract;
} else if (chainContract instanceof EvmExecutorContract) {
this.executor_contracts[chainContract.getId()] = chainContract;
} else {
this.contracts[chainContract.getId()] = chainContract;
}
Expand Down
2 changes: 1 addition & 1 deletion contract_manager/store/chains/EvmChains.json
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@
{
"id": "sepolia",
"mainnet": false,
"rpcUrl": "https://eth-sepolia.blastapi.io/$ENV_BLAST_API_KEY",
"rpcUrl": "https://eth-sepolia.public.blastapi.io",
"networkId": 11155111,
"type": "EvmChain"
},
Expand Down
2 changes: 1 addition & 1 deletion contract_manager/store/contracts/EvmEntropyContracts.json
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,4 @@
"address": "0x23f0e8FAeE7bbb405E7A7C3d60138FCfd43d7509",
"type": "EvmEntropyContract"
}
]
]
Loading
Loading