1
- import { EvmChain , PrivateKey } from "../src" ;
1
+ import { DefaultStore , EvmChain , PrivateKey } from "../src" ;
2
2
import { existsSync , readFileSync , writeFileSync } from "fs" ;
3
3
import { join } from "path" ;
4
4
import Web3 from "web3" ;
5
5
import { Contract } from "web3-eth-contract" ;
6
+ import { InferredOptionType } from "yargs" ;
6
7
7
8
interface DeployConfig {
8
9
gasMultiplier : number ;
@@ -23,39 +24,26 @@ export async function deployIfNotCached(
23
24
deployArgs : any [ ] , // eslint-disable-line @typescript-eslint/no-explicit-any
24
25
cacheKey ?: string
25
26
) : Promise < string > {
26
- const cache = existsSync ( cacheFile )
27
- ? JSON . parse ( readFileSync ( cacheFile , "utf8" ) )
28
- : { } ;
29
-
27
+ const runIfNotCached = makeCacheFunction ( cacheFile ) ;
30
28
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" )
35
32
) ;
36
- return address ;
37
- }
38
-
39
- const artifact = JSON . parse (
40
- readFileSync ( join ( config . jsonOutputDir , `${ artifactName } .json` ) , "utf8" )
41
- ) ;
42
33
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 } ` ) ;
55
44
56
- cache [ key ] = addr ;
57
- writeFileSync ( cacheFile , JSON . stringify ( cache , null , 2 ) ) ;
58
- return addr ;
45
+ return addr ;
46
+ } ) ;
59
47
}
60
48
61
49
export function getWeb3Contract (
@@ -69,3 +57,127 @@ export function getWeb3Contract(
69
57
const web3 = new Web3 ( ) ;
70
58
return new web3 . eth . Contract ( artifact [ "abi" ] , address ) ;
71
59
}
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
+ }
0 commit comments