Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Update not before #30

Merged
merged 19 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
"yaml",
"json"
],
"words": ["idkit", "merkle", "OIDC", "SIWE"]
"words": ["idkit", "merkle", "OIDC", "SIWE", "USDCE"]
}
5 changes: 3 additions & 2 deletions demo/with-next/app/api/verify-siwe/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const schema = yup.object({
signature: yup.string().required(),
address: yup.string().required(),
}),
nonce: yup.string().required(),
});

export const POST = async (req: NextRequest) => {
Expand All @@ -24,10 +25,10 @@ export const POST = async (req: NextRequest) => {
throw new Error("Invalid data");
}

const { siweResponsePayload } = validData;
const { siweResponsePayload, nonce } = validData;
const validMessage = await verifySiweMessage(
siweResponsePayload as MiniAppWalletAuthSuccessPayload,
"12345678"
nonce
);

return new Response(
Expand Down
79 changes: 60 additions & 19 deletions demo/with-next/components/ClientContent/Pay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,25 @@ export const Pay = () => {
};
}, []);

const onPayClick = useCallback(async (token: Tokens, amount: number) => {
const tokenAmount = tokenToDecimals(amount, token);

const payPayload: PayCommandInput = {
to: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
token_amount: tokenAmount,
token: token,
description: "Test example payment for minikit",
reference: new Date().toISOString(),
};

const payload = MiniKit.commands.pay(payPayload);
setSentPayPayload({
payload,
});
}, []);
const onPayClick = useCallback(
async (token: Tokens, amount: number, address: string) => {
const tokenAmount = tokenToDecimals(amount, token);

const payPayload: PayCommandInput = {
to: address,
token_amount: tokenAmount.toString(),
token: token,
description: "Test example payment for minikit",
reference: new Date().toISOString(),
};

const payload = MiniKit.commands.pay(payPayload);
setSentPayPayload({
payload,
});
},
[]
);

