Raw File
client_proto_multisig_commands.ml
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2019-2021 Nomadic Labs <contact@nomadic-labs.com>           *)
(*                                                                           *)
(* Permission is hereby granted, free of charge, to any person obtaining a   *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense,  *)
(* and/or sell copies of the Software, and to permit persons to whom the     *)
(* Software is furnished to do so, subject to the following conditions:      *)
(*                                                                           *)
(* The above copyright notice and this permission notice shall be included   *)
(* in all copies or substantial portions of the Software.                    *)
(*                                                                           *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL   *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING   *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER       *)
(* DEALINGS IN THE SOFTWARE.                                                 *)
(*                                                                           *)
(*****************************************************************************)

open Protocol
open Alpha_context
open Client_proto_args
open Tezos_micheline

let group =
  {
    Tezos_clic.name = "multisig";
    title = "Commands for managing a multisig smart contract";
  }

let threshold_param () =
  Tezos_clic.param
    ~name:"threshold"
    ~desc:"Number of required signatures"
    Client_proto_args.int_parameter

let public_key_param () =
  Client_keys.Public_key.source_param
    ~name:"key"
    ~desc:"Each signer of the multisig contract"

let secret_key_param () =
  Client_keys.Secret_key.source_param
    ~name:"key"
    ~desc:
      "Secret key corresponding to one of the public keys stored on the \
       multisig contract"

let signature_param () =
  Tezos_clic.param
    ~name:"signature"
    ~desc:"Each signer of the multisig contract"
    Client_proto_args.signature_parameter

let lambda_param () =
  Tezos_clic.param
    ~name:"lambda"
    ~desc:"the lambda to execute, of type lambda unit (list operation)"
    string_parameter

let bytes_only_switch =
  Tezos_clic.switch
    ~long:"bytes-only"
    ~doc:"return only the byte sequence to be signed"
    ()

let bytes_param ~name ~desc =
  Tezos_clic.param ~name ~desc Client_proto_args.bytes_parameter

let transfer_options =
  Tezos_clic.args11
    Client_proto_args.fee_arg
    Client_proto_context_commands.dry_run_switch
    Client_proto_context_commands.verbose_signing_switch
    Client_proto_args.gas_limit_arg
    Client_proto_args.safety_guard_arg
    Client_proto_args.storage_limit_arg
    Client_proto_args.counter_arg
    Client_proto_args.arg_arg
    Client_proto_args.no_print_source_flag
    Client_proto_args.fee_parameter_args
    Client_proto_args.entrypoint_arg

let non_transfer_options =
  Tezos_clic.args9
    Client_proto_args.fee_arg
    Client_proto_context_commands.dry_run_switch
    Client_proto_context_commands.verbose_signing_switch
    Client_proto_args.gas_limit_arg
    Client_proto_args.safety_guard_arg
    Client_proto_args.storage_limit_arg
    Client_proto_args.counter_arg
    Client_proto_args.no_print_source_flag
    Client_proto_args.fee_parameter_args

let prepare_command_display prepared_command bytes_only =
  if bytes_only then
    Format.printf
      "0x%a@."
      Hex.pp
      (Hex.of_bytes prepared_command.Client_proto_multisig.bytes)
  else
    Format.printf
      "%a@.%a@.%a@.%a@."
      (fun ppf x ->
        Format.fprintf ppf "Bytes to sign: '0x%a'" Hex.pp (Hex.of_bytes x))
      prepared_command.Client_proto_multisig.bytes
      (fun ppf x ->
        Format.fprintf
          ppf
          "Blake 2B Hash: '%s'"
          (Tezos_crypto.Base58.raw_encode
             Tezos_crypto.Blake2B.(hash_bytes [x] |> to_string)))
      prepared_command.Client_proto_multisig.bytes
      (fun ppf z ->
        Format.fprintf
          ppf
          "Threshold (number of signatures required): %s"
          (Z.to_string z))
      prepared_command.Client_proto_multisig.threshold
      (fun ppf ->
        Format.fprintf
          ppf
          "@[<2>Public keys of the signers:@ %a@]"
          (Format.pp_print_list
             ~pp_sep:(fun ppf () -> Format.fprintf ppf "@ ")
             Signature.Public_key.pp))
      prepared_command.Client_proto_multisig.keys

