diff --git a/.changeset/itchy-baboons-camp.md b/.changeset/itchy-baboons-camp.md new file mode 100644 index 0000000000..6d2471c077 --- /dev/null +++ b/.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. diff --git a/e2e/packages/sync-test/registerDelegationWithSignature.test.ts b/e2e/packages/sync-test/registerDelegationWithSignature.test.ts index 2ee24aab38..b12a46791b 100644 --- a/e2e/packages/sync-test/registerDelegationWithSignature.test.ts +++ b/e2e/packages/sync-test/registerDelegationWithSignature.test.ts @@ -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"; @@ -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", diff --git a/packages/world-modules/mud.config.ts b/packages/world-modules/mud.config.ts index e4a75fd37c..c9813db299 100644 --- a/packages/world-modules/mud.config.ts +++ b/packages/world-modules/mud.config.ts @@ -282,7 +282,7 @@ export default defineWorld({ schema: { signer: "address", nonce: "uint256" }, key: ["signer"], codegen: { - outputDirectory: "modules/delegation/tables", + outputDirectory: "modules/callwithsignature/tables", }, }, }, diff --git a/packages/world-modules/src/index.sol b/packages/world-modules/src/index.sol index 1d323d8fe4..5fa265ec1f 100644 --- a/packages/world-modules/src/index.sol +++ b/packages/world-modules/src/index.sol @@ -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"; diff --git a/packages/world-modules/src/modules/delegation/ECDSA.sol b/packages/world-modules/src/modules/callwithsignature/ECDSA.sol similarity index 100% rename from packages/world-modules/src/modules/delegation/ECDSA.sol rename to packages/world-modules/src/modules/callwithsignature/ECDSA.sol diff --git a/packages/world-modules/src/modules/delegation/IUnstable_CallWithSignatureErrors.sol b/packages/world-modules/src/modules/callwithsignature/IUnstable_CallWithSignatureErrors.sol similarity index 100% rename from packages/world-modules/src/modules/delegation/IUnstable_CallWithSignatureErrors.sol rename to packages/world-modules/src/modules/callwithsignature/IUnstable_CallWithSignatureErrors.sol diff --git a/packages/world-modules/src/modules/delegation/Unstable_CallWithSignatureModule.sol b/packages/world-modules/src/modules/callwithsignature/Unstable_CallWithSignatureModule.sol similarity index 100% rename from packages/world-modules/src/modules/delegation/Unstable_CallWithSignatureModule.sol rename to packages/world-modules/src/modules/callwithsignature/Unstable_CallWithSignatureModule.sol diff --git a/packages/world-modules/src/modules/delegation/Unstable_CallWithSignatureSystem.sol b/packages/world-modules/src/modules/callwithsignature/Unstable_CallWithSignatureSystem.sol similarity index 100% rename from packages/world-modules/src/modules/delegation/Unstable_CallWithSignatureSystem.sol rename to packages/world-modules/src/modules/callwithsignature/Unstable_CallWithSignatureSystem.sol diff --git a/packages/world-modules/src/modules/delegation/constants.sol b/packages/world-modules/src/modules/callwithsignature/constants.sol similarity index 100% rename from packages/world-modules/src/modules/delegation/constants.sol rename to packages/world-modules/src/modules/callwithsignature/constants.sol diff --git a/packages/world-modules/src/modules/delegation/getSignedMessageHash.sol b/packages/world-modules/src/modules/callwithsignature/getSignedMessageHash.sol similarity index 69% rename from packages/world-modules/src/modules/delegation/getSignedMessageHash.sol rename to packages/world-modules/src/modules/callwithsignature/getSignedMessageHash.sol index 617b304484..46a42fe5f9 100644 --- a/packages/world-modules/src/modules/delegation/getSignedMessageHash.sol +++ b/packages/world-modules/src/modules/callwithsignature/getSignedMessageHash.sol @@ -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)"); /** @@ -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( diff --git a/packages/world-modules/src/modules/delegation/tables/CallWithSignatureNonces.sol b/packages/world-modules/src/modules/callwithsignature/tables/CallWithSignatureNonces.sol similarity index 100% rename from packages/world-modules/src/modules/delegation/tables/CallWithSignatureNonces.sol rename to packages/world-modules/src/modules/callwithsignature/tables/CallWithSignatureNonces.sol diff --git a/packages/world-modules/src/modules/delegation/validateCallWithSignature.sol b/packages/world-modules/src/modules/callwithsignature/validateCallWithSignature.sol similarity index 100% rename from packages/world-modules/src/modules/delegation/validateCallWithSignature.sol rename to packages/world-modules/src/modules/callwithsignature/validateCallWithSignature.sol diff --git a/packages/world-modules/test/CallWithSignatureModule.t.sol b/packages/world-modules/test/CallWithSignatureModule.t.sol index 70c7bfb6a6..1d2b74a36f 100644 --- a/packages/world-modules/test/CallWithSignatureModule.t.sol +++ b/packages/world-modules/test/CallWithSignatureModule.t.sol @@ -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; @@ -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(