Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions contract_manager/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/contract-manager",
"version": "1.0.1",
"version": "1.1.0",
"description": "Set of tools to manage pyth contracts",
"private": true,
"exports": {
Expand Down Expand Up @@ -86,12 +86,9 @@
"starknet": "^6.9.0",
"ts-node": "catalog:",
"typescript": "catalog:",
"viem": "^2.23.5",
"web3": "^1.8.2",
"web3-eth-contract": "^1.8.2"
"viem": "^2.23.5"
},
"devDependencies": {
"@types/web3": "^1.2.2",
"@types/node": "catalog:",
"eslint": "^8.0.0",
"prettier": "catalog:",
Expand Down
27 changes: 13 additions & 14 deletions contract_manager/scripts/batchDeployReceivers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@

import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import {
DefaultStore,
EvmChain,
loadHotWallet,
EvmWormholeContract,
} from "@pythnetwork/contract-manager";
import Web3 from "web3";
import { DefaultStore } from "../src/node/utils/store";
import { EvmChain } from "../src/core/chains";
import { loadHotWallet } from "../src/node/utils/governance";
import { EvmWormholeContract } from "../src/core/contracts";
import { encodeFunctionData, type Abi } from "viem";
import { CHAINS } from "@pythnetwork/xc-admin-common";
import * as fs from "fs";
import { toPrivateKey } from "../src/core/base";

import { getDefaultConfig } from "../../target_chains/ethereum/contracts/scripts/contractManagerConfig";

Expand Down Expand Up @@ -62,7 +61,7 @@ async function memoize(

async function main() {
const argv = await parser.argv;
const privateKey = argv["private-key"];
const privateKey = toPrivateKey(argv["private-key"]);
const network = argv["network"];

const setupInfo = await import(argv["contract"] + "/ReceiverSetup.json");
Expand Down Expand Up @@ -101,17 +100,17 @@ async function main() {
[],
);
console.log("implementationAddress", implementationAddress);
const web3 = new Web3();
const setup = new web3.eth.Contract(setupInfo.abi, setupAddress);
const initData = setup.methods
.setup(
const initData = encodeFunctionData({
abi: setupInfo.abi as Abi,
functionName: "setup",
args: [
implementationAddress,
wormholeInitialSigners,
CHAINS[chain.wormholeChainName],
wormholeGovernanceChainId,
wormholeGovernanceContract,
)
.encodeABI();
],
});

// deploy proxy
const receiverAddress = await chain.deploy(
Expand Down
38 changes: 23 additions & 15 deletions contract_manager/scripts/check_proposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ import {
getCodeDigestWithoutAddress,
EvmWormholeContract,
} from "../src/core/contracts/evm";
import Web3 from "web3";
import {
keccak256,
toHex,
toFunctionSignature,
decodeAbiParameters,
} from "viem";

const parser = yargs(hideBin(process.argv))
.usage("Usage: $0 --cluster <cluster_id> --proposal <proposal_address>")
Expand Down Expand Up @@ -85,11 +90,12 @@ async function main() {
chain,
receiverImplementation,
).getCode();
const proxyDigest = Web3.utils.keccak256(proxyCode);
const implementationDigest =
Web3.utils.keccak256(implementationCode);
const guardianSetDigest = Web3.utils.keccak256(
JSON.stringify(guardianSet),
const proxyDigest = keccak256(proxyCode as `0x${string}`);
const implementationDigest = keccak256(
implementationCode as `0x${string}`,
);
const guardianSetDigest = keccak256(
toHex(JSON.stringify(guardianSet)),
);
console.log(
`${chain.getId()} Address:\t\t${address}\nproxy digest:\t\t${proxyDigest}\nimplementation digest:\t${implementationDigest} \nguardian set index:\t${currentIndex} \nguardian set:\t\t${guardianSetDigest}`,
Expand Down Expand Up @@ -174,17 +180,19 @@ async function main() {
// In the future, this logic may need to be generalized to support calling other functions.
const invokedMethod = "upgradeTo(address)";
const calldataHex = calldata.toString("hex");
const web3 = new Web3();
const methodSignature = web3.eth.abi
.encodeFunctionSignature(invokedMethod)
.replace("0x", "");
const methodSignature = toFunctionSignature(invokedMethod).replace(
"0x",
"",
);

let newImplementationAddress: string | undefined = undefined;
if (calldataHex.startsWith(methodSignature)) {
newImplementationAddress = web3.eth.abi.decodeParameter(
"address",
calldataHex.replace(methodSignature, ""),
) as unknown as string;
const decoded = decodeAbiParameters(
[{ name: "implementation", type: "address" }],
("0x" +
calldataHex.replace(methodSignature, "")) as `0x${string}`,
);
newImplementationAddress = decoded[0] as string;
}

if (newImplementationAddress === undefined) {
Expand All @@ -195,7 +203,7 @@ async function main() {
}

const newImplementationCode = await getCodeDigestWithoutAddress(
chain.getWeb3(),
chain.getPublicClient(),
newImplementationAddress,
);
// this should be the same keccak256 of the deployedCode property generated by truffle
Expand Down
83 changes: 44 additions & 39 deletions contract_manager/scripts/common.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { DefaultStore } from "../src/node/utils/store";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { join } from "path";
import Web3 from "web3";
import { Contract } from "web3-eth-contract";
import { getContract, encodeFunctionData, formatEther, parseEther } from "viem";
import type { Abi } from "viem";
import { InferredOptionType } from "yargs";
import { PrivateKey, getDefaultDeploymentConfig } from "../src/core/base";
import { EvmChain } from "../src/core/chains";
Expand Down Expand Up @@ -75,19 +75,24 @@ export async function deployIfNotCached(
});
}

export function getWeb3Contract(
export function getViemContract(
chain: EvmChain,
jsonOutputDir: string,
artifactName: string,
address: string,
): Contract {
) {
const artifact = JSON.parse(
readFileSync(
join(jsonOutputDir, `${artifactName}.sol`, `${artifactName}.json`),
"utf8",
),
);
const web3 = new Web3();
return new web3.eth.Contract(artifact["abi"], address);
const client = chain.getPublicClient();
return getContract({
address: address as `0x${string}`,
abi: artifact["abi"] as Abi,
client,
});
}

export const COMMON_DEPLOY_OPTIONS = {
Expand Down Expand Up @@ -306,23 +311,28 @@ export async function deployWormholeContract(
);

// Craft the init data for the proxy contract
const setupContract = getWeb3Contract(
config.jsonOutputDir,
"ReceiverSetup",
receiverSetupAddr,
const artifact = JSON.parse(
readFileSync(
join(config.jsonOutputDir, "ReceiverSetup.sol", "ReceiverSetup.json"),
"utf8",
),
);

const { wormholeConfig } = getDefaultDeploymentConfig(config.type);

const initData = setupContract.methods
.setup(
const initData = encodeFunctionData({
abi: artifact["abi"] as Abi,
functionName: "setup",
args: [
receiverImplAddr,
wormholeConfig.initialGuardianSet.map((addr: string) => "0x" + addr),
wormholeConfig.initialGuardianSet.map(
(addr: string) => ("0x" + addr) as `0x${string}`,
),
chain.getWormholeChainId(),
wormholeConfig.governanceChainId,
"0x" + wormholeConfig.governanceContract,
)
.encodeABI();
("0x" + wormholeConfig.governanceContract) as `0x${string}`,
],
});

const wormholeReceiverAddr = await deployIfNotCached(
cacheFile,
Expand Down Expand Up @@ -384,36 +394,31 @@ export async function topupAccountsIfNecessary(
const accountAddress = chain.isMainnet()
? defaultAddresses.mainnet
: defaultAddresses.testnet;
const web3 = chain.getWeb3();
const balance = Number(
web3.utils.fromWei(await web3.eth.getBalance(accountAddress), "ether"),
);
console.log(`${accountName} balance: ${balance} ETH`);
if (balance < minBalance) {
const publicClient = chain.getPublicClient();
const walletClient = chain.getWalletClient(deploymentConfig.privateKey);
const balance = await publicClient.getBalance({
address: accountAddress as `0x${string}`,
});
const balanceEth = Number(formatEther(balance));
console.log(`${accountName} balance: ${balanceEth} ETH`);
if (balanceEth < minBalance) {
console.log(
`Balance is less than ${minBalance}. Topping up the ${accountName} address...`,
);
const signer = web3.eth.accounts.privateKeyToAccount(
deploymentConfig.privateKey,
);
web3.eth.accounts.wallet.add(signer);
const estimatedGas = await web3.eth.estimateGas({
from: signer.address,
to: accountAddress,
value: web3.utils.toWei(`${minBalance}`, "ether"),
const topupValue = parseEther(minBalance.toString());
const estimatedGas = await publicClient.estimateGas({
account: walletClient.account!,
to: accountAddress as `0x${string}`,
value: topupValue,
});

const tx = await web3.eth.sendTransaction({
from: signer.address,
to: accountAddress,
gas: estimatedGas * deploymentConfig.gasMultiplier,
value: web3.utils.toWei(`${minBalance}`, "ether"),
const hash = await walletClient.sendTransaction({
to: accountAddress as `0x${string}`,
gas: estimatedGas * BigInt(deploymentConfig.gasMultiplier),
value: topupValue,
});

console.log(
`Topped up the ${accountName} address. Tx: `,
tx.transactionHash,
);
console.log(`Topped up the ${accountName} address. Tx: `, hash);
}
}
}
27 changes: 18 additions & 9 deletions contract_manager/scripts/deploy_evm_entropy_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import {
import {
COMMON_DEPLOY_OPTIONS,
deployIfNotCached,
getWeb3Contract,
getOrDeployWormholeContract,
BaseDeployConfig,
topupAccountsIfNecessary,
DefaultAddresses,
} from "./common";
import { encodeFunctionData } from "viem";
import * as fs from "fs";
import { join } from "path";
import { getOrDeployExecutorContract } from "./deploy_evm_executor_contracts";

interface DeploymentConfig extends BaseDeployConfig {
Expand Down Expand Up @@ -57,23 +59,30 @@ async function deployEntropyContracts(
[],
);

const entropyImplContract = getWeb3Contract(
config.jsonOutputDir,
"EntropyUpgradable",
entropyImplAddr,
const artifact = JSON.parse(
fs.readFileSync(
join(
config.jsonOutputDir,
"EntropyUpgradable.sol",
"EntropyUpgradable.json",
),
"utf8",
),
);

const entropyInitData = entropyImplContract.methods
.initialize(
const entropyInitData = encodeFunctionData({
abi: artifact["abi"],
functionName: "initialize",
args: [
executorAddr, // owner
executorAddr, // admin
1, // pythFeeInWei
chain.isMainnet()
? ENTROPY_DEFAULT_PROVIDER.mainnet
: ENTROPY_DEFAULT_PROVIDER.testnet,
true, // prefillRequestStorage
)
.encodeABI();
],
});

return await deployIfNotCached(
CACHE_FILE,
Expand Down
5 changes: 3 additions & 2 deletions contract_manager/scripts/deploy_evm_executor_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
deployIfNotCached,
findExecutorContract,
getOrDeployWormholeContract,
getWeb3Contract,
getViemContract,
} from "./common";
import {
DeploymentType,
Expand Down Expand Up @@ -73,7 +73,8 @@ export async function deployExecutorContracts(
// Craft the init data for the proxy contract
const { governanceDataSource } = getDefaultDeploymentConfig(config.type);

const executorImplContract = getWeb3Contract(
const executorImplContract = getViemContract(
chain,
config.jsonOutputDir,
"ExecutorUpgradable",
executorImplAddr,
Expand Down
5 changes: 3 additions & 2 deletions contract_manager/scripts/deploy_evm_pricefeed_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { hideBin } from "yargs/helpers";
import {
COMMON_DEPLOY_OPTIONS,
deployIfNotCached,
getWeb3Contract,
getViemContract,
getOrDeployWormholeContract,
BaseDeployConfig,
} from "./common";
Expand Down Expand Up @@ -81,7 +81,8 @@ async function deployPriceFeedContracts(
config.type,
);

const pythImplContract = getWeb3Contract(
const pythImplContract = getViemContract(
chain,
config.jsonOutputDir,
"PythUpgradable",
pythImplAddr,
Expand Down
5 changes: 3 additions & 2 deletions contract_manager/scripts/deploy_evm_pulse_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { hideBin } from "yargs/helpers";
import {
COMMON_DEPLOY_OPTIONS,
deployIfNotCached,
getWeb3Contract,
getViemContract,
getOrDeployWormholeContract,
BaseDeployConfig,
topupAccountsIfNecessary,
Expand Down Expand Up @@ -71,7 +71,8 @@ async function deployPulseContracts(

console.log("PulseUpgradeable implementation deployed at:", pulseImplAddr);

const pulseImplContract = getWeb3Contract(
const pulseImplContract = getViemContract(
chain,
config.jsonOutputDir,
"PulseUpgradeable",
pulseImplAddr,
Expand Down
Loading
Loading