From 51914d656d8cd8d851ccc8296d249cf09f53e670 Mon Sep 17 00:00:00 2001 From: alvarius Date: Tue, 12 Sep 2023 22:14:48 +0100 Subject: [PATCH] feat(world): change requireOwnerOrSelf to requireOwner (#1457) --- .changeset/mighty-eels-type.md | 16 +++ .../abi/CoreModule.sol/CoreModule.abi.json | 23 ++++ .../CoreModule.sol/CoreModule.abi.json.d.ts | 23 ++++ .../world/abi/IModule.sol/IModule.abi.json | 23 ++++ .../abi/IModule.sol/IModule.abi.json.d.ts | 23 ++++ .../KeysInTableModule.abi.json | 25 +++- .../KeysInTableModule.abi.json.d.ts | 25 +++- .../KeysWithValueModule.abi.json | 54 ++++----- .../KeysWithValueModule.abi.json.d.ts | 54 ++++----- .../StandardDelegationsModule.abi.json | 108 ++++++++++++++++++ .../StandardDelegationsModule.abi.json.d.ts | 108 ++++++++++++++++++ .../UniqueEntityModule.abi.json | 23 ++++ .../UniqueEntityModule.abi.json.d.ts | 23 ++++ packages/world/gas-report.json | 30 ++--- packages/world/src/AccessControl.sol | 7 +- packages/world/src/World.sol | 4 +- packages/world/src/interfaces/IModule.sol | 13 ++- .../world/src/modules/core/CoreModule.sol | 24 ++-- .../AccessManagementSystem.sol | 6 +- .../StoreRegistrationSystem.sol | 6 +- .../WorldRegistrationSystem.sol | 10 +- .../modules/keysintable/KeysInTableModule.sol | 84 +++++++++++--- .../keyswithvalue/KeysWithValueModule.sol | 47 +++++--- .../StandardDelegationsModule.sol | 22 +++- .../uniqueentity/UniqueEntityModule.sol | 6 +- packages/world/test/KeysInTableModule.t.sol | 48 ++++---- packages/world/test/World.t.sol | 12 +- 27 files changed, 660 insertions(+), 187 deletions(-) create mode 100644 .changeset/mighty-eels-type.md diff --git a/.changeset/mighty-eels-type.md b/.changeset/mighty-eels-type.md new file mode 100644 index 0000000000..dd807d4bae --- /dev/null +++ b/.changeset/mighty-eels-type.md @@ -0,0 +1,16 @@ +--- +"@latticexyz/world": major +--- + +- The access control library no longer allows calls by the `World` contract to itself to bypass the ownership check. + This is a breaking change for root modules that relied on this mechanism to register root tables, systems or function selectors. + To upgrade, root modules must use `delegatecall` instead of a regular `call` to install root tables, systems or function selectors. + + ```diff + - world.registerSystem(rootSystemId, rootSystemAddress); + + address(world).delegatecall(abi.encodeCall(world.registerSystem, (rootSystemId, rootSystemAddress))); + ``` + +- An `installRoot` method was added to the `IModule` interface. + This method is now called when installing a root module via `world.installRootModule`. + When installing non-root modules via `world.installModule`, the module's `install` function continues to be called. diff --git a/packages/world/abi/CoreModule.sol/CoreModule.abi.json b/packages/world/abi/CoreModule.sol/CoreModule.abi.json index 43437a8fc5..472cd505dc 100644 --- a/packages/world/abi/CoreModule.sol/CoreModule.abi.json +++ b/packages/world/abi/CoreModule.sol/CoreModule.abi.json @@ -1,4 +1,9 @@ [ + { + "inputs": [], + "name": "NonRootInstallNotSupported", + "type": "error" + }, { "inputs": [ { @@ -21,6 +26,11 @@ "name": "RequiredModuleNotFound", "type": "error" }, + { + "inputs": [], + "name": "RootInstallModeNotSupported", + "type": "error" + }, { "inputs": [ { @@ -145,6 +155,19 @@ ], "name": "install", "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "installRoot", + "outputs": [], "stateMutability": "nonpayable", "type": "function" } diff --git a/packages/world/abi/CoreModule.sol/CoreModule.abi.json.d.ts b/packages/world/abi/CoreModule.sol/CoreModule.abi.json.d.ts index 60ff77131c..1f2c1eb490 100644 --- a/packages/world/abi/CoreModule.sol/CoreModule.abi.json.d.ts +++ b/packages/world/abi/CoreModule.sol/CoreModule.abi.json.d.ts @@ -1,4 +1,9 @@ declare const abi: [ + { + inputs: []; + name: "NonRootInstallNotSupported"; + type: "error"; + }, { inputs: [ { @@ -21,6 +26,11 @@ declare const abi: [ name: "RequiredModuleNotFound"; type: "error"; }, + { + inputs: []; + name: "RootInstallModeNotSupported"; + type: "error"; + }, { inputs: [ { @@ -145,6 +155,19 @@ declare const abi: [ ]; name: "install"; outputs: []; + stateMutability: "pure"; + type: "function"; + }, + { + inputs: [ + { + internalType: "bytes"; + name: ""; + type: "bytes"; + } + ]; + name: "installRoot"; + outputs: []; stateMutability: "nonpayable"; type: "function"; } diff --git a/packages/world/abi/IModule.sol/IModule.abi.json b/packages/world/abi/IModule.sol/IModule.abi.json index 0296b60f47..e4683fbb5e 100644 --- a/packages/world/abi/IModule.sol/IModule.abi.json +++ b/packages/world/abi/IModule.sol/IModule.abi.json @@ -1,4 +1,9 @@ [ + { + "inputs": [], + "name": "NonRootInstallNotSupported", + "type": "error" + }, { "inputs": [ { @@ -10,6 +15,11 @@ "name": "RequiredModuleNotFound", "type": "error" }, + { + "inputs": [], + "name": "RootInstallModeNotSupported", + "type": "error" + }, { "inputs": [], "name": "getName", @@ -35,5 +45,18 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "name": "installRoot", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } ] \ No newline at end of file diff --git a/packages/world/abi/IModule.sol/IModule.abi.json.d.ts b/packages/world/abi/IModule.sol/IModule.abi.json.d.ts index d9577d5f19..522a06fb65 100644 --- a/packages/world/abi/IModule.sol/IModule.abi.json.d.ts +++ b/packages/world/abi/IModule.sol/IModule.abi.json.d.ts @@ -1,4 +1,9 @@ declare const abi: [ + { + inputs: []; + name: "NonRootInstallNotSupported"; + type: "error"; + }, { inputs: [ { @@ -10,6 +15,11 @@ declare const abi: [ name: "RequiredModuleNotFound"; type: "error"; }, + { + inputs: []; + name: "RootInstallModeNotSupported"; + type: "error"; + }, { inputs: []; name: "getName"; @@ -35,6 +45,19 @@ declare const abi: [ outputs: []; stateMutability: "nonpayable"; type: "function"; + }, + { + inputs: [ + { + internalType: "bytes"; + name: "args"; + type: "bytes"; + } + ]; + name: "installRoot"; + outputs: []; + stateMutability: "nonpayable"; + type: "function"; } ]; export default abi; diff --git a/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json b/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json index 64373ae108..54e901cb10 100644 --- a/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json +++ b/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json @@ -1,4 +1,9 @@ [ + { + "inputs": [], + "name": "NonRootInstallNotSupported", + "type": "error" + }, { "inputs": [ { @@ -10,6 +15,11 @@ "name": "RequiredModuleNotFound", "type": "error" }, + { + "inputs": [], + "name": "RootInstallModeNotSupported", + "type": "error" + }, { "inputs": [ { @@ -43,12 +53,25 @@ "inputs": [ { "internalType": "bytes", - "name": "args", + "name": "", "type": "bytes" } ], "name": "install", "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "name": "installRoot", + "outputs": [], "stateMutability": "nonpayable", "type": "function" } diff --git a/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json.d.ts b/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json.d.ts index 7ceee8b586..96427e2f6b 100644 --- a/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json.d.ts +++ b/packages/world/abi/KeysInTableModule.sol/KeysInTableModule.abi.json.d.ts @@ -1,4 +1,9 @@ declare const abi: [ + { + inputs: []; + name: "NonRootInstallNotSupported"; + type: "error"; + }, { inputs: [ { @@ -10,6 +15,11 @@ declare const abi: [ name: "RequiredModuleNotFound"; type: "error"; }, + { + inputs: []; + name: "RootInstallModeNotSupported"; + type: "error"; + }, { inputs: [ { @@ -43,12 +53,25 @@ declare const abi: [ inputs: [ { internalType: "bytes"; - name: "args"; + name: ""; type: "bytes"; } ]; name: "install"; outputs: []; + stateMutability: "pure"; + type: "function"; + }, + { + inputs: [ + { + internalType: "bytes"; + name: "args"; + type: "bytes"; + } + ]; + name: "installRoot"; + outputs: []; stateMutability: "nonpayable"; type: "function"; } diff --git a/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json b/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json index aeaee69069..54e901cb10 100644 --- a/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json +++ b/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json @@ -1,13 +1,7 @@ [ { - "inputs": [ - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "PackedCounter_InvalidLength", + "inputs": [], + "name": "NonRootInstallNotSupported", "type": "error" }, { @@ -21,46 +15,25 @@ "name": "RequiredModuleNotFound", "type": "error" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "SchemaLib_InvalidLength", - "type": "error" - }, { "inputs": [], - "name": "SchemaLib_StaticTypeAfterDynamicType", + "name": "RootInstallModeNotSupported", "type": "error" }, { "inputs": [ - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "start", - "type": "uint256" - }, { "internalType": "uint256", - "name": "end", + "name": "length", "type": "uint256" } ], - "name": "Slice_OutOfBounds", + "name": "SchemaLib_InvalidLength", "type": "error" }, { "inputs": [], - "name": "StoreCore_NotDynamicField", + "name": "SchemaLib_StaticTypeAfterDynamicType", "type": "error" }, { @@ -80,12 +53,25 @@ "inputs": [ { "internalType": "bytes", - "name": "args", + "name": "", "type": "bytes" } ], "name": "install", "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "name": "installRoot", + "outputs": [], "stateMutability": "nonpayable", "type": "function" } diff --git a/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json.d.ts b/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json.d.ts index 4b124c1e24..96427e2f6b 100644 --- a/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json.d.ts +++ b/packages/world/abi/KeysWithValueModule.sol/KeysWithValueModule.abi.json.d.ts @@ -1,13 +1,7 @@ declare const abi: [ { - inputs: [ - { - internalType: "uint256"; - name: "length"; - type: "uint256"; - } - ]; - name: "PackedCounter_InvalidLength"; + inputs: []; + name: "NonRootInstallNotSupported"; type: "error"; }, { @@ -21,46 +15,25 @@ declare const abi: [ name: "RequiredModuleNotFound"; type: "error"; }, - { - inputs: [ - { - internalType: "uint256"; - name: "length"; - type: "uint256"; - } - ]; - name: "SchemaLib_InvalidLength"; - type: "error"; - }, { inputs: []; - name: "SchemaLib_StaticTypeAfterDynamicType"; + name: "RootInstallModeNotSupported"; type: "error"; }, { inputs: [ - { - internalType: "bytes"; - name: "data"; - type: "bytes"; - }, - { - internalType: "uint256"; - name: "start"; - type: "uint256"; - }, { internalType: "uint256"; - name: "end"; + name: "length"; type: "uint256"; } ]; - name: "Slice_OutOfBounds"; + name: "SchemaLib_InvalidLength"; type: "error"; }, { inputs: []; - name: "StoreCore_NotDynamicField"; + name: "SchemaLib_StaticTypeAfterDynamicType"; type: "error"; }, { @@ -80,12 +53,25 @@ declare const abi: [ inputs: [ { internalType: "bytes"; - name: "args"; + name: ""; type: "bytes"; } ]; name: "install"; outputs: []; + stateMutability: "pure"; + type: "function"; + }, + { + inputs: [ + { + internalType: "bytes"; + name: "args"; + type: "bytes"; + } + ]; + name: "installRoot"; + outputs: []; stateMutability: "nonpayable"; type: "function"; } diff --git a/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json b/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json index 646de1964b..1235206c8a 100644 --- a/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json +++ b/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json @@ -1,4 +1,9 @@ [ + { + "inputs": [], + "name": "NonRootInstallNotSupported", + "type": "error" + }, { "inputs": [ { @@ -10,6 +15,11 @@ "name": "RequiredModuleNotFound", "type": "error" }, + { + "inputs": [], + "name": "RootInstallModeNotSupported", + "type": "error" + }, { "inputs": [ { @@ -26,6 +36,91 @@ "name": "SchemaLib_StaticTypeAfterDynamicType", "type": "error" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "end", + "type": "uint256" + } + ], + "name": "Slice_OutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "StoreCore_InvalidDataLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "StoreCore_InvalidFieldNamesLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "StoreCore_InvalidKeyNamesLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "tableId", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "tableIdString", + "type": "string" + } + ], + "name": "StoreCore_TableAlreadyExists", + "type": "error" + }, { "inputs": [], "name": "getName", @@ -49,6 +144,19 @@ ], "name": "install", "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "installRoot", + "outputs": [], "stateMutability": "nonpayable", "type": "function" } diff --git a/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json.d.ts b/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json.d.ts index 3c113d1eed..1b9972cc81 100644 --- a/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json.d.ts +++ b/packages/world/abi/StandardDelegationsModule.sol/StandardDelegationsModule.abi.json.d.ts @@ -1,4 +1,9 @@ declare const abi: [ + { + inputs: []; + name: "NonRootInstallNotSupported"; + type: "error"; + }, { inputs: [ { @@ -10,6 +15,11 @@ declare const abi: [ name: "RequiredModuleNotFound"; type: "error"; }, + { + inputs: []; + name: "RootInstallModeNotSupported"; + type: "error"; + }, { inputs: [ { @@ -26,6 +36,91 @@ declare const abi: [ name: "SchemaLib_StaticTypeAfterDynamicType"; type: "error"; }, + { + inputs: [ + { + internalType: "bytes"; + name: "data"; + type: "bytes"; + }, + { + internalType: "uint256"; + name: "start"; + type: "uint256"; + }, + { + internalType: "uint256"; + name: "end"; + type: "uint256"; + } + ]; + name: "Slice_OutOfBounds"; + type: "error"; + }, + { + inputs: [ + { + internalType: "uint256"; + name: "expected"; + type: "uint256"; + }, + { + internalType: "uint256"; + name: "received"; + type: "uint256"; + } + ]; + name: "StoreCore_InvalidDataLength"; + type: "error"; + }, + { + inputs: [ + { + internalType: "uint256"; + name: "expected"; + type: "uint256"; + }, + { + internalType: "uint256"; + name: "received"; + type: "uint256"; + } + ]; + name: "StoreCore_InvalidFieldNamesLength"; + type: "error"; + }, + { + inputs: [ + { + internalType: "uint256"; + name: "expected"; + type: "uint256"; + }, + { + internalType: "uint256"; + name: "received"; + type: "uint256"; + } + ]; + name: "StoreCore_InvalidKeyNamesLength"; + type: "error"; + }, + { + inputs: [ + { + internalType: "bytes32"; + name: "tableId"; + type: "bytes32"; + }, + { + internalType: "string"; + name: "tableIdString"; + type: "string"; + } + ]; + name: "StoreCore_TableAlreadyExists"; + type: "error"; + }, { inputs: []; name: "getName"; @@ -49,6 +144,19 @@ declare const abi: [ ]; name: "install"; outputs: []; + stateMutability: "pure"; + type: "function"; + }, + { + inputs: [ + { + internalType: "bytes"; + name: ""; + type: "bytes"; + } + ]; + name: "installRoot"; + outputs: []; stateMutability: "nonpayable"; type: "function"; } diff --git a/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json b/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json index 646de1964b..90b64315e3 100644 --- a/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json +++ b/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json @@ -1,4 +1,9 @@ [ + { + "inputs": [], + "name": "NonRootInstallNotSupported", + "type": "error" + }, { "inputs": [ { @@ -10,6 +15,11 @@ "name": "RequiredModuleNotFound", "type": "error" }, + { + "inputs": [], + "name": "RootInstallModeNotSupported", + "type": "error" + }, { "inputs": [ { @@ -51,5 +61,18 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "args", + "type": "bytes" + } + ], + "name": "installRoot", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } ] \ No newline at end of file diff --git a/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json.d.ts b/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json.d.ts index 3c113d1eed..7965ef95be 100644 --- a/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json.d.ts +++ b/packages/world/abi/UniqueEntityModule.sol/UniqueEntityModule.abi.json.d.ts @@ -1,4 +1,9 @@ declare const abi: [ + { + inputs: []; + name: "NonRootInstallNotSupported"; + type: "error"; + }, { inputs: [ { @@ -10,6 +15,11 @@ declare const abi: [ name: "RequiredModuleNotFound"; type: "error"; }, + { + inputs: []; + name: "RootInstallModeNotSupported"; + type: "error"; + }, { inputs: [ { @@ -51,6 +61,19 @@ declare const abi: [ outputs: []; stateMutability: "nonpayable"; type: "function"; + }, + { + inputs: [ + { + internalType: "bytes"; + name: "args"; + type: "bytes"; + } + ]; + name: "installRoot"; + outputs: []; + stateMutability: "nonpayable"; + type: "function"; } ]; export default abi; diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 0029f237db..980f15a975 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -39,13 +39,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1413349 + "gasUsed": 1433865 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1413349 + "gasUsed": 1433865 }, { "file": "test/KeysInTableModule.t.sol", @@ -57,13 +57,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1413349 + "gasUsed": 1433865 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1413349 + "gasUsed": 1433865 }, { "file": "test/KeysInTableModule.t.sol", @@ -81,7 +81,7 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1413349 + "gasUsed": 1433865 }, { "file": "test/KeysInTableModule.t.sol", @@ -99,7 +99,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 651540 + "gasUsed": 677067 }, { "file": "test/KeysWithValueModule.t.sol", @@ -117,7 +117,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 651540 + "gasUsed": 677067 }, { "file": "test/KeysWithValueModule.t.sol", @@ -129,7 +129,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 651540 + "gasUsed": 677067 }, { "file": "test/KeysWithValueModule.t.sol", @@ -147,7 +147,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 651540 + "gasUsed": 677067 }, { "file": "test/KeysWithValueModule.t.sol", @@ -255,7 +255,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 727309 + "gasUsed": 727195 }, { "file": "test/UniqueEntityModule.t.sol", @@ -267,7 +267,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 706087 + "gasUsed": 712496 }, { "file": "test/UniqueEntityModule.t.sol", @@ -309,19 +309,19 @@ "file": "test/World.t.sol", "test": "testRegisterFallbackSystem", "name": "Register a fallback system", - "gasUsed": 70620 + "gasUsed": 70563 }, { "file": "test/World.t.sol", "test": "testRegisterFallbackSystem", "name": "Register a root fallback system", - "gasUsed": 63860 + "gasUsed": 63803 }, { "file": "test/World.t.sol", "test": "testRegisterFunctionSelector", "name": "Register a function selector", - "gasUsed": 91214 + "gasUsed": 91157 }, { "file": "test/World.t.sol", @@ -333,7 +333,7 @@ "file": "test/World.t.sol", "test": "testRegisterRootFunctionSelector", "name": "Register a root function selector", - "gasUsed": 79771 + "gasUsed": 85721 }, { "file": "test/World.t.sol", diff --git a/packages/world/src/AccessControl.sol b/packages/world/src/AccessControl.sol index ae42b34b02..ca637f7c3f 100644 --- a/packages/world/src/AccessControl.sol +++ b/packages/world/src/AccessControl.sol @@ -32,12 +32,11 @@ library AccessControl { } /** - * Check for ownership of the namespace of the given resource selector - * or identity of the caller to this contract's own address. + * Check for ownership of the namespace of the given resource selector. * Reverts with AccessDenied if the check fails. */ - function requireOwnerOrSelf(bytes32 resourceSelector, address caller) internal view { - if (address(this) != caller && NamespaceOwner.get(resourceSelector.getNamespace()) != caller) { + function requireOwner(bytes32 resourceSelector, address caller) internal view { + if (NamespaceOwner.get(resourceSelector.getNamespace()) != caller) { revert IWorldErrors.AccessDenied(resourceSelector.toString(), caller); } } diff --git a/packages/world/src/World.sol b/packages/world/src/World.sol index 8f5256ef75..75839ca583 100644 --- a/packages/world/src/World.sol +++ b/packages/world/src/World.sol @@ -49,13 +49,13 @@ contract World is StoreRead, IStoreData, IWorldKernel { * The module is delegatecalled and installed in the root namespace. */ function installRootModule(IModule module, bytes memory args) public { - AccessControl.requireOwnerOrSelf(ROOT_NAMESPACE, msg.sender); + AccessControl.requireOwner(ROOT_NAMESPACE, msg.sender); WorldContextProvider.delegatecallWithContextOrRevert({ msgSender: msg.sender, msgValue: 0, target: address(module), - funcSelectorAndArgs: abi.encodeWithSelector(IModule.install.selector, args) + funcSelectorAndArgs: abi.encodeWithSelector(IModule.installRoot.selector, args) }); // Register the module in the InstalledModules table diff --git a/packages/world/src/interfaces/IModule.sol b/packages/world/src/interfaces/IModule.sol index 5e9dda86ed..990fbcde48 100644 --- a/packages/world/src/interfaces/IModule.sol +++ b/packages/world/src/interfaces/IModule.sol @@ -3,6 +3,8 @@ pragma solidity >=0.8.0; interface IModule { error RequiredModuleNotFound(string resourceSelector); + error RootInstallModeNotSupported(); + error NonRootInstallNotSupported(); /** * Return the module name as a bytes16. @@ -10,7 +12,16 @@ interface IModule { function getName() external view returns (bytes16 name); /** - * A module expects to be called via the World contract, and therefore installs itself on its `msg.sender`. + * This function is called by the World as part of `installRootModule`. + * The module expects to be called via the World contract, and therefore installs itself on the `msg.sender`. + */ + function installRoot(bytes memory args) external; + + /** + * This function is called by the World as part of `installModule`. + * The module expects to be called via the World contract, and therefore installs itself on the `msg.sender`. + * This function is separate from `installRoot` because the logic might be different (eg. accepting namespace parameters, + * or using `callFrom`) */ function install(bytes memory args) external; } diff --git a/packages/world/src/modules/core/CoreModule.sol b/packages/world/src/modules/core/CoreModule.sol index 72842d9c84..2a2e44dc7b 100644 --- a/packages/world/src/modules/core/CoreModule.sol +++ b/packages/world/src/modules/core/CoreModule.sol @@ -37,7 +37,7 @@ import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSyst * The CoreModule registers internal World tables, the CoreSystem, and its function selectors. * Note: - * This module is required to be delegatecalled (via `World.registerRootSystem`), + * This module only supports `installRoot` (via `World.registerRootSystem`), * because it needs to install root tables, systems and function selectors. */ contract CoreModule is IModule, WorldContextConsumer { @@ -49,12 +49,16 @@ contract CoreModule is IModule, WorldContextConsumer { return CORE_MODULE_NAME; } - function install(bytes memory) public override { + function installRoot(bytes memory) public override { _registerCoreTables(); _registerCoreSystem(); _registerFunctionSelectors(); } + function install(bytes memory) public pure { + revert NonRootInstallNotSupported(); + } + /** * Register core tables in the World */ @@ -81,11 +85,9 @@ contract CoreModule is IModule, WorldContextConsumer { msgSender: _msgSender(), msgValue: 0, target: coreSystem, - funcSelectorAndArgs: abi.encodeWithSelector( - WorldRegistrationSystem.registerSystem.selector, - ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME), - coreSystem, - true + funcSelectorAndArgs: abi.encodeCall( + WorldRegistrationSystem.registerSystem, + (ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME), CoreSystem(coreSystem), true) ) }); } @@ -127,11 +129,9 @@ contract CoreModule is IModule, WorldContextConsumer { msgSender: _msgSender(), msgValue: 0, target: coreSystem, - funcSelectorAndArgs: abi.encodeWithSelector( - WorldRegistrationSystem.registerRootFunctionSelector.selector, - ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME), - functionSelectors[i], - functionSelectors[i] + funcSelectorAndArgs: abi.encodeCall( + WorldRegistrationSystem.registerRootFunctionSelector, + (ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME), functionSelectors[i], functionSelectors[i]) ) }); } diff --git a/packages/world/src/modules/core/implementations/AccessManagementSystem.sol b/packages/world/src/modules/core/implementations/AccessManagementSystem.sol index d85a759f84..c29d693ac0 100644 --- a/packages/world/src/modules/core/implementations/AccessManagementSystem.sol +++ b/packages/world/src/modules/core/implementations/AccessManagementSystem.sol @@ -19,7 +19,7 @@ contract AccessManagementSystem is System { */ function grantAccess(bytes32 resourceSelector, address grantee) public virtual { // Require the caller to own the namespace - AccessControl.requireOwnerOrSelf(resourceSelector, _msgSender()); + AccessControl.requireOwner(resourceSelector, _msgSender()); // Grant access to the given resource ResourceAccess.set(resourceSelector, grantee, true); @@ -31,7 +31,7 @@ contract AccessManagementSystem is System { */ function revokeAccess(bytes32 resourceSelector, address grantee) public virtual { // Require the caller to own the namespace - AccessControl.requireOwnerOrSelf(resourceSelector, _msgSender()); + AccessControl.requireOwner(resourceSelector, _msgSender()); // Revoke access from the given resource ResourceAccess.deleteRecord(resourceSelector, grantee); @@ -44,7 +44,7 @@ contract AccessManagementSystem is System { */ function transferOwnership(bytes16 namespace, address newOwner) public virtual { // Require the caller to own the namespace - AccessControl.requireOwnerOrSelf(namespace, _msgSender()); + AccessControl.requireOwner(namespace, _msgSender()); // Set namespace new owner NamespaceOwner.set(namespace, newOwner); diff --git a/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol b/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol index 4d9c77bc00..bf6a081237 100644 --- a/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol +++ b/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol @@ -59,7 +59,7 @@ contract StoreRegistrationSystem is System, IWorldErrors { }); } else { // otherwise require caller to own the namespace - AccessControl.requireOwnerOrSelf(namespace, _msgSender()); + AccessControl.requireOwner(namespace, _msgSender()); } // Require no resource to exist at this selector yet @@ -80,7 +80,7 @@ contract StoreRegistrationSystem is System, IWorldErrors { */ function registerStoreHook(bytes32 tableId, IStoreHook hookAddress, uint8 enabledHooksBitmap) public virtual { // Require caller to own the namespace - AccessControl.requireOwnerOrSelf(tableId, _msgSender()); + AccessControl.requireOwner(tableId, _msgSender()); // Register the hook StoreCore.registerStoreHook(tableId, hookAddress, enabledHooksBitmap); @@ -92,7 +92,7 @@ contract StoreRegistrationSystem is System, IWorldErrors { */ function unregisterStoreHook(bytes32 tableId, IStoreHook hookAddress) public virtual { // Require caller to own the namespace - AccessControl.requireOwnerOrSelf(tableId, _msgSender()); + AccessControl.requireOwner(tableId, _msgSender()); // Unregister the hook StoreCore.unregisterStoreHook(tableId, hookAddress); diff --git a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol index e0153c7795..c64337b454 100644 --- a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol +++ b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol @@ -58,7 +58,7 @@ contract WorldRegistrationSystem is System, IWorldErrors { uint8 enabledHooksBitmap ) public virtual { // Require caller to own the namespace - AccessControl.requireOwnerOrSelf(resourceSelector, _msgSender()); + AccessControl.requireOwner(resourceSelector, _msgSender()); // Register the hook SystemHooks.push(resourceSelector, Hook.unwrap(SystemHookLib.encode(hookAddress, enabledHooksBitmap))); @@ -69,7 +69,7 @@ contract WorldRegistrationSystem is System, IWorldErrors { */ function unregisterSystemHook(bytes32 resourceSelector, ISystemHook hookAddress) public virtual { // Require caller to own the namespace - AccessControl.requireOwnerOrSelf(resourceSelector, _msgSender()); + AccessControl.requireOwner(resourceSelector, _msgSender()); // Remove the hook from the list of hooks for this resourceSelector in the system hooks table HookLib.filterListByAddress(SystemHooksTableId, resourceSelector, address(hookAddress)); @@ -98,7 +98,7 @@ contract WorldRegistrationSystem is System, IWorldErrors { // otherwise require caller to own the namespace bytes16 namespace = resourceSelector.getNamespace(); if (ResourceType.get(namespace) == Resource.NONE) registerNamespace(namespace); - else AccessControl.requireOwnerOrSelf(namespace, _msgSender()); + else AccessControl.requireOwner(namespace, _msgSender()); // Require no resource other than a system to exist at this selector yet Resource resourceType = ResourceType.get(resourceSelector); @@ -144,7 +144,7 @@ contract WorldRegistrationSystem is System, IWorldErrors { string memory systemFunctionArguments ) public returns (bytes4 worldFunctionSelector) { // Require the caller to own the namespace - AccessControl.requireOwnerOrSelf(resourceSelector, _msgSender()); + AccessControl.requireOwner(resourceSelector, _msgSender()); // Compute global function selector string memory namespaceString = ResourceSelector.toTrimmedString(resourceSelector.getNamespace()); @@ -179,7 +179,7 @@ contract WorldRegistrationSystem is System, IWorldErrors { bytes4 systemFunctionSelector ) public returns (bytes4) { // Require the caller to own the root namespace - AccessControl.requireOwnerOrSelf(ROOT_NAMESPACE, _msgSender()); + AccessControl.requireOwner(ROOT_NAMESPACE, _msgSender()); // Require the function selector to be globally unique bytes32 existingResourceSelector = FunctionSelectors.getResourceSelector(worldFunctionSelector); diff --git a/packages/world/src/modules/keysintable/KeysInTableModule.sol b/packages/world/src/modules/keysintable/KeysInTableModule.sol index 253d9d0f9f..b01cf1ea49 100644 --- a/packages/world/src/modules/keysintable/KeysInTableModule.sol +++ b/packages/world/src/modules/keysintable/KeysInTableModule.sol @@ -11,6 +11,7 @@ import { IModule } from "../../interfaces/IModule.sol"; import { WorldContextConsumer } from "../../WorldContext.sol"; import { ResourceSelector } from "../../ResourceSelector.sol"; +import { revertWithBytes } from "../../revertWithBytes.sol"; import { KeysInTableHook } from "./KeysInTableHook.sol"; import { KeysInTable, KeysInTableTableId } from "./tables/KeysInTable.sol"; @@ -23,48 +24,93 @@ import { UsedKeysIndex, UsedKeysIndexTableId } from "./tables/UsedKeysIndex.sol" * * Note: if a table with composite keys is used, only the first key is indexed * - * Note: this module currently expects to be `delegatecalled` via World.installRootModule. - * Support for installing it via `World.installModule` depends on `World.callFrom` being implemented. + * Note: this module currently only supports `installRoot` (via `World.installRootModule`). + * TODO: add support for `install` (via `World.installModule`) by using `callFrom` with the `msgSender()` */ contract KeysInTableModule is IModule, WorldContextConsumer { using ResourceSelector for bytes32; // The KeysInTableHook is deployed once and infers the target table id // from the source table id (passed as argument to the hook methods) - KeysInTableHook immutable hook = new KeysInTableHook(); + KeysInTableHook private immutable hook = new KeysInTableHook(); function getName() public pure returns (bytes16) { return bytes16("keysInTable"); } - function install(bytes memory args) public override { + function installRoot(bytes memory args) public override { // Extract source table id from args bytes32 sourceTableId = abi.decode(args, (bytes32)); IBaseWorld world = IBaseWorld(_world()); + // Initialize variable to reuse in low level calls + bool success; + bytes memory returnData; + if (ResourceType.get(KeysInTableTableId) == Resource.NONE) { // Register the tables - KeysInTable.register(world); - UsedKeysIndex.register(world); + (success, returnData) = address(world).delegatecall( + abi.encodeCall( + world.registerTable, + ( + KeysInTableTableId, + KeysInTable.getKeySchema(), + KeysInTable.getValueSchema(), + KeysInTable.getKeyNames(), + KeysInTable.getFieldNames() + ) + ) + ); + if (!success) revertWithBytes(returnData); + + (success, returnData) = address(world).delegatecall( + abi.encodeCall( + world.registerTable, + ( + UsedKeysIndexTableId, + UsedKeysIndex.getKeySchema(), + UsedKeysIndex.getValueSchema(), + UsedKeysIndex.getKeyNames(), + UsedKeysIndex.getFieldNames() + ) + ) + ); + if (!success) revertWithBytes(returnData); // Grant the hook access to the tables - world.grantAccess(KeysInTableTableId, address(hook)); - world.grantAccess(UsedKeysIndexTableId, address(hook)); + (success, returnData) = address(world).delegatecall( + abi.encodeCall(world.grantAccess, (KeysInTableTableId, address(hook))) + ); + if (!success) revertWithBytes(returnData); + + (success, returnData) = address(world).delegatecall( + abi.encodeCall(world.grantAccess, (UsedKeysIndexTableId, address(hook))) + ); + if (!success) revertWithBytes(returnData); } // Register a hook that is called when a value is set in the source table - world.registerStoreHook( - sourceTableId, - hook, - StoreHookLib.encodeBitmap({ - onBeforeSetRecord: true, - onAfterSetRecord: false, - onBeforeSetField: false, - onAfterSetField: true, - onBeforeDeleteRecord: true, - onAfterDeleteRecord: false - }) + (success, returnData) = address(world).delegatecall( + abi.encodeCall( + world.registerStoreHook, + ( + sourceTableId, + hook, + StoreHookLib.encodeBitmap({ + onBeforeSetRecord: true, + onAfterSetRecord: false, + onBeforeSetField: false, + onAfterSetField: true, + onBeforeDeleteRecord: true, + onAfterDeleteRecord: false + }) + ) + ) ); } + + function install(bytes memory) public pure { + revert NonRootInstallNotSupported(); + } } diff --git a/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol b/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol index 1cd17800d2..dad35bd968 100644 --- a/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol +++ b/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol @@ -9,6 +9,7 @@ import { IModule } from "../../interfaces/IModule.sol"; import { WorldContextConsumer } from "../../WorldContext.sol"; import { ResourceSelector } from "../../ResourceSelector.sol"; +import { revertWithBytes } from "../../revertWithBytes.sol"; import { MODULE_NAMESPACE } from "./constants.sol"; import { KeysWithValueHook } from "./KeysWithValueHook.sol"; @@ -23,43 +24,55 @@ import { getTargetTableSelector } from "../utils/getTargetTableSelector.sol"; * * Note: if a table with composite keys is used, only the first key is indexed * - * Note: this module currently expects to be `delegatecalled` via World.installRootModule. - * Support for installing it via `World.installModule` depends on `World.callFrom` being implemented. + * Note: this module currently only supports `installRoot` (via `World.installRootModule`). + * TODO: add support for `install` (via `World.installModule`) by using `callFrom` with the `msgSender()` */ contract KeysWithValueModule is IModule, WorldContextConsumer { using ResourceSelector for bytes32; // The KeysWithValueHook is deployed once and infers the target table id // from the source table id (passed as argument to the hook methods) - KeysWithValueHook immutable hook = new KeysWithValueHook(); + KeysWithValueHook private immutable hook = new KeysWithValueHook(); function getName() public pure returns (bytes16) { return bytes16("index"); } - function install(bytes memory args) public override { + function installRoot(bytes memory args) public { // Extract source table id from args bytes32 sourceTableId = abi.decode(args, (bytes32)); bytes32 targetTableSelector = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + IBaseWorld world = IBaseWorld(_world()); + // Register the target table - KeysWithValue.register(IBaseWorld(_world()), targetTableSelector); + KeysWithValue.register(world, targetTableSelector); // Grant the hook access to the target table - IBaseWorld(_world()).grantAccess(targetTableSelector, address(hook)); + world.grantAccess(targetTableSelector, address(hook)); // Register a hook that is called when a value is set in the source table - StoreSwitch.registerStoreHook( - sourceTableId, - hook, - StoreHookLib.encodeBitmap({ - onBeforeSetRecord: true, - onAfterSetRecord: false, - onBeforeSetField: true, - onAfterSetField: true, - onBeforeDeleteRecord: true, - onAfterDeleteRecord: false - }) + (bool success, bytes memory returnData) = address(world).delegatecall( + abi.encodeCall( + world.registerStoreHook, + ( + sourceTableId, + hook, + StoreHookLib.encodeBitmap({ + onBeforeSetRecord: true, + onAfterSetRecord: false, + onBeforeSetField: true, + onAfterSetField: true, + onBeforeDeleteRecord: true, + onAfterDeleteRecord: false + }) + ) + ) ); + if (!success) revertWithBytes(returnData); + } + + function install(bytes memory) public pure { + revert NonRootInstallNotSupported(); } } diff --git a/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol b/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol index 97d31ef2ec..74057574dc 100644 --- a/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol +++ b/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol @@ -6,6 +6,7 @@ import { IModule } from "../../interfaces/IModule.sol"; import { WorldContextConsumer } from "../../WorldContext.sol"; import { ResourceSelector } from "../../ResourceSelector.sol"; +import { revertWithBytes } from "../../revertWithBytes.sol"; import { CallboundDelegationControl } from "./CallboundDelegationControl.sol"; import { TimeboundDelegationControl } from "./TimeboundDelegationControl.sol"; @@ -25,15 +26,26 @@ contract StandardDelegationsModule is IModule, WorldContextConsumer { return MODULE_NAME; } - function install(bytes memory) public { + function installRoot(bytes memory) public { IBaseWorld world = IBaseWorld(_world()); // Register tables - CallboundDelegations.register(world); - TimeboundDelegations.register(world); + CallboundDelegations.register(); + TimeboundDelegations.register(); // Register systems - world.registerSystem(CALLBOUND_DELEGATION, callboundDelegationControl, true); - world.registerSystem(TIMEBOUND_DELEGATION, timeboundDelegationControl, true); + (bool success, bytes memory returnData) = address(world).delegatecall( + abi.encodeCall(world.registerSystem, (CALLBOUND_DELEGATION, callboundDelegationControl, true)) + ); + if (!success) revertWithBytes(returnData); + + (success, returnData) = address(world).delegatecall( + abi.encodeCall(world.registerSystem, (TIMEBOUND_DELEGATION, timeboundDelegationControl, true)) + ); + if (!success) revertWithBytes(returnData); + } + + function install(bytes memory) public pure { + revert NonRootInstallNotSupported(); } } diff --git a/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol b/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol index cfff61f6bc..18d87c7dfe 100644 --- a/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol +++ b/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol @@ -19,12 +19,16 @@ import { NAMESPACE, MODULE_NAME, SYSTEM_NAME, TABLE_NAME } from "./constants.sol contract UniqueEntityModule is IModule, WorldContextConsumer { // Since the UniqueEntitySystem only exists once per World and writes to // known tables, we can deploy it once and register it in multiple Worlds. - UniqueEntitySystem immutable uniqueEntitySystem = new UniqueEntitySystem(); + UniqueEntitySystem private immutable uniqueEntitySystem = new UniqueEntitySystem(); function getName() public pure returns (bytes16) { return MODULE_NAME; } + function installRoot(bytes memory args) public { + install(args); + } + function install(bytes memory) public { IBaseWorld world = IBaseWorld(_world()); diff --git a/packages/world/test/KeysInTableModule.t.sol b/packages/world/test/KeysInTableModule.t.sol index 1968d14a00..3446b8e238 100644 --- a/packages/world/test/KeysInTableModule.t.sol +++ b/packages/world/test/KeysInTableModule.t.sol @@ -20,30 +20,30 @@ import { hasKey } from "../src/modules/keysintable/hasKey.sol"; contract KeysInTableModuleTest is Test, GasReporter { using ResourceSelector for bytes32; - IBaseWorld world; - KeysInTableModule keysInTableModule = new KeysInTableModule(); // Modules can be deployed once and installed multiple times - - bytes16 namespace = ROOT_NAMESPACE; - bytes16 name = bytes16("source"); - bytes16 singletonName = bytes16("singleton"); - bytes16 compositeName = bytes16("composite"); - bytes32 key1 = keccak256("test"); - bytes32[] keyTuple1; - bytes32 key2 = keccak256("test2"); - bytes32[] keyTuple2; - bytes32 key3 = keccak256("test3"); - bytes32[] keyTuple3; - - Schema tableValueSchema; - Schema tableKeySchema; - Schema singletonKeySchema; - Schema compositeKeySchema; - bytes32 tableId = ResourceSelector.from(namespace, name); - bytes32 singletonTableId = ResourceSelector.from(namespace, singletonName); - bytes32 compositeTableId = ResourceSelector.from(namespace, compositeName); - - uint256 val1 = 123; - uint256 val2 = 42; + IBaseWorld private world; + KeysInTableModule private keysInTableModule = new KeysInTableModule(); // Modules can be deployed once and installed multiple times + + bytes16 private namespace = ROOT_NAMESPACE; + bytes16 private name = bytes16("source"); + bytes16 private singletonName = bytes16("singleton"); + bytes16 private compositeName = bytes16("composite"); + bytes32 private key1 = keccak256("test"); + bytes32[] private keyTuple1; + bytes32 private key2 = keccak256("test2"); + bytes32[] private keyTuple2; + bytes32 private key3 = keccak256("test3"); + bytes32[] private keyTuple3; + + Schema private tableValueSchema; + Schema private tableKeySchema; + Schema private singletonKeySchema; + Schema private compositeKeySchema; + bytes32 private tableId = ResourceSelector.from(namespace, name); + bytes32 private singletonTableId = ResourceSelector.from(namespace, singletonName); + bytes32 private compositeTableId = ResourceSelector.from(namespace, compositeName); + + uint256 private val1 = 123; + uint256 private val2 = 42; function setUp() public { tableValueSchema = SchemaEncodeHelper.encode(SchemaType.UINT256); diff --git a/packages/world/test/World.t.sol b/packages/world/test/World.t.sol index 1be65a4342..bfe8ee79c5 100644 --- a/packages/world/test/World.t.sol +++ b/packages/world/test/World.t.sol @@ -304,8 +304,8 @@ contract WorldTest is Test, GasReporter { _expectAccessDenied(address(0x01), namespace, ""); world.registerTable(otherTableSelector, defaultKeySchema, valueSchema, keyNames, fieldNames); - // Expect the World to be allowed to call registerTable - vm.prank(address(world)); + // Expect the World to not be allowed to call registerTable via an external call + _expectAccessDenied(address(world), namespace, ""); world.registerTable(otherTableSelector, defaultKeySchema, valueSchema, keyNames, fieldNames); } @@ -362,8 +362,8 @@ contract WorldTest is Test, GasReporter { _expectAccessDenied(address(0x01), "", ""); world.registerSystem(ResourceSelector.from("", "rootSystem"), yetAnotherSystem, true); - // Expect the registration to succeed when coming from the World - vm.prank(address(world)); + // Expect the registration to fail when coming from the World (since the World address doesn't have access) + _expectAccessDenied(address(world), "", ""); world.registerSystem(ResourceSelector.from("", "rootSystem"), yetAnotherSystem, true); } @@ -1047,8 +1047,8 @@ contract WorldTest is Test, GasReporter { _expectAccessDenied(address(0x01), "", ""); world.registerRootFunctionSelector(resourceSelector, worldFunc, sysFunc); - // Expect the World to be able to register a root function selector - vm.prank(address(world)); + // Expect the World to not be able to register a root function selector when calling the function externally + _expectAccessDenied(address(world), "", ""); world.registerRootFunctionSelector(resourceSelector, "smth", "smth"); startGasReport("Register a root function selector");