From b9dbd54d5a2725630cba0a884e55e266e629d5b3 Mon Sep 17 00:00:00 2001 From: Mohammad Amin Khashkhashi Moghaddam Date: Wed, 23 Aug 2023 16:29:43 +0200 Subject: [PATCH] [contract-manager] General improvements (#1024) * Better return types for transaction execution functions * Use new type for passing PrivateKey * Small typing improvements * Stricter liniting * Rename edge to beta for DeploymentType * Reduce any usage across the contract manager * Fix explicit any linting warnings --- contract_manager/.eslintrc.js | 6 + contract_manager/package.json | 3 +- contract_manager/scripts/update_pricefeed.ts | 11 +- contract_manager/src/base.ts | 34 +++- contract_manager/src/chains.ts | 45 +++--- contract_manager/src/contracts/aptos.ts | 78 +++++++--- contract_manager/src/contracts/cosmwasm.ts | 145 +++++++++--------- contract_manager/src/contracts/evm.ts | 33 ++-- contract_manager/src/contracts/sui.ts | 78 ++++++---- contract_manager/src/contracts/wormhole.ts | 8 +- contract_manager/src/executor.ts | 3 +- contract_manager/src/governance.ts | 36 +++-- contract_manager/src/shell.ts | 1 + contract_manager/src/store.ts | 18 +-- target_chains/cosmwasm/tools/src/helper.ts | 4 +- .../cosmwasm/tools/src/instantiate-pyth.ts | 6 +- target_chains/cosmwasm/tools/src/test.ts | 6 +- .../cosmwasm/tools/src/wormhole-stub.ts | 6 +- .../scripts/contractManagerConfig.js | 2 +- target_chains/sui/cli/src/cli.ts | 2 +- 20 files changed, 317 insertions(+), 208 deletions(-) create mode 100644 contract_manager/.eslintrc.js diff --git a/contract_manager/.eslintrc.js b/contract_manager/.eslintrc.js new file mode 100644 index 00000000..fca472f3 --- /dev/null +++ b/contract_manager/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], + extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], +}; diff --git a/contract_manager/package.json b/contract_manager/package.json index 869ee2a4..503ce898 100644 --- a/contract_manager/package.json +++ b/contract_manager/package.json @@ -10,7 +10,8 @@ ], "scripts": { "build": "tsc", - "shell": "ts-node ./src/shell.ts" + "shell": "ts-node ./src/shell.ts", + "lint": "eslint src/" }, "author": "", "license": "Apache-2.0", diff --git a/contract_manager/scripts/update_pricefeed.ts b/contract_manager/scripts/update_pricefeed.ts index cbd71c7c..dd258e77 100644 --- a/contract_manager/scripts/update_pricefeed.ts +++ b/contract_manager/scripts/update_pricefeed.ts @@ -1,6 +1,6 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { DefaultStore } from "../src"; +import { DefaultStore, toPrivateKey } from "../src"; import { PriceServiceConnection } from "@pythnetwork/price-service-client"; const parser = yargs(hideBin(process.argv)) @@ -43,9 +43,12 @@ async function main() { argv.endpoint || defaultEndpoint ); const vaas = await priceService.getLatestVaas(argv["feed-id"] as string[]); - await contract.executeUpdatePriceFeed( - argv["private-key"], - vaas.map((vaa) => Buffer.from(vaa, "base64")) + const privateKey = toPrivateKey(argv["private-key"]); + console.log( + await contract.executeUpdatePriceFeed( + privateKey, + vaas.map((vaa) => Buffer.from(vaa, "base64")) + ) ); } diff --git a/contract_manager/src/base.ts b/contract_manager/src/base.ts index 6679bf81..c75370be 100644 --- a/contract_manager/src/base.ts +++ b/contract_manager/src/base.ts @@ -1,6 +1,24 @@ import { DataSource } from "xc_admin_common"; import { Chain } from "./chains"; +export interface TxResult { + id: string; + info: unknown; // chain specific info +} + +export type DeploymentType = "stable" | "beta"; +export type PrivateKey = string & { __type: "PrivateKey" }; +function checkIsPrivateKey(key: string): asserts key is PrivateKey { + if (Buffer.from(key, "hex").length !== 32) + throw new Error("Invalid private key, must be 64 hex chars"); +} +export function toPrivateKey(key: string): PrivateKey { + checkIsPrivateKey(key); + return key; +} + +export type KeyValueConfig = Record; + export abstract class Storable { /** * Returns the unique identifier for this object @@ -17,7 +35,7 @@ export abstract class Storable { * Returns a JSON representation of this object. It should be possible to * reconstruct the object from the JSON using the fromJson method. */ - abstract toJson(): any; + abstract toJson(): KeyValueConfig; } export interface Price { @@ -75,9 +93,9 @@ export abstract class Contract extends Storable { * @param vaas an array of VAAs containing price update messages to execute */ abstract executeUpdatePriceFeed( - senderPrivateKey: string, + senderPrivateKey: PrivateKey, vaas: Buffer[] - ): Promise; + ): Promise; /** * Executes the governance instruction contained in the VAA using the sender credentials @@ -85,9 +103,9 @@ export abstract class Contract extends Storable { * @param vaa the VAA to execute */ abstract executeGovernanceInstruction( - senderPrivateKey: string, + senderPrivateKey: PrivateKey, vaa: Buffer - ): Promise; + ): Promise; /** * Returns the single data source that this contract accepts governance messages from @@ -95,11 +113,11 @@ export abstract class Contract extends Storable { abstract getGovernanceDataSource(): Promise; } -export function getDefaultDeploymentConfig(deploymentType: "stable" | "edge"): { +export function getDefaultDeploymentConfig(deploymentType: DeploymentType): { dataSources: DataSource[]; governanceDataSource: DataSource; wormholeConfig: { - governanceChainId: Number; + governanceChainId: number; governanceContract: string; // 32 byte address in 64 char hex format initialGuardianSet: string[]; // 20 byte addresses in 40 char hex format }; @@ -135,7 +153,7 @@ export function getDefaultDeploymentConfig(deploymentType: "stable" | "edge"): { initialGuardianSet: ["58cc3ae5c097b213ce3c81979e1b9f9570746aa5"], }, }; - else if (deploymentType === "edge") + else if (deploymentType === "beta") return { dataSources: [ { diff --git a/contract_manager/src/chains.ts b/contract_manager/src/chains.ts index 4f368c19..e6350990 100644 --- a/contract_manager/src/chains.ts +++ b/contract_manager/src/chains.ts @@ -1,7 +1,6 @@ -import { Storable } from "./base"; +import { KeyValueConfig, PrivateKey, Storable } from "./base"; import { ChainName, - CHAINS, SetFee, CosmosUpgradeContract, EvmUpgradeContract, @@ -22,6 +21,10 @@ import { } from "@pythnetwork/cosmwasm-deploy-tools"; import { Network } from "@injectivelabs/networks"; +export type ChainConfig = Record & { + mainnet: boolean; + id: string; +}; export abstract class Chain extends Storable { public wormholeChainName: ChainName; @@ -92,15 +95,15 @@ export abstract class Chain extends Storable { * Returns the payload for a governance contract upgrade instruction for contracts deployed on this chain * @param upgradeInfo based on the contract type, this can be a contract address, codeId, package digest, etc. */ - abstract generateGovernanceUpgradePayload(upgradeInfo: any): Buffer; + abstract generateGovernanceUpgradePayload(upgradeInfo: unknown): Buffer; } export class GlobalChain extends Chain { - static type: string = "GlobalChain"; + static type = "GlobalChain"; constructor() { super("global", true, "unset"); } - generateGovernanceUpgradePayload(upgradeInfo: any): Buffer { + generateGovernanceUpgradePayload(): Buffer { throw new Error( "Can not create a governance message for upgrading contracts on all chains!" ); @@ -110,7 +113,7 @@ export class GlobalChain extends Chain { return GlobalChain.type; } - toJson(): any { + toJson(): KeyValueConfig { return { id: this.id, wormholeChainName: this.wormholeChainName, @@ -121,7 +124,7 @@ export class GlobalChain extends Chain { } export class CosmWasmChain extends Chain { - static type: string = "CosmWasmChain"; + static type = "CosmWasmChain"; constructor( id: string, @@ -135,7 +138,7 @@ export class CosmWasmChain extends Chain { super(id, mainnet, wormholeChainName); } - static fromJson(parsed: any): CosmWasmChain { + static fromJson(parsed: ChainConfig): CosmWasmChain { if (parsed.type !== CosmWasmChain.type) throw new Error("Invalid type"); return new CosmWasmChain( parsed.id, @@ -148,7 +151,7 @@ export class CosmWasmChain extends Chain { ); } - toJson(): any { + toJson(): KeyValueConfig { return { endpoint: this.endpoint, id: this.id, @@ -174,7 +177,7 @@ export class CosmWasmChain extends Chain { return new CosmosUpgradeContract(this.wormholeChainName, codeId).encode(); } - async getExecutor(privateKey: string) { + async getExecutor(privateKey: PrivateKey) { if (this.getId().indexOf("injective") > -1) { return InjectiveExecutor.fromPrivateKey( this.isMainnet() ? Network.Mainnet : Network.Testnet, @@ -190,7 +193,7 @@ export class CosmWasmChain extends Chain { } export class SuiChain extends Chain { - static type: string = "SuiChain"; + static type = "SuiChain"; constructor( id: string, @@ -201,7 +204,7 @@ export class SuiChain extends Chain { super(id, mainnet, wormholeChainName); } - static fromJson(parsed: any): SuiChain { + static fromJson(parsed: ChainConfig): SuiChain { if (parsed.type !== SuiChain.type) throw new Error("Invalid type"); return new SuiChain( parsed.id, @@ -211,7 +214,7 @@ export class SuiChain extends Chain { ); } - toJson(): any { + toJson(): KeyValueConfig { return { id: this.id, wormholeChainName: this.wormholeChainName, @@ -238,7 +241,7 @@ export class SuiChain extends Chain { } export class EvmChain extends Chain { - static type: string = "EvmChain"; + static type = "EvmChain"; constructor( id: string, @@ -250,7 +253,7 @@ export class EvmChain extends Chain { super(id, mainnet, wormholeChainName); } - static fromJson(parsed: any): EvmChain { + static fromJson(parsed: ChainConfig & { networkId: number }): EvmChain { if (parsed.type !== EvmChain.type) throw new Error("Invalid type"); return new EvmChain( parsed.id, @@ -277,7 +280,7 @@ export class EvmChain extends Chain { return new EvmSetWormholeAddress(this.wormholeChainName, address).encode(); } - toJson(): any { + toJson(): KeyValueConfig { return { id: this.id, wormholeChainName: this.wormholeChainName, @@ -311,10 +314,10 @@ export class EvmChain extends Chain { * @returns the address of the deployed contract */ async deploy( - privateKey: string, - abi: any, + privateKey: PrivateKey, + abi: any, // eslint-disable-line @typescript-eslint/no-explicit-any bytecode: string, - deployArgs: any[] + deployArgs: any[] // eslint-disable-line @typescript-eslint/no-explicit-any ): Promise { const web3 = new Web3(this.getRpcUrl()); const signer = web3.eth.accounts.privateKeyToAccount(privateKey); @@ -375,7 +378,7 @@ export class AptosChain extends Chain { return AptosChain.type; } - toJson(): any { + toJson(): KeyValueConfig { return { id: this.id, wormholeChainName: this.wormholeChainName, @@ -385,7 +388,7 @@ export class AptosChain extends Chain { }; } - static fromJson(parsed: any): AptosChain { + static fromJson(parsed: ChainConfig): AptosChain { if (parsed.type !== AptosChain.type) throw new Error("Invalid type"); return new AptosChain( parsed.id, diff --git a/contract_manager/src/contracts/aptos.ts b/contract_manager/src/contracts/aptos.ts index 81f56012..bce813e1 100644 --- a/contract_manager/src/contracts/aptos.ts +++ b/contract_manager/src/contracts/aptos.ts @@ -1,11 +1,11 @@ -import { Contract, PriceFeed } from "../base"; -import { AptosAccount, BCS, TxnBuilderTypes } from "aptos"; +import { Contract, PriceFeed, PrivateKey, TxResult } from "../base"; +import { ApiError, AptosAccount, BCS, TxnBuilderTypes } from "aptos"; import { AptosChain, Chain } from "../chains"; import { DataSource } from "xc_admin_common"; import { CoinClient } from "aptos"; export class AptosContract extends Contract { - static type: string = "AptosContract"; + static type = "AptosContract"; /** * Given the ids of the pyth state and wormhole state, create a new AptosContract @@ -23,7 +23,10 @@ export class AptosContract extends Contract { super(); } - static fromJson(chain: Chain, parsed: any): AptosContract { + static fromJson( + chain: Chain, + parsed: { type: string; stateId: string; wormholeStateId: string } + ): AptosContract { if (parsed.type !== AptosContract.type) throw new Error("Invalid type"); if (!(chain instanceof AptosChain)) throw new Error(`Wrong chain type ${chain}`); @@ -31,9 +34,9 @@ export class AptosContract extends Contract { } async executeGovernanceInstruction( - senderPrivateKey: string, + senderPrivateKey: PrivateKey, vaa: Buffer - ): Promise { + ): Promise { const txPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction( TxnBuilderTypes.EntryFunction.natural( `${this.stateId}::governance`, @@ -45,23 +48,28 @@ export class AptosContract extends Contract { return this.sendTransaction(senderPrivateKey, txPayload); } - private sendTransaction( - senderPrivateKey: string, + private async sendTransaction( + senderPrivateKey: PrivateKey, txPayload: TxnBuilderTypes.TransactionPayloadEntryFunction - ) { + ): Promise { const client = this.chain.getClient(); const sender = new AptosAccount( new Uint8Array(Buffer.from(senderPrivateKey, "hex")) ); - return client.generateSignSubmitWaitForTransaction(sender, txPayload, { - maxGasAmount: BigInt(30000), - }); + const result = await client.generateSignSubmitWaitForTransaction( + sender, + txPayload, + { + maxGasAmount: BigInt(30000), + } + ); + return { id: result.hash, info: result }; } async executeUpdatePriceFeed( - senderPrivateKey: string, + senderPrivateKey: PrivateKey, vaas: Buffer[] - ): Promise { + ): Promise { const txPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction( TxnBuilderTypes.EntryFunction.natural( `${this.stateId}::pyth`, @@ -93,7 +101,7 @@ export class AptosContract extends Contract { } async getBaseUpdateFee() { - const data = (await this.findResource("BaseUpdateFee")) as any; + const data = (await this.findResource("BaseUpdateFee")) as { fee: string }; return { amount: data.fee }; } @@ -101,7 +109,12 @@ export class AptosContract extends Contract { return this.chain; } - private parsePrice(priceInfo: any) { + private parsePrice(priceInfo: { + expo: { magnitude: string; negative: boolean }; + price: { magnitude: string; negative: boolean }; + conf: string; + timestamp: string; + }) { let expo = priceInfo.expo.magnitude; if (priceInfo.expo.negative) expo = "-" + expo; let price = priceInfo.price.magnitude; @@ -116,7 +129,9 @@ export class AptosContract extends Contract { async getPriceFeed(feedId: string): Promise { const client = this.chain.getClient(); - const res = (await this.findResource("LatestPriceInfo")) as any; + const res = (await this.findResource("LatestPriceInfo")) as { + info: { handle: string }; + }; const handle = res.info.handle; try { const priceItemRes = await client.getTableItem(handle, { @@ -130,15 +145,23 @@ export class AptosContract extends Contract { price: this.parsePrice(priceItemRes.price_feed.price), emaPrice: this.parsePrice(priceItemRes.price_feed.ema_price), }; - } catch (e: any) { - if (e.errorCode === "table_item_not_found") return undefined; + } catch (e) { + if (e instanceof ApiError && e.errorCode === "table_item_not_found") + return undefined; throw e; } } async getDataSources(): Promise { - const data = (await this.findResource("DataSources")) as any; - return data.sources.keys.map((source: any) => { + const data = (await this.findResource("DataSources")) as { + sources: { + keys: { + emitter_chain: string; + emitter_address: { external_address: string }; + }[]; + }; + }; + return data.sources.keys.map((source) => { return { emitterChain: Number(source.emitter_chain), emitterAddress: source.emitter_address.external_address.replace( @@ -150,7 +173,12 @@ export class AptosContract extends Contract { } async getGovernanceDataSource(): Promise { - const data = (await this.findResource("GovernanceDataSource")) as any; + const data = (await this.findResource("GovernanceDataSource")) as { + source: { + emitter_chain: string; + emitter_address: { external_address: string }; + }; + }; return { emitterChain: Number(data.source.emitter_chain), emitterAddress: data.source.emitter_address.external_address.replace( @@ -163,7 +191,7 @@ export class AptosContract extends Contract { async getLastExecutedGovernanceSequence() { const data = (await this.findResource( "LastExecutedGovernanceSequence" - )) as any; + )) as { sequence: string }; return Number(data.sequence); } @@ -181,7 +209,9 @@ export class AptosContract extends Contract { } async getValidTimePeriod() { - const data = (await this.findResource("StalePriceThreshold")) as any; + const data = (await this.findResource("StalePriceThreshold")) as { + threshold_secs: string; + }; return Number(data.threshold_secs); } diff --git a/contract_manager/src/contracts/cosmwasm.ts b/contract_manager/src/contracts/cosmwasm.ts index d1f5fdf4..9f549b3b 100644 --- a/contract_manager/src/contracts/cosmwasm.ts +++ b/contract_manager/src/contracts/cosmwasm.ts @@ -9,30 +9,29 @@ import { PythWrapperExecutor, PythWrapperQuerier, } from "@pythnetwork/cosmwasm-deploy-tools"; +import { Coin } from "@cosmjs/stargate"; import { CHAINS, DataSource } from "xc_admin_common"; import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate"; -import { Contract } from "../base"; +import { Contract, PrivateKey, TxResult } from "../base"; import { WormholeContract } from "./wormhole"; /** * Variables here need to be snake case to match the on-chain contract configs */ -namespace CosmWasmContract { - export interface WormholeSource { - emitter: string; - chain_id: number; - } +export interface WormholeSource { + emitter: string; + chain_id: number; +} - export interface DeploymentConfig { - data_sources: WormholeSource[]; - governance_source: WormholeSource; - wormhole_contract: string; - governance_source_index: number; - governance_sequence_number: number; - chain_id: number; - valid_time_period_secs: number; - fee: { amount: string; denom: string }; - } +export interface DeploymentConfig { + data_sources: WormholeSource[]; + governance_source: WormholeSource; + wormhole_contract: string; + governance_source_index: number; + governance_sequence_number: number; + chain_id: number; + valid_time_period_secs: number; + fee: { amount: string; denom: string }; } export class WormholeCosmWasmContract extends WormholeContract { @@ -44,7 +43,7 @@ export class WormholeCosmWasmContract extends WormholeContract { const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint); return (await chainQuerier.getAllContractState({ contractAddr: this.address, - })) as any; + })) as Record; } async getCurrentGuardianSetIndex(): Promise { @@ -68,28 +67,31 @@ export class WormholeCosmWasmContract extends WormholeContract { } async upgradeGuardianSets( - senderPrivateKey: string, + senderPrivateKey: PrivateKey, vaa: Buffer - ): Promise { + ): Promise { const executor = await this.chain.getExecutor(senderPrivateKey); - return executor.executeContract({ + const result = await executor.executeContract({ contractAddr: this.address, msg: { submit_v_a_a: { vaa: vaa.toString("base64") }, }, }); + return { id: result.txHash, info: result }; } } export class CosmWasmContract extends Contract { async getDataSources(): Promise { const config = await this.getConfig(); - return config.config_v1.data_sources.map(({ emitter, chain_id }: any) => { - return { - emitterChain: Number(chain_id), - emitterAddress: Buffer.from(emitter, "base64").toString("hex"), - }; - }); + return config.config_v1.data_sources.map( + ({ emitter, chain_id }: { emitter: string; chain_id: string }) => { + return { + emitterChain: Number(chain_id), + emitterAddress: Buffer.from(emitter, "base64").toString("hex"), + }; + } + ); } async getGovernanceDataSource(): Promise { @@ -108,7 +110,10 @@ export class CosmWasmContract extends Contract { super(); } - static fromJson(chain: Chain, parsed: any): CosmWasmContract { + static fromJson( + chain: Chain, + parsed: { type: string; address: string } + ): CosmWasmContract { if (parsed.type !== CosmWasmContract.type) throw new Error("Invalid type"); if (!(chain instanceof CosmWasmChain)) throw new Error(`Wrong chain type ${chain}`); @@ -119,17 +124,16 @@ export class CosmWasmContract extends Contract { return CosmWasmContract.type; } - //TODO : make deploymentType enum stable | edge static getDeploymentConfig( chain: CosmWasmChain, - deploymentType: string, + deploymentType: DeploymentType, wormholeContract: string - ): CosmWasmContract.DeploymentConfig { + ): DeploymentConfig { return getPythConfig({ feeDenom: chain.feeDenom, - wormholeChainId: CHAINS[chain.getId() as keyof typeof CHAINS], + wormholeChainId: CHAINS[chain.wormholeChainName], wormholeContract, - deploymentType: deploymentType as DeploymentType, + deploymentType: deploymentType, }); } @@ -142,11 +146,11 @@ export class CosmWasmContract extends Contract { */ static async storeCode( chain: CosmWasmChain, - privateKey: string, + privateKey: PrivateKey, wasmPath: string ) { const contractBytes = readFileSync(wasmPath); - let executor = await chain.getExecutor(privateKey); + const executor = await chain.getExecutor(privateKey); return executor.storeCode({ contractBytes }); } @@ -160,11 +164,11 @@ export class CosmWasmContract extends Contract { static async initialize( chain: CosmWasmChain, codeId: number, - config: CosmWasmContract.DeploymentConfig, - privateKey: string + config: DeploymentConfig, + privateKey: PrivateKey ): Promise { - let executor = await chain.getExecutor(privateKey); - let result = await executor.instantiateContract({ + const executor = await chain.getExecutor(privateKey); + const result = await executor.instantiateContract({ codeId: codeId, instMsg: config, label: "pyth", @@ -190,10 +194,10 @@ export class CosmWasmContract extends Contract { static async deploy( chain: CosmWasmChain, wormholeContract: string, - privateKey: string, + privateKey: PrivateKey, wasmPath: string ): Promise { - let config = this.getDeploymentConfig(chain, "edge", wormholeContract); + const config = this.getDeploymentConfig(chain, "beta", wormholeContract); const { codeId } = await this.storeCode(chain, privateKey, wasmPath); return this.initialize(chain, codeId, config, privateKey); } @@ -217,7 +221,7 @@ export class CosmWasmContract extends Contract { } async getCodeId(): Promise { - let result = await this.getWasmContractInfo(); + const result = await this.getWasmContractInfo(); return result.codeId; } @@ -228,10 +232,10 @@ export class CosmWasmContract extends Contract { async getConfig() { const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint); - let allStates = (await chainQuerier.getAllContractState({ + const allStates = (await chainQuerier.getAllContractState({ contractAddr: this.address, - })) as any; - let config = { + })) as Record; + const config = { config_v1: JSON.parse(allStates["\x00\tconfig_v1"]), contract_version: JSON.parse(allStates["\x00\x10contract_version"]), }; @@ -256,7 +260,7 @@ export class CosmWasmContract extends Contract { } async getPriceFeed(feedId: string) { - let querier = await this.getQuerier(); + const querier = await this.getQuerier(); try { const response = await querier.getPriceFeed(this.address, feedId); return { @@ -269,8 +273,8 @@ export class CosmWasmContract extends Contract { } equalDataSources( - dataSources1: CosmWasmContract.WormholeSource[], - dataSources2: CosmWasmContract.WormholeSource[] + dataSources1: WormholeSource[], + dataSources2: WormholeSource[] ): boolean { if (dataSources1.length !== dataSources2.length) return false; for (let i = 0; i < dataSources1.length; i++) { @@ -290,19 +294,19 @@ export class CosmWasmContract extends Contract { } async getDeploymentType(): Promise { - let config = await this.getConfig(); - let wormholeContract = config.config_v1.wormhole_contract; - let stableConfig = getPythConfig({ + const config = await this.getConfig(); + const wormholeContract = config.config_v1.wormhole_contract; + const stableConfig = getPythConfig({ feeDenom: this.chain.feeDenom, wormholeChainId: CHAINS[this.chain.getId() as keyof typeof CHAINS], wormholeContract, deploymentType: "stable", }); - let edgeConfig = getPythConfig({ + const betaConfig = getPythConfig({ feeDenom: this.chain.feeDenom, wormholeChainId: CHAINS[this.chain.getId() as keyof typeof CHAINS], wormholeContract, - deploymentType: "edge", + deploymentType: "beta", }); if ( this.equalDataSources( @@ -314,52 +318,53 @@ export class CosmWasmContract extends Contract { else if ( this.equalDataSources( config.config_v1.data_sources, - edgeConfig.data_sources + betaConfig.data_sources ) ) - return "edge"; + return "beta"; else return "unknown"; } - async executeUpdatePriceFeed(senderPrivateKey: string, vaas: Buffer[]) { + async executeUpdatePriceFeed(senderPrivateKey: PrivateKey, vaas: Buffer[]) { const base64Vaas = vaas.map((v) => v.toString("base64")); const fund = await this.getUpdateFee(base64Vaas); - let executor = await this.chain.getExecutor(senderPrivateKey); - let pythExecutor = new PythWrapperExecutor(executor); - return pythExecutor.executeUpdatePriceFeeds({ + const executor = await this.chain.getExecutor(senderPrivateKey); + const pythExecutor = new PythWrapperExecutor(executor); + const result = await pythExecutor.executeUpdatePriceFeeds({ contractAddr: this.address, vaas: base64Vaas, fund, }); + return { id: result.txHash, info: result }; } - async executeGovernanceInstruction(privateKey: string, vaa: Buffer) { - let executor = await this.chain.getExecutor(privateKey); - let pythExecutor = new PythWrapperExecutor(executor); - return pythExecutor.executeGovernanceInstruction({ + async executeGovernanceInstruction(privateKey: PrivateKey, vaa: Buffer) { + const executor = await this.chain.getExecutor(privateKey); + const pythExecutor = new PythWrapperExecutor(executor); + const result = await pythExecutor.executeGovernanceInstruction({ contractAddr: this.address, vaa: vaa.toString("base64"), }); + return { id: result.txHash, info: result }; } async getWormholeContract(): Promise { - let config = await this.getConfig(); - const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint); + const config = await this.getConfig(); const wormholeAddress = config.config_v1.wormhole_contract; return new WormholeCosmWasmContract(this.chain, wormholeAddress); } - async getUpdateFee(msgs: string[]): Promise { - let querier = await this.getQuerier(); + async getUpdateFee(msgs: string[]): Promise { + const querier = await this.getQuerier(); return querier.getUpdateFee(this.address, msgs); } - async getBaseUpdateFee(): Promise { + async getBaseUpdateFee(): Promise<{ amount: string; denom: string }> { const config = await this.getConfig(); return config.config_v1.fee; } - async getVersion(): Promise { + async getVersion(): Promise { const config = await this.getConfig(); return config.contract_version; } @@ -378,8 +383,8 @@ export class CosmWasmContract extends Contract { } async getValidTimePeriod() { - let client = await CosmWasmClient.connect(this.chain.endpoint); - let result = await client.queryContractSmart( + const client = await CosmWasmClient.connect(this.chain.endpoint); + const result = await client.queryContractSmart( this.address, "get_valid_time_period" ); diff --git a/contract_manager/src/contracts/evm.ts b/contract_manager/src/contracts/evm.ts index 4f1fba55..8e1fa48b 100644 --- a/contract_manager/src/contracts/evm.ts +++ b/contract_manager/src/contracts/evm.ts @@ -1,6 +1,6 @@ -import Web3 from "web3"; //TODO: decide on using web3 or ethers.js +import Web3 from "web3"; import PythInterfaceAbi from "@pythnetwork/pyth-sdk-solidity/abis/IPyth.json"; -import { Contract } from "../base"; +import { Contract, PrivateKey } from "../base"; import { Chain, EvmChain } from "../chains"; import { DataSource } from "xc_admin_common"; import { WormholeContract } from "./wormhole"; @@ -138,7 +138,7 @@ const EXTENDED_PYTH_ABI = [ type: "function", }, ...PythInterfaceAbi, -] as any; +] as any; // eslint-disable-line @typescript-eslint/no-explicit-any const WORMHOLE_ABI = [ { @@ -211,7 +211,7 @@ const WORMHOLE_ABI = [ stateMutability: "view", type: "function", }, -] as any; +] as any; // eslint-disable-line @typescript-eslint/no-explicit-any export class WormholeEvmContract extends WormholeContract { constructor(public chain: EvmChain, public address: string) { super(); @@ -256,7 +256,7 @@ export class WormholeEvmContract extends WormholeContract { } } - async upgradeGuardianSets(senderPrivateKey: string, vaa: Buffer) { + async upgradeGuardianSets(senderPrivateKey: PrivateKey, vaa: Buffer) { const web3 = new Web3(this.chain.getRpcUrl()); const { address } = web3.eth.accounts.wallet.add(senderPrivateKey); const wormholeContract = new web3.eth.Contract(WORMHOLE_ABI, this.address); @@ -267,11 +267,12 @@ export class WormholeEvmContract extends WormholeContract { from: address, gas: 100000000, }); - return transactionObject.send({ + const result = await transactionObject.send({ from: address, gas: gasEstiamte * GAS_ESTIMATE_MULTIPLIER, gasPrice: await this.chain.getGasPrice(), }); + return { id: result.transactionHash, info: result }; } } @@ -282,7 +283,10 @@ export class EvmContract extends Contract { super(); } - static fromJson(chain: Chain, parsed: any): EvmContract { + static fromJson( + chain: Chain, + parsed: { type: string; address: string } + ): EvmContract { if (parsed.type !== EvmContract.type) throw new Error("Invalid type"); if (!(chain instanceof EvmChain)) throw new Error(`Wrong chain type ${chain}`); @@ -321,7 +325,7 @@ export class EvmContract extends Contract { async getImplementationAddress(): Promise { const web3 = new Web3(this.chain.getRpcUrl()); // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) according to EIP-1967 - let storagePosition = + const storagePosition = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; let address = await web3.eth.getStorageAt(this.address, storagePosition); address = "0x" + address.slice(26); @@ -433,7 +437,7 @@ export class EvmContract extends Contract { }; } - async executeUpdatePriceFeed(senderPrivateKey: string, vaas: Buffer[]) { + async executeUpdatePriceFeed(senderPrivateKey: PrivateKey, vaas: Buffer[]) { const web3 = new Web3(this.chain.getRpcUrl()); const { address } = web3.eth.accounts.wallet.add(senderPrivateKey); const pythContract = new web3.eth.Contract(EXTENDED_PYTH_ABI, this.address); @@ -448,15 +452,19 @@ export class EvmContract extends Contract { gas: 100000000, value: updateFee, }); - return transactionObject.send({ + const result = await transactionObject.send({ from: address, value: updateFee, gas: gasEstiamte * GAS_ESTIMATE_MULTIPLIER, gasPrice: await this.chain.getGasPrice(), }); + return { id: result.transactionHash, info: result }; } - async executeGovernanceInstruction(senderPrivateKey: string, vaa: Buffer) { + async executeGovernanceInstruction( + senderPrivateKey: PrivateKey, + vaa: Buffer + ) { const web3 = new Web3(this.chain.getRpcUrl()); const { address } = web3.eth.accounts.wallet.add(senderPrivateKey); const pythContract = new web3.eth.Contract(EXTENDED_PYTH_ABI, this.address); @@ -467,11 +475,12 @@ export class EvmContract extends Contract { from: address, gas: 100000000, }); - return transactionObject.send({ + const result = await transactionObject.send({ from: address, gas: gasEstiamte * GAS_ESTIMATE_MULTIPLIER, gasPrice: await this.chain.getGasPrice(), }); + return { id: result.transactionHash, info: result }; } getChain(): EvmChain { diff --git a/contract_manager/src/contracts/sui.ts b/contract_manager/src/contracts/sui.ts index 3ec712c3..3c589dc2 100644 --- a/contract_manager/src/contracts/sui.ts +++ b/contract_manager/src/contracts/sui.ts @@ -9,7 +9,7 @@ import { } from "@mysten/sui.js"; import { Chain, SuiChain } from "../chains"; import { DataSource } from "xc_admin_common"; -import { Contract } from "../base"; +import { Contract, PrivateKey, TxResult } from "../base"; import { SuiPythClient } from "@pythnetwork/pyth-sui-js"; export class SuiContract extends Contract { @@ -31,7 +31,10 @@ export class SuiContract extends Contract { super(); } - static fromJson(chain: Chain, parsed: any): SuiContract { + static fromJson( + chain: Chain, + parsed: { type: string; stateId: string; wormholeStateId: string } + ): SuiContract { if (parsed.type !== SuiContract.type) throw new Error("Invalid type"); if (!(chain instanceof SuiChain)) throw new Error(`Wrong chain type ${chain}`); @@ -81,7 +84,7 @@ export class SuiContract extends Contract { */ async getPriceTableId(): Promise { const provider = this.getProvider(); - let result = await provider.getDynamicFieldObject({ + const result = await provider.getDynamicFieldObject({ parentId: this.stateId, name: { type: "vector", @@ -94,7 +97,15 @@ export class SuiContract extends Contract { return result.data.objectId; } - private async parsePrice(priceInfo: any) { + private async parsePrice(priceInfo: { + type: string; + fields: { + expo: { fields: { magnitude: string; negative: boolean } }; + price: { fields: { magnitude: string; negative: boolean } }; + conf: string; + timestamp: string; + }; + }) { const packageId = await this.getPythPackageId(); const expectedType = `${packageId}::price::Price`; if (priceInfo.type !== expectedType) { @@ -117,7 +128,7 @@ export class SuiContract extends Contract { async getPriceFeedObjectId(feedId: string): Promise { const tableId = await this.getPriceTableId(); const provider = this.getProvider(); - let result = await provider.getDynamicFieldObject({ + const result = await provider.getDynamicFieldObject({ parentId: tableId, name: { type: `${await this.getPythPackageId()}::price_identifier::PriceIdentifier`, @@ -137,9 +148,9 @@ export class SuiContract extends Contract { async getPriceFeed(feedId: string) { const provider = this.getProvider(); - let priceInfoObjectId = await this.getPriceFeedObjectId(feedId); + const priceInfoObjectId = await this.getPriceFeedObjectId(feedId); if (!priceInfoObjectId) return undefined; - let priceInfo = await provider.getObject({ + const priceInfo = await provider.getObject({ id: priceInfoObjectId, options: { showContent: true }, }); @@ -173,7 +184,7 @@ export class SuiContract extends Contract { async executeMigrateInstruction(vaa: Buffer, keypair: Ed25519Keypair) { const tx = new TransactionBlock(); const packageId = await this.getPythPackageId(); - let verificationReceipt = await this.getVaaVerificationReceipt( + const verificationReceipt = await this.getVaaVerificationReceipt( tx, packageId, vaa @@ -187,7 +198,7 @@ export class SuiContract extends Contract { return this.executeTransaction(tx, keypair); } - async executeUpdatePriceFeed(senderPrivateKey: string, vaas: Buffer[]) { + async executeUpdatePriceFeed(): Promise { // We need the feed ids to be able to execute the transaction // it may be possible to get them from the VAA but in batch transactions, // it is also possible to hava fewer feeds that user wants to update compared to @@ -207,17 +218,20 @@ export class SuiContract extends Contract { senderPrivateKey: string, vaas: Buffer[], feedIds: string[] - ) { + ): Promise { const tx = new TransactionBlock(); const client = this.getSdkClient(); await client.updatePriceFeeds(tx, vaas, feedIds); const keypair = Ed25519Keypair.fromSecretKey( Buffer.from(senderPrivateKey, "hex") ); - let result = await this.executeTransaction(tx, keypair); - return result.digest; + const result = await this.executeTransaction(tx, keypair); + return { id: result.digest, info: result }; } - async executeCreatePriceFeed(senderPrivateKey: string, vaas: Buffer[]) { + async executeCreatePriceFeed( + senderPrivateKey: string, + vaas: Buffer[] + ): Promise { const tx = new TransactionBlock(); const client = this.getSdkClient(); await client.createPriceFeed(tx, vaas); @@ -225,17 +239,20 @@ export class SuiContract extends Contract { Buffer.from(senderPrivateKey, "hex") ); - let result = await this.executeTransaction(tx, keypair); - return result.digest; + const result = await this.executeTransaction(tx, keypair); + return { id: result.digest, info: result }; } - async executeGovernanceInstruction(senderPrivateKey: string, vaa: Buffer) { + async executeGovernanceInstruction( + senderPrivateKey: PrivateKey, + vaa: Buffer + ): Promise { const keypair = Ed25519Keypair.fromSecretKey( Buffer.from(senderPrivateKey, "hex") ); const tx = new TransactionBlock(); const packageId = await this.getPythPackageId(); - let verificationReceipt = await this.getVaaVerificationReceipt( + const verificationReceipt = await this.getVaaVerificationReceipt( tx, packageId, vaa @@ -246,7 +263,8 @@ export class SuiContract extends Contract { arguments: [tx.object(this.stateId), verificationReceipt], }); - return this.executeTransaction(tx, keypair); + const result = await this.executeTransaction(tx, keypair); + return { id: result.digest, info: result }; } async executeUpgradeInstruction( @@ -257,7 +275,7 @@ export class SuiContract extends Contract { ) { const tx = new TransactionBlock(); const packageId = await this.getPythPackageId(); - let verificationReceipt = await this.getVaaVerificationReceipt( + const verificationReceipt = await this.getVaaVerificationReceipt( tx, packageId, vaa @@ -279,7 +297,8 @@ export class SuiContract extends Contract { target: `${packageId}::contract_upgrade::commit_upgrade`, arguments: [tx.object(this.stateId), upgradeReceipt], }); - return this.executeTransaction(tx, keypair); + const result = await this.executeTransaction(tx, keypair); + return { id: result.digest, info: result }; } /** @@ -297,7 +316,7 @@ export class SuiContract extends Contract { ) { const wormholePackageId = await this.getWormholePackageId(); - let [verifiedVAA] = tx.moveCall({ + const [verifiedVAA] = tx.moveCall({ target: `${wormholePackageId}::vaa::parse_and_verify`, arguments: [ tx.object(this.wormholeStateId), @@ -306,7 +325,7 @@ export class SuiContract extends Contract { ], }); - let [verificationReceipt] = tx.moveCall({ + const [verificationReceipt] = tx.moveCall({ target: `${packageId}::governance::verify_vaa`, arguments: [tx.object(this.stateId), verifiedVAA], }); @@ -325,7 +344,7 @@ export class SuiContract extends Contract { keypair: Ed25519Keypair ) { const provider = this.getProvider(); - let txBlock = { + const txBlock = { transactionBlock: tx, options: { showEffects: true, @@ -333,7 +352,7 @@ export class SuiContract extends Contract { }, }; const wallet = new RawSigner(keypair, provider); - let gasCost = await wallet.getGasCostEstimation(txBlock); + const gasCost = await wallet.getGasCostEstimation(txBlock); tx.setGasBudget(gasCost * BigInt(2)); return wallet.signAndExecuteTransactionBlock(txBlock); } @@ -345,7 +364,7 @@ export class SuiContract extends Contract { async getDataSources(): Promise { const provider = this.getProvider(); - let result = await provider.getDynamicFieldObject({ + const result = await provider.getDynamicFieldObject({ parentId: this.stateId, name: { type: "vector", @@ -361,7 +380,14 @@ export class SuiContract extends Contract { throw new Error("Data Sources type mismatch"); } return result.data.content.fields.value.fields.keys.map( - ({ fields }: any) => { + ({ + fields, + }: { + fields: { + emitter_address: { fields: { value: { fields: { data: string } } } }; + emitter_chain: string; + }; + }) => { return { emitterChain: Number(fields.emitter_chain), emitterAddress: Buffer.from( diff --git a/contract_manager/src/contracts/wormhole.ts b/contract_manager/src/contracts/wormhole.ts index 3b1008ad..ac87fdec 100644 --- a/contract_manager/src/contracts/wormhole.ts +++ b/contract_manager/src/contracts/wormhole.ts @@ -1,3 +1,5 @@ +import { PrivateKey, TxResult } from "../base"; + export abstract class WormholeContract { abstract getCurrentGuardianSetIndex(): Promise; @@ -12,15 +14,15 @@ export abstract class WormholeContract { * @param vaa */ abstract upgradeGuardianSets( - senderPrivateKey: string, + senderPrivateKey: PrivateKey, vaa: Buffer - ): Promise; + ): Promise; /** * Upgrades the guardian set of this contract with the 3 pre-configured VAAs for mainnet assuming this is a mainnet contract * @param senderPrivateKey */ - async syncMainnetGuardianSets(senderPrivateKey: string) { + async syncMainnetGuardianSets(senderPrivateKey: PrivateKey) { const MAINNET_UPGRADE_VAAS = [ "010000000001007ac31b282c2aeeeb37f3385ee0de5f8e421d30b9e5ae8ba3d4375c1c77a86e77159bb697d9c456d6f8c02d22a94b1279b65b0d6a9957e7d3857423845ac758e300610ac1d2000000030001000000000000000000000000000000000000000000000000000000000000000400000000000005390000000000000000000000000000000000000000000000000000000000436f7265020000000000011358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cdeb5f7389fa26941519f0863349c223b73a6ddee774a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d", "01000000010d0012e6b39c6da90c5dfd3c228edbb78c7a4c97c488ff8a346d161a91db067e51d638c17216f368aa9bdf4836b8645a98018ca67d2fec87d769cabfdf2406bf790a0002ef42b288091a670ef3556596f4f47323717882881eaf38e03345078d07a156f312b785b64dae6e9a87e3d32872f59cb1931f728cecf511762981baf48303668f0103cef2616b84c4e511ff03329e0853f1bd7ee9ac5ba71d70a4d76108bddf94f69c2a8a84e4ee94065e8003c334e899184943634e12043d0dda78d93996da073d190104e76d166b9dac98f602107cc4b44ac82868faf00b63df7d24f177aa391e050902413b71046434e67c770b19aecdf7fce1d1435ea0be7262e3e4c18f50ddc8175c0105d9450e8216d741e0206a50f93b750a47e0a258b80eb8fed1314cc300b3d905092de25cd36d366097b7103ae2d184121329ba3aa2d7c6cc53273f11af14798110010687477c8deec89d36a23e7948feb074df95362fc8dcbd8ae910ac556a1dee1e755c56b9db5d710c940938ed79bc1895a3646523a58bc55f475a23435a373ecfdd0107fb06734864f79def4e192497362513171530daea81f07fbb9f698afe7e66c6d44db21323144f2657d4a5386a954bb94eef9f64148c33aef6e477eafa2c5c984c01088769e82216310d1827d9bd48645ec23e90de4ef8a8de99e2d351d1df318608566248d80cdc83bdcac382b3c30c670352be87f9069aab5037d0b747208eae9c650109e9796497ff9106d0d1c62e184d83716282870cef61a1ee13d6fc485b521adcce255c96f7d1bca8d8e7e7d454b65783a830bddc9d94092091a268d311ecd84c26010c468c9fb6d41026841ff9f8d7368fa309d4dbea3ea4bbd2feccf94a92cc8a20a226338a8e2126cd16f70eaf15b4fc9be2c3fa19def14e071956a605e9d1ac4162010e23fcb6bd445b7c25afb722250c1acbc061ed964ba9de1326609ae012acdfb96942b2a102a2de99ab96327859a34a2b49a767dbdb62e0a1fb26af60fe44fd496a00106bb0bac77ac68b347645f2fb1ad789ea9bd76fb9b2324f25ae06f97e65246f142df717f662e73948317182c62ce87d79c73def0dba12e5242dfc038382812cfe00126da03c5e56cb15aeeceadc1e17a45753ab4dc0ec7bf6a75ca03143ed4a294f6f61bc3f478a457833e43084ecd7c985bf2f55a55f168aac0e030fc49e845e497101626e9d9a5d9e343f00010000000000000000000000000000000000000000000000000000000000000004c1759167c43f501c2000000000000000000000000000000000000000000000000000000000436f7265020000000000021358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cd66b9590e1c41e0b226937bf9217d1d67fd4e91f574a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d", diff --git a/contract_manager/src/executor.ts b/contract_manager/src/executor.ts index 24171efd..9123bbf1 100644 --- a/contract_manager/src/executor.ts +++ b/contract_manager/src/executor.ts @@ -1,13 +1,14 @@ import { parseVaa } from "@certusone/wormhole-sdk"; import { decodeGovernancePayload } from "xc_admin_common"; import { DefaultStore } from "./store"; +import { PrivateKey } from "./base"; /** * A general executor that tries to find any contract that can execute a given VAA and executes it * @param senderPrivateKey the private key to execute the governance instruction with * @param vaa the VAA to execute */ -export async function executeVaa(senderPrivateKey: string, vaa: Buffer) { +export async function executeVaa(senderPrivateKey: PrivateKey, vaa: Buffer) { const parsedVaa = parseVaa(vaa); const action = decodeGovernancePayload(parsedVaa.payload); if (!action) return; //TODO: handle other actions diff --git a/contract_manager/src/governance.ts b/contract_manager/src/governance.ts index 0df514b2..1c04e929 100644 --- a/contract_manager/src/governance.ts +++ b/contract_manager/src/governance.ts @@ -31,7 +31,7 @@ import { deriveFeeCollectorKey, deriveWormholeBridgeDataKey, } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole"; -import { Storable } from "./base"; +import { KeyValueConfig, Storable } from "./base"; class InvalidTransactionError extends Error { constructor(message: string) { @@ -75,8 +75,8 @@ export class SubmittedWormholeMessage { ) ); - const wormholeAddress = - WORMHOLE_ADDRESS[cluster as keyof typeof WORMHOLE_ADDRESS]!; + const wormholeAddress = WORMHOLE_ADDRESS[cluster]; + if (!wormholeAddress) throw new Error(`Invalid cluster ${cluster}`); let emitter: PublicKey | undefined = undefined; let allInstructions: (ParsedInstruction | PartiallyDecodedInstruction)[] = @@ -103,10 +103,10 @@ export class SubmittedWormholeMessage { * before giving up and throwing an error * @param waitingSeconds how long to wait before giving up */ - async fetchVaa(waitingSeconds: number = 1): Promise { - let rpcUrl = WORMHOLE_API_ENDPOINT[this.cluster]; + async fetchVaa(waitingSeconds = 1): Promise { + const rpcUrl = WORMHOLE_API_ENDPOINT[this.cluster]; - let startTime = Date.now(); + const startTime = Date.now(); while (Date.now() - startTime < waitingSeconds * 1000) { const response = await fetch( `${rpcUrl}/v1/signed_vaa/1/${this.emitter.toBuffer().toString("hex")}/${ @@ -158,12 +158,12 @@ export class WormholeEmitter { preflightCommitment: "confirmed", } ); - let wormholeAddress = - WORMHOLE_ADDRESS[this.cluster as keyof typeof WORMHOLE_ADDRESS]!; - let kp = Keypair.generate(); - let feeCollector = deriveFeeCollectorKey(wormholeAddress); - let emitter = this.wallet.publicKey; - let accounts = { + const wormholeAddress = WORMHOLE_ADDRESS[this.cluster]; + if (!wormholeAddress) throw new Error(`Invalid cluster ${this.cluster}`); + const kp = Keypair.generate(); + const feeCollector = deriveFeeCollectorKey(wormholeAddress); + const emitter = this.wallet.publicKey; + const accounts = { bridge: deriveWormholeBridgeDataKey(wormholeAddress), message: kp.publicKey, emitter: emitter, @@ -230,7 +230,7 @@ export class WormholeMultiSigTransaction { this.cluster ) ); - } catch (e: any) { + } catch (e) { if (!(e instanceof InvalidTransactionError)) throw e; } } @@ -240,7 +240,7 @@ export class WormholeMultiSigTransaction { } export class Vault extends Storable { - static type: string = "vault"; + static type = "vault"; key: PublicKey; squad?: SquadsMesh; cluster: PythCluster; @@ -255,7 +255,11 @@ export class Vault extends Storable { return Vault.type; } - static fromJson(parsed: any): Vault { + static fromJson(parsed: { + type: string; + key: string; + cluster: string; + }): Vault { if (parsed.type !== Vault.type) throw new Error("Invalid type"); return new Vault(parsed.key, parsed.cluster); } @@ -264,7 +268,7 @@ export class Vault extends Storable { return `${this.cluster}_${this.key.toString()}`; } - toJson(): any { + toJson(): KeyValueConfig { return { key: this.key.toString(), cluster: this.cluster, diff --git a/contract_manager/src/shell.ts b/contract_manager/src/shell.ts index f6e49998..756947f6 100644 --- a/contract_manager/src/shell.ts +++ b/contract_manager/src/shell.ts @@ -12,5 +12,6 @@ repl.evalCode( "import { WormholeEvmContract, EvmContract } from './src/contracts/evm';" + "import { AptosContract } from './src/contracts/aptos';" + "import { DefaultStore } from './src/store';" + + "import { toPrivateKey } from './src/base';" + "DefaultStore" ); diff --git a/contract_manager/src/store.ts b/contract_manager/src/store.ts index f9faa0e1..8a95a3e8 100644 --- a/contract_manager/src/store.ts +++ b/contract_manager/src/store.ts @@ -53,7 +53,7 @@ export class Store { } loadAllChains() { - let allChainClasses = { + const allChainClasses = { [CosmWasmChain.type]: CosmWasmChain, [SuiChain.type]: SuiChain, [EvmChain.type]: EvmChain, @@ -61,10 +61,10 @@ export class Store { }; this.getYamlFiles(`${this.path}/chains/`).forEach((yamlFile) => { - let parsedArray = parse(readFileSync(yamlFile, "utf-8")); + const parsedArray = parse(readFileSync(yamlFile, "utf-8")); for (const parsed of parsedArray) { if (allChainClasses[parsed.type] === undefined) return; - let chain = allChainClasses[parsed.type].fromJson(parsed); + const chain = allChainClasses[parsed.type].fromJson(parsed); if (this.chains[chain.getId()]) throw new Error(`Multiple chains with id ${chain.getId()} found`); this.chains[chain.getId()] = chain; @@ -73,7 +73,7 @@ export class Store { } saveAllContracts() { - let contractsByType: Record = {}; + const contractsByType: Record = {}; for (const contract of Object.values(this.contracts)) { if (!contractsByType[contract.getType()]) { contractsByType[contract.getType()] = []; @@ -89,7 +89,7 @@ export class Store { } saveAllChains() { - let chainsByType: Record = {}; + const chainsByType: Record = {}; for (const chain of Object.values(this.chains)) { if (!chainsByType[chain.getType()]) { chainsByType[chain.getType()] = []; @@ -105,20 +105,20 @@ export class Store { } loadAllContracts() { - let allContractClasses = { + const allContractClasses = { [CosmWasmContract.type]: CosmWasmContract, [SuiContract.type]: SuiContract, [EvmContract.type]: EvmContract, [AptosContract.type]: AptosContract, }; this.getYamlFiles(`${this.path}/contracts/`).forEach((yamlFile) => { - let parsedArray = parse(readFileSync(yamlFile, "utf-8")); + const parsedArray = parse(readFileSync(yamlFile, "utf-8")); for (const parsed of parsedArray) { if (allContractClasses[parsed.type] === undefined) return; if (!this.chains[parsed.chain]) throw new Error(`Chain ${parsed.chain} not found`); const chain = this.chains[parsed.chain]; - let chainContract = allContractClasses[parsed.type].fromJson( + const chainContract = allContractClasses[parsed.type].fromJson( chain, parsed ); @@ -133,7 +133,7 @@ export class Store { loadAllVaults() { this.getYamlFiles(`${this.path}/vaults/`).forEach((yamlFile) => { - let parsedArray = parse(readFileSync(yamlFile, "utf-8")); + const parsedArray = parse(readFileSync(yamlFile, "utf-8")); for (const parsed of parsedArray) { if (parsed.type !== Vault.type) return; diff --git a/target_chains/cosmwasm/tools/src/helper.ts b/target_chains/cosmwasm/tools/src/helper.ts index c789721b..c28c452a 100644 --- a/target_chains/cosmwasm/tools/src/helper.ts +++ b/target_chains/cosmwasm/tools/src/helper.ts @@ -18,7 +18,7 @@ export function getChainIdsForStableDeployment(): ChainId[] { ]; } -export function getChainIdsForEdgeDeployment(): ChainId[] { +export function getChainIdsForBetaDeployment(): ChainId[] { return [ ChainId.INJECTIVE_TESTNET, ChainId.OSMOSIS_TESTNET_5, @@ -28,7 +28,7 @@ export function getChainIdsForEdgeDeployment(): ChainId[] { ]; } -export type DeploymentType = "stable" | "edge"; +export type DeploymentType = "stable" | "beta"; // We have released the compile contacts on github. If a chain needs some specific // feature in a contract, a version of the contract with that specific features is diff --git a/target_chains/cosmwasm/tools/src/instantiate-pyth.ts b/target_chains/cosmwasm/tools/src/instantiate-pyth.ts index a22121b5..ab94ddc7 100644 --- a/target_chains/cosmwasm/tools/src/instantiate-pyth.ts +++ b/target_chains/cosmwasm/tools/src/instantiate-pyth.ts @@ -12,7 +12,7 @@ import { Pipeline } from "./pipeline"; import { DeploymentType, WORMHOLE_CONTRACT_VERSION, - getChainIdsForEdgeDeployment, + getChainIdsForBetaDeployment, getChainIdsForStableDeployment, getContractBytesDict, getPythInstantiateFileName, @@ -35,7 +35,7 @@ const argv = yargs(hideBin(process.argv)) .option("deploy", { type: "string", desc: "Execute this script for the given networks.", - choices: ["edge", "stable"], + choices: ["beta", "stable"], demandOption: "Please provide the deployment type", }) .help() @@ -48,7 +48,7 @@ async function run() { if (argv.deploy === "stable") { chainIds = getChainIdsForStableDeployment(); } else { - chainIds = getChainIdsForEdgeDeployment(); + chainIds = getChainIdsForBetaDeployment(); } // get the wasm code from github diff --git a/target_chains/cosmwasm/tools/src/test.ts b/target_chains/cosmwasm/tools/src/test.ts index 615abfc9..3dab49dc 100644 --- a/target_chains/cosmwasm/tools/src/test.ts +++ b/target_chains/cosmwasm/tools/src/test.ts @@ -8,7 +8,7 @@ import { Pipeline } from "./pipeline"; import { PythWrapperExecutor, PythWrapperQuerier } from "./pyth-wrapper"; import { DeploymentType, - getChainIdsForEdgeDeployment, + getChainIdsForBetaDeployment, getChainIdsForStableDeployment, getPythContractAddress, getTestPythContractFileName, @@ -29,7 +29,7 @@ const argv = yargs(hideBin(process.argv)) .option("deploy", { type: "string", desc: "test the following deployment type.", - choices: ["stable", "edge"], + choices: ["stable", "beta"], demandOption: "Please provide the deployment type", }) .help() @@ -42,7 +42,7 @@ async function run() { if (argv.deploy === "stable") { chainIds = getChainIdsForStableDeployment(); } else { - chainIds = getChainIdsForEdgeDeployment(); + chainIds = getChainIdsForBetaDeployment(); } for (let chainId of chainIds) { diff --git a/target_chains/cosmwasm/tools/src/wormhole-stub.ts b/target_chains/cosmwasm/tools/src/wormhole-stub.ts index 9c4af757..8505f3b6 100644 --- a/target_chains/cosmwasm/tools/src/wormhole-stub.ts +++ b/target_chains/cosmwasm/tools/src/wormhole-stub.ts @@ -12,7 +12,7 @@ import { import { Pipeline } from "./pipeline"; import { DeploymentType, - getChainIdsForEdgeDeployment, + getChainIdsForBetaDeployment, getChainIdsForStableDeployment, getWormholeFileName, hexToBase64, @@ -33,7 +33,7 @@ const argv = yargs(hideBin(process.argv)) .option("deploy", { type: "string", desc: "Execute this script for the given deployment type.", - choices: ["stable", "edge"], + choices: ["stable", "beta"], demandOption: "Please provide the deployment type", }) .help() @@ -60,7 +60,7 @@ async function run() { if (argv.deploy === "stable") { chainIds = getChainIdsForStableDeployment(); } else { - chainIds = getChainIdsForEdgeDeployment(); + chainIds = getChainIdsForBetaDeployment(); } for (let chainId of chainIds) { diff --git a/target_chains/ethereum/contracts/scripts/contractManagerConfig.js b/target_chains/ethereum/contracts/scripts/contractManagerConfig.js index 4b37aa71..6f376275 100644 --- a/target_chains/ethereum/contracts/scripts/contractManagerConfig.js +++ b/target_chains/ethereum/contracts/scripts/contractManagerConfig.js @@ -16,7 +16,7 @@ function convertChainId(number) { function getDefaultConfig(chainName) { const chain = DefaultStore.chains[chainName]; const { dataSources, governanceDataSource, wormholeConfig } = - getDefaultDeploymentConfig(chain.isMainnet() ? "stable" : "edge"); + getDefaultDeploymentConfig(chain.isMainnet() ? "stable" : "beta"); const emitterChainIds = dataSources.map((dataSource) => convertChainId(dataSource.emitterChain) diff --git a/target_chains/sui/cli/src/cli.ts b/target_chains/sui/cli/src/cli.ts index 7bb52944..386ab937 100644 --- a/target_chains/sui/cli/src/cli.ts +++ b/target_chains/sui/cli/src/cli.ts @@ -182,7 +182,7 @@ yargs(hideBin(process.argv)) provider ); const result = await publishPackage(wallet, argv.path); - const deploymentType = chain.isMainnet() ? "stable" : "edge"; + const deploymentType = chain.isMainnet() ? "stable" : "beta"; const config = getDefaultDeploymentConfig(deploymentType); await initPyth( wallet,