Skip to content

Commit

Permalink
Add minting
Browse files Browse the repository at this point in the history
  • Loading branch information
ax0 committed Jul 19, 2024
1 parent 87ac23e commit 4589b92
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 6 deletions.
63 changes: 62 additions & 1 deletion apps/consumer-client/src/pages/examples/add-pcd.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { GPCPCDArgs, GPCPCDPackage } from "@pcd/gpc-pcd";
import {
constructZupassPcdAddRequestUrl,
constructZupassPcdMintRequestUrl,
constructZupassPcdProveAndAddRequestUrl,
openSignedZuzaluSignInPopup,
useZupassPopupMessages
Expand Down Expand Up @@ -91,6 +92,9 @@ export default function Page(): JSX.Element {
_setPODPrivateKey2(key);
setPODPublicKey2(encodePublicKey(derivePublicKey(decodePrivateKey(key))));
};
const [podMintUrl, setPODMintUrl] = useState(
"http://localhost:4000/api/mintPOD"
);
const [gpcConfig, setGPCConfig] = useState(EXAMPLE_GPC_CONFIG);
const [membershipLists, setMembershipLists] = useState(
EXAMPLE_MEMBERSHIP_LISTS
Expand Down Expand Up @@ -234,7 +238,7 @@ export default function Page(): JSX.Element {
</label>
<br />
<br />
Card POD content to sign: <br />
Card POD content to sign and/or mint: <br />
<br />
<textarea
cols={45}
Expand Down Expand Up @@ -269,6 +273,19 @@ export default function Page(): JSX.Element {
add a new POD to Zupass (redirect)
</button>
<br />
<button
onClick={() =>
mintPODPCD(
podMintUrl,
podContent2,
podPrivateKey2,
podFolder2.length > 0 ? podFolder2 : undefined
)
}
>
mint a new POD in Zupass (popup)
</button>
<br />
<label>
Private key to sign POD with:
<input
Expand Down Expand Up @@ -297,6 +314,19 @@ export default function Page(): JSX.Element {
/>
</label>
<br />
<label>
Mint URL:
<input
type="text"
value={podMintUrl}
placeholder="Enter mint URL..."
style={{ marginLeft: "16px" }}
onChange={(e): void => {
setPODMintUrl(e.target.value);
}}
/>
</label>
<br />
<br />
GPC Proof config: <br />
<textarea
Expand Down Expand Up @@ -734,6 +764,37 @@ async function addPODPCD(
}
}

async function mintPODPCD(
mintUrl: string,
podContent: string,
podPrivateKey: string,
podFolder: string | undefined,
redirectToFolder?: boolean
): Promise<void> {
const newPOD = new PODPCD(
uuid(),
POD.sign(podEntriesFromSimplifiedJSON(podContent), podPrivateKey)
);

const serializedPODPCD = await PODPCDPackage.serialize(newPOD);

const url = constructZupassPcdMintRequestUrl(
ZUPASS_URL,
mintUrl,
window.location.origin + "#/popup",
serializedPODPCD,
podFolder,
false,
redirectToFolder
);

if (redirectToFolder) {
open(url);
} else {
sendZupassRequest(url);
}
}

async function addGPCPCD(
podContent: string,
podContent2: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import { getErrorMessage } from "@pcd/util";
import { useCallback, useEffect, useRef, useState } from "react";
import styled from "styled-components";
import { appConfig } from "../../../src/appConfig";
import { useDispatch, useIsSyncSettled, useSelf } from "../../../src/appHooks";
import {
useCredentialManager,
useDispatch,
useIsSyncSettled,
useSelf
} from "../../../src/appHooks";
import { mintPODPCD } from "../../../src/mintUtils";
import {
clearAllPendingRequests,
pendingRequestKeys
Expand Down Expand Up @@ -40,8 +46,14 @@ export function JustAddScreen({
const dispatch = useDispatch();
const [added, setAdded] = useState(false);
const { error, pcd } = useDeserialized(request.pcd);
console.log("Error: ", error);
const syncSettled = useIsSyncSettled();
const self = useSelf();
const isMintable =
request.pcd.type === "pod-pcd" && request.mintUrl !== undefined;
const semaphoreSignaturePCD = useCredentialManager().requestCredential({
signatureType: "sempahore-signature-pcd"
});
const isProtocolWorlds = request.folder === ProtocolWorldsFolderName;
const [ref, setRef] = useState<HTMLElement | null>(null);
const confetti = useTensionConfetti(ref);
Expand All @@ -59,12 +71,23 @@ export function JustAddScreen({
}=${encodeURIComponent(stringifiedRequest)}`;
return;
}

try {
// This is mostly for typechecking and should never throw
// because <AddScreen /> checks if the user is logged in

// If the (POD)PCD is mintable, mint it first.
const maybeSerialisedMintedPCD = isMintable
? await mintPODPCD(
request.mintUrl as string,
request.pcd,
await semaphoreSignaturePCD
)
: request.pcd;

await dispatch({
type: "add-pcds",
pcds: [request.pcd],
pcds: [maybeSerialisedMintedPCD],
folder: request.folder
});
if (isProtocolWorlds) {
Expand All @@ -80,7 +103,16 @@ export function JustAddScreen({
} catch (e) {
await err(dispatch, "Error Adding PCD", getErrorMessage(e));
}
}, [confetti, dispatch, self, pcd, isProtocolWorlds, request]);
}, [
confetti,
dispatch,
self,
pcd,
isMintable,
isProtocolWorlds,
request,
semaphoreSignaturePCD
]);

useEffect(() => {
if (autoAdd && !hasAutoAdded.current) {
Expand Down Expand Up @@ -115,7 +147,7 @@ export function JustAddScreen({
{error && JSON.stringify(error)}
<Spacer h={16} />
<Button onClick={onAddClick}>
{isProtocolWorlds ? "Collect" : "Add"}
{isProtocolWorlds ? "Collect" : isMintable ? "Mint" : "Add"}
</Button>
</>
);
Expand Down
47 changes: 47 additions & 0 deletions apps/passport-client/src/mintUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { SerializedPCD } from "@pcd/pcd-types";
import { POD } from "@pcd/pod";
import { PODPCD, PODPCDPackage } from "@pcd/pod-pcd";

export async function mintPODPCD(
mintUrl: string,
podPCDTemplate: SerializedPCD<PODPCD>,
semaphoreSignaturePCD: SerializedPCD
): Promise<SerializedPCD<PODPCD>> {
// Request POD by content ID.
const pcd = (await PODPCDPackage.deserialize(podPCDTemplate.pcd)) as PODPCD;
const contentID = pcd.pod.contentID.toString(16);
const requestBody = JSON.stringify({
contentID,
semaphoreSignaturePCD
});
let mintedPOD: POD;
let serialisedMintedPOD: string;

try {
const resp = await fetch(mintUrl, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: requestBody
});
serialisedMintedPOD = await resp.text();
} catch {
throw new Error("Mint server error.");
}

try {
mintedPOD = POD.deserialize(serialisedMintedPOD);
} catch {
throw new Error("Invalid mint request!");
}

// Throw if signer's keys don't match.
if (pcd.claim.signerPublicKey !== mintedPOD.signerPublicKey) {
throw new Error("The minted POD was signed by a different party.");
}

const mintedPCD = new PODPCD(pcd.id, mintedPOD);
return PODPCDPackage.serialize(mintedPCD);
}
25 changes: 24 additions & 1 deletion packages/lib/passport-interface/src/PassportInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface PCDGetWithoutProvingRequest extends PCDRequest {
export interface PCDAddRequest extends PCDRequest {
type: PCDRequestType.Add;
pcd: SerializedPCD;
mintUrl?: string;
folder?: string;
redirectToFolder?: boolean;
}
Expand Down Expand Up @@ -113,7 +114,29 @@ export function constructZupassPcdAddRequestUrl(
): string {
const req: PCDAddRequest = {
type: PCDRequestType.Add,
returnUrl: returnUrl,
returnUrl,
pcd,
folder,
postMessage,
redirectToFolder
};
const eqReq = encodeURIComponent(JSON.stringify(req));
return `${zupassClientUrl}#/add?request=${eqReq}`;
}

export function constructZupassPcdMintRequestUrl(
zupassClientUrl: string,
mintUrl: string,
returnUrl: string,
pcd: SerializedPCD,
folder?: string,
postMessage: boolean = false,
redirectToFolder?: boolean
): string {
const req: PCDAddRequest = {
type: PCDRequestType.Add,
mintUrl,
returnUrl,
pcd,
folder,
postMessage,
Expand Down

0 comments on commit 4589b92

Please sign in to comment.