@@ -170,7 +170,19 @@ function validateBidEntry(value: unknown, field: string): BidReceiptEntry {
170170 assertNullableHexString ( evidence . ciphertext , `${ field } .evidence.ciphertext` ) ;
171171 assertNullableHexString ( evidence . auditorBlob , `${ field } .evidence.auditorBlob` ) ;
172172
173- return entry as BidReceiptEntry ;
173+ return {
174+ commitment : entry . commitment as string ,
175+ escrow : entry . escrow as string ,
176+ revealedValue : entry . revealedValue as string | null ,
177+ nonce : entry . nonce as string | null ,
178+ hashValid : entry . hashValid as boolean | null ,
179+ valid : entry . valid as boolean ,
180+ settled : entry . settled as boolean ,
181+ evidence : {
182+ ciphertext : evidence . ciphertext as string | null ,
183+ auditorBlob : evidence . auditorBlob as string | null ,
184+ } ,
185+ } ;
174186}
175187
176188/** Validate a parsed or in-memory receipt before export/serialize. */
@@ -224,11 +236,12 @@ export function validateReceipt(value: unknown): RoundReceipt {
224236 }
225237
226238 const bids = receipt . bids as Record < string , unknown > ;
239+ const validatedBids : Record < string , BidReceiptEntry > = { } ;
227240 for ( const bidder of receipt . bidders as string [ ] ) {
228241 if ( ! ( bidder in bids ) ) {
229242 validationError ( `missing bid entry for bidder ${ bidder } ` , `bids.${ bidder } ` ) ;
230243 }
231- validateBidEntry ( bids [ bidder ] , `bids.${ bidder } ` ) ;
244+ validatedBids [ bidder ] = validateBidEntry ( bids [ bidder ] , `bids.${ bidder } ` ) ;
232245 }
233246
234247 if ( receipt . winner !== null ) {
@@ -240,14 +253,44 @@ export function validateReceipt(value: unknown): RoundReceipt {
240253 assertNonEmptyString ( receipt . artifactChecksum , "artifactChecksum" ) ;
241254 }
242255
243- return receipt as RoundReceipt ;
256+ const validated : RoundReceipt = {
257+ version : RECEIPT_VERSION ,
258+ network : receipt . network as string ,
259+ networkFingerprint : receipt . networkFingerprint as string ,
260+ contractId : receipt . contractId as string ,
261+ exportedAt : receipt . exportedAt as string ,
262+ roundId : receipt . roundId as string ,
263+ itemRef : receipt . itemRef as string ,
264+ revealRound : receipt . revealRound as number ,
265+ clearingRule : receipt . clearingRule as string ,
266+ commitDeadline : receipt . commitDeadline as string ,
267+ revealDeadline : receipt . revealDeadline as string ,
268+ operator : receipt . operator as string ,
269+ auditorPubkey : receipt . auditorPubkey as string ,
270+ bidders : [ ...( receipt . bidders as string [ ] ) ] ,
271+ bids : validatedBids ,
272+ winner : receipt . winner as string | null ,
273+ winningValue : receipt . winningValue as string | null ,
274+ status : receipt . status as string ,
275+ } ;
276+ if ( receipt . artifactChecksum !== undefined ) {
277+ validated . artifactChecksum = receipt . artifactChecksum as string ;
278+ }
279+ return validated ;
280+ }
281+
282+ /** Canonical JSON (deep-sorted keys, trailing newline) without schema checks.
283+ * Use for redacted / partial artifacts that are not valid RoundReceipt values.
284+ * Verifiable receipts must go through {@link serializeReceipt}. */
285+ export function serializeCanonicalJson ( value : unknown ) : string {
286+ return JSON . stringify ( value , sortKeys ) + "\n" ;
244287}
245288
246289/** Serialise a receipt to canonical JSON (deep-sorted keys, no whitespace).
247290 * This is the format the CLI writes and the verifier reads. */
248291export function serializeReceipt ( receipt : RoundReceipt ) : string {
249292 validateReceipt ( receipt ) ;
250- return JSON . stringify ( receipt , sortKeys ) + "\n" ;
293+ return serializeCanonicalJson ( receipt ) ;
251294}
252295
253296/** Parse a receipt from its canonical JSON form. */
0 commit comments