Skip to content

Commit

Permalink
feat(world-modules): callWithSignature chain id is salt (#2648)
Browse files Browse the repository at this point in the history
Co-authored-by: Kevin Ingersoll <kingersoll@gmail.com>
  • Loading branch information
yonadaaa and holic committed Apr 12, 2024
1 parent 66c64ee commit 96e82b7
Show file tree
Hide file tree
Showing 13 changed files with 20 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/itchy-baboons-camp.md
@@ -0,0 +1,5 @@
---
"@latticexyz/world-modules": patch
---

Moved the chain ID in `CallWithSignature` from the `domain.chainId` to the `domain.salt` field to allow for cross-chain signing without requiring wallets to switch networks. The value of this field should be the chain on which the world lives, rather than the chain the wallet is connected to.
Expand Up @@ -6,7 +6,7 @@ import { deployContracts, startViteServer, startBrowserAndPage, openClientWithRo
import { rpcHttpUrl } from "./setup/constants";
import { waitForInitialSync } from "./data/waitForInitialSync";
import { createBurnerAccount, resourceToHex, transportObserver } from "@latticexyz/common";
import { http, createWalletClient, ClientConfig, encodeFunctionData } from "viem";
import { http, createWalletClient, ClientConfig, encodeFunctionData, toHex } from "viem";
import { mudFoundry } from "@latticexyz/common/chains";
import { encodeEntity } from "@latticexyz/store-sync/recs";
import { callPageFunction } from "./data/callPageFunction";
Expand Down Expand Up @@ -79,8 +79,8 @@ describe("callWithSignature", async () => {
// Sign registration call message
const signature = await delegatorWalletClient.signTypedData({
domain: {
chainId: delegatorWalletClient.chain.id,
verifyingContract: worldContract.address,
salt: toHex(delegatorWalletClient.chain.id, { size: 32 }),
},
types: callWithSignatureTypes,
primaryType: "Call",
Expand Down
2 changes: 1 addition & 1 deletion packages/world-modules/mud.config.ts
Expand Up @@ -282,7 +282,7 @@ export default defineWorld({
schema: { signer: "address", nonce: "uint256" },
key: ["signer"],
codegen: {
outputDirectory: "modules/delegation/tables",
outputDirectory: "modules/callwithsignature/tables",
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/world-modules/src/index.sol
Expand Up @@ -22,4 +22,4 @@ import { Owners } from "./modules/erc721-puppet/tables/Owners.sol";
import { TokenApproval } from "./modules/erc721-puppet/tables/TokenApproval.sol";
import { OperatorApproval } from "./modules/erc721-puppet/tables/OperatorApproval.sol";
import { ERC721Registry } from "./modules/erc721-puppet/tables/ERC721Registry.sol";
import { CallWithSignatureNonces } from "./modules/delegation/tables/CallWithSignatureNonces.sol";
import { CallWithSignatureNonces } from "./modules/callwithsignature/tables/CallWithSignatureNonces.sol";
Expand Up @@ -3,6 +3,10 @@ pragma solidity >=0.8.24;

import { ResourceId } from "@latticexyz/store/src/ResourceId.sol";

// Note the intended value of the `salt` field is the chain ID.
// It is not included in `chainId`, to allow cross-chain signing without requiring wallets to switch networks.
// The value of this field should be the chain on which the world lives, rather than the chain the wallet is connected to.
bytes32 constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(address verifyingContract,bytes32 salt)");
bytes32 constant CALL_TYPEHASH = keccak256("Call(address signer,bytes32 systemId,bytes callData,uint256 nonce)");

/**
Expand All @@ -23,9 +27,7 @@ function getSignedMessageHash(
uint256 nonce,
address worldAddress
) view returns (bytes32) {
bytes32 domainSeperator = keccak256(
abi.encode(keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"), block.chainid, worldAddress)
);
bytes32 domainSeperator = keccak256(abi.encode(DOMAIN_TYPEHASH, worldAddress, bytes32(block.chainid)));

return
keccak256(
Expand Down
12 changes: 6 additions & 6 deletions packages/world-modules/test/CallWithSignatureModule.t.sol
Expand Up @@ -19,11 +19,11 @@ import { REGISTRATION_SYSTEM_ID } from "@latticexyz/world/src/modules/init/const
import { createWorld } from "@latticexyz/world/test/createWorld.sol";
import { WorldTestSystem } from "@latticexyz/world/test/World.t.sol";

import { Unstable_CallWithSignatureModule } from "../src/modules/delegation/Unstable_CallWithSignatureModule.sol";
import { Unstable_CallWithSignatureSystem } from "../src/modules/delegation/Unstable_CallWithSignatureSystem.sol";
import { IUnstable_CallWithSignatureErrors } from "../src/modules/delegation/IUnstable_CallWithSignatureErrors.sol";
import { getSignedMessageHash } from "../src/modules/delegation/getSignedMessageHash.sol";
import { ECDSA } from "../src/modules/delegation/ECDSA.sol";
import { Unstable_CallWithSignatureModule } from "../src/modules/callwithsignature/Unstable_CallWithSignatureModule.sol";
import { Unstable_CallWithSignatureSystem } from "../src/modules/callwithsignature/Unstable_CallWithSignatureSystem.sol";
import { IUnstable_CallWithSignatureErrors } from "../src/modules/callwithsignature/IUnstable_CallWithSignatureErrors.sol";
import { getSignedMessageHash } from "../src/modules/callwithsignature/getSignedMessageHash.sol";
import { ECDSA } from "../src/modules/callwithsignature/ECDSA.sol";

contract Unstable_CallWithSignatureModuleTest is Test, GasReporter {
using WorldResourceIdInstance for ResourceId;
Expand Down Expand Up @@ -104,7 +104,7 @@ contract Unstable_CallWithSignatureModuleTest is Test, GasReporter {
vm.expectRevert(
abi.encodeWithSelector(
IUnstable_CallWithSignatureErrors.InvalidSignature.selector,
0x824E5E0aF3eA693b906527Dc41E4a29F037d515b
0x5266996Bb73ce3ac0E75D79Db87f4a96063cEe1F
)
);
Unstable_CallWithSignatureSystem(address(world)).callWithSignature(
Expand Down

0 comments on commit 96e82b7

Please sign in to comment.