Skip to content

Commit 17b579c

Browse files
authored
Merge pull request #14 from kojibai/main
v2.6.0
2 parents 2bc0e24 + 5947ba0 commit 17b579c

8 files changed

Lines changed: 64 additions & 20 deletions

File tree

src/SigilMarkets/SigilMarketsShell.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ export type SigilMarketsShellProps = Readonly<{
4444

4545
type AppliedResolutionKey = string;
4646

47-
const isResolvedLike = (status: string): boolean => status === "resolved" || status === "voided" || status === "canceled";
47+
const isResolvedLike = (status: string, hasResolution: boolean): boolean =>
48+
hasResolution || status === "resolved" || status === "voided" || status === "canceled";
4849

4950
const resolutionKey = (m: Market): AppliedResolutionKey => {
5051
const rid = m.state.resolution;
@@ -209,7 +210,7 @@ const ShellInner = (props: Readonly<{ windowScroll: boolean }>) => {
209210
let shouldRefresh = false;
210211

211212
for (const m of list) {
212-
if (isResolvedLike(m.state.status)) continue;
213+
if (isResolvedLike(m.state.status, !!m.state.resolution)) continue;
213214

214215
const closePulse = m.def.timing.closePulse;
215216
const resolvePulse = Math.max(
@@ -259,7 +260,6 @@ const ShellInner = (props: Readonly<{ windowScroll: boolean }>) => {
259260
.filter((m): m is Market => m !== undefined);
260261

261262
for (const m of list) {
262-
if (!isResolvedLike(m.state.status)) continue;
263263
const r = m.state.resolution;
264264
if (!r) continue;
265265

src/SigilMarkets/hooks/useMarketGrid.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ const tagsAllowed = (tags: readonly string[], required?: readonly string[]): boo
7575
return true;
7676
};
7777

78-
const isResolvedLike = (status: string): boolean => status === "resolved" || status === "voided" || status === "canceled";
78+
const isResolvedLike = (status: string, hasResolution: boolean): boolean =>
79+
hasResolution || status === "resolved" || status === "voided" || status === "canceled";
7980

8081
const microToNumberSafe = (v?: PhiMicro): number => {
8182
if (v === undefined) return 0;
@@ -216,7 +217,7 @@ export const useMarketGrid = (nowPulse: KaiPulse): UseMarketGridResult => {
216217

217218
for (const m of markets) {
218219
// includeResolved gate
219-
if (!filters.includeResolved && isResolvedLike(m.state.status)) continue;
220+
if (!filters.includeResolved && isResolvedLike(m.state.status, !!m.state.resolution)) continue;
220221

221222
// query
222223
if (!matchesQuery(m, filters.query)) continue;

src/SigilMarkets/sigils/PositionSigilMint.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -927,8 +927,8 @@ export const buildClaimPayload = async (
927927
openedAt: coerceKaiMoment(pos.entry.openedAt as unknown),
928928
claimedAt: claimMoment,
929929
marketDefinitionHash: pos.entry.marketDefinitionHash,
930-
label: `Victory ${outcome}`,
931-
note: pos.status === "lost" ? "Loss settled" : "Won Sealed",
930+
label: pos.status === "lost" ? `Loss ${outcome}` : `Victory ${outcome}`,
931+
note: pos.status === "lost" ? "Loss settled" : "Won sealed",
932932
lineageRootSigilId: lineageRoot.lineageRootSigilId,
933933
lineageRootSvgHash: lineageRoot.lineageRootSvgHash,
934934
lineageId,
@@ -1193,13 +1193,15 @@ const amountW = wholeW + fracW;
11931193

11941194

11951195
// Center ring microtext (official feel)
1196+
const claimTone = payload.label?.toLowerCase().includes("loss") ? "LOSS" : "VICTORY";
1197+
const claimLabel = claimTone === "LOSS" ? "Loss" : "Victory";
11961198
const microSeal = isClaim
1197-
? `ΦNET • VICTORY${seal.scheme}${payload.claimedAt.pulse}${String(payload.marketId)} •`
1199+
? `ΦNET • ${claimTone}${seal.scheme}${payload.claimedAt.pulse}${String(payload.marketId)} •`
11981200
: `ΦNET • ${okWord}${seal.scheme}${openedShort}${String(payload.marketId)} •`;
11991201

12001202
const dataKind = isClaim ? "sigilmarkets-claim" : "sigilmarkets-position";
12011203
const ariaLabel = isClaim
1202-
? `SigilMarkets Victory${payload.outcome} — pulse ${payload.claimedAt.pulse}`
1204+
? `SigilMarkets ${claimLabel}${payload.outcome} — pulse ${payload.claimedAt.pulse}`
12031205
: `SigilMarkets Position — ${payload.side} — pulse ${payload.openedAt.pulse}`;
12041206

12051207
return `<?xml version="1.0" encoding="UTF-8"?>

src/SigilMarkets/sigils/SigilExport.tsx

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,10 @@ const manifestFromSigil = async (opts: {
239239
return { manifestHash, ...manifestPayload };
240240
};
241241

242-
const ensureZkProofInSvg = async (svgText: string): Promise<string> => {
242+
const ensureZkProofInSvg = async (
243+
svgText: string,
244+
opts?: Readonly<{ allowMissingZkProof?: boolean }>,
245+
): Promise<string> => {
243246
const metadataRegex = /<metadata(?:\s[^>]*)?>([\s\S]*?)<\/metadata>/gi;
244247
let match: RegExpExecArray | null;
245248

@@ -292,11 +295,15 @@ const ensureZkProofInSvg = async (svgText: string): Promise<string> => {
292295
proofHints,
293296
});
294297
if (!generated) {
295-
throw new Error("ZK proof unavailable for export");
298+
if (!opts?.allowMissingZkProof) {
299+
throw new Error("ZK proof unavailable for export");
300+
}
301+
payload.proofHints = proofHints;
302+
} else {
303+
payload.zkProof = generated.proof as unknown;
304+
payload.zkPublicInputs = generated.zkPublicInputs;
305+
payload.proofHints = generated.proofHints;
296306
}
297-
payload.zkProof = generated.proof as unknown;
298-
payload.zkPublicInputs = generated.zkPublicInputs;
299-
payload.proofHints = generated.proofHints;
300307
} else {
301308
payload.proofHints = proofHints;
302309
}
@@ -371,6 +378,9 @@ export type SigilExportOptions = Readonly<{
371378
/** Export which formats. Default: both */
372379
exportSvg?: boolean;
373380
exportPng?: boolean;
381+
382+
/** Allow export without an embedded ZK proof. */
383+
allowMissingZkProof?: boolean;
374384
}>;
375385

376386
export type SigilZipOptions = Readonly<{
@@ -383,6 +393,9 @@ export type SigilZipOptions = Readonly<{
383393

384394
/** PNG size px (square). Default: 1024 */
385395
pngSizePx?: number;
396+
397+
/** Allow export without an embedded ZK proof. */
398+
allowMissingZkProof?: boolean;
386399
}>;
387400

388401
export const exportSigil = async (opts: SigilExportOptions): Promise<ExportResult> => {
@@ -397,7 +410,15 @@ export const exportSigil = async (opts: SigilExportOptions): Promise<ExportResul
397410
const svgText = opts.svgText ?? (opts.svgUrl ? await fetchText(opts.svgUrl) : null);
398411
if (!svgText) return { ok: false, error: "Missing svgText/svgUrl" };
399412

400-
const svgWithProof = await ensureZkProofInSvg(svgText);
413+
let svgWithProof = svgText;
414+
try {
415+
svgWithProof = await ensureZkProofInSvg(svgText, { allowMissingZkProof: opts.allowMissingZkProof });
416+
} catch (err) {
417+
const message = err instanceof Error ? err.message : "export failed";
418+
if (!opts.allowMissingZkProof || message !== "Sigil metadata missing; cannot generate ZK proof") {
419+
throw err;
420+
}
421+
}
401422

402423
if (exportSvg) {
403424
const blob = new Blob([svgWithProof], { type: "image/svg+xml" });
@@ -423,7 +444,15 @@ export const exportSigilZip = async (opts: SigilZipOptions): Promise<ExportResul
423444
const svgText = opts.svgText ?? (opts.svgUrl ? await fetchText(opts.svgUrl) : null);
424445
if (!svgText) return { ok: false, error: "Missing svgText/svgUrl" };
425446

426-
const svgWithProof = await ensureZkProofInSvg(svgText);
447+
let svgWithProof = svgText;
448+
try {
449+
svgWithProof = await ensureZkProofInSvg(svgText, { allowMissingZkProof: opts.allowMissingZkProof });
450+
} catch (err) {
451+
const message = err instanceof Error ? err.message : "export failed";
452+
if (!opts.allowMissingZkProof || message !== "Sigil metadata missing; cannot generate ZK proof") {
453+
throw err;
454+
}
455+
}
427456
const size = Math.max(256, Math.min(4096, Math.floor(opts.pngSizePx ?? 1024)));
428457
const png = await svgToPngBlob(svgWithProof, size);
429458
const exportMoment = momentFromUTC(new Date());
@@ -459,6 +488,7 @@ export type SigilExportButtonProps = Readonly<{
459488
mode?: "pair" | "zip";
460489
className?: string;
461490
label?: string;
491+
allowMissingZkProof?: boolean;
462492
}>;
463493

464494
export const SigilExportButton = (props: SigilExportButtonProps) => {
@@ -478,6 +508,7 @@ export const SigilExportButton = (props: SigilExportButtonProps) => {
478508
svgText: props.svgText,
479509
svgUrl: props.svgUrl,
480510
pngSizePx: props.pngSizePx ?? 1400,
511+
allowMissingZkProof: props.allowMissingZkProof,
481512
})
482513
: await exportSigil({
483514
filenameBase: props.filenameBase,
@@ -486,6 +517,7 @@ export const SigilExportButton = (props: SigilExportButtonProps) => {
486517
pngSizePx: props.pngSizePx ?? 1024,
487518
exportSvg: true,
488519
exportPng: true,
520+
allowMissingZkProof: props.allowMissingZkProof,
489521
});
490522
if (!res.ok) ui.toast("error", "Export failed", res.error);
491523
else {

src/SigilMarkets/utils/marketTiming.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ const clampPulse = (p: KaiPulse): number => {
1010

1111
export const deriveMarketStatus = (market: Market, nowPulse: KaiPulse): MarketStatus => {
1212
const status = market.state.status;
13-
if (status === "resolved" || status === "voided" || status === "canceled") return status;
13+
if (status === "canceled") return status;
14+
if (market.state.resolution) {
15+
return market.state.resolution.outcome === "VOID" ? "voided" : "resolved";
16+
}
17+
if (status === "resolved" || status === "voided") return status;
1418
if (status === "resolving" || status === "closed") return status;
1519

1620
const closePulse = clampPulse(market.def.timing.closePulse);

src/SigilMarkets/views/Positions/ExportPositionSheet.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export const ExportPositionSheet = (props: ExportPositionSheetProps) => {
5151

5252
const hasResolution = !!p.resolution;
5353
const shouldLabelClaimProof = hasResolution && (p.status === "claimable" || p.status === "lost");
54-
const exportLabel = shouldLabelClaimProof ? "Download victory proof" : undefined;
54+
const exportLabel = shouldLabelClaimProof ? (p.status === "lost" ? "Download loss proof" : "Download victory proof") : undefined;
5555

5656
const filenameBase = useMemo(() => {
5757
const pid = p.id as unknown as string;
@@ -187,6 +187,7 @@ export const ExportPositionSheet = (props: ExportPositionSheetProps) => {
187187
pngSizePx={2048}
188188
mode="zip"
189189
label={exportLabel}
190+
allowMissingZkProof={p.status === "lost"}
190191
/>
191192
) : (
192193
<Button

src/SigilMarkets/views/Positions/PositionDetail.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ export const PositionDetail = (props: PositionDetailProps) => {
114114
const position = p;
115115
const hasClaimProof =
116116
!!position.resolution && (position.status === "claimable" || position.status === "lost");
117-
const exportLabel = hasClaimProof ? "Download victory proof" : "Export";
117+
const exportLabel = hasClaimProof
118+
? position.status === "lost"
119+
? "Download loss proof"
120+
: "Download victory proof"
121+
: "Export";
118122
const canAccessVault = !!activeVault && activeVault.vaultId === position.lock.vaultId;
119123

120124
const openClaimSheet = (): void => {

src/config/buildInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const APP_NAME = "Vérahai";
2-
export const APP_VERSION = "2.5.0";
2+
export const APP_VERSION = "2.6.0";
33
export const GITHUB_REPO_URL = "https://github.com/phinetwork/verahai";
44

55
export const GITHUB_RELEASE_URL = (version: string): string =>

0 commit comments

Comments
 (0)