Abolish xc governance sdk (#957)
* Replace xc-governance-sdk with xc_admin_common package xc_admin_package was not using the CHAIN overrides declared in the governance-sdk so it was moved to that package as well * Replace xc-governance-sdk with xc_admin_common in other packages * Remove the package and all of its references * Fix tests * Fix bug in GovernanceDataSourceTransfer encoding * Rename all references to the old package * Redeploy neutron_testnet contract with new chain id * Move SetWormholeAddress to separate file
This commit is contained in:
parent
b64090aa75
commit
c732fcf586
|
@ -2,13 +2,13 @@ on:
|
|||
pull_request:
|
||||
paths:
|
||||
- target_chains/ethereum/contracts/**
|
||||
- governance/xc_governance_sdk_js/**
|
||||
- governance/xc_admin/packages/xc_admin_common/**
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- target_chains/ethereum/contracts/**
|
||||
- governance/xc_governance_sdk_js/**
|
||||
- governance/xc_admin/packages/xc_admin_common/**
|
||||
|
||||
name: Ethereum Contract
|
||||
|
||||
|
@ -22,10 +22,6 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install XC-governance sdk dependencies
|
||||
run: npm ci
|
||||
working-directory: governance/xc_governance_sdk_js
|
||||
|
||||
- name: Install contract npm dependencies
|
||||
run: npm ci
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
lib/
|
|
@ -17,7 +17,6 @@
|
|||
"@certusone/wormhole-sdk": "^0.9.8",
|
||||
"@pythnetwork/cosmwasm-deploy-tools": "*",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@pythnetwork/xc-governance-sdk": "*",
|
||||
"bs58": "^5.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.3"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Contract } from "./base";
|
||||
import { AptosChain, Chain } from "./chains";
|
||||
import { DataSource, HexString32Bytes } from "@pythnetwork/xc-governance-sdk";
|
||||
import { AptosClient } from "aptos";
|
||||
import { DataSource } from "xc_admin_common";
|
||||
|
||||
export class AptosContract extends Contract {
|
||||
static type: string = "AptosContract";
|
||||
|
@ -64,19 +63,25 @@ export class AptosContract extends Contract {
|
|||
async getDataSources(): Promise<DataSource[]> {
|
||||
const data = (await this.findResource("DataSources")) as any;
|
||||
return data.sources.keys.map((source: any) => {
|
||||
return new DataSource(
|
||||
Number(source.emitter_chain),
|
||||
new HexString32Bytes(source.emitter_address.external_address)
|
||||
);
|
||||
return {
|
||||
emitterChain: Number(source.emitter_chain),
|
||||
emitterAddress: source.emitter_address.external_address.replace(
|
||||
"0x",
|
||||
""
|
||||
),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async getGovernanceDataSource(): Promise<DataSource> {
|
||||
const data = (await this.findResource("GovernanceDataSource")) as any;
|
||||
return new DataSource(
|
||||
Number(data.source.emitter_chain),
|
||||
new HexString32Bytes(data.source.emitter_address.external_address)
|
||||
);
|
||||
return {
|
||||
emitterChain: Number(data.source.emitter_chain),
|
||||
emitterAddress: data.source.emitter_address.external_address.replace(
|
||||
"0x",
|
||||
""
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
import {
|
||||
CHAINS,
|
||||
DataSource,
|
||||
HexString32Bytes,
|
||||
SetFeeInstruction,
|
||||
} from "@pythnetwork/xc-governance-sdk";
|
||||
import { DataSource } from "xc_admin_common";
|
||||
import { Chain } from "./chains";
|
||||
|
||||
export abstract class Storable {
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
import { readdirSync, readFileSync, writeFileSync } from "fs";
|
||||
import { Storable } from "./base";
|
||||
import {
|
||||
ChainName,
|
||||
CHAINS,
|
||||
CosmwasmUpgradeContractInstruction,
|
||||
EthereumUpgradeContractInstruction,
|
||||
HexString20Bytes,
|
||||
HexString32Bytes,
|
||||
SetFeeInstruction,
|
||||
SuiAuthorizeUpgradeContractInstruction,
|
||||
} from "@pythnetwork/xc-governance-sdk";
|
||||
import { BufferBuilder } from "@pythnetwork/xc-governance-sdk/lib/serialize";
|
||||
SetFee,
|
||||
CosmosUpgradeContract,
|
||||
EvmUpgradeContract,
|
||||
SuiAuthorizeUpgradeContract,
|
||||
AptosAuthorizeUpgradeContract,
|
||||
} from "xc_admin_common";
|
||||
import { AptosClient } from "aptos";
|
||||
|
||||
export abstract class Chain extends Storable {
|
||||
|
@ -27,11 +25,11 @@ export abstract class Chain extends Storable {
|
|||
* @param exponent the new fee exponent to set
|
||||
*/
|
||||
generateGovernanceSetFeePayload(fee: number, exponent: number): Buffer {
|
||||
return new SetFeeInstruction(
|
||||
CHAINS[this.getId() as keyof typeof CHAINS],
|
||||
return new SetFee(
|
||||
this.getId() as ChainName,
|
||||
BigInt(fee),
|
||||
BigInt(exponent)
|
||||
).serialize();
|
||||
).encode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,10 +82,10 @@ export class CosmWasmChain extends Chain {
|
|||
}
|
||||
|
||||
generateGovernanceUpgradePayload(codeId: bigint): Buffer {
|
||||
return new CosmwasmUpgradeContractInstruction(
|
||||
CHAINS[this.getId() as keyof typeof CHAINS],
|
||||
return new CosmosUpgradeContract(
|
||||
this.getId() as ChainName,
|
||||
codeId
|
||||
).serialize();
|
||||
).encode();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,37 +113,42 @@ export class SuiChain extends Chain {
|
|||
return SuiChain.type;
|
||||
}
|
||||
|
||||
//TODO: Move this logic to xc_admin_common
|
||||
private wrapWithWormholeGovernancePayload(
|
||||
actionVariant: number,
|
||||
payload: Buffer
|
||||
): Buffer {
|
||||
const builder = new BufferBuilder();
|
||||
builder.addBuffer(
|
||||
const actionVariantBuffer = Buffer.alloc(1);
|
||||
actionVariantBuffer.writeUint8(actionVariant, 0);
|
||||
const chainBuffer = Buffer.alloc(2);
|
||||
chainBuffer.writeUint16BE(CHAINS["sui"], 0);
|
||||
const result = Buffer.concat([
|
||||
Buffer.from(
|
||||
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"hex"
|
||||
)
|
||||
);
|
||||
builder.addUint8(actionVariant);
|
||||
builder.addUint16(CHAINS["sui"]); // should always be sui (21) no matter devnet or testnet
|
||||
builder.addBuffer(payload);
|
||||
return builder.build();
|
||||
),
|
||||
actionVariantBuffer,
|
||||
chainBuffer,
|
||||
payload,
|
||||
]);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payload for a governance contract upgrade instruction for contracts deployed on this chain
|
||||
* @param digest hex string of the 32 byte digest for the new package without the 0x prefix
|
||||
*/
|
||||
generateGovernanceUpgradePayload(digest: string): Buffer {
|
||||
let setFee = new SuiAuthorizeUpgradeContractInstruction(
|
||||
CHAINS["sui"],
|
||||
new HexString32Bytes(digest)
|
||||
).serialize();
|
||||
let setFee = new SuiAuthorizeUpgradeContract("sui", digest).encode();
|
||||
return this.wrapWithWormholeGovernancePayload(0, setFee);
|
||||
}
|
||||
|
||||
generateGovernanceSetFeePayload(fee: number, exponent: number): Buffer {
|
||||
let setFee = new SetFeeInstruction(
|
||||
CHAINS["sui"],
|
||||
let setFee = new SetFee(
|
||||
"sui", // should always be sui no matter devnet or testnet or mainnet
|
||||
BigInt(fee),
|
||||
BigInt(exponent)
|
||||
).serialize();
|
||||
).encode();
|
||||
return this.wrapWithWormholeGovernancePayload(3, setFee);
|
||||
}
|
||||
}
|
||||
|
@ -162,11 +165,12 @@ export class EVMChain extends Chain {
|
|||
return new EVMChain(parsed.id, parsed.rpcUrl);
|
||||
}
|
||||
|
||||
generateGovernanceUpgradePayload(address: HexString20Bytes): Buffer {
|
||||
return new EthereumUpgradeContractInstruction(
|
||||
CHAINS[this.getId() as keyof typeof CHAINS],
|
||||
address
|
||||
).serialize();
|
||||
/**
|
||||
* Returns the payload for a governance contract upgrade instruction for contracts deployed on this chain
|
||||
* @param address hex string of the 20 byte address of the contract to upgrade to without the 0x prefix
|
||||
*/
|
||||
generateGovernanceUpgradePayload(address: string): Buffer {
|
||||
return new EvmUpgradeContract(this.getId() as ChainName, address).encode();
|
||||
}
|
||||
|
||||
toJson(): any {
|
||||
|
@ -193,19 +197,20 @@ export class AptosChain extends Chain {
|
|||
return new AptosClient(this.rpcUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payload for a governance contract upgrade instruction for contracts deployed on this chain
|
||||
* @param digest hex string of the 32 byte digest for the new package without the 0x prefix
|
||||
*/
|
||||
generateGovernanceUpgradePayload(digest: string): Buffer {
|
||||
return new SuiAuthorizeUpgradeContractInstruction(
|
||||
CHAINS["aptos"],
|
||||
new HexString32Bytes(digest)
|
||||
).serialize();
|
||||
return new AptosAuthorizeUpgradeContract("aptos", digest).encode();
|
||||
}
|
||||
|
||||
generateGovernanceSetFeePayload(fee: number, exponent: number): Buffer {
|
||||
return new SetFeeInstruction(
|
||||
CHAINS["aptos"], // should always be aptos (22) no matter devnet or testnet or mainnet
|
||||
return new SetFee(
|
||||
"aptos", // should always be aptos no matter devnet or testnet or mainnet
|
||||
BigInt(fee),
|
||||
BigInt(exponent)
|
||||
).serialize();
|
||||
).encode();
|
||||
}
|
||||
|
||||
getType(): string {
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { Chain, CosmWasmChain } from "./chains";
|
||||
import { readFileSync } from "fs";
|
||||
import { getPythConfig } from "@pythnetwork/cosmwasm-deploy-tools/lib/configs";
|
||||
import {
|
||||
CHAINS,
|
||||
DataSource,
|
||||
HexString32Bytes,
|
||||
} from "@pythnetwork/xc-governance-sdk";
|
||||
import { CHAINS, DataSource } from "xc_admin_common";
|
||||
import { DeploymentType } from "@pythnetwork/cosmwasm-deploy-tools/lib/helper";
|
||||
import {
|
||||
CosmwasmExecutor,
|
||||
|
@ -45,10 +41,10 @@ export class CosmWasmContract extends Contract {
|
|||
async getDataSources(): Promise<DataSource[]> {
|
||||
const config = await this.getConfig();
|
||||
return config.config_v1.data_sources.map(({ emitter, chain_id }: any) => {
|
||||
return new DataSource(
|
||||
Number(chain_id),
|
||||
new HexString32Bytes(Buffer.from(emitter, "base64").toString("hex"))
|
||||
);
|
||||
return {
|
||||
emitterChain: Number(chain_id),
|
||||
emitterAddress: Buffer.from(emitter, "base64").toString("hex"),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -56,12 +52,10 @@ export class CosmWasmContract extends Contract {
|
|||
const config = await this.getConfig();
|
||||
const { emitter: emitterAddress, chain_id: chainId } =
|
||||
config.config_v1.governance_source;
|
||||
return new DataSource(
|
||||
Number(chainId),
|
||||
new HexString32Bytes(
|
||||
Buffer.from(emitterAddress, "base64").toString("hex")
|
||||
)
|
||||
);
|
||||
return {
|
||||
emitterChain: Number(chainId),
|
||||
emitterAddress: Buffer.from(emitterAddress, "base64").toString("hex"),
|
||||
};
|
||||
}
|
||||
|
||||
static type = "CosmWasmContract";
|
||||
|
|
|
@ -2,7 +2,7 @@ import Web3 from "web3"; //TODO: decide on using web3 or ethers.js
|
|||
import PythInterfaceAbi from "@pythnetwork/pyth-sdk-solidity/abis/IPyth.json";
|
||||
import { Contract } from "./base";
|
||||
import { Chain, EVMChain } from "./chains";
|
||||
import { DataSource, HexString32Bytes } from "@pythnetwork/xc-governance-sdk";
|
||||
import { DataSource } from "xc_admin_common";
|
||||
|
||||
const EXTENDED_PYTH_ABI = [
|
||||
{
|
||||
|
@ -136,12 +136,20 @@ export class EVMContract extends Contract {
|
|||
async getDataSources(): Promise<DataSource[]> {
|
||||
const pythContract = this.getContract();
|
||||
const result = await pythContract.methods.validDataSources().call();
|
||||
return result.map(({ chainId, emitterAddress }: any) => {
|
||||
return new DataSource(
|
||||
Number(chainId),
|
||||
new HexString32Bytes(emitterAddress)
|
||||
);
|
||||
});
|
||||
return result.map(
|
||||
({
|
||||
chainId,
|
||||
emitterAddress,
|
||||
}: {
|
||||
chainId: string;
|
||||
emitterAddress: string;
|
||||
}) => {
|
||||
return {
|
||||
emitterChain: Number(chainId),
|
||||
emitterAddress: emitterAddress.replace("0x", ""),
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async getGovernanceDataSource(): Promise<DataSource> {
|
||||
|
@ -149,10 +157,10 @@ export class EVMContract extends Contract {
|
|||
const [chainId, emitterAddress] = await pythContract.methods
|
||||
.governanceDataSource()
|
||||
.call();
|
||||
return new DataSource(
|
||||
Number(chainId),
|
||||
new HexString32Bytes(emitterAddress)
|
||||
);
|
||||
return {
|
||||
emitterChain: Number(chainId),
|
||||
emitterAddress: emitterAddress.replace("0x", ""),
|
||||
};
|
||||
}
|
||||
|
||||
async executeGovernanceInstruction(privateKey: string, vaa: Buffer) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
TransactionBlock,
|
||||
} from "@mysten/sui.js";
|
||||
import { Chain, SuiChain } from "./chains";
|
||||
import { DataSource, HexString32Bytes } from "@pythnetwork/xc-governance-sdk";
|
||||
import { DataSource } from "xc_admin_common";
|
||||
import { Contract } from "./base";
|
||||
|
||||
export class SuiContract extends Contract {
|
||||
|
@ -294,14 +294,12 @@ export class SuiContract extends Contract {
|
|||
}
|
||||
return result.data.content.fields.value.fields.keys.map(
|
||||
({ fields }: any) => {
|
||||
return new DataSource(
|
||||
Number(fields.emitter_chain),
|
||||
new HexString32Bytes(
|
||||
Buffer.from(
|
||||
fields.emitter_address.fields.value.fields.data
|
||||
).toString("hex")
|
||||
)
|
||||
);
|
||||
return {
|
||||
emitterChain: Number(fields.emitter_chain),
|
||||
emitterAddress: Buffer.from(
|
||||
fields.emitter_address.fields.value.fields.data
|
||||
).toString("hex"),
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -312,10 +310,10 @@ export class SuiContract extends Contract {
|
|||
const chainId = governanceFields.emitter_chain;
|
||||
const emitterAddress =
|
||||
governanceFields.emitter_address.fields.value.fields.data;
|
||||
return new DataSource(
|
||||
Number(chainId),
|
||||
new HexString32Bytes(Buffer.from(emitterAddress).toString("hex"))
|
||||
);
|
||||
return {
|
||||
emitterChain: Number(chainId),
|
||||
emitterAddress: Buffer.from(emitterAddress).toString("hex"),
|
||||
};
|
||||
}
|
||||
|
||||
async getBaseUpdateFee() {
|
||||
|
|
|
@ -1,51 +1,10 @@
|
|||
import {
|
||||
Vault,
|
||||
Contracts,
|
||||
Vaults,
|
||||
loadHotWallet,
|
||||
WormholeEmitter,
|
||||
SubmittedWormholeMessage,
|
||||
} from "./entities";
|
||||
import { SuiContract } from "./sui";
|
||||
import { CosmWasmContract } from "./cosmwasm";
|
||||
import { Ed25519Keypair, RawSigner } from "@mysten/sui.js";
|
||||
import { DefaultStore } from "./store";
|
||||
import { Chains } from "./chains";
|
||||
import { executeProposal } from "xc_admin_common";
|
||||
import { EVMContract } from "./evm";
|
||||
|
||||
async function test() {
|
||||
// Deploy the same cosmwasm code with different config
|
||||
|
||||
// let c = Contracts.osmosis_testnet_5_osmo1lltupx02sj99suakmuk4sr4ppqf34ajedaxut3ukjwkv6469erwqtpg9t3 as CosmWasmContract;
|
||||
// let old_conf = await c.getConfig();
|
||||
// let config = CosmWasmContract.getDeploymentConfig(c.chain, 'edge', old_conf.config_v1.wormhole_contract);
|
||||
// console.log(config);
|
||||
// config.governance_source.emitter = wallet.publicKey.toBuffer().toString('base64');
|
||||
// let mnemonic = 'FILLME'
|
||||
// console.log(await CosmWasmContract.deploy(c.chain, await c.getCodeId(), config, mnemonic));
|
||||
|
||||
let s = DefaultStore;
|
||||
Object.values(Contracts).forEach((c) => {
|
||||
console.log(c);
|
||||
s.save(c);
|
||||
});
|
||||
|
||||
Object.values(Chains).forEach((c) => {
|
||||
console.log(c);
|
||||
s.save(c);
|
||||
});
|
||||
|
||||
// Execute some governance instruction on sui contract
|
||||
|
||||
// let c = Contracts.sui_testnet_0x651dcb84d579fcdf51f15d79eb28f7e10b416c9202b6a156495bb1a4aecd55ea as SuiContract
|
||||
// let wallet = await loadHotWallet('/tmp/priv.json');
|
||||
// let emitter = new WormholeEmitter("devnet", wallet);
|
||||
// let proposal = c.setUpdateFee(200);
|
||||
// let submittedWormholeMessage = await emitter.sendMessage(proposal);
|
||||
// let vaa = await submittedWormholeMessage.fetchVAA(10);
|
||||
// const keypair = Ed25519Keypair.fromSecretKey(Buffer.from('FILLME', "hex"));
|
||||
// await c.executeGovernanceInstruction(vaa);
|
||||
for (const contract of Object.values(DefaultStore.contracts)) {
|
||||
console.log("Contract", contract.getId());
|
||||
console.log(await contract.getGovernanceDataSource());
|
||||
}
|
||||
}
|
||||
|
||||
test();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
querierEndpoint: https://rpc.pion.rs-testnet.polypore.xyz/
|
||||
executorEndpoint: https://rpc.pion.rs-testnet.polypore.xyz/
|
||||
querierEndpoint: https://rpc-palvus.pion-1.ntrn.tech/
|
||||
executorEndpoint: https://rpc-palvus.pion-1.ntrn.tech/
|
||||
id: neutron_testnet_pion_1
|
||||
gasPrice: "0.05"
|
||||
prefix: neutron
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
chain: neutron_testnet_pion_1
|
||||
address: neutron1xxmcu6wxgawjlajx8jalyk9cxsudnygjg0tvjesfyurh4utvtpes5wmpjp
|
||||
address: neutron16zwrmx3zgggmxhzau86xfycm42cr4sj888hdvzsxya3qarp6zhhqzhlkvz
|
||||
type: CosmWasmContract
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
"@coral-xyz/anchor": "^0.26.0",
|
||||
"@pythnetwork/client": "^2.17.0",
|
||||
"@pythnetwork/pyth-sdk-solidity": "*",
|
||||
"@pythnetwork/xc-governance-sdk": "*",
|
||||
"@solana/buffer-layout": "^4.0.1",
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
"@sqds/mesh": "^1.0.6",
|
||||
|
|
|
@ -9,20 +9,16 @@ import {
|
|||
ActionName,
|
||||
PythGovernanceAction,
|
||||
decodeGovernancePayload,
|
||||
EvmSetWormholeAddress,
|
||||
} from "..";
|
||||
import * as fc from "fast-check";
|
||||
import {
|
||||
ChainId,
|
||||
ChainName,
|
||||
CHAINS,
|
||||
toChainId,
|
||||
toChainName,
|
||||
} from "@certusone/wormhole-sdk";
|
||||
import { ChainName, CHAINS } from "../chains";
|
||||
import { Arbitrary, IntArrayConstraints } from "fast-check";
|
||||
import {
|
||||
AptosAuthorizeUpgradeContract,
|
||||
CosmosUpgradeContract,
|
||||
EvmUpgradeContract,
|
||||
SuiAuthorizeUpgradeContract,
|
||||
} from "../governance_payload/UpgradeContract";
|
||||
import {
|
||||
AuthorizeGovernanceDataSourceTransfer,
|
||||
|
@ -219,6 +215,12 @@ function governanceActionArb(): Arbitrary<PythGovernanceAction> {
|
|||
);
|
||||
}
|
||||
);
|
||||
|
||||
const suiArb = hexBytesArb({ minLength: 32, maxLength: 32 }).map(
|
||||
(buffer) => {
|
||||
return new SuiAuthorizeUpgradeContract(header.targetChainId, buffer);
|
||||
}
|
||||
);
|
||||
const evmArb = hexBytesArb({ minLength: 20, maxLength: 20 }).map(
|
||||
(address) => {
|
||||
return new EvmUpgradeContract(header.targetChainId, address);
|
||||
|
@ -254,6 +256,10 @@ function governanceActionArb(): Arbitrary<PythGovernanceAction> {
|
|||
parseInt(index.toString())
|
||||
);
|
||||
});
|
||||
} else if (header.action === "SetWormholeAddress") {
|
||||
return hexBytesArb({ minLength: 20, maxLength: 20 }).map((address) => {
|
||||
return new EvmSetWormholeAddress(header.targetChainId, address);
|
||||
});
|
||||
} else {
|
||||
throw new Error("Unsupported action type");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { CHAINS as WORMHOLE_CHAINS } from "@certusone/wormhole-sdk";
|
||||
|
||||
export { CHAINS as WORMHOLE_CHAINS } from "@certusone/wormhole-sdk";
|
||||
// GUIDELINES to add a chain
|
||||
// PYTH will have:
|
||||
// 1. Mainnet Deployment - which will have pyth mainnet governance and data sources
|
||||
|
@ -34,12 +32,12 @@ export const RECEIVER_CHAINS = {
|
|||
sei_pacific_1: 60017,
|
||||
sei_testnet_atlantic_2: 60018,
|
||||
neutron: 60019,
|
||||
neutron_testnet_pion_1: 60020,
|
||||
juno: 60020,
|
||||
juno_testnet: 60021,
|
||||
kava: 60022,
|
||||
wemix: 60023,
|
||||
linea: 60024,
|
||||
neutron_testnet_pion_1: 60025,
|
||||
};
|
||||
|
||||
// If there is any overlapping value the receiver chain will replace the wormhole
|
||||
|
@ -47,3 +45,16 @@ export const RECEIVER_CHAINS = {
|
|||
export const CHAINS = { ...WORMHOLE_CHAINS, ...RECEIVER_CHAINS };
|
||||
export declare type ChainName = keyof typeof CHAINS;
|
||||
export declare type ChainId = typeof CHAINS[ChainName];
|
||||
|
||||
export function toChainId(chainName: ChainName): ChainId {
|
||||
return CHAINS[chainName];
|
||||
}
|
||||
|
||||
const CHAIN_ID_TO_NAME = Object.entries(CHAINS).reduce((obj, [name, id]) => {
|
||||
obj[id] = name;
|
||||
return obj;
|
||||
}, {} as any);
|
||||
|
||||
export function toChainName(chainId: ChainId): ChainName {
|
||||
return CHAIN_ID_TO_NAME[chainId];
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import { ChainId, Instruction } from "@pythnetwork/xc-governance-sdk";
|
||||
import { ChainId } from "../chains";
|
||||
import { ethers } from "ethers";
|
||||
import { PythGovernanceAction } from "../governance_payload";
|
||||
|
||||
export enum ContractType {
|
||||
Oracle,
|
||||
|
@ -70,13 +71,13 @@ export interface SyncOp {
|
|||
}
|
||||
|
||||
export class SendGovernanceInstruction implements SyncOp {
|
||||
private instruction: Instruction;
|
||||
private instruction: PythGovernanceAction;
|
||||
private sender: WormholeAddress;
|
||||
// function to submit the signed VAA to the target chain contract
|
||||
private submitVaa: (vaa: string) => Promise<boolean>;
|
||||
|
||||
constructor(
|
||||
instruction: Instruction,
|
||||
instruction: PythGovernanceAction,
|
||||
from: WormholeAddress,
|
||||
submitVaa: (vaa: string) => Promise<boolean>
|
||||
) {
|
||||
|
@ -87,7 +88,7 @@ export class SendGovernanceInstruction implements SyncOp {
|
|||
|
||||
public id(): string {
|
||||
// TODO: use a more understandable identifier (also this may not be unique)
|
||||
return ethers.utils.sha256(this.instruction.serialize());
|
||||
return ethers.utils.sha256(this.instruction.encode());
|
||||
}
|
||||
|
||||
public async run(cache: Record<string, any>): Promise<boolean> {
|
||||
|
|
|
@ -7,11 +7,9 @@ import {
|
|||
WormholeAddress,
|
||||
WormholeNetwork,
|
||||
} from "./Contract";
|
||||
import {
|
||||
ChainId,
|
||||
SetValidPeriodInstruction,
|
||||
} from "@pythnetwork/xc-governance-sdk";
|
||||
import { ethers } from "ethers";
|
||||
import { ChainName } from "../chains";
|
||||
import { SetValidPeriod } from "../governance_payload";
|
||||
|
||||
export class EvmPythUpgradable implements Contract<EvmPythUpgradableState> {
|
||||
public type = ContractType.EvmPythUpgradable;
|
||||
|
@ -45,9 +43,9 @@ export class EvmPythUpgradable implements Contract<EvmPythUpgradableState> {
|
|||
}
|
||||
|
||||
// get the chainId that identifies this contract
|
||||
public async getChainId(): Promise<ChainId> {
|
||||
public async getChain(): Promise<ChainName> {
|
||||
// FIXME: read from data sources
|
||||
return 23;
|
||||
return "polygon";
|
||||
}
|
||||
|
||||
public async getState(): Promise<EvmPythUpgradableState> {
|
||||
|
@ -65,12 +63,12 @@ export class EvmPythUpgradable implements Contract<EvmPythUpgradableState> {
|
|||
public async sync(target: EvmPythUpgradableState): Promise<SyncOp[]> {
|
||||
const myState = await this.getState();
|
||||
const authority = await this.getAuthority();
|
||||
const myChainId = await this.getChainId();
|
||||
const myChainId = await this.getChain();
|
||||
const whInstructions = [];
|
||||
|
||||
if (myState.validTimePeriod !== target.validTimePeriod) {
|
||||
whInstructions.push(
|
||||
new SetValidPeriodInstruction(myChainId, BigInt(target.validTimePeriod))
|
||||
new SetValidPeriod(myChainId, BigInt(target.validTimePeriod))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ChainId, ChainName } from "@certusone/wormhole-sdk";
|
||||
import { ChainName } from "../chains";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import {
|
||||
PythGovernanceAction,
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
PythGovernanceHeader,
|
||||
} from "./PythGovernanceAction";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import { ChainName } from "@certusone/wormhole-sdk";
|
||||
import { ChainName } from "../chains";
|
||||
|
||||
/**
|
||||
* Authorize transferring the governance data source from the sender's emitter address to another emitter.
|
||||
|
@ -53,7 +53,7 @@ export class AuthorizeGovernanceDataSourceTransfer
|
|||
export class RequestGovernanceDataSourceTransfer extends PythGovernanceActionImpl {
|
||||
static layout: BufferLayout.Structure<
|
||||
Readonly<{ governanceDataSourceIndex: number }>
|
||||
> = BufferLayout.struct([BufferLayout.u32be()]);
|
||||
> = BufferLayout.struct([BufferLayout.u32be("governanceDataSourceIndex")]);
|
||||
|
||||
constructor(
|
||||
targetChainId: ChainName,
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
import {
|
||||
ChainId,
|
||||
ChainName,
|
||||
toChainId,
|
||||
toChainName,
|
||||
} from "@certusone/wormhole-sdk";
|
||||
import { ChainId, ChainName, toChainId, toChainName } from "../chains";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import { PACKET_DATA_SIZE } from "@solana/web3.js";
|
||||
|
||||
|
@ -19,6 +14,7 @@ export const TargetAction = {
|
|||
SetFee: 3,
|
||||
SetValidPeriod: 4,
|
||||
RequestGovernanceDataSourceTransfer: 5,
|
||||
SetWormholeAddress: 6,
|
||||
} as const;
|
||||
|
||||
/** Helper to get the ActionName from a (moduleId, actionId) tuple*/
|
||||
|
@ -41,6 +37,8 @@ export function toActionName(
|
|||
return "SetValidPeriod";
|
||||
case 5:
|
||||
return "RequestGovernanceDataSourceTransfer";
|
||||
case 6:
|
||||
return "SetWormholeAddress";
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
PythGovernanceActionImpl,
|
||||
PythGovernanceHeader,
|
||||
} from "./PythGovernanceAction";
|
||||
import { ChainName } from "@certusone/wormhole-sdk";
|
||||
import { ChainName } from "../chains";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import * as BufferLayoutExt from "./BufferLayoutExt";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { PythGovernanceActionImpl } from "./PythGovernanceAction";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import * as BufferLayoutExt from "./BufferLayoutExt";
|
||||
import { ChainName } from "@certusone/wormhole-sdk";
|
||||
import { ChainName } from "../chains";
|
||||
|
||||
/** Set the fee on the target chain to newFeeValue * 10^newFeeExpo */
|
||||
export class SetFee extends PythGovernanceActionImpl {
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
} from "./PythGovernanceAction";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import * as BufferLayoutExt from "./BufferLayoutExt";
|
||||
import { ChainName } from "@certusone/wormhole-sdk";
|
||||
import { ChainName } from "../chains";
|
||||
|
||||
/** Set the valid period (the default amount of time in which prices are considered fresh) to the provided value */
|
||||
export class SetValidPeriod extends PythGovernanceActionImpl {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { ChainName } from "../chains";
|
||||
import { PythGovernanceActionImpl } from "./PythGovernanceAction";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import * as BufferLayoutExt from "./BufferLayoutExt";
|
||||
|
||||
export class EvmSetWormholeAddress extends PythGovernanceActionImpl {
|
||||
static layout: BufferLayout.Structure<Readonly<{ address: string }>> =
|
||||
BufferLayout.struct([BufferLayoutExt.hexBytes(20, "address")]);
|
||||
|
||||
constructor(targetChainId: ChainName, readonly address: string) {
|
||||
super(targetChainId, "SetWormholeAddress");
|
||||
}
|
||||
|
||||
static decode(data: Buffer): EvmSetWormholeAddress | undefined {
|
||||
const decoded = PythGovernanceActionImpl.decodeWithPayload(
|
||||
data,
|
||||
"SetWormholeAddress",
|
||||
this.layout
|
||||
);
|
||||
if (!decoded) return undefined;
|
||||
|
||||
return new EvmSetWormholeAddress(
|
||||
decoded[0].targetChainId,
|
||||
decoded[1].address
|
||||
);
|
||||
}
|
||||
|
||||
encode(): Buffer {
|
||||
return super.encodeWithPayload(EvmSetWormholeAddress.layout, {
|
||||
address: this.address,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { ChainName } from "@certusone/wormhole-sdk";
|
||||
import { ChainName } from "../chains";
|
||||
import { PythGovernanceActionImpl } from "./PythGovernanceAction";
|
||||
import * as BufferLayout from "@solana/buffer-layout";
|
||||
import * as BufferLayoutExt from "./BufferLayoutExt";
|
||||
|
@ -63,6 +63,35 @@ export class AptosAuthorizeUpgradeContract extends PythGovernanceActionImpl {
|
|||
}
|
||||
}
|
||||
|
||||
export class SuiAuthorizeUpgradeContract extends PythGovernanceActionImpl {
|
||||
static layout: BufferLayout.Structure<Readonly<{ hash: string }>> =
|
||||
BufferLayout.struct([BufferLayoutExt.hexBytes(32, "hash")]);
|
||||
|
||||
constructor(targetChainId: ChainName, readonly hash: string) {
|
||||
super(targetChainId, "UpgradeContract");
|
||||
}
|
||||
|
||||
static decode(data: Buffer): SuiAuthorizeUpgradeContract | undefined {
|
||||
const decoded = PythGovernanceActionImpl.decodeWithPayload(
|
||||
data,
|
||||
"UpgradeContract",
|
||||
this.layout
|
||||
);
|
||||
if (!decoded) return undefined;
|
||||
|
||||
return new SuiAuthorizeUpgradeContract(
|
||||
decoded[0].targetChainId,
|
||||
decoded[1].hash
|
||||
);
|
||||
}
|
||||
|
||||
encode(): Buffer {
|
||||
return super.encodeWithPayload(SuiAuthorizeUpgradeContract.layout, {
|
||||
hash: this.hash,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class EvmUpgradeContract extends PythGovernanceActionImpl {
|
||||
static layout: BufferLayout.Structure<Readonly<{ address: string }>> =
|
||||
BufferLayout.struct([BufferLayoutExt.hexBytes(20, "address")]);
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
import { SetDataSources } from "./SetDataSources";
|
||||
import { SetValidPeriod } from "./SetValidPeriod";
|
||||
import { SetFee } from "./SetFee";
|
||||
import { EvmSetWormholeAddress } from "./SetWormholeAddress";
|
||||
|
||||
/** Decode a governance payload */
|
||||
export function decodeGovernancePayload(
|
||||
|
@ -50,6 +51,8 @@ export function decodeGovernancePayload(
|
|||
return SetValidPeriod.decode(data);
|
||||
case "RequestGovernanceDataSourceTransfer":
|
||||
return RequestGovernanceDataSourceTransfer.decode(data);
|
||||
case "SetWormholeAddress":
|
||||
return EvmSetWormholeAddress.decode(data);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
@ -57,3 +60,10 @@ export function decodeGovernancePayload(
|
|||
|
||||
export { ExecutePostedVaa } from "./ExecutePostedVaa";
|
||||
export * from "./PythGovernanceAction";
|
||||
export * from "./UpgradeContract";
|
||||
export * from "./PythGovernanceAction";
|
||||
export * from "./GovernanceDataSourceTransfer";
|
||||
export * from "./SetDataSources";
|
||||
export * from "./SetValidPeriod";
|
||||
export * from "./SetFee";
|
||||
export * from "./SetWormholeAddress";
|
||||
|
|
|
@ -11,3 +11,4 @@ export * from "./cranks";
|
|||
export * from "./message_buffer";
|
||||
export * from "./contracts";
|
||||
export * from "./executor";
|
||||
export * from "./chains";
|
||||
|
|
|
@ -9,7 +9,7 @@ USER 1000
|
|||
COPY --chown=1000:1000 governance/xc_admin governance/xc_admin
|
||||
COPY --chown=1000:1000 pythnet/message_buffer pythnet/message_buffer
|
||||
COPY --chown=1000:1000 target_chains/ethereum/sdk/solidity target_chains/ethereum/sdk/solidity
|
||||
COPY --chown=1000:1000 governance/xc_governance_sdk_js governance/xc_governance_sdk_js
|
||||
COPY --chown=1000:1000 governance/xc_admin/packages/xc_admin_common governance/xc_admin/packages/xc_admin_common
|
||||
|
||||
ENV NODE_ENV production
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["@typescript-eslint"],
|
||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
},
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
node_modules
|
||||
lib
|
||||
.dccache
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [2021] [Pyth Data Foundation]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,5 +0,0 @@
|
|||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
};
|
|
@ -1,42 +0,0 @@
|
|||
{
|
||||
"name": "@pythnetwork/xc-governance-sdk",
|
||||
"version": "0.4.0",
|
||||
"description": "Pyth Cross-chain Governance SDK",
|
||||
"private": "true",
|
||||
"homepage": "https://pyth.network",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*"
|
||||
],
|
||||
"repository": "https://github.com/pyth-network/pyth-crosschain/",
|
||||
"scripts": {
|
||||
"test": "jest src/ --passWithNoTests",
|
||||
"build": "tsc",
|
||||
"format": "prettier --write \"src/**/*.ts\"",
|
||||
"lint": "eslint src/",
|
||||
"prepublishOnly": "npm run build && npm test && npm run lint",
|
||||
"preversion": "npm run lint",
|
||||
"version": "npm run format && git add -A src"
|
||||
},
|
||||
"keywords": [
|
||||
"pyth",
|
||||
"oracle"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^28.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^5.36.2",
|
||||
"@typescript-eslint/parser": "^5.36.2",
|
||||
"eslint": "^8.23.0",
|
||||
"jest": "^28.0.8",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-jest": "^28.0.8",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.6.2",
|
||||
"ethers": "^5.7.0"
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
export {
|
||||
DataSource,
|
||||
AptosAuthorizeUpgradeContractInstruction,
|
||||
SuiAuthorizeUpgradeContractInstruction,
|
||||
EthereumUpgradeContractInstruction,
|
||||
EthereumSetWormholeAddress,
|
||||
HexString20Bytes,
|
||||
HexString32Bytes,
|
||||
SetDataSourcesInstruction,
|
||||
SetFeeInstruction,
|
||||
SetValidPeriodInstruction,
|
||||
RequestGovernanceDataSourceTransferInstruction,
|
||||
AuthorizeGovernanceDataSourceTransferInstruction,
|
||||
CosmwasmUpgradeContractInstruction,
|
||||
Instruction,
|
||||
} from "./instructions";
|
||||
|
||||
export {
|
||||
WORMHOLE_CHAINS,
|
||||
RECEIVER_CHAINS,
|
||||
CHAINS,
|
||||
ChainId,
|
||||
ChainName,
|
||||
} from "./chains";
|
|
@ -1,217 +0,0 @@
|
|||
import { ChainId } from "./chains";
|
||||
|
||||
import { Serializable, BufferBuilder } from "./serialize";
|
||||
|
||||
enum Module {
|
||||
Executor = 0,
|
||||
Target,
|
||||
}
|
||||
|
||||
enum TargetAction {
|
||||
UpgradeContract = 0,
|
||||
AuthorizeGovernanceDataSourceTransfer,
|
||||
SetDataSources,
|
||||
SetFee,
|
||||
SetValidPeriod,
|
||||
RequestGovernanceDataSourceTransfer,
|
||||
SetWormholeAddress,
|
||||
}
|
||||
|
||||
abstract class HexString implements Serializable {
|
||||
private readonly addressBuffer: Buffer;
|
||||
|
||||
constructor(address: string, byteLen: number) {
|
||||
if (address.startsWith("0x")) {
|
||||
address = address.substring(2);
|
||||
}
|
||||
if (address.length !== 2 * byteLen) {
|
||||
throw new Error(
|
||||
`Expected address of length ${2 * byteLen}, found ${address.length}`
|
||||
);
|
||||
}
|
||||
this.addressBuffer = Buffer.from(address, "hex");
|
||||
if (this.addressBuffer.length === 0) {
|
||||
throw new Error(`Given address is not in hex format`);
|
||||
}
|
||||
}
|
||||
|
||||
serialize(): Buffer {
|
||||
return this.addressBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
export class HexString20Bytes extends HexString {
|
||||
constructor(address: string) {
|
||||
super(address, 20);
|
||||
}
|
||||
}
|
||||
|
||||
export class HexString32Bytes extends HexString {
|
||||
constructor(address: string) {
|
||||
super(address, 32);
|
||||
}
|
||||
}
|
||||
|
||||
export class DataSource implements Serializable {
|
||||
constructor(
|
||||
private readonly emitterChain: ChainId,
|
||||
private readonly emitterAddress: HexString32Bytes
|
||||
) {}
|
||||
|
||||
serialize(): Buffer {
|
||||
return new BufferBuilder()
|
||||
.addUint16(Number(this.emitterChain))
|
||||
.addObject(this.emitterAddress)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
// Magic is `PTGM` encoded as a 4 byte data: Pyth Governance Message
|
||||
const MAGIC = 0x5054474d;
|
||||
|
||||
export abstract class Instruction implements Serializable {
|
||||
constructor(
|
||||
private module: Module,
|
||||
private action: number,
|
||||
private targetChainId: ChainId
|
||||
) {}
|
||||
|
||||
protected abstract serializePayload(): Buffer;
|
||||
|
||||
private serializeHeader(): Buffer {
|
||||
return new BufferBuilder()
|
||||
.addUint32(MAGIC)
|
||||
.addUint8(this.module)
|
||||
.addUint8(this.action)
|
||||
.addUint16(Number(this.targetChainId))
|
||||
.build();
|
||||
}
|
||||
|
||||
public serialize(): Buffer {
|
||||
return new BufferBuilder()
|
||||
.addBuffer(this.serializeHeader())
|
||||
.addBuffer(this.serializePayload())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TargetInstruction extends Instruction {
|
||||
constructor(action: TargetAction, targetChainId: ChainId) {
|
||||
super(Module.Target, Number(action), targetChainId);
|
||||
}
|
||||
}
|
||||
|
||||
export class AptosAuthorizeUpgradeContractInstruction extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private hash: HexString32Bytes) {
|
||||
super(TargetAction.UpgradeContract, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return this.hash.serialize();
|
||||
}
|
||||
}
|
||||
|
||||
export class SuiAuthorizeUpgradeContractInstruction extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private digest: HexString32Bytes) {
|
||||
super(TargetAction.UpgradeContract, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return this.digest.serialize();
|
||||
}
|
||||
}
|
||||
|
||||
export class EthereumUpgradeContractInstruction extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private address: HexString20Bytes) {
|
||||
super(TargetAction.UpgradeContract, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return this.address.serialize();
|
||||
}
|
||||
}
|
||||
|
||||
export class CosmwasmUpgradeContractInstruction extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private codeId: bigint) {
|
||||
super(TargetAction.UpgradeContract, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return new BufferBuilder().addBigUint64(this.codeId).build();
|
||||
}
|
||||
}
|
||||
|
||||
export class AuthorizeGovernanceDataSourceTransferInstruction extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private claimVaa: Buffer) {
|
||||
super(TargetAction.AuthorizeGovernanceDataSourceTransfer, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return this.claimVaa;
|
||||
}
|
||||
}
|
||||
|
||||
export class SetDataSourcesInstruction extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private dataSources: DataSource[]) {
|
||||
super(TargetAction.SetDataSources, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
const builder = new BufferBuilder();
|
||||
builder.addUint8(this.dataSources.length);
|
||||
this.dataSources.forEach((datasource) => builder.addObject(datasource));
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
export class SetFeeInstruction extends TargetInstruction {
|
||||
constructor(
|
||||
targetChainId: ChainId,
|
||||
private newFeeValue: bigint,
|
||||
private newFeeExpo: bigint
|
||||
) {
|
||||
super(TargetAction.SetFee, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return new BufferBuilder()
|
||||
.addBigUint64(this.newFeeValue)
|
||||
.addBigUint64(this.newFeeExpo)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
export class SetValidPeriodInstruction extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private newValidPeriod: bigint) {
|
||||
super(TargetAction.SetValidPeriod, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return new BufferBuilder().addBigUint64(this.newValidPeriod).build();
|
||||
}
|
||||
}
|
||||
|
||||
export class RequestGovernanceDataSourceTransferInstruction extends TargetInstruction {
|
||||
constructor(
|
||||
targetChainId: ChainId,
|
||||
private governanceDataSourceIndex: number
|
||||
) {
|
||||
super(TargetAction.RequestGovernanceDataSourceTransfer, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return new BufferBuilder()
|
||||
.addUint32(this.governanceDataSourceIndex)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
export class EthereumSetWormholeAddress extends TargetInstruction {
|
||||
constructor(targetChainId: ChainId, private address: HexString20Bytes) {
|
||||
super(TargetAction.SetWormholeAddress, targetChainId);
|
||||
}
|
||||
|
||||
protected serializePayload(): Buffer {
|
||||
return this.address.serialize();
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
export interface Serializable {
|
||||
serialize(): Buffer;
|
||||
}
|
||||
|
||||
export class BufferBuilder {
|
||||
private items: Buffer[];
|
||||
|
||||
constructor() {
|
||||
this.items = [];
|
||||
}
|
||||
|
||||
addUint8(value: number): BufferBuilder {
|
||||
const buffer = Buffer.alloc(1);
|
||||
buffer.writeUint8(value);
|
||||
this.items.push(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
addUint16(value: number): BufferBuilder {
|
||||
const buffer = Buffer.alloc(2);
|
||||
buffer.writeUint16BE(value);
|
||||
this.items.push(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
addUint32(value: number): BufferBuilder {
|
||||
const buffer = Buffer.alloc(4);
|
||||
buffer.writeUint32BE(value);
|
||||
this.items.push(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
addBigUint64(value: bigint): BufferBuilder {
|
||||
const buffer = Buffer.alloc(8);
|
||||
buffer.writeBigInt64BE(value);
|
||||
this.items.push(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
addObject(obj: Serializable): BufferBuilder {
|
||||
this.items.push(obj.serialize());
|
||||
return this;
|
||||
}
|
||||
|
||||
addBuffer(buffer: Buffer): BufferBuilder {
|
||||
this.items.push(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): Buffer {
|
||||
const totalLength = this.items.reduce((prev, cur) => prev + cur.length, 0);
|
||||
|
||||
const result = Buffer.alloc(totalLength);
|
||||
|
||||
let offset = 0;
|
||||
for (const arr of this.items) {
|
||||
result.set(arr, offset);
|
||||
offset += arr.length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"rootDir": "src/",
|
||||
"outDir": "./lib"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,6 @@
|
|||
"name": "root",
|
||||
"workspaces": [
|
||||
"governance/xc_admin/packages/*",
|
||||
"governance/xc_governance_sdk_js",
|
||||
"governance/multisig_wh_message_builder",
|
||||
"price_pusher",
|
||||
"price_service/server",
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"@injectivelabs/networks": "1.0.68",
|
||||
"@injectivelabs/sdk-ts": "1.0.354",
|
||||
"@ltd/j-toml": "^1.38.0",
|
||||
"@pythnetwork/xc-governance-sdk": "*",
|
||||
"xc_admin_common": "*",
|
||||
"@terra-money/terra.js": "^3.1.3",
|
||||
"adm-zip": "^0.5.10",
|
||||
"chain-registry": "^1.6.0",
|
||||
|
|
|
@ -93,8 +93,8 @@ export const CHAINS_NETWORK_CONFIG: Record<ChainId, ChainNetworkConfig> = {
|
|||
[ChainId.NEUTRON_TESTNET_PION_1]: {
|
||||
chainId: ChainId.NEUTRON_TESTNET_PION_1,
|
||||
chainType: ChainType.COSMWASM,
|
||||
executorEndpoint: "https://rpc.pion.rs-testnet.polypore.xyz/",
|
||||
querierEndpoint: "https://rpc.pion.rs-testnet.polypore.xyz/",
|
||||
executorEndpoint: "https://rpc-palvus.pion-1.ntrn.tech/",
|
||||
querierEndpoint: "https://rpc-palvus.pion-1.ntrn.tech/",
|
||||
prefix: "neutron",
|
||||
gasPrice: "0.025untrn",
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CHAINS } from "@pythnetwork/xc-governance-sdk";
|
||||
import { CHAINS } from "xc_admin_common";
|
||||
import { ChainId } from "./chains-manager/chains";
|
||||
import { DeploymentType } from "./helper";
|
||||
|
||||
|
|
|
@ -2,21 +2,21 @@
|
|||
"deploy-pyth-code": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"codeId": 473,
|
||||
"txHash": "73EFB113F0AA5D4C7DC98E96F1452E5DCC1C8C43F335CADEB7351777F0D7F7F1"
|
||||
"codeId": 1175,
|
||||
"txHash": "5A9961A345856E14C2F42D04A881BEF1678A90DEDCC5C9F7B87EE2F6CAA7CA0C"
|
||||
}
|
||||
},
|
||||
"instantiate-contract": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"contractAddr": "neutron1xxmcu6wxgawjlajx8jalyk9cxsudnygjg0tvjesfyurh4utvtpes5wmpjp",
|
||||
"txHash": "CD0D6CB6C80757DB1CBC6B4FF3E1C7526DFD4F8877743A04EB77B5848195D3FF"
|
||||
"contractAddr": "neutron16zwrmx3zgggmxhzau86xfycm42cr4sj888hdvzsxya3qarp6zhhqzhlkvz",
|
||||
"txHash": "1B483BFC11C7D155167E8BAB1D4083B685B69E3A7667CA541C9AE7B9F8C8611B"
|
||||
}
|
||||
},
|
||||
"set-own-admin": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"txHash": "B26BCEB73B826C797B78BE1E1AD35BC23752E3E670E106A396CD1D1648089304"
|
||||
"txHash": "5E160580E230DA5ADD0576ACFDEA02FD0776E272AB84E0AE4C520DD8E5CF70C5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"push-price-update": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"txHash": "20B98E3DD44B950E390303281A862734C4DB4BC5252588B02DB7BD0652637E51"
|
||||
"txHash": "ECA134B6CB6C9240AA80B49CF15C8215CA08949C3F68B7720D7E8B9B8E998E41"
|
||||
}
|
||||
},
|
||||
"fetch-price-feed-update": {
|
||||
|
@ -11,16 +11,16 @@
|
|||
"price_feed": {
|
||||
"id": "f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b",
|
||||
"price": {
|
||||
"price": "2628800000000",
|
||||
"conf": "988214743",
|
||||
"price": "3012903119923",
|
||||
"conf": "722024077",
|
||||
"expo": -8,
|
||||
"publish_time": 1684939947
|
||||
"publish_time": 1689590826
|
||||
},
|
||||
"ema_price": {
|
||||
"price": "2646641040000",
|
||||
"conf": "828376020",
|
||||
"price": "3017327600000",
|
||||
"conf": "741279200",
|
||||
"expo": -8,
|
||||
"publish_time": 1684939947
|
||||
"publish_time": 1689590826
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,21 +2,21 @@
|
|||
"deploy-pyth-code": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"codeId": 472,
|
||||
"txHash": "00A7125012E7B5ECE6DB5938DC177B37A37C0AEC42B08D3D5A7B3CC9C1A2161D"
|
||||
"codeId": 1176,
|
||||
"txHash": "E71CB5A163B58222D0458F4C661369D00190C81FF6BBF0C6A5442CE5E8558235"
|
||||
}
|
||||
},
|
||||
"instantiate-contract": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"contractAddr": "neutron1f86ct5az9qpz2hqfd5uxru02px2a3tz5zkw7hugd7acqq496dcms22ehpy",
|
||||
"txHash": "3DEBFABE0AFB4BB2F9C40427DB2E2C91BC4F5BC34324FD3E3962158063BFB88D"
|
||||
"contractAddr": "neutron15ldst8t80982akgr8w8ekcytejzkmfpgdkeq4xgtge48qs7435jqp87u3t",
|
||||
"txHash": "EA0B91043F0281D4A4E58D9749C109304BEC3C5A309E70C3918F5C0F8951A079"
|
||||
}
|
||||
},
|
||||
"set-own-admin": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"txHash": "5D4E120C11134B610DD15BD3C32F834300D4662358E10BBABD9907961E34DFF1"
|
||||
"txHash": "572A32BCFF99FB5A83DD5B50A77A20214FA54064F2D4FEA3BD8E70F8372FEA02"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"push-price-update": {
|
||||
"status": "fulfilled",
|
||||
"result": {
|
||||
"txHash": "C236ECE2ACA96AE4325AB02C7FCF7BFE5974C3B2D4BF52903FB4F483F1CA5970"
|
||||
"txHash": "0747A3C2A608C154B291BB11C621E1C7C3F30A1356FAA051E138659471765F4E"
|
||||
}
|
||||
},
|
||||
"fetch-price-feed-update": {
|
||||
|
@ -11,16 +11,16 @@
|
|||
"price_feed": {
|
||||
"id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
|
||||
"price": {
|
||||
"price": "2630007893200",
|
||||
"conf": "1119111601",
|
||||
"price": "3015369873290",
|
||||
"conf": "941626709",
|
||||
"expo": -8,
|
||||
"publish_time": 1684939862
|
||||
"publish_time": 1689590919
|
||||
},
|
||||
"ema_price": {
|
||||
"price": "2648559910000",
|
||||
"conf": "802705780",
|
||||
"price": "3017698600000",
|
||||
"conf": "899541390",
|
||||
"expo": -8,
|
||||
"publish_time": 1684939862
|
||||
"publish_time": 1689590919
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ MIGRATIONS_NETWORK= # xyz
|
|||
# This value should derive from Pyth to wormhole latency, and target chain blocktime and latency.
|
||||
VALID_TIME_PERIOD_SECONDS= # 60
|
||||
|
||||
WORMHOLE_CHAIN_NAME= # ethereum, defined in <repo-root>/third_party/pyth/xc_governance_sdk_js/src/chains.ts
|
||||
WORMHOLE_CHAIN_NAME= # ethereum, defined in <repo-root>/governance/xc_admin/packages/xc_admin_common/src/chains.ts
|
||||
|
||||
CLUSTER= #mainnet/testnet The configs below are read from the cluster file
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ Each network that Pyth is deployed on has some configuration stored on this repo
|
|||
- `MIGRATIONS_NETWORK`: Network name in the [`truffle-config.js`](./truffle-config.js) file.
|
||||
- `WORMHOLE_CHAIN_NAME`: Chain name in Wormhole. It is either defined in the
|
||||
[Wormhole SDK constants](https://github.com/wormhole-foundation/wormhole/blob/dev.v2/sdk/js/src/utils/consts.ts)
|
||||
or is defined in [Wormhole Receiver names](../../../governance/xc_governance_sdk_js/src/chains.ts). If the new
|
||||
or is defined in [Wormhole Receiver names](../../../governance/xc_admin/packages/xc_admin_common/src/chains.ts). If the new
|
||||
network requires a Receiver contract you need to update the latter file and add the network there.
|
||||
- `CLUSTER`: Cluster of this network. It is either `testnet` or `mainnet`. There are some cluster specific
|
||||
configuration that are loaded from [`.env.cluster.testnet`](./.env.cluster.testnet) or
|
||||
|
@ -69,7 +69,7 @@ This is the deployment process:
|
|||
5. Make sure the deployment account has proper balance on this network and top it up if needed. Search
|
||||
for testnet faucets if it is a testnet network. Sometimes you need to bridge the network token (e.g., L2s).
|
||||
6. Deploy the new contract or changes using the [`deploy.sh`](./deploy.sh) script. If you have made changes
|
||||
to [`chains.ts`](../../../governance/xc_governance_sdk_js/src/chains.ts), please make sure to
|
||||
to [`chains.ts`](../../../governance/xc_admin/packages/xc_admin_common/src/chains.ts), please make sure to
|
||||
run `npx lerna run build --scope="@pythnetwork/pyth-evm-contract" --include-dependencies` in the
|
||||
root directory before running the deployment script.
|
||||
You might need to repeat this script because of busy RPCs. Repeating would not cause any problem even
|
||||
|
|
|
@ -2,7 +2,7 @@ import { utils, Wallet } from "zksync-web3";
|
|||
import { HardhatRuntimeEnvironment } from "hardhat/types";
|
||||
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
|
||||
import loadEnv from "../scripts/loadEnv";
|
||||
import { CHAINS } from "@pythnetwork/xc-governance-sdk";
|
||||
import { CHAINS } from "xc_admin_common";
|
||||
import { assert } from "chai";
|
||||
import { writeFileSync } from "fs";
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import { utils, Wallet } from "zksync-web3";
|
|||
import { HardhatRuntimeEnvironment } from "hardhat/types";
|
||||
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
|
||||
import loadEnv from "../scripts/loadEnv";
|
||||
import { CHAINS } from "@pythnetwork/xc-governance-sdk";
|
||||
import { assert } from "chai";
|
||||
import { writeFileSync } from "fs";
|
||||
import { ethers } from "ethers";
|
||||
|
|
|
@ -2,7 +2,7 @@ const loadEnv = require("../../scripts/loadEnv");
|
|||
loadEnv("../../");
|
||||
|
||||
const tdr = require("truffle-deploy-registry");
|
||||
const governance = require("@pythnetwork/xc-governance-sdk");
|
||||
const governance = require("xc_admin_common");
|
||||
const { assert } = require("chai");
|
||||
|
||||
const ReceiverSetup = artifacts.require("ReceiverSetup");
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"@openzeppelin/hardhat-upgrades": "^1.22.1",
|
||||
"@pythnetwork/pyth-multisig-wh-message-builder": "*",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^2.2.0",
|
||||
"@pythnetwork/xc-governance-sdk": "*",
|
||||
"xc_admin_common": "*",
|
||||
"dotenv": "^10.0.0",
|
||||
"elliptic": "^6.5.2",
|
||||
"ethers": "^5.7.2",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* the previous step in the next run.
|
||||
*/
|
||||
|
||||
const governance = require("@pythnetwork/xc-governance-sdk");
|
||||
const governance = require("xc_admin_common");
|
||||
const wormhole = require("@certusone/wormhole-sdk");
|
||||
const assertVaaPayloadEquals = require("./assertVaaPayloadEquals");
|
||||
const { assert } = require("chai");
|
||||
|
@ -233,10 +233,10 @@ async function upgradeContract(proxy, desiredVersion) {
|
|||
newImplementationAddress = newImplementation.address;
|
||||
}
|
||||
|
||||
const upgradePayload = new governance.EthereumUpgradeContractInstruction(
|
||||
governance.CHAINS[chainName],
|
||||
new governance.HexString20Bytes(newImplementationAddress)
|
||||
).serialize();
|
||||
const upgradePayload = new governance.EvmUpgradeContract(
|
||||
chainName,
|
||||
newImplementationAddress.replace("0x", "")
|
||||
).encode();
|
||||
|
||||
const upgradePayloadHex = upgradePayload.toString("hex");
|
||||
|
||||
|
@ -277,11 +277,11 @@ async function syncUpdateFee(proxy) {
|
|||
`desired update fee: ${desiredUpdateFee}. Updating...`
|
||||
);
|
||||
|
||||
const setFeePayload = new governance.SetFeeInstruction(
|
||||
governance.CHAINS[chainName],
|
||||
const setFeePayload = new governance.SetFee(
|
||||
chainName,
|
||||
BigInt(desiredUpdateFee),
|
||||
BigInt(0)
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
await createAndExecuteVaaFromPayloadThroughMultiSig(proxy, setFeePayload);
|
||||
|
||||
|
@ -308,10 +308,10 @@ async function syncValidTimePeriod(proxy) {
|
|||
`desired valid time period: ${desiredValidTimePeriod}s. Updating...`
|
||||
);
|
||||
|
||||
const setValidPeriodPayload = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS[chainName],
|
||||
const setValidPeriodPayload = new governance.SetValidPeriod(
|
||||
chainName,
|
||||
BigInt(desiredValidTimePeriod)
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
await createAndExecuteVaaFromPayloadThroughMultiSig(
|
||||
proxy,
|
||||
|
@ -357,16 +357,13 @@ async function syncDataSources(proxy) {
|
|||
|
||||
// Usually this change is universal, so the Payload is generated for all
|
||||
// the chains.
|
||||
const setDataSourcesPayload = new governance.SetDataSourcesInstruction(
|
||||
governance.CHAINS[chainName],
|
||||
Array.from(desiredDataSources).map(
|
||||
(ds) =>
|
||||
new governance.DataSource(
|
||||
Number(ds[0]),
|
||||
new governance.HexString32Bytes(ds[1])
|
||||
)
|
||||
)
|
||||
).serialize();
|
||||
const setDataSourcesPayload = new governance.SetDataSources(
|
||||
chainName,
|
||||
Array.from(desiredDataSources).map((ds) => ({
|
||||
emitterChain: Number(ds[0]),
|
||||
emitterAddress: ds[1].replace("0x", ""),
|
||||
}))
|
||||
).encode();
|
||||
await createAndExecuteVaaFromPayloadThroughMultiSig(
|
||||
proxy,
|
||||
setDataSourcesPayload
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const elliptic = require("elliptic");
|
||||
const governance = require("@pythnetwork/xc-governance-sdk");
|
||||
const governance = require("xc_admin_common");
|
||||
|
||||
const { deployProxy, upgradeProxy } = require("@openzeppelin/truffle-upgrades");
|
||||
const {
|
||||
|
@ -8,6 +8,7 @@ const {
|
|||
time,
|
||||
} = require("@openzeppelin/test-helpers");
|
||||
const { assert, expect } = require("chai");
|
||||
const { EvmSetWormholeAddress } = require("xc_admin_common");
|
||||
|
||||
// Use "WormholeReceiver" if you are testing with Wormhole Receiver
|
||||
const Setup = artifacts.require("Setup");
|
||||
|
@ -226,7 +227,7 @@ contract("Pyth", function () {
|
|||
* Create a governance instruction VAA from the Instruction object. Then
|
||||
* Submit and execute it on the contract.
|
||||
* @param contract Pyth contract
|
||||
* @param {governance.Instruction} governanceInstruction
|
||||
* @param {governance.PythGovernanceAction} governanceInstruction
|
||||
* @param {number} sequence
|
||||
*/
|
||||
async function createAndThenSubmitGovernanceInstructionVaa(
|
||||
|
@ -236,7 +237,7 @@ contract("Pyth", function () {
|
|||
) {
|
||||
await contract.executeGovernanceInstruction(
|
||||
await createVAAFromUint8Array(
|
||||
governanceInstruction.serialize(),
|
||||
governanceInstruction.encode(),
|
||||
testGovernanceChainId,
|
||||
testGovernanceEmitter,
|
||||
sequence
|
||||
|
@ -299,11 +300,7 @@ contract("Pyth", function () {
|
|||
async function setFeeTo(contract, newFee, governanceSequence) {
|
||||
await createAndThenSubmitGovernanceInstructionVaa(
|
||||
contract,
|
||||
new governance.SetFeeInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
BigInt(newFee),
|
||||
BigInt(0)
|
||||
),
|
||||
new governance.SetFee("ethereum", BigInt(newFee), BigInt(0)),
|
||||
governanceSequence ?? 1
|
||||
);
|
||||
}
|
||||
|
@ -514,10 +511,7 @@ contract("Pyth", function () {
|
|||
) {
|
||||
await createAndThenSubmitGovernanceInstructionVaa(
|
||||
contract,
|
||||
new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
BigInt(newValidPeriod)
|
||||
),
|
||||
new governance.SetValidPeriod("ethereum", BigInt(newValidPeriod)),
|
||||
governanceSequence ?? 1
|
||||
);
|
||||
}
|
||||
|
@ -606,10 +600,7 @@ contract("Pyth", function () {
|
|||
// Logics that apply to all governance messages
|
||||
it("Make sure invalid magic and module won't work", async function () {
|
||||
// First 4 bytes of data are magic and the second byte after that is module
|
||||
const data = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
BigInt(10)
|
||||
).serialize();
|
||||
const data = new governance.SetValidPeriod("ethereum", BigInt(10)).encode();
|
||||
|
||||
const wrongMagic = Buffer.from(data);
|
||||
wrongMagic[1] = 0;
|
||||
|
@ -658,10 +649,7 @@ contract("Pyth", function () {
|
|||
});
|
||||
|
||||
it("Make sure governance with wrong sender won't work", async function () {
|
||||
const data = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
BigInt(10)
|
||||
).serialize();
|
||||
const data = new governance.SetValidPeriod("ethereum", BigInt(10)).encode();
|
||||
|
||||
const vaaWrongEmitter = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -689,10 +677,10 @@ contract("Pyth", function () {
|
|||
});
|
||||
|
||||
it("Make sure governance with only target chain id and 0 work", async function () {
|
||||
const wrongChainData = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.solana,
|
||||
const wrongChainData = new governance.SetValidPeriod(
|
||||
"solana",
|
||||
BigInt(10)
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
const wrongChainVaa = await createVAAFromUint8Array(
|
||||
wrongChainData,
|
||||
|
@ -706,10 +694,10 @@ contract("Pyth", function () {
|
|||
"InvalidGovernanceTarget"
|
||||
);
|
||||
|
||||
const dataForAllChains = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.unset,
|
||||
const dataForAllChains = new governance.SetValidPeriod(
|
||||
"unset",
|
||||
BigInt(10)
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
const vaaForAllChains = await createVAAFromUint8Array(
|
||||
dataForAllChains,
|
||||
|
@ -720,10 +708,10 @@ contract("Pyth", function () {
|
|||
|
||||
await this.pythProxy.executeGovernanceInstruction(vaaForAllChains);
|
||||
|
||||
const dataForEth = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
const dataForEth = new governance.SetValidPeriod(
|
||||
"ethereum",
|
||||
BigInt(10)
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
const vaaForEth = await createVAAFromUint8Array(
|
||||
dataForEth,
|
||||
|
@ -736,10 +724,7 @@ contract("Pyth", function () {
|
|||
});
|
||||
|
||||
it("Make sure that governance messages are executed in order and cannot be reused", async function () {
|
||||
const data = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
BigInt(10)
|
||||
).serialize();
|
||||
const data = new governance.SetValidPeriod("ethereum", BigInt(10)).encode();
|
||||
|
||||
const vaaSeq1 = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -778,10 +763,10 @@ contract("Pyth", function () {
|
|||
it("Upgrading the contract with chain id 0 is invalid", async function () {
|
||||
const newImplementation = await PythUpgradable.new();
|
||||
|
||||
const data = new governance.EthereumUpgradeContractInstruction(
|
||||
governance.CHAINS.unset, // 0
|
||||
new governance.HexString20Bytes(newImplementation.address)
|
||||
).serialize();
|
||||
const data = new governance.EvmUpgradeContract(
|
||||
"unset", // 0
|
||||
newImplementation.address.replace("0x", "")
|
||||
).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -799,10 +784,10 @@ contract("Pyth", function () {
|
|||
it("Upgrading the contract should work", async function () {
|
||||
const newImplementation = await PythUpgradable.new();
|
||||
|
||||
const data = new governance.EthereumUpgradeContractInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
new governance.HexString20Bytes(newImplementation.address)
|
||||
).serialize();
|
||||
const data = new governance.EvmUpgradeContract(
|
||||
"ethereum",
|
||||
newImplementation.address.replace("0x", "")
|
||||
).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -825,10 +810,10 @@ contract("Pyth", function () {
|
|||
it("Upgrading the contract to a non-pyth contract won't work", async function () {
|
||||
const newImplementation = await MockUpgradeableProxy.new();
|
||||
|
||||
const data = new governance.EthereumUpgradeContractInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
new governance.HexString20Bytes(newImplementation.address)
|
||||
).serialize();
|
||||
const data = new governance.EvmUpgradeContract(
|
||||
"ethereum",
|
||||
newImplementation.address.replace("0x", "")
|
||||
).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -850,10 +835,7 @@ contract("Pyth", function () {
|
|||
const newEmitterChain = governance.CHAINS.acala;
|
||||
|
||||
const claimInstructionData =
|
||||
new governance.RequestGovernanceDataSourceTransferInstruction(
|
||||
governance.CHAINS.unset,
|
||||
1
|
||||
).serialize();
|
||||
new governance.RequestGovernanceDataSourceTransfer("unset", 1).encode();
|
||||
|
||||
const claimVaaHexString = await createVAAFromUint8Array(
|
||||
claimInstructionData,
|
||||
|
@ -869,11 +851,10 @@ contract("Pyth", function () {
|
|||
|
||||
const claimVaa = Buffer.from(claimVaaHexString.substring(2), "hex");
|
||||
|
||||
const data =
|
||||
new governance.AuthorizeGovernanceDataSourceTransferInstruction(
|
||||
governance.CHAINS.unset,
|
||||
claimVaa
|
||||
).serialize();
|
||||
const data = new governance.AuthorizeGovernanceDataSourceTransfer(
|
||||
"unset",
|
||||
claimVaa
|
||||
).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -904,11 +885,10 @@ contract("Pyth", function () {
|
|||
|
||||
// Make sure a claim vaa does not get executed
|
||||
|
||||
const claimLonely =
|
||||
new governance.RequestGovernanceDataSourceTransferInstruction(
|
||||
governance.CHAINS.unset,
|
||||
2
|
||||
).serialize();
|
||||
const claimLonely = new governance.RequestGovernanceDataSourceTransfer(
|
||||
"unset",
|
||||
2
|
||||
).encode();
|
||||
|
||||
const claimLonelyVaa = await createVAAFromUint8Array(
|
||||
claimLonely,
|
||||
|
@ -927,10 +907,10 @@ contract("Pyth", function () {
|
|||
|
||||
// A wrong vaa that does not move the governance index
|
||||
const transferBackClaimInstructionDataWrong =
|
||||
new governance.RequestGovernanceDataSourceTransferInstruction(
|
||||
governance.CHAINS.unset,
|
||||
new governance.RequestGovernanceDataSourceTransfer(
|
||||
"unset",
|
||||
1 // The same governance data source index => Should fail
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
const transferBackClaimVaaHexStringWrong = await createVAAFromUint8Array(
|
||||
transferBackClaimInstructionDataWrong,
|
||||
|
@ -945,10 +925,10 @@ contract("Pyth", function () {
|
|||
);
|
||||
|
||||
const transferBackDataWrong =
|
||||
new governance.AuthorizeGovernanceDataSourceTransferInstruction(
|
||||
governance.CHAINS.unset,
|
||||
new governance.AuthorizeGovernanceDataSourceTransfer(
|
||||
"unset",
|
||||
transferBackClaimVaaWrong
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
const transferBackVaaWrong = await createVAAFromUint8Array(
|
||||
transferBackDataWrong,
|
||||
|
@ -964,17 +944,13 @@ contract("Pyth", function () {
|
|||
});
|
||||
|
||||
it("Setting data sources should work", async function () {
|
||||
const data = new governance.SetDataSourcesInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
[
|
||||
new governance.DataSource(
|
||||
governance.CHAINS.acala,
|
||||
new governance.HexString32Bytes(
|
||||
"0x0000000000000000000000000000000000000000000000000000000000001111"
|
||||
)
|
||||
),
|
||||
]
|
||||
).serialize();
|
||||
const data = new governance.SetDataSources("ethereum", [
|
||||
{
|
||||
emitterChain: governance.CHAINS.acala,
|
||||
emitterAddress:
|
||||
"0000000000000000000000000000000000000000000000000000000000001111",
|
||||
},
|
||||
]).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -1020,11 +996,11 @@ contract("Pyth", function () {
|
|||
});
|
||||
|
||||
it("Setting fee should work", async function () {
|
||||
const data = new governance.SetFeeInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
const data = new governance.SetFee(
|
||||
"ethereum",
|
||||
BigInt(5),
|
||||
BigInt(3) // 5*10**3 = 5000
|
||||
).serialize();
|
||||
).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -1053,10 +1029,7 @@ contract("Pyth", function () {
|
|||
});
|
||||
|
||||
it("Setting valid period should work", async function () {
|
||||
const data = new governance.SetValidPeriodInstruction(
|
||||
governance.CHAINS.ethereum,
|
||||
BigInt(0)
|
||||
).serialize();
|
||||
const data = new governance.SetValidPeriod("ethereum", BigInt(0)).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -1098,10 +1071,10 @@ contract("Pyth", function () {
|
|||
const newWormhole = await Wormhole.new(newSetup.address, initData);
|
||||
|
||||
// Creating the vaa to set the new wormhole address
|
||||
const data = new governance.EthereumSetWormholeAddress(
|
||||
governance.CHAINS.ethereum,
|
||||
new governance.HexString20Bytes(newWormhole.address)
|
||||
).serialize();
|
||||
const data = new governance.EvmSetWormholeAddress(
|
||||
"ethereum",
|
||||
newWormhole.address.replace("0x", "")
|
||||
).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -1146,10 +1119,10 @@ contract("Pyth", function () {
|
|||
);
|
||||
|
||||
// Creating the vaa to set the new wormhole address
|
||||
const data = new governance.EthereumSetWormholeAddress(
|
||||
governance.CHAINS.ethereum,
|
||||
new governance.HexString20Bytes(newWormholeReceiver.address)
|
||||
).serialize();
|
||||
const data = new governance.EvmSetWormholeAddress(
|
||||
"ethereum",
|
||||
newWormholeReceiver.address.replace("0x", "")
|
||||
).encode();
|
||||
|
||||
const vaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
@ -1191,10 +1164,10 @@ contract("Pyth", function () {
|
|||
const newWormhole = await Wormhole.new(newSetup.address, initData);
|
||||
|
||||
// Creating the vaa to set the new wormhole address
|
||||
const data = new governance.EthereumSetWormholeAddress(
|
||||
governance.CHAINS.ethereum,
|
||||
new governance.HexString20Bytes(newWormhole.address)
|
||||
).serialize();
|
||||
const data = new governance.EvmSetWormholeAddress(
|
||||
"ethereum",
|
||||
newWormhole.address.replace("0x", "")
|
||||
).encode();
|
||||
|
||||
const wrongVaa = await createVAAFromUint8Array(
|
||||
data,
|
||||
|
|
|
@ -37,7 +37,7 @@ COPY --from=pyth_builder /code/artifacts/pyth_cosmwasm.wasm /home/node/target_ch
|
|||
|
||||
WORKDIR /home/node/
|
||||
|
||||
COPY --chown=1000:1000 governance/xc_governance_sdk_js governance/xc_governance_sdk_js
|
||||
COPY --chown=1000:1000 governance/xc_admin/packages/xc_admin_common/ governance/xc_admin/packages/xc_admin_common/
|
||||
COPY --chown=1000:1000 target_chains/cosmwasm/tools target_chains/cosmwasm/tools
|
||||
|
||||
RUN npx lerna run build --scope="@pythnetwork/cosmwasm-deploy-tools" --include-dependencies
|
||||
|
|
|
@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y ncat
|
|||
USER 1000
|
||||
WORKDIR /home/node
|
||||
COPY --chown=1000:1000 governance/multisig_wh_message_builder governance/multisig_wh_message_builder
|
||||
COPY --chown=1000:1000 governance/xc_governance_sdk_js governance/xc_governance_sdk_js
|
||||
COPY --chown=1000:1000 governance/xc_admin/packages/xc_admin_common/ governance/xc_admin/packages/xc_admin_common/
|
||||
COPY --chown=1000:1000 target_chains/ethereum/sdk/solidity target_chains/ethereum/sdk/solidity
|
||||
COPY --chown=1000:1000 target_chains/ethereum/contracts target_chains/ethereum/contracts
|
||||
|
||||
|
|
Loading…
Reference in New Issue