feat(contract_manager): upgrade deploy scripts to use wormhole store (#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
This commit is contained in:
Dev Kalra 2024-05-02 16:48:16 +05:30 committed by GitHub
parent a592c6bc33
commit 587a6fa524
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 177 additions and 118 deletions

View File

@ -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;
@ -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
@ -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))
);
}

View File

@ -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 = {
@ -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,
@ -72,7 +67,7 @@ async function deployExecutorContracts(
const executorInitData = executorImplContract.methods
.initialize(
config.wormholeAddr,
wormholeAddr,
0, // lastExecutedSequence,
chain.getWormholeChainId(),
governanceDataSource.emitterChain,
@ -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;
@ -185,12 +167,6 @@ 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,
@ -198,18 +174,14 @@ async function main() {
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(
@ -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,

View File

@ -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";
@ -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,
@ -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) {

View File

@ -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

View File

@ -43,3 +43,6 @@
- chain: injective
address: inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d
type: CosmWasmWormholeContract
- chain: xion_testnet
address: xion14ycw3tx0hpz3aawmzm6cufs6hx94d64ht5qawd0ej9ug9j2ffzsqmpecys
type: CosmWasmWormholeContract

View File

@ -61,3 +61,6 @@
- chain: sei_evm_devnet
address: "0x23f0e8FAeE7bbb405E7A7C3d60138FCfd43d7509"
type: EvmEntropyContract
- chain: taiko_hekla
address: "0x98046Bd286715D3B0BC227Dd7a956b83D8978603"
type: EvmEntropyContract

View File

@ -316,6 +316,9 @@
- chain: flow_previewnet
address: "0x2880aB155794e7179c9eE2e38200202908C17B43"
type: EvmPriceFeedContract
- chain: olive_testnet
- chain: taiko_hekla
address: "0x2880aB155794e7179c9eE2e38200202908C17B43"
type: EvmPriceFeedContract
- chain: olive_testnet
address: "0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c"
type: EvmPriceFeedContract

View File

@ -295,3 +295,9 @@
- chain: linea_goerli
address: "0xfA25E653b44586dBbe27eE9d252192F0e4956683"
type: EvmWormholeContract
- chain: taiko_hekla
address: "0xb27e5ca259702f209a29225d0eDdC131039C9933"
type: EvmWormholeContract
- chain: olive_testnet
address: "0x74f09cb3c7e2A01865f424FD14F6dc9A14E3e94E"
type: EvmWormholeContract

View File

@ -145,7 +145,8 @@ export const RECEIVER_CHAINS = {
boba_sepolia: 50068,
astar_zkyoto_testnet: 50069,
xion_testnet: 50070,
olive_testnet: 50071,
taiko_hekla: 50071,
olive_testnet: 50072,
};
// If there is any overlapping value the receiver chain will replace the wormhole

View File

@ -1,6 +1,6 @@
{
"name": "@pythnetwork/pyth-evm-js",
"version": "1.45.0",
"version": "1.46.0",
"description": "Pyth Network EVM Utils in JS",
"homepage": "https://pyth.network",
"author": {

View File

@ -103,7 +103,7 @@ export const CONTRACT_ADDR: Record<string, string> = {
movement_evm_devnet: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
mumbai: "0xFC6bd9F9f0c6481c6Af3A7Eb46b296A5B85ed379",
neon_devnet: "0x0708325268dF9F66270F1401206434524814508b",
olive_testnet: "0x2880aB155794e7179c9eE2e38200202908C17B43",
olive_testnet: "0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c",
optimism_celestia_raspberry: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
optimism_goerli: "0xDd24F84d36BF92C65F92307595335bdFab5Bbd21",
optimism_sepolia: "0x0708325268dF9F66270F1401206434524814508b",
@ -116,6 +116,7 @@ export const CONTRACT_ADDR: Record<string, string> = {
scroll_sepolia: "0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c",
sepolia: "0xDd24F84d36BF92C65F92307595335bdFab5Bbd21",
shimmer_testnet: "0x8D254a21b3C86D32F7179855531CE99164721933",
taiko_hekla: "0x2880aB155794e7179c9eE2e38200202908C17B43",
viction_testnet: "0x5D289Ad1CE59fCC25b6892e7A303dfFf3a9f7167",
wemix_testnet: "0x26DD80569a8B23768A1d80869Ed7339e07595E85",
zetachain_testnet: "0x0708325268dF9F66270F1401206434524814508b",