From 0b742f876ae951a75d5b14c21742d62803635cb5 Mon Sep 17 00:00:00 2001 From: nonergodic Date: Fri, 13 Oct 2023 13:08:12 -0700 Subject: [PATCH] improve naming of types for external consumption in vaa.ts --- core/definitions/src/vaa.ts | 138 ++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 68 deletions(-) diff --git a/core/definitions/src/vaa.ts b/core/definitions/src/vaa.ts index f8b00ceed..3d4d947f5 100644 --- a/core/definitions/src/vaa.ts +++ b/core/definitions/src/vaa.ts @@ -21,7 +21,7 @@ import { import { keccak256 } from "./utils"; -//PayloadLiteralToLayoutMapping is the compile-time analog/complement to the runtime +//LayoutLiteralToLayoutMapping is the compile-time analog/complement to the runtime // payload factory. It uses TypeScript's interface merging mechanic to "dynamically" extend known // payload types that are declared in different modules. This allows us to have full type safety // when constructing payloads via the factory without having to ever declare the mapping of all @@ -34,17 +34,21 @@ declare global { } } -type PayloadLiteral = keyof Wormhole.PayloadLiteralToLayoutMapping & string; -type LayoutOf = +type LayoutLiteral = keyof Wormhole.PayloadLiteralToLayoutMapping & string; +type LayoutOf = //TODO check if this lazy instantiation hack is actually necessary - PL extends infer V extends PayloadLiteral + LL extends infer V extends LayoutLiteral ? Wormhole.PayloadLiteralToLayoutMapping[V] : never; -type PayloadLiteralToPayloadType = LayoutToType< - LayoutOf +type LayoutLiteralToPayloadType = LayoutToType< + LayoutOf >; +type PayloadLiteral = LayoutLiteral | "Uint8Array"; +type PayloadLiteralToPayloadType = + PL extends LayoutLiteral ? LayoutLiteralToPayloadType : Uint8Array; + const guardianSignatureLayout = [ { name: "guardianIndex", binary: "uint", size: 1 }, { name: "signature", ...signatureItem }, @@ -74,14 +78,10 @@ const envelopeLayout = [ const baseLayout = [...headerLayout, ...envelopeLayout] as const; type BaseLayout = LayoutToType; -type ExtendedLiteral = PayloadLiteral | "Uint8Array"; -type ExtendedLiteralToPayloadType = - EL extends PayloadLiteral ? PayloadLiteralToPayloadType : Uint8Array; - -export interface VAA +export interface VAA extends BaseLayout { - readonly payloadLiteral: EL; - readonly payload: ExtendedLiteralToPayloadType; + readonly payloadLiteral: PL; + readonly payload: PayloadLiteralToPayloadType; //TODO various problems with storing the hash here: // 1. On EVM the core bridge actually uses the double keccak-ed hash because of an early oversight // 2. As discussed on slack, storing memoized values on an object is a smell too @@ -90,48 +90,48 @@ export interface VAA readonly hash: Uint8Array; } -const payloadFactory = new Map(); +const payloadFactory = new Map(); -function getPayloadLayout(payloadLiteral: PL) { - const layout = payloadFactory.get(payloadLiteral); +function getPayloadLayout(layoutLiteral: LL) { + const layout = payloadFactory.get(layoutLiteral); if (!layout) - throw new Error(`No layout registered for payload type ${payloadLiteral}`); - return layout as LayoutOf; + throw new Error(`No layout registered for payload type ${layoutLiteral}`); + return layout as LayoutOf; } -const extendedLiteralToPayloadItem = ( - extendedLiteral: EL, +const payloadLiteralToPayloadItem = ( + payloadLiteral: PL, ) => - (extendedLiteral === "Uint8Array" + (payloadLiteral === "Uint8Array" ? ({ name: "payload", binary: "bytes" } as const) : ({ name: "payload", binary: "object", - layout: getPayloadLayout(extendedLiteral), + layout: getPayloadLayout(payloadLiteral), } as const)) satisfies LayoutItem; -//annoyingly we can't use the return value of extendedLiteralToPayloadItem -type ExtendedLiteralToDynamicItems = +//annoyingly we can't use the return value of payloadLiteralToPayloadItem +type PayloadLiteralToDynamicItems = DynamicItemsOfLayout< [ ...typeof baseLayout, - EL extends PayloadLiteral + PL extends LayoutLiteral ? { name: "payload"; binary: "object"; - layout: DynamicItemsOfLayout>; + layout: DynamicItemsOfLayout>; } : { name: "payload"; binary: "bytes" }, ] >; -export const create = ( - extendedLiteral: EL, - vaaData: LayoutToType>, -): VAA => { +export const create = ( + payloadLiteral: PL, + vaaData: LayoutToType>, +): VAA => { const bodyLayout = [ ...envelopeLayout, - extendedLiteralToPayloadItem(extendedLiteral), + payloadLiteralToPayloadItem(payloadLiteral), ] as const; const bodyWithFixed = addFixedValues( bodyLayout, @@ -139,18 +139,18 @@ export const create = ( vaaData as LayoutToType>, ); return { - payloadLiteral: extendedLiteral, + payloadLiteral, ...addFixedValues( headerLayout, vaaData as LayoutToType, ), ...bodyWithFixed, hash: keccak256(serializeLayout(bodyLayout, bodyWithFixed)), - } as VAA; + } as VAA; }; -export function registerPayloadType( - payloadLiteral: PL, +export function registerPayloadType( + payloadLiteral: LL, payloadLayout: Layout, ) { if (payloadFactory.has(payloadLiteral)) @@ -159,26 +159,28 @@ export function registerPayloadType( payloadFactory.set(payloadLiteral, payloadLayout); } -export const serialize = ( - vaa: VAA, +export const serialize = ( + vaa: VAA, ): Uint8Array => { const layout = [ ...baseLayout, - extendedLiteralToPayloadItem(vaa.payloadLiteral), + payloadLiteralToPayloadItem(vaa.payloadLiteral), ] as const satisfies Layout; return serializeLayout(layout, vaa as unknown as LayoutToType); }; -export const serializePayload = ( - extendedLiteral: EL, - payload: ExtendedLiteralToPayloadType, +export const serializePayload = ( + payloadLiteral: PL, + payload: PayloadLiteralToPayloadType, ) => { - if (extendedLiteral === "Uint8Array") return payload; + if (payloadLiteral === "Uint8Array") + return payload as Uint8Array; - const layout = getPayloadLayout(extendedLiteral); + const layout = getPayloadLayout(payloadLiteral); return serializeLayout(layout, payload as LayoutToType); }; +//can't use PayloadLiteral because it leads to a circular reference export type NamedPayloads = readonly (readonly [string, Layout])[]; export const payloadDiscriminator = ( @@ -196,22 +198,22 @@ export const payloadDiscriminator = ( }; }; -export function deserialize( - extendedLiteral: EL, - data: Uint8Array | string, -): VAA; - export function deserialize( - discriminator: (data: Uint8Array | string) => PL | null, + payloadLiteral: PL, data: Uint8Array | string, ): VAA; -export function deserialize( +export function deserialize( + discriminator: (data: Uint8Array | string) => LL | null, + data: Uint8Array | string, +): VAA; + +export function deserialize( payloadDet: - | EL - | ((data: Uint8Array | string) => (EL & PayloadLiteral) | null), + | PL + | ((data: Uint8Array | string) => (PL & LayoutLiteral) | null), data: Uint8Array | string, -): VAA { +): VAA { if (typeof data === "string") data = hexByteStringToUint8Array(data); const [header, envelopeOffset] = deserializeLayout( @@ -250,32 +252,32 @@ export function deserialize( : deserializePayload(payloadDet, data, payloadOffset); const hash = keccak256(data.slice(envelopeOffset)); - return { payloadLiteral, ...header, ...envelope, payload, hash } as VAA; + return { payloadLiteral, ...header, ...envelope, payload, hash } as VAA; } -type DeserializePayloadReturn = - | ExtendedLiteralToPayloadType - | [EL & PayloadLiteral, PayloadLiteralToPayloadType]; +type DeserializePayloadReturn = + | PayloadLiteralToPayloadType + | [PL & LayoutLiteral, LayoutLiteralToPayloadType]; -export function deserializePayload( - payloadLiteral: EL, +export function deserializePayload( + payloadLiteral: PL, data: Uint8Array | string, offset?: number, -): ExtendedLiteralToPayloadType; +): PayloadLiteralToPayloadType; -export function deserializePayload( - discriminator: (data: Uint8Array | string) => PL | null, +export function deserializePayload( + discriminator: (data: Uint8Array | string) => LL | null, data: Uint8Array | string, offset?: number, -): [PL, PayloadLiteralToPayloadType]; +): [LL, LayoutLiteralToPayloadType]; -export function deserializePayload( +export function deserializePayload( payloadDet: - | EL - | ((data: Uint8Array | string) => (EL & PayloadLiteral) | null), + | PL + | ((data: Uint8Array | string) => (PL & LayoutLiteral) | null), data: Uint8Array | string, offset = 0, -): DeserializePayloadReturn { +): DeserializePayloadReturn { //grouped together to have just a single cast on the return type return (() => { if (typeof data === "string") data = hexByteStringToUint8Array(data); @@ -295,5 +297,5 @@ export function deserializePayload( candidate, deserializeLayout(getPayloadLayout(candidate), data, offset), ]; - })() as DeserializePayloadReturn; + })() as DeserializePayloadReturn; }