[@@@ocaml.warning "-26-27"] open Syntax open Api module String_map = Stdlib.Map.Make (Stdlib.String) let denomgroup_of_denomdata Denom_data. { pub; value; stamp_start; stamp_expire_withdraw; stamp_expire_deposit; stamp_expire_legal; fee_withdraw; fee_deposit; fee_refresh; fee_refund; age_mask; h_pub; master_sig; revoked_sig; } = let master_sig = match master_sig with None -> assert false | Some v -> v in let denoms = [ RsaDenom. { rsa_pub= pub; master_sig; stamp_start; stamp_expire_withdraw; stamp_expire_deposit; stamp_expire_legal; lost= None; }; ] in DenomGroup.Rsa RsaDenomGroup. { denoms; value; fee_withdraw; fee_deposit; fee_refresh; fee_refund } let mk_keys ~db_conn ~sm ~last_issue_date = let version = "0" in let base_url = Config.base_url in let currency = Config.currency in let shopping_url = Config.shopping_url in let open_banking_gateway = Config.open_banking_gateway_url in let bank_compliance_language = Config.bank_compliance_language in let currency_specification = let v = Config.Currency.v in let alt_unit_names = Parse_config.Alt_unit_names.encode_exn v.alt_unit_names in CurrencySpecification. { name= v.name; num_fractional_input_digits= v.fractional_input_digits; num_fractional_normal_digits= v.fractional_normal_digits; num_fractional_trailing_zero_digits= v.fractional_trailing_zero_digits; alt_unit_names; common_amounts= []; } in let tiny_amount = Config.tiny_amount in let stefan_abs = Config.stefan_abs in let stefan_log = Config.stefan_log in let stefan_lin = Config.stefan_lin in (* todo asset_type Type of the asset. "fiat", "crypto", "regional" or "stock". *) let asset_type = "xxx" in let* accounts = Pg.get_wire_accounts db_conn |> unwrap_err_caqti in let* wire_fees = (* todo where does wire_methods comes from? *) let wire_method = "xxx" in let+ wire_fees = Pg.get_wire_fees db_conn ~wire_method |> unwrap_err_caqti in String_map.singleton wire_method wire_fees in let wads = (* TODO wads *) [] in let rewards_allowed = false in let kyc_enabled = false in let disable_direct_deposit = (* todo *) false in let master_public_key = Config.master_public_key in let reserve_closing_delay = Some Config.Exchangedb.idle_reserve_expiration_time in (* todo *) let wallet_balance_limit_without_kyc = None in let hard_limits = [] in let zero_limits = [] in let* denom_data_l = Pg.get_denominations db_conn |> unwrap_err_caqti in (* TODO check order!! *) let denom_data_l = List.sort (fun a b -> let open Denom_data in Stdlib.compare a.stamp_start b.stamp_start) denom_data_l in let list_issue_date = (* TODO is this the last [stamp_start] value? *) (* date when the denomination keys were last updated *) match denom_data_l with | [] -> None | v :: _ -> v.stamp_start in let denominations = (* TODO really need to understand and correctly group denoms 'exchange_sig' depends on correct denom group/order *) List.map denomgroup_of_denomdata denom_data_l in let* signkeys = let+ signkey_data_l = Pg.get_active_signkeys db_conn |> unwrap_err_caqti in let signkey_data_l = List.sort (fun a b -> let open Signkey_data in Stdlib.compare a.stamp_start b.stamp_start) signkey_data_l in List.map (fun Signkey_data. { pub; stamp_start; stamp_expire; stamp_end; master_sig; revoked_sig= _; } -> let master_sig = match master_sig with | None -> Fmt.failwith "signkey_data without master_sig" | Some v -> v in SignKey.{ key= pub; stamp_start; stamp_expire; stamp_end; master_sig }) signkey_data_l in let exchange_pub = (* the eddsa pub key used to sign exchange_sig *) match signkeys with | [] -> Fmt.failwith "exchange has no active signkey" | v :: _ -> v.SignKey.key in let exchange_sig = (* Compact EdDSA signature (binary-only) over the contatentation of all of the master_sigs (in reverse chronological order by group) in the arrays under "denominations". *) let l = List.map (fun v -> match v.Denom_data.master_sig with | None -> Fmt.failwith "denom_data without master_sig" | Some v -> v) denom_data_l in let l = List.map (fun v -> Bin_sig.DenominationKeyValidity.to_octets v) l in let data = String.concat "" l in let hc = Bin_type.Hash_64.hash data in let open Bin_sig.ExchangeKeySet in sign_f ~f:(Secmod.sign_with_signkey sm ~pub:exchange_pub) R.{ list_issue_date; hc } in let recoup = [] in let global_fees = (* TODO *) [] in let auditors = (* TODO *) [] in let extensions = None in let extensions_sig = None in Ok ExchangeKeysResponse. { version; base_url; currency; shopping_url; open_banking_gateway; bank_compliance_language; currency_specification; tiny_amount; stefan_abs; stefan_log; stefan_lin; asset_type; accounts; wire_fees; wads; rewards_allowed; kyc_enabled; disable_direct_deposit; master_public_key; reserve_closing_delay; wallet_balance_limit_without_kyc; hard_limits; zero_limits; denominations; exchange_sig; exchange_pub; recoup; global_fees; list_issue_date; auditors; signkeys; extensions; extensions_sig; } let jsont = ExchangeKeysResponse.jsont (* TODO query param ?last_issue_date *) let f req server _env = Logs.info (fun m -> m "GET /keys/"); let db_conn = Vif.Server.device Devices.db_connection server in let sm = Vif.Server.device Devices.secmod server in let res = let last_issue_date = Ptime_clock.now () |> Option.some in let* v = mk_keys ~db_conn ~sm ~last_issue_date in let s = Api.encode_exn jsont v in Ok s in Respond_util.respond_with_res res req