Skip to content

Commit 0d49986

Browse files
authored
refactor(contract_manager): reduce duplicate code (#1311)
* 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
1 parent bec2ddf commit 0d49986

14 files changed

+387
-308
lines changed

contract_manager/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"scripts": {
1212
"build": "tsc",
1313
"shell": "ts-node ./src/shell.ts",
14-
"lint": "eslint src/"
14+
"lint": "eslint src/ scripts/",
15+
"format": "prettier --write \"src/**/*.ts\" \"scripts/**/*.ts\""
1516
},
1617
"author": "",
1718
"license": "Apache-2.0",
@@ -27,6 +28,7 @@
2728
"@pythnetwork/entropy-sdk-solidity": "*",
2829
"@pythnetwork/price-service-client": "*",
2930
"@pythnetwork/pyth-sui-js": "*",
31+
"@types/yargs": "^17.0.32",
3032
"aptos": "^1.5.0",
3133
"bs58": "^5.0.0",
3234
"ts-node": "^10.9.1",

contract_manager/scripts/common.ts

Lines changed: 142 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { EvmChain, PrivateKey } from "../src";
1+
import { DefaultStore, EvmChain, PrivateKey } from "../src";
22
import { existsSync, readFileSync, writeFileSync } from "fs";
33
import { join } from "path";
44
import Web3 from "web3";
55
import { Contract } from "web3-eth-contract";
6+
import { InferredOptionType } from "yargs";
67

78
interface DeployConfig {
89
gasMultiplier: number;
@@ -23,39 +24,26 @@ export async function deployIfNotCached(
2324
deployArgs: any[], // eslint-disable-line @typescript-eslint/no-explicit-any
2425
cacheKey?: string
2526
): Promise<string> {
26-
const cache = existsSync(cacheFile)
27-
? JSON.parse(readFileSync(cacheFile, "utf8"))
28-
: {};
29-
27+
const runIfNotCached = makeCacheFunction(cacheFile);
3028
const key = cacheKey ?? `${chain.getId()}-${artifactName}`;
31-
if (cache[key]) {
32-
const address = cache[key];
33-
console.log(
34-
`Using cached deployment of ${artifactName} on ${chain.getId()} at ${address}`
29+
return runIfNotCached(key, async () => {
30+
const artifact = JSON.parse(
31+
readFileSync(join(config.jsonOutputDir, `${artifactName}.json`), "utf8")
3532
);
36-
return address;
37-
}
38-
39-
const artifact = JSON.parse(
40-
readFileSync(join(config.jsonOutputDir, `${artifactName}.json`), "utf8")
41-
);
4233

43-
console.log(`Deploying ${artifactName} on ${chain.getId()}...`);
44-
45-
const addr = await chain.deploy(
46-
config.privateKey,
47-
artifact["abi"],
48-
artifact["bytecode"],
49-
deployArgs,
50-
config.gasMultiplier,
51-
config.gasPriceMultiplier
52-
);
53-
54-
console.log(`✅ Deployed ${artifactName} on ${chain.getId()} at ${addr}`);
34+
console.log(`Deploying ${artifactName} on ${chain.getId()}...`);
35+
const addr = await chain.deploy(
36+
config.privateKey,
37+
artifact["abi"],
38+
artifact["bytecode"],
39+
deployArgs,
40+
config.gasMultiplier,
41+
config.gasPriceMultiplier
42+
);
43+
console.log(`✅ Deployed ${artifactName} on ${chain.getId()} at ${addr}`);
5544

56-
cache[key] = addr;
57-
writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
58-
return addr;
45+
return addr;
46+
});
5947
}
6048

6149
export function getWeb3Contract(
@@ -69,3 +57,127 @@ export function getWeb3Contract(
6957
const web3 = new Web3();
7058
return new web3.eth.Contract(artifact["abi"], address);
7159
}
60+
61+
export const COMMON_DEPLOY_OPTIONS = {
62+
"std-output-dir": {
63+
type: "string",
64+
demandOption: true,
65+
desc: "Path to the standard JSON output of the contracts (build artifact) directory",
66+
},
67+
"private-key": {
68+
type: "string",
69+
demandOption: true,
70+
desc: "Private key to sign the trnasactions with",
71+
},
72+
chain: {
73+
type: "array",
74+
demandOption: true,
75+
desc: "Chain to upload the contract on. Can be one of the evm chains available in the store",
76+
},
77+
"deployment-type": {
78+
type: "string",
79+
demandOption: false,
80+
default: "stable",
81+
desc: "Deployment type to use. Can be 'stable' or 'beta'",
82+
},
83+
"gas-multiplier": {
84+
type: "number",
85+
demandOption: false,
86+
// Proxy (ERC1967) contract gas estimate is insufficient in many networks and thus we use 2 by default to make it work.
87+
default: 2,
88+
desc: "Gas multiplier to use for the deployment. This is useful when gas estimates are not accurate",
89+
},
90+
"gas-price-multiplier": {
91+
type: "number",
92+
demandOption: false,
93+
default: 1,
94+
desc: "Gas price multiplier to use for the deployment. This is useful when gas price estimates are not accurate",
95+
},
96+
"save-contract": {
97+
type: "boolean",
98+
demandOption: false,
99+
default: true,
100+
desc: "Save the contract to the store",
101+
},
102+
} as const;
103+
export const COMMON_UPGRADE_OPTIONS = {
104+
testnet: {
105+
type: "boolean",
106+
default: false,
107+
desc: "Upgrade testnet contracts instead of mainnet",
108+
},
109+
"all-chains": {
110+
type: "boolean",
111+
default: false,
112+
desc: "Upgrade the contract on all chains. Use with --testnet flag to upgrade all testnet contracts",
113+
},
114+
chain: {
115+
type: "array",
116+
string: true,
117+
desc: "Chains to upgrade the contract on",
118+
},
119+
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
120+
"ops-key-path": {
121+
type: "string",
122+
demandOption: true,
123+
desc: "Path to the private key of the proposer to use for the operations multisig governance proposal",
124+
},
125+
"std-output": {
126+
type: "string",
127+
demandOption: true,
128+
desc: "Path to the standard JSON output of the pyth contract (build artifact)",
129+
},
130+
} as const;
131+
132+
export function makeCacheFunction(
133+
cacheFile: string
134+
): (cacheKey: string, fn: () => Promise<string>) => Promise<string> {
135+
async function runIfNotCached(
136+
cacheKey: string,
137+
fn: () => Promise<string>
138+
): Promise<string> {
139+
const cache = existsSync(cacheFile)
140+
? JSON.parse(readFileSync(cacheFile, "utf8"))
141+
: {};
142+
if (cache[cacheKey]) {
143+
return cache[cacheKey];
144+
}
145+
const result = await fn();
146+
cache[cacheKey] = result;
147+
writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
148+
return result;
149+
}
150+
151+
return runIfNotCached;
152+
}
153+
154+
export function getSelectedChains(argv: {
155+
chain: InferredOptionType<typeof COMMON_UPGRADE_OPTIONS["chain"]>;
156+
testnet: InferredOptionType<typeof COMMON_UPGRADE_OPTIONS["testnet"]>;
157+
allChains: InferredOptionType<typeof COMMON_UPGRADE_OPTIONS["all-chains"]>;
158+
}) {
159+
const selectedChains: EvmChain[] = [];
160+
if (argv.allChains && argv.chain)
161+
throw new Error("Cannot use both --all-chains and --chain");
162+
if (!argv.allChains && !argv.chain)
163+
throw new Error("Must use either --all-chains or --chain");
164+
for (const chain of Object.values(DefaultStore.chains)) {
165+
if (!(chain instanceof EvmChain)) continue;
166+
if (
167+
(argv.allChains && chain.isMainnet() !== argv.testnet) ||
168+
argv.chain?.includes(chain.getId())
169+
)
170+
selectedChains.push(chain);
171+
}
172+
if (argv.chain && selectedChains.length !== argv.chain.length)
173+
throw new Error(
174+
`Some chains were not found ${selectedChains
175+
.map((chain) => chain.getId())
176+
.toString()}`
177+
);
178+
for (const chain of selectedChains) {
179+
if (chain.isMainnet() != selectedChains[0].isMainnet())
180+
throw new Error("All chains must be either mainnet or testnet");
181+
}
182+
return selectedChains;
183+
}

contract_manager/scripts/deploy_cosmwasm.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { CosmWasmChain } from "../src/chains";
44
import { CosmWasmPriceFeedContract } from "../src/contracts/cosmwasm";
55
import { DefaultStore } from "../src/store";
66

7+
import { COMMON_DEPLOY_OPTIONS } from "./common";
8+
79
const parser = yargs(hideBin(process.argv))
810
.scriptName("deploy_cosmwasm.ts")
911
.usage(
@@ -15,11 +17,7 @@ const parser = yargs(hideBin(process.argv))
1517
demandOption: true,
1618
desc: "Path to the artifact .wasm file",
1719
},
18-
"private-key": {
19-
type: "string",
20-
demandOption: true,
21-
desc: "Private key to use for the deployment",
22-
},
20+
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
2321
chain: {
2422
type: "string",
2523
demandOption: true,

contract_manager/scripts/deploy_evm_contract.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { DefaultStore } from "../src/store";
55
import { readFileSync } from "fs";
66
import { toPrivateKey } from "../src";
77

8+
import { COMMON_DEPLOY_OPTIONS } from "./common";
9+
810
const parser = yargs(hideBin(process.argv))
911
.scriptName("deploy_evm_contract.ts")
1012
.usage(
@@ -16,16 +18,8 @@ const parser = yargs(hideBin(process.argv))
1618
demandOption: true,
1719
desc: "Path to the standard JSON output of the contract (build artifact)",
1820
},
19-
"private-key": {
20-
type: "string",
21-
demandOption: true,
22-
desc: "Private key to use for the deployment",
23-
},
24-
chain: {
25-
type: "string",
26-
demandOption: true,
27-
desc: "Chain to upload the contract on. Can be one of the evm chains available in the store",
28-
},
21+
"private-key": COMMON_DEPLOY_OPTIONS["private-key"],
22+
chain: COMMON_DEPLOY_OPTIONS["chain"],
2923
"deploy-args": {
3024
type: "array",
3125
desc: "Arguments to pass to the contract constructor. Each argument must begin with 0x if it's a hex string",

0 commit comments

Comments
 (0)