[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
This commit is contained in:
Mohammad Amin Khashkhashi Moghaddam 2023-08-23 16:29:43 +02:00 committed by GitHub
parent f316a512c3
commit b9dbd54d5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 317 additions and 208 deletions

View File

@ -0,0 +1,6 @@
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
};

View File

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

View File

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

View File

@ -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<string, string | number | boolean>;
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<any>;
): Promise<TxResult>;
/**
* 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<any>;
): Promise<TxResult>;
/**
* 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<DataSource>;
}
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: [
{

View File

@ -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<string, string> & {
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<string> {
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,

View File

@ -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<any> {
): Promise<TxResult> {
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<TxResult> {
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<any> {
): Promise<TxResult> {
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<PriceFeed | undefined> {
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<DataSource[]> {
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<DataSource> {
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);
}

View File

@ -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<string, string>;
}
async getCurrentGuardianSetIndex(): Promise<number> {
@ -68,28 +67,31 @@ export class WormholeCosmWasmContract extends WormholeContract {
}
async upgradeGuardianSets(
senderPrivateKey: string,
senderPrivateKey: PrivateKey,
vaa: Buffer
): Promise<any> {
): Promise<TxResult> {
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<DataSource[]> {
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<DataSource> {
@ -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<CosmWasmContract> {
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<CosmWasmContract> {
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<number> {
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<string, string>;
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<string> {
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<WormholeCosmWasmContract> {
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<any> {
let querier = await this.getQuerier();
async getUpdateFee(msgs: string[]): Promise<Coin> {
const querier = await this.getQuerier();
return querier.getUpdateFee(this.address, msgs);
}
async getBaseUpdateFee(): Promise<any> {
async getBaseUpdateFee(): Promise<{ amount: string; denom: string }> {
const config = await this.getConfig();
return config.config_v1.fee;
}
async getVersion(): Promise<any> {
async getVersion(): Promise<string> {
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"
);

View File

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

View File

@ -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<ObjectId> {
const provider = this.getProvider();
let result = await provider.getDynamicFieldObject({
const result = await provider.getDynamicFieldObject({
parentId: this.stateId,
name: {
type: "vector<u8>",
@ -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<ObjectId | undefined> {
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<TxResult> {
// 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<TxResult> {
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<TxResult> {
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<TxResult> {
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<DataSource[]> {
const provider = this.getProvider();
let result = await provider.getDynamicFieldObject({
const result = await provider.getDynamicFieldObject({
parentId: this.stateId,
name: {
type: "vector<u8>",
@ -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(

View File

@ -1,3 +1,5 @@
import { PrivateKey, TxResult } from "../base";
export abstract class WormholeContract {
abstract getCurrentGuardianSetIndex(): Promise<number>;
@ -12,15 +14,15 @@ export abstract class WormholeContract {
* @param vaa
*/
abstract upgradeGuardianSets(
senderPrivateKey: string,
senderPrivateKey: PrivateKey,
vaa: Buffer
): Promise<any>;
): Promise<TxResult>;
/**
* 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",

View File

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

View File

@ -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<Buffer> {
let rpcUrl = WORMHOLE_API_ENDPOINT[this.cluster];
async fetchVaa(waitingSeconds = 1): Promise<Buffer> {
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,

View File

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

View File

@ -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<string, Contract[]> = {};
const contractsByType: Record<string, Contract[]> = {};
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<string, Chain[]> = {};
const chainsByType: Record<string, Chain[]> = {};
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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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