Skip to content

Commit

Permalink
refactor(contract_manager): reduce duplicate code (#1311)
Browse files Browse the repository at this point in the history
* feat(contract_manager): Add check for wormhole address on entropy deployment

* feat(contract_manager): Add getter for wormhole in entropy contract

* feat(contract_manager): topup entropy provider if necessary

* feat(contract_manager): find out wormhole address automatically for entropy

* feat(contract_manager): parse uri

* feat(contract_manager): Add list script for entropy contracts
  • Loading branch information
m30m committed Feb 23, 2024
1 parent bec2ddf commit 0d49986
Show file tree
Hide file tree
Showing 14 changed files with 387 additions and 308 deletions.
4 changes: 3 additions & 1 deletion contract_manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"scripts": {
"build": "tsc",
"shell": "ts-node ./src/shell.ts",
"lint": "eslint src/"
"lint": "eslint src/ scripts/",
"format": "prettier --write \"src/**/*.ts\" \"scripts/**/*.ts\""
},
"author": "",
"license": "Apache-2.0",
Expand All @@ -27,6 +28,7 @@
"@pythnetwork/entropy-sdk-solidity": "*",
"@pythnetwork/price-service-client": "*",
"@pythnetwork/pyth-sui-js": "*",
"@types/yargs": "^17.0.32",
"aptos": "^1.5.0",
"bs58": "^5.0.0",
"ts-node": "^10.9.1",
Expand Down
172 changes: 142 additions & 30 deletions contract_manager/scripts/common.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { EvmChain, PrivateKey } from "../src";
import { DefaultStore, EvmChain, PrivateKey } from "../src";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { join } from "path";
import Web3 from "web3";
import { Contract } from "web3-eth-contract";
import { InferredOptionType } from "yargs";

interface DeployConfig {
gasMultiplier: number;
Expand All @@ -23,39 +24,26 @@ export async function deployIfNotCached(
deployArgs: any[], // eslint-disable-line @typescript-eslint/no-explicit-any
cacheKey?: string
): Promise<string> {
const cache = existsSync(cacheFile)
? JSON.parse(readFileSync(cacheFile, "utf8"))
: {};

const runIfNotCached = makeCacheFunction(cacheFile);
const key = cacheKey ?? `${chain.getId()}-${artifactName}`;
if (cache[key]) {
const address = cache[key];
console.log(
`Using cached deployment of ${artifactName} on ${chain.getId()} at ${address}`
return runIfNotCached(key, async () => {
const artifact = JSON.parse(
readFileSync(join(config.jsonOutputDir, `${artifactName}.json`), "utf8")
);
return address;
}

const artifact = JSON.parse(
readFileSync(join(config.jsonOutputDir, `${artifactName}.json`), "utf8")
);

console.log(`Deploying ${artifactName} on ${chain.getId()}...`);

const addr = await chain.deploy(
config.privateKey,
artifact["abi"],
artifact["bytecode"],
deployArgs,
config.gasMultiplier,
config.gasPriceMultiplier
);

console.log(`✅ Deployed ${artifactName} on ${chain.getId()} at ${addr}`);
console.log(`Deploying ${artifactName} on ${chain.getId()}...`);
const addr = await chain.deploy(
config.privateKey,
artifact["abi"],
artifact["bytecode"],
deployArgs,
config.gasMultiplier,
config.gasPriceMultiplier
);
console.log(`✅ Deployed ${artifactName} on ${chain.getId()} at ${addr}`);

cache[key] = addr;
writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
return addr;
return addr;
});
}

export function getWeb3Contract(
Expand All @@ -69,3 +57,127 @@ export function getWeb3Contract(
const web3 = new Web3();
return new web3.eth.Contract(artifact["abi"], address);
}

export const COMMON_DEPLOY_OPTIONS = {
"std-output-dir": {
type: "string",
demandOption: true,
desc: "Path to the standard JSON output of the contracts (build artifact) directory",
},
"private-key": {
type: "string",
demandOption: true,
desc: "Private key to sign the trnasactions with",
},
chain: {
type: "array",
demandOption: true,
desc: "Chain to upload the contract on. Can be one of the evm chains available in the store",
},
"deployment-type": {
type: "string",
demandOption: false,
default: "stable",
desc: "Deployment type to use. Can be 'stable' or 'beta'",
},
"gas-multiplier": {
type: "number",
demandOption: false,
// Proxy (ERC1967) contract gas estimate is insufficient in many networks and thus we use 2 by default to make it work.
default: 2,
desc: "Gas multiplier to use for the deployment. This is useful when gas estimates are not accurate",
},
"gas-price-multiplier": {
type: "number",
demandOption: false,
default: 1,
desc: "Gas price multiplier to use for the deployment. This is useful when gas price estimates are not accurate",
},
"save-contract": {
type: "boolean",
demandOption: false,
default: true,
desc: "Save the contract to the store",
},
} as const;
export const COMMON_UPGRADE_OPTIONS = {
testnet: {
type: "boolean",
default: false,
desc: "Upgrade testnet contracts instead of mainnet",
},
"all-chains": {
type: "boolean",
default: false,
desc: "Upgrade the contract on all chains. Use with --testnet flag to upgrade all testnet contracts",
},
chain: {
type: "array",
string: true,
desc: "Chains to upgrade the contract on",
},
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
"ops-key-path": {
type: "string",
demandOption: true,
desc: "Path to the private key of the proposer to use for the operations multisig governance proposal",
},
"std-output": {
type: "string",
demandOption: true,
desc: "Path to the standard JSON output of the pyth contract (build artifact)",
},
} as const;

export function makeCacheFunction(
cacheFile: string
): (cacheKey: string, fn: () => Promise<string>) => Promise<string> {
async function runIfNotCached(
cacheKey: string,
fn: () => Promise<string>
): Promise<string> {
const cache = existsSync(cacheFile)
? JSON.parse(readFileSync(cacheFile, "utf8"))
: {};
if (cache[cacheKey]) {
return cache[cacheKey];
}
const result = await fn();
cache[cacheKey] = result;
writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
return result;
}

return runIfNotCached;
}

export function getSelectedChains(argv: {
chain: InferredOptionType<typeof COMMON_UPGRADE_OPTIONS["chain"]>;
testnet: InferredOptionType<typeof COMMON_UPGRADE_OPTIONS["testnet"]>;
allChains: InferredOptionType<typeof COMMON_UPGRADE_OPTIONS["all-chains"]>;
}) {
const selectedChains: EvmChain[] = [];
if (argv.allChains && argv.chain)
throw new Error("Cannot use both --all-chains and --chain");
if (!argv.allChains && !argv.chain)
throw new Error("Must use either --all-chains or --chain");
for (const chain of Object.values(DefaultStore.chains)) {
if (!(chain instanceof EvmChain)) continue;
if (
(argv.allChains && chain.isMainnet() !== argv.testnet) ||
argv.chain?.includes(chain.getId())
)
selectedChains.push(chain);
}
if (argv.chain && selectedChains.length !== argv.chain.length)
throw new Error(
`Some chains were not found ${selectedChains
.map((chain) => chain.getId())
.toString()}`
);
for (const chain of selectedChains) {
if (chain.isMainnet() != selectedChains[0].isMainnet())
throw new Error("All chains must be either mainnet or testnet");
}
return selectedChains;
}
8 changes: 3 additions & 5 deletions contract_manager/scripts/deploy_cosmwasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { CosmWasmChain } from "../src/chains";
import { CosmWasmPriceFeedContract } from "../src/contracts/cosmwasm";
import { DefaultStore } from "../src/store";

import { COMMON_DEPLOY_OPTIONS } from "./common";

const parser = yargs(hideBin(process.argv))
.scriptName("deploy_cosmwasm.ts")
.usage(
Expand All @@ -15,11 +17,7 @@ const parser = yargs(hideBin(process.argv))
demandOption: true,
desc: "Path to the artifact .wasm file",
},
"private-key": {
type: "string",
demandOption: true,
desc: "Private key to use for the deployment",
},
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
chain: {
type: "string",
demandOption: true,
Expand Down
14 changes: 4 additions & 10 deletions contract_manager/scripts/deploy_evm_contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { DefaultStore } from "../src/store";
import { readFileSync } from "fs";
import { toPrivateKey } from "../src";

import { COMMON_DEPLOY_OPTIONS } from "./common";

const parser = yargs(hideBin(process.argv))
.scriptName("deploy_evm_contract.ts")
.usage(
Expand All @@ -16,16 +18,8 @@ const parser = yargs(hideBin(process.argv))
demandOption: true,
desc: "Path to the standard JSON output of the contract (build artifact)",
},
"private-key": {
type: "string",
demandOption: true,
desc: "Private key to use for the deployment",
},
chain: {
type: "string",
demandOption: true,
desc: "Chain to upload the contract on. Can be one of the evm chains available in the store",
},
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
chain: COMMON_DEPLOY_OPTIONS["chain"],
"deploy-args": {
type: "array",
desc: "Arguments to pass to the contract constructor. Each argument must begin with 0x if it's a hex string",
Expand Down
Loading

0 comments on commit 0d49986

Please sign in to comment.