offline tool: add global-fees cmd

This commit is contained in:
swrup 2026-02-03 15:56:05 +01:00
parent 4754517d8f
commit 4913d8ca76
8 changed files with 163 additions and 6 deletions

1
global_fees.json Normal file
View file

@ -0,0 +1 @@
{"start_date":{"t_s":1234.5},"end_date":{"t_s":99999999.900000006},"history_fee":"EUR:0.00","account_fee":"EUR:0.00","purse_fee":"EUR:0.00","history_expiration":{"t_s":9999999000000},"purse_account_limit":1,"purse_timeout":{"t_s":9999999000000},"master_sig":"C3XVRW8E4NRFRHETFY6F44PTYDEK8S35RFR5RR690A21HAK7T6P9KBBGXBD87T0XQ0MPQMTDJFT14MJZSHND3XEB8HQ7FQETVXNM008="}

View file

@ -117,3 +117,5 @@ let bin_nbo =
|+ field beint32 (fun t -> t.fraction) |+ field beint32 (fun t -> t.fraction)
|+ field (bytes currency_len) (fun t -> pad_currency t.currency) |+ field (bytes currency_len) (fun t -> pad_currency t.currency)
|> sealr |> sealr
let dummy_value = "DUMMY:0.0" |> of_string |> Result.get_ok

View file

@ -25,3 +25,7 @@ val jsont : t Jsont.t
(* only for encoding *) (* only for encoding *)
val bin : t Bin.t val bin : t Bin.t
val bin_nbo : t Bin.t val bin_nbo : t Bin.t
(* TODO
dummy value to use as placeholder for WIP *)
val dummy_value : t

View file

@ -433,13 +433,10 @@ module Global_fees = struct
purse_timeout; purse_timeout;
master_sig; master_sig;
} = } =
(* TODO what is kyc_timeout, kyc_fee ? *) (* TODO KYC
let dummy_amount = what is kyc_timeout, kyc_fee ? *)
Amount.make ~sign:None ~currency:"EUR" ~value:0_L ~fraction:0_l
|> Result.get_ok
in
let kyc_timeout = None in let kyc_timeout = None in
let kyc_fee = dummy_amount in let kyc_fee = Amount.dummy_value in
(* * *) (* * *)
let open Bin_sig.GlobalFees in let open Bin_sig.GlobalFees in
verify_f ~f:Sm.verify_with_master_key master_sig verify_f ~f:Sm.verify_with_master_key master_sig

View file