let get_parameter_type (cctxt : #Protocol_client_context.full)
    ~(destination : Contract.t) ~entrypoint =
  let open Lwt_result_syntax in
  match destination with
  | Implicit _ ->
      let open Micheline in
      return @@ strip_locations @@ Prim (0, Script.T_unit, [], [])
  | Originated contract -> (
      let* o =
        Michelson_v1_entrypoints.contract_entrypoint_type
          cctxt
          ~chain:cctxt#chain
          ~block:cctxt#block
          ~contract
          ~entrypoint
          ~normalize_types:true
      in
      match o with
      | None ->
          cctxt#error
            "Contract %a has no entrypoint named %a"
            Contract_hash.pp
            contract
            Entrypoint.pp
            entrypoint
      | Some parameter_type -> return parameter_type)

let commands_ro () : #Protocol_client_context.full Tezos_clic.command list =
  Tezos_clic.
    [
      command
        ~group
        ~desc:"Show the hashes of the supported multisig contracts."
        no_options
        (fixed ["show"; "supported"; "multisig"; "hashes"])
        (fun () _cctxt ->
          Format.printf "Hashes of supported multisig contracts:@." ;
          List.iter
            (fun h -> Format.printf "%a@." Script_expr_hash.pp h)
            Client_proto_multisig.known_multisig_hashes ;
          Lwt_result_syntax.return_unit);
      command
        ~group
        ~desc:"Show the script of the recommended multisig contract."
        no_options
        (fixed ["show"; "multisig"; "script"])
        (fun () _cctxt ->
          let {Michelson_v1_parser.source; _} =
            Michelson_v1_printer.unparse_toplevel
              Client_proto_multisig.multisig_script
          in
          Format.printf "%s@." source ;
          Lwt_result_syntax.return_unit);
    ]

let commands_rw () : #Protocol_client_context.full Tezos_clic.command list =
  Tezos_clic.
    [
      command
        ~group
        ~desc:"Originate a new multisig contract."
        (args10
           Client_proto_args.fee_arg
           Client_proto_context_commands.dry_run_switch
           Client_proto_args.gas_limit_arg
           Client_proto_args.safety_guard_arg
           Client_proto_args.storage_limit_arg
           Client_proto_args.delegate_arg
           (Client_keys.force_switch ())
           Client_proto_args.no_print_source_flag
           Client_proto_args.fee_parameter_args
           Client_proto_context_commands.verbose_signing_switch)
        (prefixes ["deploy"; "multisig"]
        @@ Client_proto_contracts.Raw_contract_alias.fresh_alias_param
             ~name:"new_multisig"
             ~desc:"name of the new multisig contract"
        @@ prefix "transferring"
        @@ Client_proto_args.tez_param
             ~name:"qty"
             ~desc:"amount taken from source"
        @@ prefix "from"
        @@ Client_keys.Public_key_hash.source_param
             ~name:"src"
             ~desc:"name of the source contract"
        @@ prefixes ["with"; "threshold"]
        @@ threshold_param ()
        @@ prefixes ["on"; "public"; "keys"]
        @@ seq_of_param (public_key_param ()))
        (fun ( fee,
               dry_run,
               gas_limit,
               safety_guard,
               storage_limit,
               delegate,
               force,
               no_print_source,
               fee_parameter,
               verbose_signing )
             alias_name
             balance
             source
             threshold
             keys
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* alias_name =
            Client_proto_contracts.Raw_contract_alias.of_fresh
              cctxt
              force
              alias_name
          in
          let* _, src_pk, src_sk = Client_keys.get_key cctxt source in
          let* keys =
            List.map_es (fun (pk_uri, _) -> Client_keys.public_key pk_uri) keys
          in
          let*! errors =
            Client_proto_multisig.originate_multisig
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ?confirmations:cctxt#confirmations
              ~dry_run
              ?fee
              ?gas_limit
              ?safety_guard
              ?storage_limit
              ~verbose_signing
              ~delegate
              ~threshold:(Z.of_int threshold)
              ~keys
              ~balance
              ~source
              ~src_pk
              ~src_sk
              ~fee_parameter
              ()
          in
          let*! o =
            Client_proto_context_commands.report_michelson_errors
              ~no_print_source
              ~msg:"multisig origination simulation failed"
              cctxt
              errors
          in
          unless dry_run @@ fun () ->
          Option.iter_es
            (fun (_res, contract) ->
              Client_proto_context.save_contract
                ~force
                cctxt
                alias_name
                contract)
            o);
      command
        ~group
        ~desc:"Sign a transaction for a multisig contract."
        (args2 arg_arg entrypoint_arg)
        (prefixes ["sign"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefix "transferring"
        @@ Client_proto_args.tez_param
             ~name:"qty"
             ~desc:"amount taken from source"
        @@ prefix "to"
        @@ Client_proto_contracts.Contract_alias.destination_param
             ~name:"dst"
             ~desc:"name/literal of the destination contract"
        @@ prefixes ["using"; "secret"; "key"]
        @@ secret_key_param () @@ stop)
        (fun (parameter, entrypoint)
             multisig_contract
             amount
             destination
             sk
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let entrypoint =
            Option.value ~default:Entrypoint.default entrypoint
          in
          let parameter = Option.value ~default:"Unit" parameter in
          let*? {expanded = parameter; _} =
            Micheline_parser.no_parsing_error
            @@ Michelson_v1_parser.parse_expression parameter
          in
          let* parameter_type =
            get_parameter_type cctxt ~destination ~entrypoint
          in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:
                (Client_proto_multisig.Transfer
                   {amount; destination; entrypoint; parameter_type; parameter})
              ()
          in
          let* signature = Client_keys.sign cctxt sk prepared_command.bytes in
          Format.printf "%a@." Signature.pp signature ;
          return_unit);
      command
        ~group
        ~desc:"Sign a lambda for a generic multisig contract."
        no_options
        (prefixes ["sign"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["running"; "lambda"]
        @@ lambda_param ()
        @@ prefixes ["using"; "secret"; "key"]
        @@ secret_key_param () @@ stop)
        (fun ()
             multisig_contract
             lambda
             sk
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let*? {expanded = lambda; _} =
            Micheline_parser.no_parsing_error
            @@ Michelson_v1_parser.parse_expression lambda
          in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:(Lambda lambda)
              ()
          in
          let* signature = Client_keys.sign cctxt sk prepared_command.bytes in
          Format.printf "%a@." Signature.pp signature ;
          return_unit);
      command
        ~group
        ~desc:"Sign a delegate change for a multisig contract."
        no_options
        (prefixes ["sign"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["setting"; "delegate"; "to"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"dlgt"
             ~desc:"new delegate of the new multisig contract"
        @@ prefixes ["using"; "secret"; "key"]
        @@ secret_key_param () @@ stop)
        (fun ()
             multisig_contract
             delegate
             sk
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:(Client_proto_multisig.Change_delegate (Some delegate))
              ()
          in
          let* signature = Client_keys.sign cctxt sk prepared_command.bytes in
          Format.printf "%a@." Signature.pp signature ;
          return_unit);
      command
        ~group
        ~desc:"Sign a delegate withdraw for a multisig contract."
        no_options
        (prefixes ["sign"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["withdrawing"; "delegate"]
        @@ prefixes ["using"; "secret"; "key"]
        @@ secret_key_param () @@ stop)
        (fun () multisig_contract sk (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:(Client_proto_multisig.Change_delegate None)
              ()
          in
          let* signature = Client_keys.sign cctxt sk prepared_command.bytes in
          Format.printf "%a@." Signature.pp signature ;
          return_unit);
      command
        ~group
        ~desc:
          "Sign a change of public keys and threshold for a multisig contract."
        no_options
        (prefixes ["sign"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["using"; "secret"; "key"]
        @@ secret_key_param ()
        @@ prefixes ["setting"; "threshold"; "to"]
        @@ threshold_param ()
        @@ prefixes ["and"; "public"; "keys"; "to"]
        @@ seq_of_param (public_key_param ()))
        (fun ()
             multisig_contract
             sk
             new_threshold
             new_keys
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* keys =
            List.map_es
              (fun (pk_uri, _) -> Client_keys.public_key pk_uri)
              new_keys
          in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:
                (Client_proto_multisig.Change_keys (Z.of_int new_threshold, keys))
              ()
          in
          let* signature = Client_keys.sign cctxt sk prepared_command.bytes in
          Format.printf "%a@." Signature.pp signature ;
          return_unit);
      command
        ~group
        ~desc:"Transfer tokens using a multisig contract."
        transfer_options
        (prefixes ["from"; "multisig"; "contract"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name/literal of the multisig contract"
        @@ prefix "transfer"
        @@ Client_proto_args.tez_param
             ~name:"qty"
             ~desc:"amount taken from the multisig contract"
        @@ prefix "to"
        @@ Client_proto_contracts.Contract_alias.destination_param
             ~name:"dst"
             ~desc:"name/literal of the destination contract"
        @@ prefixes ["on"; "behalf"; "of"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"src"
             ~desc:"source calling the multisig contract"
        @@ prefixes ["with"; "signatures"]
        @@ seq_of_param (signature_param ()))
        (fun ( fee,
               dry_run,
               verbose_signing,
               gas_limit,
               safety_guard,
               storage_limit,
               counter,
               parameter,
               no_print_source,
               fee_parameter,
               entrypoint )
             multisig_contract
             amount
             destination
             source
             signatures
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let entrypoint =
            Option.value ~default:Entrypoint.default entrypoint
          in
          let parameter = Option.value ~default:"Unit" parameter in
          let*? {expanded = parameter; _} =
            Micheline_parser.no_parsing_error
            @@ Michelson_v1_parser.parse_expression parameter
          in
          let* parameter_type =
            get_parameter_type cctxt ~destination ~entrypoint
          in
          let* _, src_pk, src_sk = Client_keys.get_key cctxt source in
          let*! errors =
            Client_proto_multisig.call_multisig
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ?confirmations:cctxt#confirmations
              ~dry_run
              ~verbose_signing
              ~fee_parameter
              ~source
              ?fee
              ~src_pk
              ~src_sk
              ~multisig_contract
              ~action:
                (Client_proto_multisig.Transfer
                   {amount; destination; entrypoint; parameter_type; parameter})
              ~signatures
              ~amount:Tez.zero
              ?gas_limit
              ?safety_guard
              ?storage_limit
              ?counter
              ()
          in
          let*! (_ : (_ Injection.result * Contract_hash.t list) option) =
            Client_proto_context_commands.report_michelson_errors
              ~no_print_source
              ~msg:"transfer simulation failed"
              cctxt
              errors
          in
          return_unit);
      command
        ~group
        ~desc:"Run a lambda on a generic multisig contract."
        non_transfer_options
        (prefixes ["from"; "multisig"; "contract"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name/literal of the multisig contract"
        @@ prefixes ["run"; "lambda"]
        @@ lambda_param ()
        @@ prefixes ["on"; "behalf"; "of"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"src"
             ~desc:"source calling the multisig contract"
        @@ prefixes ["with"; "signatures"]
        @@ seq_of_param (signature_param ()))
        (fun ( fee,
               dry_run,
               verbose_signing,
               gas_limit,
               safety_guard,
               storage_limit,
               counter,
               no_print_source,
               fee_parameter )
             multisig_contract
             lambda
             source
             signatures
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* _, src_pk, src_sk = Client_keys.get_key cctxt source in
          let*? {expanded = lambda; _} =
            Micheline_parser.no_parsing_error
            @@ Michelson_v1_parser.parse_expression lambda
          in
          let*! errors =
            Client_proto_multisig.call_multisig
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ?confirmations:cctxt#confirmations
              ~dry_run
              ~verbose_signing
              ~fee_parameter
              ~source
              ?fee
              ~src_pk
              ~src_sk
              ~multisig_contract
              ~action:(Client_proto_multisig.Lambda lambda)
              ~signatures
              ~amount:Tez.zero
              ?gas_limit
              ?safety_guard
              ?storage_limit
              ?counter
              ()
          in
          let*! (_ : (_ Injection.result * Contract_hash.t list) option) =
            Client_proto_context_commands.report_michelson_errors
              ~no_print_source
              ~msg:"transfer simulation failed"
              cctxt
              errors
          in
          return_unit);
      command
        ~group
        ~desc:"Change the delegate of a multisig contract."
        non_transfer_options
        (prefixes ["set"; "delegate"; "of"; "multisig"; "contract"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefix "to"
        @@ Client_keys.Public_key_hash.source_param
             ~name:"dlgt"
             ~desc:"new delegate of the new multisig contract"
        @@ prefixes ["on"; "behalf"; "of"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"src"
             ~desc:"source calling the multisig contract"
        @@ prefixes ["with"; "signatures"]
        @@ seq_of_param (signature_param ()))
        (fun ( fee,
               dry_run,
               verbose_signing,
               gas_limit,
               safety_guard,
               storage_limit,
               counter,
               no_print_source,
               fee_parameter )
             multisig_contract
             delegate
             source
             signatures
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* _, src_pk, src_sk = Client_keys.get_key cctxt source in
          let*! errors =
            Client_proto_multisig.call_multisig
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ?confirmations:cctxt#confirmations
              ~dry_run
              ~verbose_signing
              ~fee_parameter
              ~source
              ?fee
              ~src_pk
              ~src_sk
              ~multisig_contract
              ~action:(Client_proto_multisig.Change_delegate (Some delegate))
              ~signatures
              ~amount:Tez.zero
              ?gas_limit
              ?safety_guard
              ?storage_limit
              ?counter
              ()
          in
          let*! (_ : (_ Injection.result * Contract_hash.t list) option) =
            Client_proto_context_commands.report_michelson_errors
              ~no_print_source
              ~msg:"transfer simulation failed"
              cctxt
              errors
          in
          return_unit);
      command
        ~group
        ~desc:"Withdraw the delegate of a multisig contract."
        non_transfer_options
        (prefixes ["withdraw"; "delegate"; "of"; "multisig"; "contract"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["on"; "behalf"; "of"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"src"
             ~desc:"source calling the multisig contract"
        @@ prefixes ["with"; "signatures"]
        @@ seq_of_param (signature_param ()))
        (fun ( fee,
               dry_run,
               verbose_signing,
               gas_limit,
               safety_guard,
               storage_limit,
               counter,
               no_print_source,
               fee_parameter )
             multisig_contract
             source
             signatures
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* _, src_pk, src_sk = Client_keys.get_key cctxt source in
          let*! errors =
            Client_proto_multisig.call_multisig
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ?confirmations:cctxt#confirmations
              ~dry_run
              ~verbose_signing
              ~fee_parameter
              ~source
              ?fee
              ~src_pk
              ~src_sk
              ~multisig_contract
              ~action:(Client_proto_multisig.Change_delegate None)
              ~signatures
              ~amount:Tez.zero
              ?gas_limit
              ?safety_guard
              ?storage_limit
              ?counter
              ()
          in
          let*! (_ : (_ Injection.result * Contract_hash.t list) option) =
            Client_proto_context_commands.report_michelson_errors
              ~no_print_source
              ~msg:"transfer simulation failed"
              cctxt
              errors
          in
          return_unit);
      command
        ~group
        ~desc:"Change public keys and threshold for a multisig contract."
        non_transfer_options
        (prefixes ["set"; "threshold"; "of"; "multisig"; "contract"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["to"] @@ threshold_param ()
        @@ prefixes ["and"; "public"; "keys"; "to"]
        @@ non_terminal_seq (public_key_param ()) ~suffix:["on"; "behalf"; "of"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"src"
             ~desc:"source calling the multisig contract"
        @@ prefixes ["with"; "signatures"]
        @@ seq_of_param (signature_param ()))
        (fun ( fee,
               dry_run,
               verbose_signing,
               gas_limit,
               safety_guard,
               storage_limit,
               counter,
               no_print_source,
               fee_parameter )
             multisig_contract
             new_threshold
             new_keys
             source
             signatures
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* _, src_pk, src_sk = Client_keys.get_key cctxt source in
          let* keys =
            List.map_es
              (fun (pk_uri, _) -> Client_keys.public_key pk_uri)
              new_keys
          in
          let*! errors =
            Client_proto_multisig.call_multisig
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ?confirmations:cctxt#confirmations
              ~dry_run
              ~verbose_signing
              ~fee_parameter
              ~source
              ?fee
              ~src_pk
              ~src_sk
              ~multisig_contract
              ~action:
                (Client_proto_multisig.Change_keys (Z.of_int new_threshold, keys))
              ~signatures
              ~amount:Tez.zero
              ?gas_limit
              ?safety_guard
              ?storage_limit
              ?counter
              ()
          in
          let*! (_ : (_ Injection.result * Contract_hash.t list) option) =
            Client_proto_context_commands.report_michelson_errors
              ~no_print_source
              ~msg:"transfer simulation failed"
              cctxt
              errors
          in
          return_unit);
      (* This command is no longer necessary as Tezos_clic now supports non terminal
         lists of parameters, however, it is kept for compatibility. *)
      command
        ~group
        ~desc:
          "Run a transaction described by a sequence of bytes on a multisig \
           contract."
        non_transfer_options
        (prefixes ["run"; "transaction"]
        @@ bytes_param
             ~name:"bytes"
             ~desc:
               "the sequence of bytes to deserialize as a multisig action, can \
                be obtained by one of the \"prepare multisig transaction\" \
                commands"
        @@ prefixes ["on"; "multisig"; "contract"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["on"; "behalf"; "of"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"src"
             ~desc:"source calling the multisig contract"
        @@ prefixes ["with"; "signatures"]
        @@ seq_of_param (signature_param ()))
        (fun ( fee,
               dry_run,
               verbose_signing,
               gas_limit,
               safety_guard,
               storage_limit,
               counter,
               no_print_source,
               fee_parameter )
             bytes
             multisig_contract
             source
             signatures
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* _, src_pk, src_sk = Client_keys.get_key cctxt source in
          let*! errors =
            Client_proto_multisig.call_multisig_on_bytes
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ?confirmations:cctxt#confirmations
              ~dry_run
              ~verbose_signing
              ~fee_parameter
              ~source
              ?fee
              ~src_pk
              ~src_sk
              ~multisig_contract
              ~bytes
              ~signatures
              ~amount:Tez.zero
              ?gas_limit
              ?safety_guard
              ?storage_limit
              ?counter
              ()
          in
          let*! (_ : (_ Injection.result * Contract_hash.t list) option) =
            Client_proto_context_commands.report_michelson_errors
              ~no_print_source
              ~msg:"transfer simulation failed"
              cctxt
              errors
          in
          return_unit);
      command
        ~group
        ~desc:
          "Display the threshold, public keys, and byte sequence to sign for a \
           multisigned transfer."
        (args3 bytes_only_switch arg_arg entrypoint_arg)
        (prefixes ["prepare"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefix "transferring"
        @@ Client_proto_args.tez_param
             ~name:"qty"
             ~desc:"amount taken from source"
        @@ prefix "to"
        @@ Client_proto_contracts.Contract_alias.destination_param
             ~name:"dst"
             ~desc:"name/literal of the destination contract"
        @@ stop)
        (fun (bytes_only, parameter, entrypoint)
             multisig_contract
             amount
             destination
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let entrypoint =
            Option.value ~default:Entrypoint.default entrypoint
          in
          let parameter = Option.value ~default:"Unit" parameter in
          let*? {expanded = parameter; _} =
            Micheline_parser.no_parsing_error
            @@ Michelson_v1_parser.parse_expression parameter
          in
          let* parameter_type =
            get_parameter_type cctxt ~destination ~entrypoint
          in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:
                (Client_proto_multisig.Transfer
                   {amount; destination; entrypoint; parameter_type; parameter})
              ()
          in
          return @@ prepare_command_display prepared_command bytes_only);
      command
        ~group
        ~desc:
          "Display the threshold, public keys, and byte sequence to sign for a \
           multisigned lambda execution in a generic multisig contract."
        (args1 bytes_only_switch)
        (prefixes ["prepare"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["running"; "lambda"]
        @@ lambda_param () @@ stop)
        (fun bytes_only
             multisig_contract
             lambda
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let*? {expanded = lambda; _} =
            Micheline_parser.no_parsing_error
            @@ Michelson_v1_parser.parse_expression lambda
          in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:(Client_proto_multisig.Lambda lambda)
              ()
          in
          return @@ prepare_command_display prepared_command bytes_only);
      command
        ~group
        ~desc:
          "Display the threshold, public keys, and byte sequence to sign for a \
           multisigned delegate change."
        (args1 bytes_only_switch)
        (prefixes ["prepare"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["setting"; "delegate"; "to"]
        @@ Client_keys.Public_key_hash.source_param
             ~name:"dlgt"
             ~desc:"new delegate of the new multisig contract"
        @@ stop)
        (fun bytes_only
             multisig_contract
             new_delegate
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:
                (Client_proto_multisig.Change_delegate (Some new_delegate))
              ()
          in
          return @@ prepare_command_display prepared_command bytes_only);
      command
        ~group
        ~desc:
          "Display the threshold, public keys, and byte sequence to sign for a \
           multisigned delegate withdraw."
        (args1 bytes_only_switch)
        (prefixes ["prepare"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["withdrawing"; "delegate"]
        @@ stop)
        (fun bytes_only
             multisig_contract
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:(Client_proto_multisig.Change_delegate None)
              ()
          in
          return @@ prepare_command_display prepared_command bytes_only);
      command
        ~group
        ~desc:
          "Display the threshold, public keys, and byte sequence to sign for a \
           multisigned change of keys and threshold."
        (args1 bytes_only_switch)
        (prefixes ["prepare"; "multisig"; "transaction"; "on"]
        @@ Client_proto_contracts.Originated_contract_alias.destination_param
             ~name:"multisig"
             ~desc:"name or address of the originated multisig contract"
        @@ prefixes ["setting"; "threshold"; "to"]
        @@ threshold_param ()
        @@ prefixes ["and"; "public"; "keys"; "to"]
        @@ seq_of_param (public_key_param ()))
        (fun bytes_only
             multisig_contract
             new_threshold
             new_keys
             (cctxt : #Protocol_client_context.full) ->
          let open Lwt_result_syntax in
          let* keys =
            List.map_es
              (fun (pk_uri, _) -> Client_keys.public_key pk_uri)
              new_keys
          in
          let* prepared_command =
            Client_proto_multisig.prepare_multisig_transaction
              cctxt
              ~chain:cctxt#chain
              ~block:cctxt#block
              ~multisig_contract
              ~action:
                (Client_proto_multisig.Change_keys (Z.of_int new_threshold, keys))
              ()
          in
          return @@ prepare_command_display prepared_command bytes_only);
    ]

let commands () = commands_ro () @ commands_rw ()
back to top