123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119(** Abstract primitive types with built-in validation.
This module provides type-safe wrappers for Ethereum addresses and hashes.
Values can only be created through smart constructors that validate the
input, making it impossible to have invalid addresses or hashes in the
system. *)(** {1 Internal Validation Helpers} *)letis_hex_char=function|'0'..'9'|'a'..'f'|'A'..'F'->true|_->falseletis_hex_strings=String.for_allis_hex_charsletvalidate_hex_prefixed~name~expected_lengths=letlen=String.lengthsiniflen<>expected_lengththenError(Printf.sprintf"%s: expected %d chars, got %d"nameexpected_lengthlen)elseiflen<2||s.[0]<>'0'||s.[1]<>'x'thenError(Printf.sprintf"%s: must start with 0x"name)elseifnot(is_hex_string(String.subs2(len-2)))thenError(Printf.sprintf"%s: contains invalid hex characters"name)elseOks(** {1 Hex String Functor}
Shared implementation for validated hex string types. *)moduletypeHEX_STRING_CONFIG=sigvalname:stringvalvalidate:string->(string,string)resultendmoduleMake_hex_string(C:HEX_STRING_CONFIG)=structtypet=stringletmake=C.validateletmake_exns=matchmakeswithOkv->v|Errormsg->failwithmsgletunsafe_of_strings=sletto_stringt=tletppfmtt=Format.fprintffmt"%s"tletequal=String.equalletof_yojsonjson=matchjsonwith|`Strings->makes|_->Error(C.name^".of_yojson: expected string")letof_yojson_exnjson=matchof_yojsonjsonwithOkv->v|Errormsg->failwithmsgletto_yojsont=`Stringtletyojson_of_t=to_yojsonlett_of_yojson=of_yojson_exnend(** {1 Address Module} *)moduleAddress=Make_hex_string(structletname="Address"letvalidate=validate_hex_prefixed~name~expected_length:42end)(** {1 Hash64 Module} *)moduleHash64=Make_hex_string(structletname="Hash64"letvalidate=validate_hex_prefixed~name~expected_length:66end)(** {1 Hash Module (variable length)} *)moduleHash=Make_hex_string(structletname="Hash"letvalidates=letlen=String.lengthsiniflen<3thenError"Hash: too short"elseifs.[0]<>'0'||s.[1]<>'x'thenError"Hash: must start with 0x"elseifnot(is_hex_string(String.subs2(len-2)))thenError"Hash: contains invalid hex characters"elseOksend)(** {1 Timestamps} *)moduleTimestamp=structtypet=Ptime.tletof_strings=matchPtime.of_rfc3339swithOk(t,_,_)->Somet|Error_->Noneletof_string_exns=matchof_stringswith|Somet->t|None->invalid_arg("invalid ISO 8601 timestamp: "^s)letto_stringt=Ptime.to_rfc3339~tz_offset_s:0tletto_ptimet=tletof_ptimet=tlett_of_yojson=function|`Strings->of_string_exns|_->failwith"Timestamp: expected string"letyojson_of_tt=`String(to_stringt)letppfmtt=Format.fprintffmt"%s"(to_stringt)letequal=Ptime.equalend(** {1 Side Enum}
Trade side (Buy/Sell) shared across Data API and CLOB API. *)moduleSide=structtypet=Buy|Sell[@@derivingenum]end