type Cast = T extends U ? T : U; type Prop = K extends keyof T ? T[K] : never; type HexChars = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f"; type HexPairs = `${HexChars}${HexChars}`; /** * returns a Tuple of hex pairs (bytes), or `never` if the input doesn't contain an even number of hex characters */ type Hex = S extends "" ? [] : S extends `${HexPairs}${infer R}` ? S extends `${infer C}${R}` ? [C, ...(Hex extends infer X ? Cast : never)] : never : never; /** * Gets up to the first 8 bytes following the given prefix. `S` _must not_ start with `0x`. */ type Raw = S extends `${P}${infer I0}${infer I1}${infer I2}${infer I3}${infer I4}${infer I5}${infer I6}${infer I7}${infer I8}${infer I9}${infer I10}${infer I11}${infer I12}${infer I13}${infer I14}${infer I15}${infer _}` ? `${I0}${I1}${I2}${I3}${I4}${I5}${I6}${I7}${I8}${I9}${I10}${I11}${I12}${I13}${I14}${I15}` : S extends `${P}${infer I0}${infer I1}${infer I2}${infer I3}${infer I4}${infer I5}${infer I6}${infer I7}${infer I8}${infer I9}${infer I10}${infer I11}${infer I12}${infer I13}` ? `${I0}${I1}${I2}${I3}${I4}${I5}${I6}${I7}${I8}${I9}${I10}${I11}${I12}${I13}` : S extends `${P}${infer I0}${infer I1}${infer I2}${infer I3}${infer I4}${infer I5}${infer I6}${infer I7}${infer I8}${infer I9}${infer I10}${infer I11}` ? `${I0}${I1}${I2}${I3}${I4}${I5}${I6}${I7}${I8}${I9}${I10}${I11}` : S extends `${P}${infer I0}${infer I1}${infer I2}${infer I3}${infer I4}${infer I5}${infer I6}${infer I7}${infer I8}${infer I9}` ? `${I0}${I1}${I2}${I3}${I4}${I5}${I6}${I7}${I8}${I9}` : S extends `${P}${infer I0}${infer I1}${infer I2}${infer I3}${infer I4}${infer I5}${infer I6}${infer I7}` ? `${I0}${I1}${I2}${I3}${I4}${I5}${I6}${I7}` : S extends `${P}${infer I0}${infer I1}${infer I2}${infer I3}${infer I4}${infer I5}` ? `${I0}${I1}${I2}${I3}${I4}${I5}` : S extends `${P}${infer I0}${infer I1}${infer I2}${infer I3}` ? `${I0}${I1}${I2}${I3}` : S extends `${P}${infer I0}${infer I1}` ? `${I0}${I1}` : ""; /** * Add up all our lengths. If any length is `never`, this returns `never`. */ type ValidLengthTogether = ( L1 extends 8 ? L2 extends 8 ? L3 extends 8 ? Add<`${L4}`, "24"> : Add<`${L3}`, "16"> : Add<`${L2}`, "8"> : L1 extends never ? never : `${L1}` ); type Trim = S extends `${Prefix}${infer I}` ? I : never; type U1 = Raw; type U2 = Raw}`>; type U3 = Raw}${U2}`>; type U4 = Raw}${U2}${U3}`>; type L1 = Prop>, "length">; type L2 = Prop>, "length">; type L3 = Prop>, "length">; type L4 = Prop>, "length">; // @ts-ignore: Ignore type instantiation depth errors as we have already limited our depth type ValidLength = ValidLengthTogether, L2, L3, L4>; type Trimmed = Trim; /** * Supports hex-encoded strings up to 32 bytes (64 hex chars), `0x` prefixed */ type DATA< S extends string, Length extends number = -1, > = Length extends -1 ? ValidLength> extends never ? never : S : `${Length}` extends ValidLength> ? S : never; /* ************************** ********************************** */ type TxHash = DATA; type Address = DATA; type Nonce = DATA; /* ************************** ********************************* */ /* ************************** ******************************** */ type BaseOptions = { nonce: string; coinbase: string; }; type OptionsTypeMap = { nonce: Nonce>, coinbase: Address> } type Cond = B extends T ? B : U; type ValidOptions = { [P in keyof O]?: P extends keyof OptionsTypeMap ? Cond[P]> : O[P] }; /* ************************** ******************************* */ /* ************************** *********************************** */ type a = DATA<"0x123"> // never type b = DATA<"0x123", 3> // never (odd numbers aren't currently allowed) type c = DATA<"0x1234"> // 0x1234 type d = DATA<"0xbda2ca0611c2a952a4a25bfc175803912842c839", 4> // never, too long type e = DATA<"0xbda2ca0611c2a952a4a25bfc175803912842c839"> // 0xbda2ca0611c2a952a4a25bfc175803912842c839 type f = DATA<"0xbda2ca0611c2a952a4a25bfc175803912842c839", 20> // 0xbda2ca0611c2a952a4a25bfc175803912842c839 type g = DATA<"0xff6b938acb7d72e261c51fa255a8119d9e23d021bed440298f91342706b1538d"> // 0xff6b938acb7d72e261c51fa255a8119d9e23d021bed440298f91342706b1538d type h = DATA<"0xff6b938acb7d72e261c51fa255a8119d9e23d021bed440298f91342706b1538d", 32> // 0xff6b938acb7d72e261c51fa255a8119d9e23d021bed440298f91342706b1538d type i = DATA<"0123"> // never, invalid /* ************************** *********************************** */ /* ************************** ********************************** */ declare function provider< O extends BaseOptions >(options: ValidOptions): void; // VALID INPUT: provider({ coinbase: "0xbda2ca0611c2a952a4a25bfc175803912842c839", nonce: "0xa3079c9f" }); provider({ coinbase: "0xbda2ca0611c2a952a4a25bfc175803912842c839" }); provider({ nonce: "0xa3079c9f" }); // INVALID INPUTS: provider({ coinbase: "0xZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", // invalid chars nonce: "0xa3079c9f" }); provider({ coinbase: "0x1234", // too short nonce: "0xa3079c9f" }); provider({ coinbase: "0x", // too short nonce: "0xa3079c9f" }); provider({ coinbase: "0", // no 0x and too short nonce: "0xa3079c9f" }); provider({ coinbase: "bda2ca0611c2a952a4a25bfc175803912842c839", // no 0x nonce: "0xa3079c9f" }); provider({ coinbase: "0xbda2ca0611c2a952a4a25bfc175803912842c839", nonce: "a3079c9f" // no 0x }); provider({ coinbase: "0xbda2ca0611c2a952a4a25bfc175803912842c839", nonce: "0xQ3079c9f" // invalid character (Q) }); provider({ coinbase: "0xbda2ca0611c2a952a4a25bfc175803912842c839", nonce: "0xA3079c9f123456789" // too long }); /* ************************** ********************************* */ /* ***************************************************************************** */ /* ***************************************************************************** */ /* ***************************************************************************** */ /* ***************************************************************************** */ /* ***************************** STRING ADDITION ******************************* */ /* ***************************************************************************** */ /* ***************************************************************************** */ /* ***************************************************************************** */ /* ***************************************************************************** */ type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"; type OneDigitPlus = { "00": [false, "0"]; "01": [false, "1"]; "02": [false, "2"]; "03": [false, "3"]; "04": [false, "4"]; "05": [false, "5"]; "06": [false, "6"]; "07": [false, "7"]; "08": [false, "8"]; "09": [false, "9"]; "10": [false, "1"]; "11": [false, "2"]; "12": [false, "3"]; "13": [false, "4"]; "14": [false, "5"]; "15": [false, "6"]; "16": [false, "7"]; "17": [false, "8"]; "18": [false, "9"]; "19": [true, "0"]; "20": [false, "2"]; "21": [false, "3"]; "22": [false, "4"]; "23": [false, "5"]; "24": [false, "6"]; "25": [false, "7"]; "26": [false, "8"]; "27": [false, "9"]; "28": [true, "0"]; "29": [true, "1"]; "30": [false, "3"]; "31": [false, "4"]; "32": [false, "5"]; "33": [false, "6"]; "34": [false, "7"]; "35": [false, "8"]; "36": [false, "9"]; "37": [true, "0"]; "38": [true, "1"]; "39": [true, "2"]; "40": [false, "4"]; "41": [false, "5"]; "42": [false, "6"]; "43": [false, "7"]; "44": [false, "8"]; "45": [false, "9"]; "46": [true, "0"]; "47": [true, "1"]; "48": [true, "2"]; "49": [true, "3"]; "50": [false, "5"]; "51": [false, "6"]; "52": [false, "7"]; "53": [false, "8"]; "54": [false, "9"]; "55": [true, "0"]; "56": [true, "1"]; "57": [true, "2"]; "58": [true, "3"]; "59": [true, "4"]; "60": [false, "6"]; "61": [false, "7"]; "62": [false, "8"]; "63": [false, "9"]; "64": [true, "0"]; "65": [true, "1"]; "66": [true, "2"]; "67": [true, "3"]; "68": [true, "4"]; "69": [true, "5"]; "70": [false, "7"]; "71": [false, "8"]; "72": [false, "9"]; "73": [true, "0"]; "74": [true, "1"]; "75": [true, "2"]; "76": [true, "3"]; "77": [true, "4"]; "78": [true, "5"]; "79": [true, "6"]; "80": [false, "8"]; "81": [false, "9"]; "82": [true, "0"]; "83": [true, "1"]; "84": [true, "2"]; "85": [true, "3"]; "86": [true, "4"]; "87": [true, "5"]; "88": [true, "6"]; "89": [true, "7"]; "90": [false, "9"]; "91": [true, "0"]; "92": [true, "1"]; "93": [true, "2"]; "94": [true, "3"]; "95": [true, "4"]; "96": [true, "5"]; "97": [true, "6"]; "98": [true, "7"]; "99": [true, "8"]; } type LastDigit = D extends Digit ? Str extends `${infer Rest}${D}` ? [Rest, D] : never : never; type ConcatStr = Left extends string ? Right extends string ? `${Left}${Right}` : never : never; type Add = Left extends "" ? Right : Right extends "" ? Left : LastDigit extends [infer LeftRest, infer LeftDigit] ? LastDigit extends [infer RightRest, infer RightDigit] ? Add2> : never : never; type Add2 = LR extends keyof OneDigitPlus ? OneDigitPlus[LR] extends [infer Carry, infer LD] ? Add extends infer RestSum ? (Carry extends true ? Add : RestSum) extends infer LeftCarriedSum ? ConcatStr : never : never : never : never; type AddD = Left extends "" ? Right : Right extends "" ? Left : LastDigit extends [infer LeftRest, infer LeftDigit] ? LastDigit extends [infer RightRest, infer RightDigit] ? [LeftRest, RightRest, ConcatStr] : never : never;