Skip to content

Commit 4543877

Browse files
authored
feat(entrykit): validate signature (#3632)
1 parent af2865b commit 4543877

File tree

4 files changed

+78
-4
lines changed

4 files changed

+78
-4
lines changed

.changeset/wet-monkeys-destroy.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@latticexyz/entrykit": patch
3+
---
4+
5+
Exported an internal method to validate signatures for login flows that use session signer on behalf of user accounts.

packages/entrykit/src/exports/internal.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ export { createWagmiConfig, type CreateWagmiConfigOptions } from "../createWagmi
1515
// And some additional internal things
1616
export * from "../getConnectors";
1717
export * from "../getWallets";
18+
export * from "../validateSigner";
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
1-
import { Address, Chain, Client, Transport } from "viem";
1+
import { Address, Client } from "viem";
22
import { getRecord } from "@latticexyz/store/internal";
33
import { unlimitedDelegationControlId, worldTables } from "../common";
44

55
export type GetDelegationParams = {
6-
client: Client<Transport, Chain>;
6+
client: Client;
77
worldAddress: Address;
88
userAddress: Address;
99
sessionAddress: Address;
10+
blockTag?: "pending" | "latest";
1011
};
1112

12-
export async function getDelegation({ client, worldAddress, userAddress, sessionAddress }: GetDelegationParams) {
13+
// TODO: rename to `hasDelegation`?
14+
export async function getDelegation({
15+
client,
16+
worldAddress,
17+
userAddress,
18+
sessionAddress,
19+
// TODO: move everything to latest instead of pending
20+
blockTag = "pending",
21+
}: GetDelegationParams) {
1322
const record = await getRecord(client, {
1423
address: worldAddress,
1524
table: worldTables.UserDelegationControl,
1625
key: { delegator: userAddress, delegatee: sessionAddress },
17-
blockTag: "pending",
26+
blockTag,
1827
});
1928
return record.delegationControlId === unlimitedDelegationControlId;
2029
}
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Address, Client } from "viem";
2+
import { readContract } from "viem/actions";
3+
import { getDelegation } from "./onboarding/getDelegation";
4+
5+
/**
6+
* @internal
7+
*/
8+
export async function internal_validateSigner({
9+
client,
10+
worldAddress,
11+
userAddress,
12+
sessionAddress,
13+
signerAddress,
14+
}: {
15+
client: Client;
16+
worldAddress: Address;
17+
userAddress: Address;
18+
sessionAddress: Address;
19+
signerAddress: Address;
20+
}) {
21+
const ownerAddress = await readContract(client, {
22+
address: sessionAddress,
23+
abi: simpleAccountAbi,
24+
functionName: "owner",
25+
});
26+
27+
if (ownerAddress.toLowerCase() !== signerAddress.toLowerCase()) {
28+
throw new Error(`Session account owner (${ownerAddress}) does not match message signer (${signerAddress}).`);
29+
}
30+
31+
const hasDelegation = await getDelegation({
32+
client,
33+
worldAddress,
34+
sessionAddress,
35+
userAddress,
36+
blockTag: "latest",
37+
});
38+
39+
if (!hasDelegation) {
40+
throw new Error(`Session account (${sessionAddress}) does not have delegation for user account (${userAddress}).`);
41+
}
42+
}
43+
44+
// TODO: import ABI once we can get strongly typed JSON or expose `getOwner` or similar method on smart account
45+
const simpleAccountAbi = [
46+
{
47+
inputs: [],
48+
name: "owner",
49+
outputs: [
50+
{
51+
internalType: "address",
52+
name: "",
53+
type: "address",
54+
},
55+
],
56+
stateMutability: "view",
57+
type: "function",
58+
},
59+
] as const;

0 commit comments

Comments
 (0)