@ -23,6 +23,23 @@ let of_span_exn = function
(* -- *) (* -- *)
(* TODO
this doesn't handle "never" value, and truncate time *)
let of_string s =
match Float.of_string_opt s with
| None -> Error "Timestamp.of_string failure: not a float"
| Some v -> (
match Ptime.of_float_s v with
| None -> Error "Timestamp.of_string failure"
| Some v -> Ok (Some v))
let pp fmt t =
match t with
| None -> Fmt.pf fmt {|"never"|}
| Some v ->
let v = Ptime.to_float_s v in
Fmt.pf fmt {|%f|} v
(* microseconds since the UNIX Epoch, or "never" if None *) (* microseconds since the UNIX Epoch, or "never" if None *)
let jsont = let jsont =
let number_or_never_jsont = let number_or_never_jsont =
@ -80,6 +97,23 @@ let compare a b =
module Span = struct module Span = struct
type t = span type t = span
(* TODO
this doesn't handle "never" value, and truncate time *)
let of_string s =
match Float.of_string_opt s with
| None -> Error "Timestamp.Span.of_string failure: not a float"
| Some v -> (
match Ptime.Span.of_float_s v with
| None -> Error "Timestamp.Span.of_string failure"
| Some v -> Ok (Some v))
let pp fmt t =
match t with
| None -> Fmt.pf fmt {|"forever"|}
| Some v ->
let v = Ptime.Span.to_float_s v in
Fmt.pf fmt {|%f|} v
let to_int64 ptime = ptime |> Ptime.Span.to_float_s |> Int64.of_float let to_int64 ptime = ptime |> Ptime.Span.to_float_s |> Int64.of_float
let of_int64 i = let of_int64 i =

View file

@ -10,6 +10,11 @@ type span = Ptime.Span.t option
module Span : sig module Span : sig
type t = span type t = span
val of_string : string -> (t, string) result
val pp : Stdlib.Format.formatter -> t -> unit
(* - *)
val jsont : t Jsont.t val jsont : t Jsont.t
val bin : t Bin.t val bin : t Bin.t
val bin_nbo : t Bin.t val bin_nbo : t Bin.t
@ -21,6 +26,10 @@ val add_span_exn : t -> span -> t
val of_span_exn : span -> t val of_span_exn : span -> t
val compare : t -> t -> int option val compare : t -> t -> int option
(* used for offline tool argument conversion *)
val of_string : string -> (t, string) result
val pp : Stdlib.Format.formatter -> t -> unit
(* - *) (* - *)
val jsont : t Jsont.t val jsont : t Jsont.t
val bin : t Bin.t val bin : t Bin.t

View file

@ -9,6 +9,18 @@ let default_request_file = "request.json"
(*let to_term_ret = function Error e -> `Error (false, e) | Ok () -> `Ok ()*) (*let to_term_ret = function Error e -> `Error (false, e) | Ok () -> `Ok ()*)
let to_term_ret = Fun.id let to_term_ret = Fun.id
let timestamp =
Arg.Conv.make ~docv:"timestamp argument" ~parser:Timestamp.of_string
~pp:Timestamp.pp ()
let relative_time =
Arg.Conv.make ~docv:"relative time argument" ~parser:Timestamp.Span.of_string
~pp:Timestamp.Span.pp ()
let amount =
Arg.Conv.make ~docv:"amount argument" ~parser:Amount.of_string ~pp:Amount.pp
()
let setup_cmd = let setup_cmd =
let doc = "Generate offline master keys" in let doc = "Generate offline master keys" in
let output = let output =
@ -94,6 +106,50 @@ let revoke_signkey_cmd =
let+ output = output and+ master_key = master_key and+ signkey = signkey in let+ output = output and+ master_key = master_key and+ signkey = signkey in
revoke_signkey ~output ~master_key ~signkey |> to_term_ret revoke_signkey ~output ~master_key ~signkey |> to_term_ret
let global_fees_cmd =
let doc = "Provides global fee configuration." in
let start_date =
Arg.(required & opt (some timestamp) None & info [ "start_date" ])
in
let end_date =
Arg.(required & opt (some timestamp) None & info [ "end_date" ])
in
let history_fee =
Arg.(required & opt (some amount) None & info [ "history_fee" ])
in
let account_fee =
Arg.(required & opt (some amount) None & info [ "account_fee" ])
in
let purse_fee =
Arg.(required & opt (some amount) None & info [ "purse_fee" ])
in
let history_expiration =
Arg.(
required & opt (some relative_time) None & info [ "history_expiration" ])
in
let purse_account_limit =
Arg.(required & opt (some int) None & info [ "purse_account_limit" ])
in
let purse_timeout =
Arg.(required & opt (some relative_time) None & info [ "purse_timeout" ])
in
Cmd.make (Cmd.info "global-fees" ~doc)
@@
let+ output = output
and+ master_key = master_key
and+ start_date = start_date
and+ end_date = end_date
and+ history_fee = history_fee
and+ account_fee = account_fee
and+ purse_fee = purse_fee
and+ history_expiration = history_expiration
and+ purse_account_limit = purse_account_limit
and+ purse_timeout = purse_timeout in
global_fees ~output ~master_key ~start_date ~end_date ~history_fee
~account_fee ~purse_fee ~history_expiration ~purse_account_limit
~purse_timeout
|> to_term_ret
let cli = let cli =
let info = let info =
let doc = "MTE Offline CLI tool" in let doc = "MTE Offline CLI tool" in
@ -107,6 +163,7 @@ let cli =
upload_cmd; upload_cmd;
revoke_denom_cmd; revoke_denom_cmd;
revoke_signkey_cmd; revoke_signkey_cmd;
global_fees_cmd;
] ]
let main () = Cmd.eval_result cli let main () = Cmd.eval_result cli

View file

@ -75,3 +75,56 @@ let revoke_signkey ~output ~master_key ~signkey =
let* s = Api.encode Api.SignkeyRevocationSignature.jsont v in let* s = Api.encode Api.SignkeyRevocationSignature.jsont v in
let* () = write_file output s in let* () = write_file output s in
Ok () Ok ()
[@@@ocaml.warning "-27"]
let global_fees ~output ~master_key ~start_date ~end_date ~history_fee
~account_fee ~purse_fee ~history_expiration ~purse_account_limit
~purse_timeout =
let open Crypto in
let* key = read_file master_key in
let* key = EddsaPrivateKey.of_octets key in
let* purse_account_limit =
match
purse_account_limit >= 0
&& purse_account_limit <= Int32.to_int Int32.max_int
with
| false -> Error "invalid purse_account_limit value"
| true -> Ok (Int32.of_int purse_account_limit)
in
let master_sig =
let open Bin_sig.GlobalFees in
(* TODO KYC *)
let kyc_timeout = None in
let kyc_fee = Amount.dummy_value in
sign_f ~f:(EddsaSignature.sign ~key)
{
start_date;
end_date;
purse_timeout;
kyc_timeout;
history_expiration;
history_fee;
kyc_fee;
account_fee;
purse_fee;
purse_account_limit;
}
in
let global_fees =
Api.GlobalFees.
{
start_date;
end_date;
purse_timeout;
history_expiration;
history_fee;
account_fee;
purse_fee;
purse_account_limit;
master_sig;
}
in
let* s = Api.encode Api.GlobalFees.jsont global_fees in
let* () = write_file output s in
Ok ()