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