Skip to content

Commit

Permalink
feat(contract_manager): upgrade deploy scripts to use wormhole store (#…
Browse files Browse the repository at this point in the history
…1523)

* upgrade deploy scripts to use wormhole store

* deploy not find

* deploy price feed and entropy to taiko

* rename type

* rename method

* address feedback

* update js docs

* deploy to olive testnet

* pre commit

* rename deploy config to base deploy config
  • Loading branch information
Dev Kalra authored May 2, 2024
1 parent a592c6b commit 587a6fa
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 118 deletions.
128 changes: 125 additions & 3 deletions contract_manager/scripts/common.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { DefaultStore, EvmChain, EvmEntropyContract, PrivateKey } from "../src";
import {
DefaultStore,
EvmChain,
EvmEntropyContract,
EvmWormholeContract,
getDefaultDeploymentConfig,
PrivateKey,
} from "../src";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { join } from "path";
import Web3 from "web3";
import { Contract } from "web3-eth-contract";
import { InferredOptionType } from "yargs";

interface DeployConfig {
export interface BaseDeployConfig {
gasMultiplier: number;
gasPriceMultiplier: number;
jsonOutputDir: string;
Expand All @@ -19,7 +26,7 @@ interface DeployConfig {
export async function deployIfNotCached(
cacheFile: string,
chain: EvmChain,
config: DeployConfig,
config: BaseDeployConfig,
artifactName: string,
deployArgs: any[], // eslint-disable-line @typescript-eslint/no-explicit-any
cacheKey?: string
Expand Down Expand Up @@ -212,3 +219,118 @@ export function findEvmChain(chainName: string): EvmChain {
}
return chain;
}

/**
* Finds the wormhole contract for a given EVM chain.
* @param {EvmChain} chain The EVM chain to find the wormhole contract for.
* @returns If found, the wormhole contract for the given EVM chain. Else, undefined
*/
export function findWormholeContract(
chain: EvmChain
): EvmWormholeContract | undefined {
for (const contract of Object.values(DefaultStore.wormhole_contracts)) {
if (
contract instanceof EvmWormholeContract &&
contract.getChain().getId() === chain.getId()
) {
return contract;
}
}
}

export interface DeployWormholeReceiverContractsConfig
extends BaseDeployConfig {
saveContract: boolean;
type: "stable" | "beta";
}
/**
* Deploys the wormhole receiver contract for a given EVM chain.
* @param {EvmChain} chain The EVM chain to find the wormhole receiver contract for.
* @param {DeployWormholeReceiverContractsConfig} config The deployment configuration.
* @param {string} cacheFile The path to the cache file.
* @returns {EvmWormholeContract} The wormhole contract for the given EVM chain.
*/
export async function deployWormholeContract(
chain: EvmChain,
config: DeployWormholeReceiverContractsConfig,
cacheFile: string
): Promise<EvmWormholeContract> {
const receiverSetupAddr = await deployIfNotCached(
cacheFile,
chain,
config,
"ReceiverSetup",
[]
);

const receiverImplAddr = await deployIfNotCached(
cacheFile,
chain,
config,
"ReceiverImplementation",
[]
);

// Craft the init data for the proxy contract
const setupContract = getWeb3Contract(
config.jsonOutputDir,
"ReceiverSetup",
receiverSetupAddr
);

const { wormholeConfig } = getDefaultDeploymentConfig(config.type);

const initData = setupContract.methods
.setup(
receiverImplAddr,
wormholeConfig.initialGuardianSet.map((addr: string) => "0x" + addr),
chain.getWormholeChainId(),
wormholeConfig.governanceChainId,
"0x" + wormholeConfig.governanceContract
)
.encodeABI();

const wormholeReceiverAddr = await deployIfNotCached(
cacheFile,
chain,
config,
"WormholeReceiver",
[receiverSetupAddr, initData]
);

const wormholeContract = new EvmWormholeContract(chain, wormholeReceiverAddr);

if (config.type === "stable") {
console.log(`Syncing mainnet guardian sets for ${chain.getId()}...`);
// TODO: Add a way to pass gas configs to this
await wormholeContract.syncMainnetGuardianSets(config.privateKey);
console.log(`✅ Synced mainnet guardian sets for ${chain.getId()}`);
}

if (config.saveContract) {
DefaultStore.wormhole_contracts[wormholeContract.getId()] =
wormholeContract;
DefaultStore.saveAllContracts();
}

return wormholeContract;
}

/**
* Returns the wormhole contract for a given EVM chain.
* If there was no wormhole contract deployed for the given chain, it will deploy the wormhole contract and save it to the default store.
* @param {EvmChain} chain The EVM chain to find the wormhole contract for.
* @param {DeployWormholeReceiverContractsConfig} config The deployment configuration.
* @param {string} cacheFile The path to the cache file.
* @returns {EvmWormholeContract} The wormhole contract for the given EVM chain.
*/
export async function getOrDeployWormholeContract(
chain: EvmChain,
config: DeployWormholeReceiverContractsConfig,
cacheFile: string
): Promise<EvmWormholeContract> {
return (
findWormholeContract(chain) ??
(await deployWormholeContract(chain, config, cacheFile))
);
}
58 changes: 17 additions & 41 deletions contract_manager/scripts/deploy_evm_entropy_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,23 @@ import { DefaultStore } from "../src/store";
import {
DeploymentType,
EvmEntropyContract,
EvmPriceFeedContract,
getDefaultDeploymentConfig,
PrivateKey,
toDeploymentType,
toPrivateKey,
EvmWormholeContract,
} from "../src";
import {
COMMON_DEPLOY_OPTIONS,
deployIfNotCached,
getWeb3Contract,
getOrDeployWormholeContract,
BaseDeployConfig,
} from "./common";
import Web3 from "web3";

type DeploymentConfig = {
interface DeploymentConfig extends BaseDeployConfig {
type: DeploymentType;
gasMultiplier: number;
gasPriceMultiplier: number;
privateKey: PrivateKey;
jsonOutputDir: string;
wormholeAddr: string;
saveContract: boolean;
};
}

const CACHE_FILE = ".cache-deploy-evm-entropy-contracts";
const ENTROPY_DEFAULT_PROVIDER = {
Expand All @@ -51,7 +45,8 @@ const parser = yargs(hideBin(process.argv))

async function deployExecutorContracts(
chain: EvmChain,
config: DeploymentConfig
config: DeploymentConfig,
wormholeAddr: string
): Promise<string> {
const executorImplAddr = await deployIfNotCached(
CACHE_FILE,
Expand All @@ -72,7 +67,7 @@ async function deployExecutorContracts(

const executorInitData = executorImplContract.methods
.initialize(
config.wormholeAddr,
wormholeAddr,
0, // lastExecutedSequence,
chain.getWormholeChainId(),
governanceDataSource.emitterChain,
Expand Down Expand Up @@ -161,19 +156,6 @@ async function topupProviderIfNecessary(
}
}

async function findWormholeAddress(
chain: EvmChain
): Promise<string | undefined> {
for (const contract of Object.values(DefaultStore.contracts)) {
if (
contract instanceof EvmPriceFeedContract &&
contract.getChain().getId() === chain.getId()
) {
return (await contract.getWormholeContract()).address;
}
}
}

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

Expand All @@ -185,31 +167,21 @@ async function main() {
throw new Error(`Chain ${chainName} is not an EVM chain`);
}

const wormholeAddr = await findWormholeAddress(chain);
if (!wormholeAddr) {
// TODO: deploy wormhole if necessary and maintain a wormhole store
throw new Error(`Wormhole contract not found for chain ${chain.getId()}`);
}

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

const wormholeContract = await getOrDeployWormholeContract(
chain,
deploymentConfig.wormholeAddr
deploymentConfig,
CACHE_FILE
);
const wormholeChainId = await wormholeContract.getChainId();
if (chain.getWormholeChainId() != wormholeChainId) {
throw new Error(
`Wormhole chain id mismatch. Expected ${chain.getWormholeChainId()} but got ${wormholeChainId}`
);
}

await topupProviderIfNecessary(chain, deploymentConfig);

console.log(
Expand All @@ -218,7 +190,11 @@ async function main() {

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

const executorAddr = await deployExecutorContracts(chain, deploymentConfig);
const executorAddr = await deployExecutorContracts(
chain,
deploymentConfig,
wormholeContract.address
);
const entropyAddr = await deployEntropyContracts(
chain,
deploymentConfig,
Expand Down
79 changes: 9 additions & 70 deletions contract_manager/scripts/deploy_evm_pricefeed_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,23 @@ import {
DeploymentType,
EvmPriceFeedContract,
getDefaultDeploymentConfig,
PrivateKey,
toDeploymentType,
toPrivateKey,
EvmWormholeContract,
} from "../src";
import {
COMMON_DEPLOY_OPTIONS,
deployIfNotCached,
getWeb3Contract,
getOrDeployWormholeContract,
BaseDeployConfig,
} from "./common";

type DeploymentConfig = {
interface DeploymentConfig extends BaseDeployConfig {
type: DeploymentType;
validTimePeriodSeconds: number;
singleUpdateFeeInWei: number;
gasMultiplier: number;
gasPriceMultiplier: number;
privateKey: PrivateKey;
jsonOutputDir: string;
saveContract: boolean;
};
}

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

Expand All @@ -51,65 +47,6 @@ const parser = yargs(hideBin(process.argv))
},
});

async function deployWormholeReceiverContracts(
chain: EvmChain,
config: DeploymentConfig
): Promise<string> {
const receiverSetupAddr = await deployIfNotCached(
CACHE_FILE,
chain,
config,
"ReceiverSetup",
[]
);

const receiverImplAddr = await deployIfNotCached(
CACHE_FILE,
chain,
config,
"ReceiverImplementation",
[]
);

// Craft the init data for the proxy contract
const setupContract = getWeb3Contract(
config.jsonOutputDir,
"ReceiverSetup",
receiverSetupAddr
);

const { wormholeConfig } = getDefaultDeploymentConfig(config.type);

const initData = setupContract.methods
.setup(
receiverImplAddr,
wormholeConfig.initialGuardianSet.map((addr: string) => "0x" + addr),
chain.getWormholeChainId(),
wormholeConfig.governanceChainId,
"0x" + wormholeConfig.governanceContract
)
.encodeABI();

const wormholeReceiverAddr = await deployIfNotCached(
CACHE_FILE,
chain,
config,
"WormholeReceiver",
[receiverSetupAddr, initData]
);

const wormholeContract = new EvmWormholeContract(chain, wormholeReceiverAddr);

if (config.type === "stable") {
console.log(`Syncing mainnet guardian sets for ${chain.getId()}...`);
// TODO: Add a way to pass gas configs to this
await wormholeContract.syncMainnetGuardianSets(config.privateKey);
console.log(`✅ Synced mainnet guardian sets for ${chain.getId()}`);
}

return wormholeReceiverAddr;
}

async function deployPriceFeedContracts(
chain: EvmChain,
config: DeploymentConfig,
Expand Down Expand Up @@ -183,14 +120,16 @@ async function main() {

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

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

const priceFeedAddr = await deployPriceFeedContracts(
chain,
deploymentConfig,
wormholeAddr
wormholeContract.address
);

if (deploymentConfig.saveContract) {
Expand Down
5 changes: 5 additions & 0 deletions contract_manager/store/chains/EvmChains.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,8 @@
rpcUrl: https://olive-network-testnet.rpc.caldera.xyz/http
networkId: 8101902
type: EvmChain
- id: taiko_hekla
mainnet: false
rpcUrl: https://rpc.hekla.taiko.xyz/
networkId: 167009
type: EvmChain
Loading

0 comments on commit 587a6fa

Please sign in to comment.