[contract-manager] Contract manager improvements (#1000)

* Use arrays instead of separate files per config

* Remove redundant endpoint on cosmwasm

* Add functions for upgrading the wormhole guardian sets

* Add wormhole contract management on evm and cosmwasm

* Add getter functions to check what sort of wormhole-deployment is used

* Reorganize contract manager package to be used via other packages

* Remove .env files per network and create a script that outputs the same file

* Use env variables in truffle config and output config in deployments

* Add executeUpdatePriceFeed to contract interface

* Add update pricefeed script

* Add saving functionality to store

* Save new contract configs automatically on Evm

* Make deploy script use the create-env.js internally

* Add utility function to get implementation address for Evm Proxy contracts

* Add shimmer testnet and replace evmos nunfunctional rpc

* New procedure for contract verification

* Update docs and remove duplicate configurations

* Remove shimmer configs

* Read default data source configs via contract manager

* Remove flattened contract before compiling/deploying
This commit is contained in:
Mohammad Amin Khashkhashi Moghaddam 2023-08-07 14:13:29 +02:00 committed by GitHub
parent a9a21ae977
commit 272f3c1984
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
230 changed files with 1898 additions and 2483 deletions

View File

@ -1,10 +1,15 @@
{
"name": "@pythnetwork/pyth-contract-manager",
"name": "contract_manager",
"version": "1.0.0",
"description": "Set of tools to manage pyth contracts",
"private": true,
"main": "index.js",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib/**/*"
],
"scripts": {
"build": "tsc",
"shell": "ts-node ./src/shell.ts"
},
"author": "",

View File

@ -0,0 +1,52 @@
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { DefaultStore } from "../src";
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
const parser = yargs(hideBin(process.argv))
.scriptName("update_pricefeed.ts")
.usage(
"Usage: $0 --contract <contract_id> --feed-id <feed-id> --private-key <private-key>"
)
.options({
contract: {
type: "string",
demandOption: true,
desc: "Contract to update price feeds for (e.g mumbai_0xff1a0f4744e8582DF1aE09D5611b887B6a12925C)",
},
"feed-id": {
type: "array",
demandOption: true,
desc: "Price feed ids to update without the leading 0x (e.g f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b). Can be provided multiple times for multiple feed updates",
},
"private-key": {
type: "string",
demandOption: true,
desc: "Private key to use to sign transaction",
},
endpoint: {
type: "string",
desc: "Price service endpoint to use, defaults to https://xc-mainnet.pyth.network for mainnet and https://xc-testnet.pyth.network for testnet",
},
});
async function main() {
const argv = await parser.argv;
const contract = DefaultStore.contracts[argv.contract];
if (!contract) {
throw new Error(`Contract ${argv.contract} not found`);
}
const defaultEndpoint = contract.getChain().isMainnet()
? "https://xc-mainnet.pyth.network"
: "https://xc-testnet.pyth.network";
const priceService = new PriceServiceConnection(
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"))
);
}
main();

View File

@ -69,6 +69,16 @@ export abstract class Contract extends Storable {
*/
abstract getPriceFeed(feedId: string): Promise<PriceFeed | undefined>;
/**
* Executes the update instructions contained in the VAAs using the sender credentials
* @param senderPrivateKey private key of the sender in hex format without 0x prefix
* @param vaas an array of VAAs containing price update messages to execute
*/
abstract executeUpdatePriceFeed(
senderPrivateKey: string,
vaas: Buffer[]
): Promise<any>;
/**
* Executes the governance instruction contained in the VAA using the sender credentials
* @param senderPrivateKey private key of the sender in hex format without 0x prefix
@ -84,3 +94,77 @@ export abstract class Contract extends Storable {
*/
abstract getGovernanceDataSource(): Promise<DataSource>;
}
export function getDefaultDeploymentConfig(deploymentType: "stable" | "edge"): {
dataSources: DataSource[];
governanceDataSource: DataSource;
wormholeConfig: {
governanceChainId: Number;
governanceContract: string; // 32 byte address in 64 char hex format
initialGuardianSet: string[]; // 20 byte addresses in 40 char hex format
};
} {
if (deploymentType === "stable")
return {
dataSources: [
{
emitterChain: 1,
emitterAddress:
"6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25",
},
{
emitterChain: 26,
emitterAddress:
"f8cd23c2ab91237730770bbea08d61005cdda0984348f3f6eecb559638c0bba0",
},
{
emitterChain: 26,
emitterAddress:
"e101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71",
},
],
governanceDataSource: {
emitterChain: 1,
emitterAddress:
"5635979a221c34931e32620b9293a463065555ea71fe97cd6237ade875b12e9e",
},
wormholeConfig: {
governanceChainId: 1,
governanceContract:
"0000000000000000000000000000000000000000000000000000000000000004",
initialGuardianSet: ["58cc3ae5c097b213ce3c81979e1b9f9570746aa5"],
},
};
else if (deploymentType === "edge")
return {
dataSources: [
{
emitterChain: 1,
emitterAddress:
"f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0",
},
{
emitterChain: 26,
emitterAddress:
"a27839d641b07743c0cb5f68c51f8cd31d2c0762bec00dc6fcd25433ef1ab5b6",
},
{
emitterChain: 26,
emitterAddress:
"e101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71",
},
],
governanceDataSource: {
emitterChain: 1,
emitterAddress:
"63278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c385",
},
wormholeConfig: {
governanceChainId: 1,
governanceContract:
"0000000000000000000000000000000000000000000000000000000000000004",
initialGuardianSet: ["13947bd48b18e53fdaeee77f3473391ac727c638"],
},
};
else throw new Error(`Invalid deployment type ${deploymentType}`);
}

View File

@ -14,7 +14,12 @@ import {
} from "xc_admin_common";
import { AptosClient } from "aptos";
import Web3 from "web3";
import { CosmwasmQuerier } from "@pythnetwork/cosmwasm-deploy-tools";
import {
CosmwasmExecutor,
CosmwasmQuerier,
InjectiveExecutor,
} from "@pythnetwork/cosmwasm-deploy-tools";
import { Network } from "@injectivelabs/networks";
export abstract class Chain extends Storable {
public wormholeChainName: ChainName;
@ -119,8 +124,7 @@ export class CosmWasmChain extends Chain {
id: string,
mainnet: boolean,
wormholeChainName: string,
public querierEndpoint: string,
public executorEndpoint: string,
public endpoint: string,
public gasPrice: string,
public prefix: string,
public feeDenom: string
@ -134,8 +138,7 @@ export class CosmWasmChain extends Chain {
parsed.id,
parsed.mainnet,
parsed.wormholeChainName,
parsed.querierEndpoint,
parsed.executorEndpoint,
parsed.endpoint,
parsed.gasPrice,
parsed.prefix,
parsed.feeDenom
@ -144,8 +147,7 @@ export class CosmWasmChain extends Chain {
toJson(): any {
return {
querierEndpoint: this.querierEndpoint,
executorEndpoint: this.executorEndpoint,
endpoint: this.endpoint,
id: this.id,
wormholeChainName: this.wormholeChainName,
mainnet: this.mainnet,
@ -161,13 +163,27 @@ export class CosmWasmChain extends Chain {
}
async getCode(codeId: number): Promise<Buffer> {
const chainQuerier = await CosmwasmQuerier.connect(this.querierEndpoint);
const chainQuerier = await CosmwasmQuerier.connect(this.endpoint);
return await chainQuerier.getCode({ codeId });
}
generateGovernanceUpgradePayload(codeId: bigint): Buffer {
return new CosmosUpgradeContract(this.wormholeChainName, codeId).encode();
}
async getExecutor(privateKey: string) {
if (this.getId().indexOf("injective") > -1) {
return InjectiveExecutor.fromPrivateKey(
this.isMainnet() ? Network.Mainnet : Network.Testnet,
privateKey
);
}
return new CosmwasmExecutor(
this.endpoint,
await CosmwasmExecutor.getSignerFromPrivateKey(privateKey, this.prefix),
this.gasPrice + this.feeDenom
);
}
}
export class SuiChain extends Chain {

View File

@ -2,19 +2,17 @@ import { Chain, CosmWasmChain } from "../chains";
import { readFileSync } from "fs";
import {
ContractInfoResponse,
CosmwasmExecutor,
CosmwasmQuerier,
DeploymentType,
getPythConfig,
InjectiveExecutor,
Price,
PythWrapperExecutor,
PythWrapperQuerier,
} from "@pythnetwork/cosmwasm-deploy-tools";
import { CHAINS, DataSource } from "xc_admin_common";
import { Network } from "@injectivelabs/networks";
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { Contract } from "../base";
import { WormholeContract } from "./wormhole";
/**
* Variables here need to be snake case to match the on-chain contract configs
@ -37,6 +35,52 @@ namespace CosmWasmContract {
}
}
export class WormholeCosmWasmContract extends WormholeContract {
constructor(public chain: CosmWasmChain, public address: string) {
super();
}
async getConfig() {
const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint);
return (await chainQuerier.getAllContractState({
contractAddr: this.address,
})) as any;
}
async getCurrentGuardianSetIndex(): Promise<number> {
const config = await this.getConfig();
return JSON.parse(config["\x00\x06config"])["guardian_set_index"];
}
async getGuardianSet(): Promise<string[]> {
const config = await this.getConfig();
const guardianSetIndex = JSON.parse(config["\x00\x06config"])[
"guardian_set_index"
];
let key = "\x00\fguardian_set";
//append guardianSetIndex as 4 bytes to key string
key += Buffer.from(guardianSetIndex.toString(16).padStart(8, "0"), "hex");
const guardianSet = JSON.parse(config[key])["addresses"];
return guardianSet.map((entry: { bytes: string }) =>
Buffer.from(entry.bytes, "base64").toString("hex")
);
}
async upgradeGuardianSets(
senderPrivateKey: string,
vaa: Buffer
): Promise<any> {
const executor = await this.chain.getExecutor(senderPrivateKey);
return executor.executeContract({
contractAddr: this.address,
msg: {
submit_v_a_a: { vaa: vaa.toString("base64") },
},
});
}
}
export class CosmWasmContract extends Contract {
async getDataSources(): Promise<DataSource[]> {
const config = await this.getConfig();
@ -102,7 +146,7 @@ export class CosmWasmContract extends Contract {
wasmPath: string
) {
const contractBytes = readFileSync(wasmPath);
let executor = await this.getExecutor(chain, privateKey);
let executor = await chain.getExecutor(privateKey);
return executor.storeCode({ contractBytes });
}
@ -119,7 +163,7 @@ export class CosmWasmContract extends Contract {
config: CosmWasmContract.DeploymentConfig,
privateKey: string
): Promise<CosmWasmContract> {
let executor = await this.getExecutor(chain, privateKey);
let executor = await chain.getExecutor(privateKey);
let result = await executor.instantiateContract({
codeId: codeId,
instMsg: config,
@ -154,20 +198,6 @@ export class CosmWasmContract extends Contract {
return this.initialize(chain, codeId, config, privateKey);
}
private static async getExecutor(chain: CosmWasmChain, privateKey: string) {
if (chain.getId().indexOf("injective") > -1) {
return InjectiveExecutor.fromPrivateKey(
chain.isMainnet() ? Network.Mainnet : Network.Testnet,
privateKey
);
}
return new CosmwasmExecutor(
chain.executorEndpoint,
await CosmwasmExecutor.getSignerFromPrivateKey(privateKey, chain.prefix),
chain.gasPrice + chain.feeDenom
);
}
getId(): string {
return `${this.chain.getId()}_${this.address}`;
}
@ -181,9 +211,7 @@ export class CosmWasmContract extends Contract {
}
async getQuerier(): Promise<PythWrapperQuerier> {
const chainQuerier = await CosmwasmQuerier.connect(
this.chain.querierEndpoint
);
const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint);
const pythQuerier = new PythWrapperQuerier(chainQuerier);
return pythQuerier;
}
@ -194,16 +222,12 @@ export class CosmWasmContract extends Contract {
}
async getWasmContractInfo(): Promise<ContractInfoResponse> {
const chainQuerier = await CosmwasmQuerier.connect(
this.chain.querierEndpoint
);
const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint);
return chainQuerier.getContractInfo({ contractAddr: this.address });
}
async getConfig() {
const chainQuerier = await CosmwasmQuerier.connect(
this.chain.querierEndpoint
);
const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint);
let allStates = (await chainQuerier.getAllContractState({
contractAddr: this.address,
})) as any;
@ -300,10 +324,7 @@ export class CosmWasmContract extends Contract {
async executeUpdatePriceFeed(senderPrivateKey: string, vaas: Buffer[]) {
const base64Vaas = vaas.map((v) => v.toString("base64"));
const fund = await this.getUpdateFee(base64Vaas);
let executor = await CosmWasmContract.getExecutor(
this.chain,
senderPrivateKey
);
let executor = await this.chain.getExecutor(senderPrivateKey);
let pythExecutor = new PythWrapperExecutor(executor);
return pythExecutor.executeUpdatePriceFeeds({
contractAddr: this.address,
@ -313,7 +334,7 @@ export class CosmWasmContract extends Contract {
}
async executeGovernanceInstruction(privateKey: string, vaa: Buffer) {
let executor = await CosmWasmContract.getExecutor(this.chain, privateKey);
let executor = await this.chain.getExecutor(privateKey);
let pythExecutor = new PythWrapperExecutor(executor);
return pythExecutor.executeGovernanceInstruction({
contractAddr: this.address,
@ -321,6 +342,13 @@ export class CosmWasmContract extends Contract {
});
}
async getWormholeContract(): Promise<WormholeCosmWasmContract> {
let config = await this.getConfig();
const chainQuerier = await CosmwasmQuerier.connect(this.chain.endpoint);
const wormholeAddress = config.config_v1.wormhole_contract;
return new WormholeCosmWasmContract(this.chain, wormholeAddress);
}
async getUpdateFee(msgs: string[]): Promise<any> {
let querier = await this.getQuerier();
return querier.getUpdateFee(this.address, msgs);
@ -341,7 +369,7 @@ export class CosmWasmContract extends Contract {
}
async getValidTimePeriod() {
let client = await CosmWasmClient.connect(this.chain.querierEndpoint);
let client = await CosmWasmClient.connect(this.chain.endpoint);
let result = await client.queryContractSmart(
this.address,
"get_valid_time_period"

View File

@ -3,6 +3,7 @@ import PythInterfaceAbi from "@pythnetwork/pyth-sdk-solidity/abis/IPyth.json";
import { Contract } from "../base";
import { Chain, EvmChain } from "../chains";
import { DataSource } from "xc_admin_common";
import { WormholeContract } from "./wormhole";
// Just to make sure tx gas limit is enough
const GAS_ESTIMATE_MULTIPLIER = 2;
@ -184,27 +185,94 @@ const WORMHOLE_ABI = [
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes",
name: "_vm",
type: "bytes",
},
],
name: "submitNewGuardianSet",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "messageFee",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
] as any;
export class WormholeEvmContract {
constructor(public chain: EvmChain, public address: string) {}
export class WormholeEvmContract extends WormholeContract {
constructor(public chain: EvmChain, public address: string) {
super();
}
getContract() {
const web3 = new Web3(this.chain.getRpcUrl());
return new web3.eth.Contract(WORMHOLE_ABI, this.address);
}
async getCurrentGuardianSetIndex(): Promise<number> {
const wormholeContract = this.getContract();
return Number(
await wormholeContract.methods.getCurrentGuardianSetIndex().call()
);
}
/**
* Returns an array of guardian addresses used for VAA verification in this contract
*/
async getGuardianSet(): Promise<string[]> {
const wormholeContract = this.getContract();
const currentIndex = await wormholeContract.methods
.getCurrentGuardianSetIndex()
.call();
const currentIndex = await this.getCurrentGuardianSetIndex();
const [currentSet] = await wormholeContract.methods
.getGuardianSet(currentIndex)
.call();
return currentSet;
}
/**
* Checks whether this contract is a deployment of wormhole-receiver or wormhole.
* The wormhole-receiver is a subset of the wormhole contract optimized for just verifying the VAAs.
* The check is done by calling a function that only exists in the wormhole contract and not in the wormhole-receiver.
* If the function call fails, we know that this is a wormhole-receiver contract.
*/
async isWormholeReceiver(): Promise<boolean> {
const wormholeContract = this.getContract();
try {
await wormholeContract.methods.messageFee().call();
return false;
} catch (e) {
return true;
}
}
async upgradeGuardianSets(senderPrivateKey: string, 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);
const transactionObject = wormholeContract.methods.submitNewGuardianSet(
"0x" + vaa.toString("hex")
);
const gasEstiamte = await transactionObject.estimateGas({
from: address,
gas: 100000000,
});
return transactionObject.send({
from: address,
gas: gasEstiamte * GAS_ESTIMATE_MULTIPLIER,
gasPrice: await this.chain.getGasPrice(),
});
}
}
export class EvmContract extends Contract {
@ -283,6 +351,16 @@ export class EvmContract extends Contract {
return web3.eth.getCode(this.address);
}
async getImplementationAddress(): Promise<string> {
const web3 = new Web3(this.chain.getRpcUrl());
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) according to EIP-1967
let storagePosition =
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
let address = await web3.eth.getStorageAt(this.address, storagePosition);
address = "0x" + address.slice(26);
return address;
}
/**
* Returns the keccak256 digest of the contract bytecode after replacing any occurrences of the contract addr in
* the bytecode with 0.The bytecode stores the deployment address as an immutable variable.

View File

@ -0,0 +1,5 @@
export * from "./aptos";
export * from "./cosmwasm";
export * from "./evm";
export * from "./sui";
export * from "./wormhole";

View File

@ -195,6 +195,10 @@ export class SuiContract extends Contract {
return this.executeTransaction(tx, keypair);
}
async executeUpdatePriceFeed(senderPrivateKey: string, vaas: Buffer[]) {
throw new Error("Not implemented");
}
async executeGovernanceInstruction(senderPrivateKey: string, vaa: Buffer) {
const keypair = Ed25519Keypair.fromSecretKey(
Buffer.from(senderPrivateKey, "hex")

View File

@ -0,0 +1,35 @@
export abstract class WormholeContract {
abstract getCurrentGuardianSetIndex(): Promise<number>;
/**
* Returns an array of guardian addresses used for VAA verification in this contract
*/
abstract getGuardianSet(): Promise<string[]>;
/**
* Upgrades the guardian set of this contract using an upgrade VAA
* @param senderPrivateKey
* @param vaa
*/
abstract upgradeGuardianSets(
senderPrivateKey: string,
vaa: Buffer
): Promise<any>;
/**
* 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) {
const MAINNET_UPGRADE_VAAS = [
"010000000001007ac31b282c2aeeeb37f3385ee0de5f8e421d30b9e5ae8ba3d4375c1c77a86e77159bb697d9c456d6f8c02d22a94b1279b65b0d6a9957e7d3857423845ac758e300610ac1d2000000030001000000000000000000000000000000000000000000000000000000000000000400000000000005390000000000000000000000000000000000000000000000000000000000436f7265020000000000011358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cdeb5f7389fa26941519f0863349c223b73a6ddee774a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d",
"01000000010d0012e6b39c6da90c5dfd3c228edbb78c7a4c97c488ff8a346d161a91db067e51d638c17216f368aa9bdf4836b8645a98018ca67d2fec87d769cabfdf2406bf790a0002ef42b288091a670ef3556596f4f47323717882881eaf38e03345078d07a156f312b785b64dae6e9a87e3d32872f59cb1931f728cecf511762981baf48303668f0103cef2616b84c4e511ff03329e0853f1bd7ee9ac5ba71d70a4d76108bddf94f69c2a8a84e4ee94065e8003c334e899184943634e12043d0dda78d93996da073d190104e76d166b9dac98f602107cc4b44ac82868faf00b63df7d24f177aa391e050902413b71046434e67c770b19aecdf7fce1d1435ea0be7262e3e4c18f50ddc8175c0105d9450e8216d741e0206a50f93b750a47e0a258b80eb8fed1314cc300b3d905092de25cd36d366097b7103ae2d184121329ba3aa2d7c6cc53273f11af14798110010687477c8deec89d36a23e7948feb074df95362fc8dcbd8ae910ac556a1dee1e755c56b9db5d710c940938ed79bc1895a3646523a58bc55f475a23435a373ecfdd0107fb06734864f79def4e192497362513171530daea81f07fbb9f698afe7e66c6d44db21323144f2657d4a5386a954bb94eef9f64148c33aef6e477eafa2c5c984c01088769e82216310d1827d9bd48645ec23e90de4ef8a8de99e2d351d1df318608566248d80cdc83bdcac382b3c30c670352be87f9069aab5037d0b747208eae9c650109e9796497ff9106d0d1c62e184d83716282870cef61a1ee13d6fc485b521adcce255c96f7d1bca8d8e7e7d454b65783a830bddc9d94092091a268d311ecd84c26010c468c9fb6d41026841ff9f8d7368fa309d4dbea3ea4bbd2feccf94a92cc8a20a226338a8e2126cd16f70eaf15b4fc9be2c3fa19def14e071956a605e9d1ac4162010e23fcb6bd445b7c25afb722250c1acbc061ed964ba9de1326609ae012acdfb96942b2a102a2de99ab96327859a34a2b49a767dbdb62e0a1fb26af60fe44fd496a00106bb0bac77ac68b347645f2fb1ad789ea9bd76fb9b2324f25ae06f97e65246f142df717f662e73948317182c62ce87d79c73def0dba12e5242dfc038382812cfe00126da03c5e56cb15aeeceadc1e17a45753ab4dc0ec7bf6a75ca03143ed4a294f6f61bc3f478a457833e43084ecd7c985bf2f55a55f168aac0e030fc49e845e497101626e9d9a5d9e343f00010000000000000000000000000000000000000000000000000000000000000004c1759167c43f501c2000000000000000000000000000000000000000000000000000000000436f7265020000000000021358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cd66b9590e1c41e0b226937bf9217d1d67fd4e91f574a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d",
"01000000020d00ce45474d9e1b1e7790a2d210871e195db53a70ffd6f237cfe70e2686a32859ac43c84a332267a8ef66f59719cf91cc8df0101fd7c36aa1878d5139241660edc0010375cc906156ae530786661c0cd9aef444747bc3d8d5aa84cac6a6d2933d4e1a031cffa30383d4af8131e929d9f203f460b07309a647d6cd32ab1cc7724089392c000452305156cfc90343128f97e499311b5cae174f488ff22fbc09591991a0a73d8e6af3afb8a5968441d3ab8437836407481739e9850ad5c95e6acfcc871e951bc30105a7956eefc23e7c945a1966d5ddbe9e4be376c2f54e45e3d5da88c2f8692510c7429b1ea860ae94d929bd97e84923a18187e777aa3db419813a80deb84cc8d22b00061b2a4f3d2666608e0aa96737689e3ba5793810ff3a52ff28ad57d8efb20967735dc5537a2e43ef10f583d144c12a1606542c207f5b79af08c38656d3ac40713301086b62c8e130af3411b3c0d91b5b50dcb01ed5f293963f901fc36e7b0e50114dce203373b32eb45971cef8288e5d928d0ed51cd86e2a3006b0af6a65c396c009080009e93ab4d2c8228901a5f4525934000b2c26d1dc679a05e47fdf0ff3231d98fbc207103159ff4116df2832eea69b38275283434e6cd4a4af04d25fa7a82990b707010aa643f4cf615dfff06ffd65830f7f6cf6512dabc3690d5d9e210fdc712842dc2708b8b2c22e224c99280cd25e5e8bfb40e3d1c55b8c41774e287c1e2c352aecfc010b89c1e85faa20a30601964ccc6a79c0ae53cfd26fb10863db37783428cd91390a163346558239db3cd9d420cfe423a0df84c84399790e2e308011b4b63e6b8015010ca31dcb564ac81a053a268d8090e72097f94f366711d0c5d13815af1ec7d47e662e2d1bde22678113d15963da100b668ba26c0c325970d07114b83c5698f46097010dc9fda39c0d592d9ed92cd22b5425cc6b37430e236f02d0d1f8a2ef45a00bde26223c0a6eb363c8b25fd3bf57234a1d9364976cefb8360e755a267cbbb674b39501108db01e444ab1003dd8b6c96f8eb77958b40ba7a85fefecf32ad00b7a47c0ae7524216262495977e09c0989dd50f280c21453d3756843608eacd17f4fdfe47600001261025228ef5af837cb060bcd986fcfa84ccef75b3fa100468cfd24e7fadf99163938f3b841a33496c2706d0208faab088bd155b2e20fd74c625bb1cc8c43677a0163c53c409e0c5dfa000100000000000000000000000000000000000000000000000000000000000000046c5a054d7833d1e42000000000000000000000000000000000000000000000000000000000436f7265020000000000031358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cd15e7caf07c4e3dc8e7c469f92c8cd88fb8005a2074a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d",
];
const currentIndex = await this.getCurrentGuardianSetIndex();
for (let i = currentIndex; i < MAINNET_UPGRADE_VAAS.length; i++) {
const vaa = MAINNET_UPGRADE_VAAS[i];
await this.upgradeGuardianSets(senderPrivateKey, Buffer.from(vaa, "hex"));
}
}
}

View File

@ -0,0 +1,30 @@
import { parseVaa } from "@certusone/wormhole-sdk";
import { decodeGovernancePayload } from "xc_admin_common";
import { DefaultStore } from "./store";
/**
* 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) {
const parsedVaa = parseVaa(vaa);
const action = decodeGovernancePayload(parsedVaa.payload);
if (!action) return; //TODO: handle other actions
for (const contract of Object.values(DefaultStore.contracts)) {
if (
action.targetChainId === "unset" ||
contract.getChain().wormholeChainName === action.targetChainId
) {
const governanceSource = await contract.getGovernanceDataSource();
if (
governanceSource.emitterAddress ===
parsedVaa.emitterAddress.toString("hex") &&
governanceSource.emitterChain === parsedVaa.emitterChain
) {
// TODO: check governance sequence number as well
await contract.executeGovernanceInstruction(senderPrivateKey, vaa);
}
}
}
}

View File

@ -20,7 +20,6 @@ import SquadsMesh from "@sqds/mesh";
import { AnchorProvider, Wallet } from "@coral-xyz/anchor/dist/cjs/provider";
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
import {
decodeGovernancePayload,
executeProposal,
MultisigVault,
WORMHOLE_ADDRESS,
@ -33,8 +32,6 @@ import {
deriveWormholeBridgeDataKey,
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
import { Storable } from "./base";
import { parseVaa } from "@certusone/wormhole-sdk";
import { DefaultStore } from "./store";
class InvalidTransactionError extends Error {
constructor(message: string) {
@ -127,33 +124,6 @@ export class SubmittedWormholeMessage {
}
}
/**
* 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) {
const parsedVaa = parseVaa(vaa);
const action = decodeGovernancePayload(parsedVaa.payload);
if (!action) return; //TODO: handle other actions
for (const contract of Object.values(DefaultStore.contracts)) {
if (
action.targetChainId === "unset" ||
contract.getChain().wormholeChainName === action.targetChainId
) {
const governanceSource = await contract.getGovernanceDataSource();
if (
governanceSource.emitterAddress ===
parsedVaa.emitterAddress.toString("hex") &&
governanceSource.emitterChain === parsedVaa.emitterChain
) {
// TODO: check governance sequence number as well
await contract.executeGovernanceInstruction(senderPrivateKey, vaa);
}
}
}
}
function asPythCluster(cluster: string): PythCluster {
const pythCluster = cluster as PythCluster;
getPythClusterApiUrl(pythCluster); // throws if cluster is invalid

View File

@ -0,0 +1,5 @@
export * from "./governance";
export * from "./chains";
export * from "./store";
export * from "./base";
export * from "./contracts";

View File

@ -6,23 +6,18 @@ import {
GlobalChain,
SuiChain,
} from "./chains";
import { CosmWasmContract } from "./contracts/cosmwasm";
import { SuiContract } from "./contracts/sui";
import {
AptosContract,
CosmWasmContract,
EvmContract,
SuiContract,
} from "./contracts";
import { Contract } from "./base";
import { parse, stringify } from "yaml";
import {
existsSync,
mkdirSync,
readdirSync,
readFileSync,
statSync,
writeFileSync,
} from "fs";
import { EvmContract } from "./contracts/evm";
import { AptosContract } from "./contracts/aptos";
import { readdirSync, readFileSync, statSync, writeFileSync } from "fs";
import { Vault } from "./governance";
class Store {
export class Store {
public chains: Record<string, Chain> = { global: new GlobalChain() };
public contracts: Record<string, Contract> = {};
public vaults: Record<string, Vault> = {};
@ -33,30 +28,8 @@ class Store {
this.loadAllVaults();
}
save(obj: any) {
let dir, file, content;
if (obj instanceof Contract) {
let contract = obj;
dir = `${this.path}/contracts/${contract.getType()}`;
file = contract.getId();
content = contract.toJson();
} else if (obj instanceof Chain) {
let chain = obj;
dir = `${this.path}/chains/${chain.getType()}`;
file = chain.getId();
content = chain.toJson();
} else if (obj instanceof Vault) {
let vault = obj;
dir = `${this.path}/vaults`;
file = vault.getId();
content = vault.toJson();
} else {
throw new Error("Invalid type");
}
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
writeFileSync(`${dir}/${file}.yaml`, stringify(content));
static serialize(obj: Contract | Chain | Vault) {
return stringify([obj.toJson()]);
}
getYamlFiles(path: string) {
@ -88,15 +61,49 @@ class Store {
};
this.getYamlFiles(`${this.path}/chains/`).forEach((yamlFile) => {
let parsed = parse(readFileSync(yamlFile, "utf-8"));
if (allChainClasses[parsed.type] === undefined) return;
let 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;
let parsedArray = parse(readFileSync(yamlFile, "utf-8"));
for (const parsed of parsedArray) {
if (allChainClasses[parsed.type] === undefined) return;
let 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;
}
});
}
saveAllContracts() {
let contractsByType: Record<string, Contract[]> = {};
for (const contract of Object.values(this.contracts)) {
if (!contractsByType[contract.getType()]) {
contractsByType[contract.getType()] = [];
}
contractsByType[contract.getType()].push(contract);
}
for (const [type, contracts] of Object.entries(contractsByType)) {
writeFileSync(
`${this.path}/contracts/${type}s.yaml`,
stringify(contracts.map((c) => c.toJson()))
);
}
}
saveAllChains() {
let chainsByType: Record<string, Chain[]> = {};
for (const chain of Object.values(this.chains)) {
if (!chainsByType[chain.getType()]) {
chainsByType[chain.getType()] = [];
}
chainsByType[chain.getType()].push(chain);
}
for (const [type, chains] of Object.entries(chainsByType)) {
writeFileSync(
`${this.path}/chains/${type}s.yaml`,
stringify(chains.map((c) => c.toJson()))
);
}
}
loadAllContracts() {
let allContractClasses = {
[CosmWasmContract.type]: CosmWasmContract,
@ -105,32 +112,36 @@ class Store {
[AptosContract.type]: AptosContract,
};
this.getYamlFiles(`${this.path}/contracts/`).forEach((yamlFile) => {
let parsed = parse(readFileSync(yamlFile, "utf-8"));
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(
chain,
parsed
);
if (this.contracts[chainContract.getId()])
throw new Error(
`Multiple contracts with id ${chainContract.getId()} found`
let 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(
chain,
parsed
);
this.contracts[chainContract.getId()] = chainContract;
if (this.contracts[chainContract.getId()])
throw new Error(
`Multiple contracts with id ${chainContract.getId()} found`
);
this.contracts[chainContract.getId()] = chainContract;
}
});
}
loadAllVaults() {
this.getYamlFiles(`${this.path}/vaults/`).forEach((yamlFile) => {
let parsed = parse(readFileSync(yamlFile, "utf-8"));
if (parsed.type !== Vault.type) return;
let parsedArray = parse(readFileSync(yamlFile, "utf-8"));
for (const parsed of parsedArray) {
if (parsed.type !== Vault.type) return;
const vault = Vault.fromJson(parsed);
if (this.vaults[vault.getId()])
throw new Error(`Multiple vaults with id ${vault.getId()} found`);
this.vaults[vault.getId()] = vault;
const vault = Vault.fromJson(parsed);
if (this.vaults[vault.getId()])
throw new Error(`Multiple vaults with id ${vault.getId()} found`);
this.vaults[vault.getId()] = vault;
}
});
}
}

View File

@ -1,10 +0,0 @@
import { DefaultStore } from "./store";
async function test() {
for (const contract of Object.values(DefaultStore.contracts)) {
console.log("Contract", contract.getId());
console.log(await contract.getGovernanceDataSource());
}
}
test();

View File

@ -1,5 +0,0 @@
id: aptos_mainnet
wormholeChainName: aptos
mainnet: true
rpcUrl: https://fullnode.mainnet.aptoslabs.com/v1
type: AptosChain

View File

@ -1,5 +0,0 @@
id: aptos_testnet
wormholeChainName: aptos
mainnet: false
rpcUrl: https://fullnode.testnet.aptoslabs.com/v1
type: AptosChain

View File

@ -0,0 +1,10 @@
- id: aptos_testnet
wormholeChainName: aptos
mainnet: false
rpcUrl: https://fullnode.testnet.aptoslabs.com/v1
type: AptosChain
- id: aptos_mainnet
wormholeChainName: aptos
mainnet: true
rpcUrl: https://fullnode.mainnet.aptoslabs.com/v1
type: AptosChain

View File

@ -1,5 +0,0 @@
querierEndpoint: https://injective-rpc.quickapi.com:443
id: injective
wormholeChainName: injective
mainnet: true
type: CosmWasmChain

View File

@ -1,5 +0,0 @@
querierEndpoint: https://k8s.testnet.tm.injective.network:443
id: injective_testnet
wormholeChainName: injective_testnet
mainnet: false
type: CosmWasmChain

View File

@ -1,9 +0,0 @@
querierEndpoint: https://rpc.uni.junonetwork.io/
executorEndpoint: https://rpc.uni.junonetwork.io/
id: juno_testnet
wormholeChainName: juno_testnet
mainnet: false
gasPrice: "0.025"
prefix: juno
feeDenom: ujunox
type: CosmWasmChain

View File

@ -1,9 +0,0 @@
querierEndpoint: https://rpc-kralum.neutron-1.neutron.org
executorEndpoint: https://rpc-kralum.neutron-1.neutron.org
id: neutron
wormholeChainName: neutron
mainnet: true
gasPrice: "0.025"
prefix: neutron
feeDenom: untrn
type: CosmWasmChain

View File

@ -1,9 +0,0 @@
querierEndpoint: https://rpc-palvus.pion-1.ntrn.tech/
executorEndpoint: https://rpc-palvus.pion-1.ntrn.tech/
id: neutron_testnet_pion_1
wormholeChainName: neutron_testnet_pion_1
mainnet: false
gasPrice: "0.05"
prefix: neutron
feeDenom: untrn
type: CosmWasmChain

View File

@ -1,9 +0,0 @@
querierEndpoint: https://rpc.osmosis.zone:443
executorEndpoint: https://rpc.osmosis.zone:443
id: osmosis
wormholeChainName: osmosis
mainnet: true
gasPrice: "0.025"
prefix: osmo
feeDenom: uosmo
type: CosmWasmChain

View File

@ -1,9 +0,0 @@
querierEndpoint: https://rpc.osmotest5.osmosis.zone/
executorEndpoint: https://rpc.osmotest5.osmosis.zone/
id: osmosis_testnet_5
wormholeChainName: osmosis_testnet_5
mainnet: false
gasPrice: "0.025"
prefix: osmo
feeDenom: uosmo
type: CosmWasmChain

View File

@ -1,9 +0,0 @@
querierEndpoint: https://sei-rpc.polkachu.com
executorEndpoint: https://sei-rpc.polkachu.com
id: sei_pacific_1
wormholeChainName: sei_pacific_1
mainnet: true
gasPrice: "0.025"
prefix: sei
feeDenom: usei
type: CosmWasmChain

View File

@ -1,9 +0,0 @@
querierEndpoint: https://rpc.atlantic-2.seinetwork.io/
executorEndpoint: https://rpc.atlantic-2.seinetwork.io/
id: sei_testnet_atlantic_2
wormholeChainName: sei_testnet_atlantic_2
mainnet: false
gasPrice: "0.10"
prefix: sei
feeDenom: usei
type: CosmWasmChain

View File

@ -0,0 +1,66 @@
- endpoint: https://injective-rpc.quickapi.com:443
id: injective
wormholeChainName: injective
mainnet: true
type: CosmWasmChain
- endpoint: https://rpc.atlantic-2.seinetwork.io/
id: sei_testnet_atlantic_2
wormholeChainName: sei_testnet_atlantic_2
mainnet: false
gasPrice: "0.10"
prefix: sei
feeDenom: usei
type: CosmWasmChain
- endpoint: https://rpc.osmosis.zone:443
id: osmosis
wormholeChainName: osmosis
mainnet: true
gasPrice: "0.025"
prefix: osmo
feeDenom: uosmo
type: CosmWasmChain
- endpoint: https://k8s.testnet.tm.injective.network:443
id: injective_testnet
wormholeChainName: injective_testnet
mainnet: false
type: CosmWasmChain
- endpoint: https://rpc-palvus.pion-1.ntrn.tech/
id: neutron_testnet_pion_1
wormholeChainName: neutron_testnet_pion_1
mainnet: false
gasPrice: "0.05"
prefix: neutron
feeDenom: untrn
type: CosmWasmChain
- endpoint: https://rpc.osmotest5.osmosis.zone/
id: osmosis_testnet_5
wormholeChainName: osmosis_testnet_5
mainnet: false
gasPrice: "0.025"
prefix: osmo
feeDenom: uosmo
type: CosmWasmChain
- endpoint: https://sei-rpc.polkachu.com
id: sei_pacific_1
wormholeChainName: sei_pacific_1
mainnet: true
gasPrice: "0.025"
prefix: sei
feeDenom: usei
type: CosmWasmChain
- endpoint: https://rpc-kralum.neutron-1.neutron.org
id: neutron
wormholeChainName: neutron
mainnet: true
gasPrice: "0.025"
prefix: neutron
feeDenom: untrn
type: CosmWasmChain
- endpoint: https://rpc.uni.junonetwork.io/
id: juno_testnet
wormholeChainName: juno_testnet
mainnet: false
gasPrice: "0.025"
prefix: juno
feeDenom: ujunox
type: CosmWasmChain

View File

@ -1,6 +0,0 @@
id: arbitrum
wormholeChainName: arbitrum
mainnet: true
rpcUrl: https://arb1.arbitrum.io/rpc
networkId: 42161
type: EvmChain

View File

@ -1,6 +0,0 @@
id: arbitrum_testnet
wormholeChainName: arbitrum
mainnet: false
rpcUrl: https://goerli-rollup.arbitrum.io/rpc
networkId: 421613
type: EvmChain

View File

@ -1,6 +0,0 @@
id: aurora
wormholeChainName: aurora
mainnet: true
rpcUrl: https://mainnet.aurora.dev
networkId: 1313161554
type: EvmChain

View File

@ -1,6 +0,0 @@
id: aurora_testnet
wormholeChainName: aurora
mainnet: false
rpcUrl: https://testnet.aurora.dev
networkId: 1313161555
type: EvmChain

View File

@ -1,6 +0,0 @@
id: avalanche
wormholeChainName: avalanche
mainnet: true
rpcUrl: https://api.avax.network/ext/bc/C/rpc
networkId: 43114
type: EvmChain

View File

@ -1,6 +0,0 @@
id: base
wormholeChainName: base
mainnet: true
rpcUrl: https://developer-access-mainnet.base.org/
networkId: 8453
type: EvmChain

View File

@ -1,6 +0,0 @@
id: base_goerli
wormholeChainName: base
mainnet: false
rpcUrl: https://goerli.base.org
networkId: 84531
type: EvmChain

View File

@ -1,6 +0,0 @@
id: bnb
wormholeChainName: bsc
mainnet: true
rpcUrl: https://rpc.ankr.com/bsc
networkId: 56
type: EvmChain

View File

@ -1,6 +0,0 @@
id: bnb_testnet
wormholeChainName: bsc
mainnet: false
rpcUrl: https://rpc.ankr.com/bsc_testnet_chapel
networkId: 97
type: EvmChain

View File

@ -1,6 +0,0 @@
id: canto
wormholeChainName: canto
mainnet: true
rpcUrl: https://canto.gravitychain.io
networkId: 7700
type: EvmChain

View File

@ -1,6 +0,0 @@
id: canto_testnet
wormholeChainName: canto
mainnet: false
rpcUrl: https://canto-testnet.plexnode.wtf
networkId: 7701
type: EvmChain

View File

@ -1,6 +0,0 @@
id: celo
wormholeChainName: celo
mainnet: true
rpcUrl: https://forno.celo.org
networkId: 42220
type: EvmChain

View File

@ -1,6 +0,0 @@
id: celo_alfajores_testnet
wormholeChainName: celo
mainnet: false
rpcUrl: https://alfajores-forno.celo-testnet.org
networkId: 44787
type: EvmChain

View File

@ -1,6 +0,0 @@
id: chiado
wormholeChainName: gnosis
mainnet: false
rpcUrl: https://rpc.chiadochain.net
networkId: 10200
type: EvmChain

View File

@ -1,6 +0,0 @@
id: conflux_espace
wormholeChainName: conflux_espace
mainnet: true
rpcUrl: https://evm.confluxrpc.org
networkId: 1030
type: EvmChain

View File

@ -1,6 +0,0 @@
id: conflux_espace_testnet
wormholeChainName: conflux_espace
mainnet: false
rpcUrl: https://evmtestnet.confluxrpc.com
networkId: 71
type: EvmChain

View File

@ -1,6 +0,0 @@
id: cronos
wormholeChainName: cronos
mainnet: true
rpcUrl: https://cronosrpc-1.xstaking.sg
networkId: 25
type: EvmChain

View File

@ -1,6 +0,0 @@
id: cronos_testnet
wormholeChainName: cronos
mainnet: false
rpcUrl: https://evm-t3.cronos.org
networkId: 338
type: EvmChain

View File

@ -1,6 +0,0 @@
id: eos
wormholeChainName: eos
mainnet: true
rpcUrl: https://api.evm.eosnetwork.com
networkId: 17777
type: EvmChain

View File

@ -1,6 +0,0 @@
id: eos_testnet
wormholeChainName: eos
mainnet: false
rpcUrl: https://api.testnet.evm.eosnetwork.com
networkId: 15557
type: EvmChain

View File

@ -1,6 +0,0 @@
id: ethereum
wormholeChainName: ethereum
mainnet: true
rpcUrl: https://eth.llamarpc.com
networkId: 1
type: EvmChain

View File

@ -1,6 +0,0 @@
id: evmos
wormholeChainName: evmos
mainnet: true
rpcUrl: https://eth.bd.evmos.org:8545/
networkId: 9001
type: EvmChain

View File

@ -1,6 +0,0 @@
id: evmos_testnet
wormholeChainName: evmos
mainnet: false
rpcUrl: https://eth.bd.evmos.dev:8545/
networkId: 9000
type: EvmChain

View File

@ -1,6 +0,0 @@
id: fantom
wormholeChainName: fantom
mainnet: true
rpcUrl: https://rpc.ankr.com/fantom
networkId: 250
type: EvmChain

View File

@ -1,6 +0,0 @@
id: fantom_testnet
wormholeChainName: fantom
mainnet: false
rpcUrl: https://rpc.ankr.com/fantom_testnet
networkId: 4002
type: EvmChain

View File

@ -1,6 +0,0 @@
id: fuji
wormholeChainName: avalanche
mainnet: false
rpcUrl: https://api.avax-test.network/ext/bc/C/rpc
networkId: 43113
type: EvmChain

View File

@ -1,6 +0,0 @@
id: gnosis
wormholeChainName: gnosis
mainnet: true
rpcUrl: https://rpc.gnosischain.com
networkId: 100
type: EvmChain

View File

@ -1,6 +0,0 @@
id: goerli
wormholeChainName: ethereum
mainnet: false
rpcUrl: https://rpc.goerli.eth.gateway.fm
networkId: 5
type: EvmChain

View File

@ -1,6 +0,0 @@
id: kava
wormholeChainName: kava
mainnet: true
rpcUrl: https://evm.kava.io
networkId: 2222
type: EvmChain

View File

@ -1,6 +0,0 @@
id: kava_testnet
wormholeChainName: kava
mainnet: false
rpcUrl: https://evm.testnet.kava.io
networkId: 2221
type: EvmChain

View File

@ -1,6 +0,0 @@
id: kcc
wormholeChainName: kcc
mainnet: true
rpcUrl: https://rpc-mainnet.kcc.network
networkId: 321
type: EvmChain

View File

@ -1,6 +0,0 @@
id: kcc_testnet
wormholeChainName: kcc
mainnet: false
rpcUrl: https://rpc-testnet.kcc.network
networkId: 322
type: EvmChain

View File

@ -1,6 +0,0 @@
id: linea
wormholeChainName: linea
mainnet: true
rpcUrl: https://linea.rpc.thirdweb.com
networkId: 59144
type: EvmChain

View File

@ -1,6 +0,0 @@
id: linea_goerli
wormholeChainName: linea
mainnet: false
rpcUrl: https://rpc.goerli.linea.build
networkId: 59140
type: EvmChain

View File

@ -1,6 +0,0 @@
id: mantle
wormholeChainName: mantle
mainnet: true
rpcUrl: https://rpc.mantle.xyz/
networkId: 5000
type: EvmChain

View File

@ -1,6 +0,0 @@
id: mantle_testnet
wormholeChainName: mantle
mainnet: false
rpcUrl: https://rpc.testnet.mantle.xyz/
networkId: 5001
type: EvmChain

View File

@ -1,6 +0,0 @@
id: meter
wormholeChainName: meter
mainnet: true
rpcUrl: https://rpc-meter.jellypool.xyz
networkId: 82
type: EvmChain

View File

@ -1,6 +0,0 @@
id: meter_testnet
wormholeChainName: meter
mainnet: false
rpcUrl: https://rpctest.meter.io
networkId: 83
type: EvmChain

View File

@ -1,6 +0,0 @@
id: mumbai
wormholeChainName: polygon
mainnet: false
rpcUrl: https://polygon-testnet-rpc.allthatnode.com:8545
networkId: 80001
type: EvmChain

View File

@ -1,6 +0,0 @@
id: neon
wormholeChainName: neon
mainnet: true
rpcUrl: https://neon-proxy-mainnet.solana.p2p.org
networkId: 245022934
type: EvmChain

View File

@ -1,6 +0,0 @@
id: neon_devnet
wormholeChainName: neon
mainnet: false
rpcUrl: https://devnet.neonevm.org
networkId: 245022926
type: EvmChain

View File

@ -1,6 +0,0 @@
id: optimism
wormholeChainName: optimism
mainnet: true
rpcUrl: https://rpc.ankr.com/optimism
networkId: 10
type: EvmChain

View File

@ -1,6 +0,0 @@
id: optimism_goerli
wormholeChainName: optimism
mainnet: false
rpcUrl: https://rpc.ankr.com/optimism_testnet
networkId: 420
type: EvmChain

View File

@ -1,6 +0,0 @@
id: polygon
wormholeChainName: polygon
mainnet: true
rpcUrl: https://polygon-rpc.com
networkId: 137
type: EvmChain

View File

@ -1,6 +0,0 @@
id: polygon_zkevm
wormholeChainName: polygon_zkevm
mainnet: true
rpcUrl: https://zkevm-rpc.com
networkId: 1101
type: EvmChain

View File

@ -1,6 +0,0 @@
id: polygon_zkevm_testnet
wormholeChainName: polygon_zkevm
mainnet: false
rpcUrl: https://rpc.public.zkevm-test.net/
networkId: 1442
type: EvmChain

View File

@ -1,6 +0,0 @@
id: shimmer_testnet
wormholeChainName: shimmer
mainnet: false
rpcUrl: https://json-rpc.evm.testnet.shimmer.network
networkId: 1072
type: EvmChain

View File

@ -1,6 +0,0 @@
id: syndr_nitro_testnet
wormholeChainName: syndr
mainnet: false
rpcUrl: https://syndr-nitro-testnet.calderachain.xyz/http
networkId: 412346
type: EvmChain

View File

@ -1,6 +0,0 @@
id: wemix
wormholeChainName: wemix
mainnet: true
rpcUrl: https://api.wemix.com
networkId: 1111
type: EvmChain

View File

@ -1,6 +0,0 @@
id: wemix_testnet
wormholeChainName: wemix
mainnet: false
rpcUrl: https://api.test.wemix.com
networkId: 1112
type: EvmChain

View File

@ -1,6 +0,0 @@
id: zksync
wormholeChainName: zksync
mainnet: true
rpcUrl: https://zksync2-mainnet.zksync.io
networkId: 324
type: EvmChain

View File

@ -1,6 +0,0 @@
id: zksync_goerli
wormholeChainName: zksync
mainnet: false
rpcUrl: https://zksync2-testnet.zksync.dev
networkId: 280
type: EvmChain

View File

@ -0,0 +1,312 @@
- id: linea_goerli
wormholeChainName: linea
mainnet: false
rpcUrl: https://rpc.goerli.linea.build
networkId: 59140
type: EvmChain
- id: kava
wormholeChainName: kava
mainnet: true
rpcUrl: https://evm.kava.io
networkId: 2222
type: EvmChain
- id: evmos
wormholeChainName: evmos
mainnet: true
rpcUrl: https://json-rpc.evmos.blockhunters.org
networkId: 9001
type: EvmChain
- id: goerli
wormholeChainName: ethereum
mainnet: false
rpcUrl: https://rpc.goerli.eth.gateway.fm
networkId: 5
type: EvmChain
- id: canto
wormholeChainName: canto
mainnet: true
rpcUrl: https://canto.gravitychain.io
networkId: 7700
type: EvmChain
- id: fuji
wormholeChainName: avalanche
mainnet: false
rpcUrl: https://api.avax-test.network/ext/bc/C/rpc
networkId: 43113
type: EvmChain
- id: base_goerli
wormholeChainName: base
mainnet: false
rpcUrl: https://goerli.base.org
networkId: 84531
type: EvmChain
- id: avalanche
wormholeChainName: avalanche
mainnet: true
rpcUrl: https://api.avax.network/ext/bc/C/rpc
networkId: 43114
type: EvmChain
- id: cronos_testnet
wormholeChainName: cronos
mainnet: false
rpcUrl: https://evm-t3.cronos.org
networkId: 338
type: EvmChain
- id: arbitrum_testnet
wormholeChainName: arbitrum
mainnet: false
rpcUrl: https://goerli-rollup.arbitrum.io/rpc
networkId: 421613
type: EvmChain
- id: zksync_goerli
wormholeChainName: zksync
mainnet: false
rpcUrl: https://zksync2-testnet.zksync.dev
networkId: 280
type: EvmChain
- id: canto_testnet
wormholeChainName: canto
mainnet: false
rpcUrl: https://canto-testnet.plexnode.wtf
networkId: 7701
type: EvmChain
- id: polygon_zkevm_testnet
wormholeChainName: polygon_zkevm
mainnet: false
rpcUrl: https://rpc.public.zkevm-test.net/
networkId: 1442
type: EvmChain
- id: aurora_testnet
wormholeChainName: aurora
mainnet: false
rpcUrl: https://testnet.aurora.dev
networkId: 1313161555
type: EvmChain
- id: mantle_testnet
wormholeChainName: mantle
mainnet: false
rpcUrl: https://rpc.testnet.mantle.xyz/
networkId: 5001
type: EvmChain
- id: gnosis
wormholeChainName: gnosis
mainnet: true
rpcUrl: https://rpc.gnosischain.com
networkId: 100
type: EvmChain
- id: fantom_testnet
wormholeChainName: fantom
mainnet: false
rpcUrl: https://rpc.ankr.com/fantom_testnet
networkId: 4002
type: EvmChain
- id: neon
wormholeChainName: neon
mainnet: true
rpcUrl: https://neon-proxy-mainnet.solana.p2p.org
networkId: 245022934
type: EvmChain
- id: fantom
wormholeChainName: fantom
mainnet: true
rpcUrl: https://rpc.ankr.com/fantom
networkId: 250
type: EvmChain
- id: mumbai
wormholeChainName: polygon
mainnet: false
rpcUrl: https://polygon-testnet-rpc.allthatnode.com:8545
networkId: 80001
type: EvmChain
- id: neon_devnet
wormholeChainName: neon
mainnet: false
rpcUrl: https://devnet.neonevm.org
networkId: 245022926
type: EvmChain
- id: meter
wormholeChainName: meter
mainnet: true
rpcUrl: https://rpc-meter.jellypool.xyz
networkId: 82
type: EvmChain
- id: chiado
wormholeChainName: gnosis
mainnet: false
rpcUrl: https://rpc.chiadochain.net
networkId: 10200
type: EvmChain
- id: mantle
wormholeChainName: mantle
mainnet: true
rpcUrl: https://rpc.mantle.xyz/
networkId: 5000
type: EvmChain
- id: kava_testnet
wormholeChainName: kava
mainnet: false
rpcUrl: https://evm.testnet.kava.io
networkId: 2221
type: EvmChain
- id: evmos_testnet
wormholeChainName: evmos
mainnet: false
rpcUrl: https://eth.bd.evmos.dev:8545/
networkId: 9000
type: EvmChain
- id: cronos
wormholeChainName: cronos
mainnet: true
rpcUrl: https://cronosrpc-1.xstaking.sg
networkId: 25
type: EvmChain
- id: ethereum
wormholeChainName: ethereum
mainnet: true
rpcUrl: https://eth.llamarpc.com
networkId: 1
type: EvmChain
- id: bnb_testnet
wormholeChainName: bsc
mainnet: false
rpcUrl: https://rpc.ankr.com/bsc_testnet_chapel
networkId: 97
type: EvmChain
- id: wemix
wormholeChainName: wemix
mainnet: true
rpcUrl: https://api.wemix.com
networkId: 1111
type: EvmChain
- id: aurora
wormholeChainName: aurora
mainnet: true
rpcUrl: https://mainnet.aurora.dev
networkId: 1313161554
type: EvmChain
- id: bnb
wormholeChainName: bsc
mainnet: true
rpcUrl: https://rpc.ankr.com/bsc
networkId: 56
type: EvmChain
- id: eos
wormholeChainName: eos
mainnet: true
rpcUrl: https://api.evm.eosnetwork.com
networkId: 17777
type: EvmChain
- id: conflux_espace_testnet
wormholeChainName: conflux_espace
mainnet: false
rpcUrl: https://evmtestnet.confluxrpc.com
networkId: 71
type: EvmChain
- id: conflux_espace
wormholeChainName: conflux_espace
mainnet: true
rpcUrl: https://evm.confluxrpc.org
networkId: 1030
type: EvmChain
- id: optimism_goerli
wormholeChainName: optimism
mainnet: false
rpcUrl: https://rpc.ankr.com/optimism_testnet
networkId: 420
type: EvmChain
- id: celo
wormholeChainName: celo
mainnet: true
rpcUrl: https://forno.celo.org
networkId: 42220
type: EvmChain
- id: polygon
wormholeChainName: polygon
mainnet: true
rpcUrl: https://polygon-rpc.com
networkId: 137
type: EvmChain
- id: wemix_testnet
wormholeChainName: wemix
mainnet: false
rpcUrl: https://api.test.wemix.com
networkId: 1112
type: EvmChain
- id: kcc
wormholeChainName: kcc
mainnet: true
rpcUrl: https://rpc-mainnet.kcc.network
networkId: 321
type: EvmChain
- id: polygon_zkevm
wormholeChainName: polygon_zkevm
mainnet: true
rpcUrl: https://zkevm-rpc.com
networkId: 1101
type: EvmChain
- id: celo_alfajores_testnet
wormholeChainName: celo
mainnet: false
rpcUrl: https://alfajores-forno.celo-testnet.org
networkId: 44787
type: EvmChain
- id: syndr_nitro_testnet
wormholeChainName: syndr
mainnet: false
rpcUrl: https://syndr-nitro-testnet.calderachain.xyz/http
networkId: 412346
type: EvmChain
- id: zksync
wormholeChainName: zksync
mainnet: true
rpcUrl: https://zksync2-mainnet.zksync.io
networkId: 324
type: EvmChain
- id: base
wormholeChainName: base
mainnet: true
rpcUrl: https://developer-access-mainnet.base.org/
networkId: 8453
type: EvmChain
- id: arbitrum
wormholeChainName: arbitrum
mainnet: true
rpcUrl: https://arb1.arbitrum.io/rpc
networkId: 42161
type: EvmChain
- id: optimism
wormholeChainName: optimism
mainnet: true
rpcUrl: https://rpc.ankr.com/optimism
networkId: 10
type: EvmChain
- id: kcc_testnet
wormholeChainName: kcc
mainnet: false
rpcUrl: https://rpc-testnet.kcc.network
networkId: 322
type: EvmChain
- id: eos_testnet
wormholeChainName: eos
mainnet: false
rpcUrl: https://api.testnet.evm.eosnetwork.com
networkId: 15557
type: EvmChain
- id: meter_testnet
wormholeChainName: meter
mainnet: false
rpcUrl: https://rpctest.meter.io
networkId: 83
type: EvmChain
- id: linea
wormholeChainName: linea
mainnet: true
rpcUrl: https://linea.rpc.thirdweb.com
networkId: 59144
type: EvmChain
- id: shimmer_testnet
wormholeChainName: shimmer
mainnet: false
rpcUrl: https://json-rpc.evm.testnet.shimmer.network
networkId: 1072
type: EvmChain

View File

@ -1,5 +0,0 @@
id: sui_devnet
wormholeChainName: sui
mainnet: false
rpcUrl: https://fullnode.devnet.sui.io:443
type: SuiChain

View File

@ -1,5 +0,0 @@
id: sui_mainnet
wormholeChainName: sui
mainnet: true
rpcUrl: https://fullnode.mainnet.sui.io:443
type: SuiChain

View File

@ -1,5 +0,0 @@
id: sui_testnet
wormholeChainName: sui
mainnet: false
rpcUrl: https://fullnode.testnet.sui.io:443
type: SuiChain

View File

@ -0,0 +1,15 @@
- id: sui_testnet
wormholeChainName: sui
mainnet: false
rpcUrl: https://fullnode.testnet.sui.io:443
type: SuiChain
- id: sui_devnet
wormholeChainName: sui
mainnet: false
rpcUrl: https://fullnode.devnet.sui.io:443
type: SuiChain
- id: sui_mainnet
wormholeChainName: sui
mainnet: true
rpcUrl: https://fullnode.mainnet.sui.io:443
type: SuiChain

View File

@ -1,4 +0,0 @@
chain: aptos_mainnet
stateId: "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387"
wormholeStateId: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625"
type: AptosContract

View File

@ -1,4 +0,0 @@
chain: aptos_testnet
stateId: "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387"
wormholeStateId: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625"
type: AptosContract

View File

@ -0,0 +1,8 @@
- chain: aptos_mainnet
stateId: "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387"
wormholeStateId: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625"
type: AptosContract
- chain: aptos_testnet
stateId: "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387"
wormholeStateId: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625"
type: AptosContract

View File

@ -1,3 +0,0 @@
chain: injective
address: inj12j43nf2f0qumnt2zrrmpvnsqgzndxefujlvr08
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: injective_testnet
address: inj18hckkzqf47mdhd734g6papk6wj20y24rm43sk9
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: injective_testnet
address: inj18rlflp3735h25jmjx97d22c72sxk260amdjxlu
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: juno_testnet
address: juno1eacsrua27njc35pxz37y97gmcjs899t59f8pf0rkejjyvtmhws5q6lxsdd
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: juno_testnet
address: juno1h93q9kwlnfml2gum4zj54al9w4jdmuhtzrh6vhycnemsqlqv9l9snnznxs
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: neutron
address: neutron1m2emc93m9gpwgsrsf2vylv9xvgqh654630v7dfrhrkmr5slly53spg85wv
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: neutron_testnet_pion_1
address: neutron15ldst8t80982akgr8w8ekcytejzkmfpgdkeq4xgtge48qs7435jqp87u3t
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: neutron_testnet_pion_1
address: neutron16zwrmx3zgggmxhzau86xfycm42cr4sj888hdvzsxya3qarp6zhhqzhlkvz
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: osmosis
address: osmo13ge29x4e2s63a8ytz2px8gurtyznmue4a69n5275692v3qn3ks8q7cwck7
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: osmosis_testnet_5
address: osmo1hpdzqku55lmfmptpyj6wdlugqs5etr6teqf7r4yqjjrxjznjhtuqqu5kdh
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: osmosis_testnet_5
address: osmo1lltupx02sj99suakmuk4sr4ppqf34ajedaxut3ukjwkv6469erwqtpg9t3
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: sei_pacific_1
address: sei15d2tyq2jzxmpg32y3am3w62dts32qgzmds9qnr6c87r0gwwr7ynqal0x38
type: CosmWasmContract

View File

@ -1,3 +0,0 @@
chain: sei_testnet_atlantic_2
address: sei1kpntez76v38yuxhhaaahdmvjxnr5tkr8tq077smefs7uw70rj5yqw2aewy
type: CosmWasmContract

Some files were not shown because too many files have changed in this diff Show More