return (
<div>
Expand All @@ -115,17 +118,55 @@ export const Pay = () => {
<div className="grid grid-cols-2 gap-x-4">
<button
className="bg-black text-white rounded-lg p-4 w-full"
onClick={() => onPayClick(Tokens.USDC, 0.1)}
onClick={() =>
onPayClick(
Tokens.USDCE,
0.1,
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
)
}
>
Send pay (USDC)
Send pay (USDCE)
</button>
<button
className="bg-black text-white rounded-lg p-4 w-full"
onClick={() => onPayClick(Tokens.WLD, 0.1)}
onClick={() =>
onPayClick(
Tokens.WLD,
0.1,
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
)
}
>
Send pay (WLD)
</button>
</div>
<div className="grid grid-cols-2 gap-x-4">
<button
className="bg-black text-white rounded-lg p-4 w-full"
onClick={() =>
onPayClick(
Tokens.USDCE,
0.1,
"0xc2eD884aEa29135AcaB517c0967225Bf15DeA6E9"
)
}
>
Send pay (USDCE) Addr 2
</button>
<button
className="bg-black text-white rounded-lg p-4 w-full"
onClick={() =>
onPayClick(
Tokens.WLD,
0.1,
"0xc2eD884aEa29135AcaB517c0967225Bf15DeA6E9"
)
}
>
Send pay (WLD) Addr 2
</button>
</div>
</div>

<hr />
Expand Down
13 changes: 8 additions & 5 deletions demo/with-next/components/ClientContent/WalletAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const walletAuthErrorPayloadSchema = yup.object({
export const WalletAuth = () => {
const [message, setMessage] = useState<string | null>(null);
const [generationError, setGenerationError] = useState<string | null>(null);
const [nonce, setNonce] = useState<string | null>(null);
const [receivedWalletAuthPayload, setReceivedWalletAuthPayload] =
useState<Record<string, any> | null>(null);

Expand Down Expand Up @@ -75,9 +76,10 @@ export const WalletAuth = () => {
},
body: JSON.stringify({
siweResponsePayload: payload,
nonce,
}),
});

const responseJson = await response.json();

setWalletAuthVerificationMessage(
Expand All @@ -93,18 +95,19 @@ export const WalletAuth = () => {
return () => {
MiniKit.unsubscribe(ResponseEvent.MiniAppWalletAuth);
};
}, []);
}, [nonce]);

const onGenerateMessageClick = useCallback(() => {
if (!MiniKit.isInstalled()) {
return;
}

const nonce = window.crypto.randomUUID();
setNonce(nonce);
const generateMessageResult = MiniKit.commands.walletAuth({
nonce: window.crypto.randomUUID(),
nonce: nonce,
requestId: "0",
expirationTime: new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000),
notBefore: new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000),
notBefore: new Date(new Date().getTime() - 24 * 60 * 60 * 1000),
});

if (!generateMessageResult) {
Expand Down
14 changes: 10 additions & 4 deletions src/helpers/siwe/siwe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,21 @@ export const verifySiweMessage = async (
}

if (nonce && siweMessageData.nonce !== nonce) {
throw new Error("Nonce mismatch");
throw new Error(
`Nonce mismatch. Got: ${siweMessageData.nonce}, Expected: ${nonce}`
);
}

if (statement && siweMessageData.statement !== statement) {
throw new Error("Statement mismatch");
throw new Error(
`Statement mismatch. Got: ${siweMessageData.statement}, Expected: ${statement}`
);
}

if (requestId && siweMessageData.request_id !== requestId) {
throw new Error("Request ID mismatch");
throw new Error(
`Request ID mismatch. Got: ${siweMessageData.request_id}, Expected: ${requestId}`
);
}

// Check ERC-191 Signature Matches
Expand All @@ -187,7 +193,7 @@ export const verifySiweMessage = async (
await contract.checkSignatures(
hashedMessage,
`0x${messageBytes}`,
signature
`0x${signature}`
);
} catch (error) {
throw new Error("Signature verification failed");
Expand Down
2 changes: 1 addition & 1 deletion src/types/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type VerifyCommandInput = {
export type PayCommandInput = {
reference: string;
to: string;
token_amount: number; // In Decimals
token_amount: string; // Stringified Decimals
token: Tokens;
network?: Network; // Optional
description: string;
Expand Down
5 changes: 1 addition & 4 deletions src/types/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ export const VerificationErrorMessage: Record<AppErrorCodes, string> = {
};

export enum PaymentErrorCodes {
MalformedRequest = "malformed_request",
InputError = "input_error",
PaymentRejected = "payment_rejected",
InvalidReceiver = "invalid_receiver",
InsufficientBalance = "insufficient_balance",
TransactionFailed = "transaction_failed",
InvalidTokenAddress = "invalid_token_address",
InvalidAppId = "invalid_app_id",
GenericError = "generic_error",
DuplicateReference = "duplicate_reference",
}

export enum PaymentErrorMessage {
Expand Down
4 changes: 2 additions & 2 deletions src/types/payment.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export enum Tokens {
USDC = "USDC",
USDCE = "USDC.e",
WLD = "WLD",
}

export const TokenDecimals: { [key in Tokens]: number } = {
[Tokens.USDC]: 6,
[Tokens.USDCE]: 6,
[Tokens.WLD]: 18,
};

Expand Down
18 changes: 17 additions & 1 deletion tests/siwe.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parseSiweMessage } from "@worldcoin/minikit-js";
import { parseSiweMessage, verifySiweMessage } from "@worldcoin/minikit-js";

const siweMessage = `https://test.com wants you to sign in with your Ethereum account:\n\
{{address}}\n\n\
Expand Down Expand Up @@ -31,6 +31,11 @@ Issued At: ${new Date().toISOString()}\n\
Expiration Time: 2024-05-03T00:00:00Z\n\
Request ID: 0`;

const signatureSiweMessage =
"http://localhost:3000 wants you to sign in with your Ethereum account:\n0xd809de3086ea4f53ed3979cead25e1ff72b564a3\n\n\nURI: http://localhost:3000/\nVersion: 1\nChain ID: 10\nNonce: 814434bd-ed2c-412e-aa2c-c4b266a42027\nIssued At: 2024-05-22T17:49:52.075Z\nExpiration Time: 2024-05-29T17:49:52.074Z\nNot Before: 2024-05-21T17:49:52.074Z\nRequest ID: 0\n";
const signature =
"f75530590312f5b36b6ef0003800003ba0af04640c72838580f76a3883d2365f397670d785475c39514629345cec307bcbe8c81fb85430da0dc3ef43c9a946d91b";

describe("Test SIWE Message Parsing", () => {
test("Correctly parses full SIWE message", () => {
parseSiweMessage(siweMessage);
Expand All @@ -46,4 +51,15 @@ describe("Test SIWE Message Parsing", () => {
"Missing 'Nonce: '"
);
});

test("Verify SIWE Message", () => {
const payload = {
status: "success",
message: signatureSiweMessage,
signature: signature,
address: "0xd809de3086ea4f53ed3979cead25e1ff72b564a3",
};

verifySiweMessage(payload, "814434bd-ed2c-412e-aa2c-c4b266a42027");
});
});
Loading