@@ -41,6 +41,7 @@ func GetTxCmd() *cobra.Command {
41
41
txCmd .AddCommand (
42
42
StoreCodeCmd (),
43
43
InstantiateContractCmd (),
44
+ StoreCodeAndInstantiateContractCmd (),
44
45
ExecuteContractCmd (),
45
46
MigrateContractCmd (),
46
47
UpdateContractAdminCmd (),
@@ -214,6 +215,128 @@ func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flag
214
215
return msg , nil
215
216
}
216
217
218
+ // StoreCodeAndInstantiatecontractcmd will upload code and instantiate a contract using it
219
+ func StoreCodeAndInstantiateContractCmd () * cobra.Command {
220
+ cmd := & cobra.Command {
221
+ Use : "store-instantiate [wasm file] [json_encoded_init_args] --source [source] --builder [builder] --label [text] --admin [address,optional] --amount [coins,optional]" ,
222
+ Short : "Upload a wasm binary and instantiate a wasm contract from the code" ,
223
+ Args : cobra .ExactArgs (2 ),
224
+ RunE : func (cmd * cobra.Command , args []string ) error {
225
+ clientCtx , err := client .GetClientTxContext (cmd )
226
+ if err != nil {
227
+ return err
228
+ }
229
+ msg , err := parseStoreCodeAndInstantiateContractArgs (args [0 ], args [1 ], clientCtx .GetFromAddress (), cmd .Flags ())
230
+ if err != nil {
231
+ return err
232
+ }
233
+ if err = msg .ValidateBasic (); err != nil {
234
+ return err
235
+ }
236
+ return tx .GenerateOrBroadcastTxCLI (clientCtx , cmd .Flags (), & msg )
237
+ },
238
+ }
239
+
240
+ cmd .Flags ().String (flagSource , "" , "A valid URI reference to the contract's source code, optional" )
241
+ cmd .Flags ().String (flagBuilder , "" , "A valid docker tag for the build system, optional" )
242
+ cmd .Flags ().String (flagInstantiateByEverybody , "" , "Everybody can instantiate a contract from the code, optional" )
243
+ cmd .Flags ().String (flagInstantiateByAddress , "" , "Only this address can instantiate a contract instance from the code, optional" )
244
+ cmd .Flags ().String (flagAmount , "" , "Coins to send to the contract during instantiation" )
245
+ cmd .Flags ().String (flagLabel , "" , "A human-readable name for this contract in lists" )
246
+ cmd .Flags ().String (flagAdmin , "" , "Address of an admin" )
247
+ flags .AddTxFlagsToCmd (cmd )
248
+ return cmd
249
+ }
250
+
251
+ func parseStoreCodeAndInstantiateContractArgs (file string , initMsg string , sender sdk.AccAddress , flags * flag.FlagSet ) (types.MsgStoreCodeAndInstantiateContract , error ) {
252
+ wasm , err := ioutil .ReadFile (file )
253
+ if err != nil {
254
+ return types.MsgStoreCodeAndInstantiateContract {}, err
255
+ }
256
+
257
+ // gzip the wasm file
258
+ if wasmUtils .IsWasm (wasm ) {
259
+ wasm , err = wasmUtils .GzipIt (wasm )
260
+
261
+ if err != nil {
262
+ return types.MsgStoreCodeAndInstantiateContract {}, err
263
+ }
264
+ } else if ! wasmUtils .IsGzip (wasm ) {
265
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("invalid input file. Use wasm binary or gzip" )
266
+ }
267
+
268
+ var perm * types.AccessConfig
269
+ onlyAddrStr , err := flags .GetString (flagInstantiateByAddress )
270
+ if err != nil {
271
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("instantiate by address: %s" , err )
272
+ }
273
+ if onlyAddrStr != "" {
274
+ allowedAddr , err := sdk .AccAddressFromBech32 (onlyAddrStr )
275
+ if err != nil {
276
+ return types.MsgStoreCodeAndInstantiateContract {}, sdkerrors .Wrap (err , flagInstantiateByAddress )
277
+ }
278
+ x := types .AccessTypeOnlyAddress .With (allowedAddr )
279
+ perm = & x
280
+ } else {
281
+ everybodyStr , err := flags .GetString (flagInstantiateByEverybody )
282
+ if err != nil {
283
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("instantiate by everybody: %s" , err )
284
+ }
285
+ if everybodyStr != "" {
286
+ ok , err := strconv .ParseBool (everybodyStr )
287
+ if err != nil {
288
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("boolean value expected for instantiate by everybody: %s" , err )
289
+ }
290
+ if ok {
291
+ perm = & types .AllowEverybody
292
+ }
293
+ }
294
+ }
295
+
296
+ // build and sign the transaction, then broadcast to Tendermint
297
+ source , err := flags .GetString (flagSource )
298
+ if err != nil {
299
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("source: %s" , err )
300
+ }
301
+ builder , err := flags .GetString (flagBuilder )
302
+ if err != nil {
303
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("builder: %s" , err )
304
+ }
305
+
306
+ amountStr , err := flags .GetString (flagAmount )
307
+ if err != nil {
308
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("amount: %s" , err )
309
+ }
310
+ amount , err := sdk .ParseCoinsNormalized (amountStr )
311
+ if err != nil {
312
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("amount: %s" , err )
313
+ }
314
+ label , err := flags .GetString (flagLabel )
315
+ if err != nil {
316
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("label: %s" , err )
317
+ }
318
+ if label == "" {
319
+ return types.MsgStoreCodeAndInstantiateContract {}, errors .New ("label is required on all contracts" )
320
+ }
321
+ adminStr , err := flags .GetString (flagAdmin )
322
+ if err != nil {
323
+ return types.MsgStoreCodeAndInstantiateContract {}, fmt .Errorf ("admin: %s" , err )
324
+ }
325
+
326
+ msg := types.MsgStoreCodeAndInstantiateContract {
327
+ Sender : sender .String (),
328
+ WASMByteCode : wasm ,
329
+ Source : source ,
330
+ Builder : builder ,
331
+ InstantiatePermission : perm ,
332
+ Label : label ,
333
+ Funds : amount ,
334
+ InitMsg : []byte (initMsg ),
335
+ Admin : adminStr ,
336
+ }
337
+ return msg , nil
338
+ }
339
+
217
340
// ExecuteContractCmd will instantiate a contract from previously uploaded code.
218
341
func ExecuteContractCmd () * cobra.Command {
219
342
cmd := & cobra.Command {
0 commit comments