From 0773edd2b0133d055d363dccd4d0f5b18318642a Mon Sep 17 00:00:00 2001 From: blurpesec Date: Thu, 28 Aug 2025 06:44:35 -0700 Subject: [PATCH 1/3] chore: functional install scripts --- packages/contracts/.env.pyrope | 2 +- packages/contracts/mud.config.ts | 16 - packages/contracts/package.json | 5 +- packages/contracts/scripts/ConfigureSSU.s.sol | 2 +- .../scripts/DeployStorageManagerModule.s.sol | 31 ++ .../scripts/InstallStorageManager.s.sol | 351 ------------------ .../contracts/src/StorageManagerModule.sol | 160 ++++++++ .../src/codegen/systems/SmUtilsSystemLib.sol | 36 ++ .../src/codegen/world/ISmUtilsSystem.sol | 2 + .../contracts/src/systems/SmUtilsSystem.sol | 19 + .../StorageSystem/StoreLogicSystem.sol | 6 +- packages/contracts/store/TaskTests/Task.t.sol | 130 ------- .../contracts/store/Tasklist/Constants.sol | 5 - packages/contracts/store/Tasklist/Errors.sol | 8 - .../contracts/store/Tasklist/TaskSystem.sol | 91 ----- .../contracts/store/script/PostDeploy.s.sol | 25 -- .../store/script/Tasks/CompleteTask.s.sol | 22 -- .../store/script/Tasks/CreateTask.s.sol | 29 -- .../script/Tasks/UpdateTaskAssignee.s.sol | 23 -- .../script/Tasks/UpdateTaskDeadline.s.sol | 23 -- .../script/Tasks/UpdateTaskDescription.s.sol | 23 -- 21 files changed, 256 insertions(+), 753 deletions(-) create mode 100644 packages/contracts/scripts/DeployStorageManagerModule.s.sol delete mode 100644 packages/contracts/scripts/InstallStorageManager.s.sol create mode 100644 packages/contracts/src/StorageManagerModule.sol delete mode 100644 packages/contracts/store/TaskTests/Task.t.sol delete mode 100644 packages/contracts/store/Tasklist/Constants.sol delete mode 100644 packages/contracts/store/Tasklist/Errors.sol delete mode 100644 packages/contracts/store/Tasklist/TaskSystem.sol delete mode 100644 packages/contracts/store/script/PostDeploy.s.sol delete mode 100644 packages/contracts/store/script/Tasks/CompleteTask.s.sol delete mode 100644 packages/contracts/store/script/Tasks/CreateTask.s.sol delete mode 100644 packages/contracts/store/script/Tasks/UpdateTaskAssignee.s.sol delete mode 100644 packages/contracts/store/script/Tasks/UpdateTaskDeadline.s.sol delete mode 100644 packages/contracts/store/script/Tasks/UpdateTaskDescription.s.sol diff --git a/packages/contracts/.env.pyrope b/packages/contracts/.env.pyrope index d76423d..d19bffe 100644 --- a/packages/contracts/.env.pyrope +++ b/packages/contracts/.env.pyrope @@ -8,7 +8,7 @@ DEBUG=mud:* # MUD Pyrope Configuration -WORLD_ADDRESS=0xcdb380e0cd3949caf70c45c67079f2e27a77fc47 +WORLD_ADDRESS=0x7085f3e652987f656fb8dee5aa6592197bb75de8 CHAIN_ID=695569 PRIVATE_KEY= RPC_URL=https://pyrope-external-sync-node-rpc.live.tech.evefrontier.com diff --git a/packages/contracts/mud.config.ts b/packages/contracts/mud.config.ts index b892462..ed3e898 100644 --- a/packages/contracts/mud.config.ts +++ b/packages/contracts/mud.config.ts @@ -39,18 +39,6 @@ export default defineWorld({ ResourceId: { filePath: "@latticexyz/store/src/ResourceId.sol", type: "bytes32" }, }, tables: { - // Tasklist: { - // schema: { - // id: "uint256", - // creator: "address", - // assignee: "address", - // deadline: "uint256", - // timestamp: "uint256", - // status: "TaskStatus", - // description: "string", - // }, - // key: ["id"], - // }, BucketedInventoryItem: { schema: { bucketId: "bytes32", @@ -115,8 +103,4 @@ export default defineWorld({ key: ["smartObjectId", "bucketId"], }, }, - - // enums: { - // TaskStatus: ["OPEN", "CLOSED"], - // }, }); diff --git a/packages/contracts/package.json b/packages/contracts/package.json index de6fe9f..f02e346 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -25,8 +25,9 @@ "coverage": ". ./.env.local && forge coverage --ir-minimum --fork-url $RPC_URL -vvvv", "configure-ssu": ". ./.env && pnpm forge script ./script/ConfigureSSU.s.sol:ConfigureSSU --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID --sig \"run()\" $WORLD_ADDRESS", "create-nested-bucket": ". ./.env && pnpm forge script ./script/CreateNestedBucket.s.sol:CreateNestedBucket --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID --sig \"run(string)\" $WORLD_ADDRESS", - "install:storage-manager": ". ./.env.local && pnpm forge script ./scripts/InstallStorageManager.s.sol:InstallStorageManager --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID -vvvv" - }, + "install:storage-manager": ". ./.env.local && pnpm forge script ./scripts/InstallStorageManager.s.sol:InstallStorageManager --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID -vvvv", + "pretest": "pnpm run install:storage-manager" + }, "publishConfig": { "access": "public" }, diff --git a/packages/contracts/scripts/ConfigureSSU.s.sol b/packages/contracts/scripts/ConfigureSSU.s.sol index d6d0041..8b99c83 100644 --- a/packages/contracts/scripts/ConfigureSSU.s.sol +++ b/packages/contracts/scripts/ConfigureSSU.s.sol @@ -12,7 +12,7 @@ contract ConfigureSSU is Script { address worldAddress = vm.envAddress("WORLD_ADDRESS"); bool configureAsImmutable = vm.envBool("CONFIGURE_AS_IMMUTABLE"); IWorld world = IWorld(worldAddress); - address storeProxySystemAddress = world.sm_v0_2_0sm__getStoreProxyAddress(); + address storeProxySystemAddress = world.sm_v0_2_0__getStoreProxyAddress(); if (storeProxySystemAddress == address(0)) { revert("StoreProxySystem not registered to the World"); } diff --git a/packages/contracts/scripts/DeployStorageManagerModule.s.sol b/packages/contracts/scripts/DeployStorageManagerModule.s.sol new file mode 100644 index 0000000..565e063 --- /dev/null +++ b/packages/contracts/scripts/DeployStorageManagerModule.s.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import { Script } from "forge-std/Script.sol"; +import { console } from "forge-std/console.sol"; +import { IWorld } from "../src/codegen/world/IWorld.sol"; +import { StorageManagerModule } from "../src/StorageManagerModule.sol"; + +contract DeployStorageManagerModule is Script { + function run() external { + address worldAddress = vm.envAddress("WORLD_ADDRESS"); + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + console.log("Deploying StorageManagerModule..."); + StorageManagerModule module = new StorageManagerModule(); + console.log("StorageManagerModule deployed at:", address(module)); + + console.log("Installing module into World (root)..."); + IWorld(worldAddress).installRootModule(module, bytes("")); + console.log("Module installed."); + + vm.stopBroadcast(); + + // Verify installation + address installedModule = IWorld(worldAddress).getModuleAddress(keccak256(abi.encodePacked("StorageManagerModule"))); + require(installedModule == address(module), "Module installation failed"); + console.log("Verified module installation at:", installedModule); + } +} diff --git a/packages/contracts/scripts/InstallStorageManager.s.sol b/packages/contracts/scripts/InstallStorageManager.s.sol deleted file mode 100644 index 3cbd328..0000000 --- a/packages/contracts/scripts/InstallStorageManager.s.sol +++ /dev/null @@ -1,351 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { Script } from "forge-std/Script.sol"; -import { console } from "forge-std/console.sol"; -import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; -import { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; -import { Schema } from "@latticexyz/store/src/Schema.sol"; -import { IStore } from "@latticexyz/store/src/IStore.sol"; -import { WorldResourceIdLib } from "@latticexyz/world/src/WorldResourceId.sol"; -import { RESOURCE_SYSTEM } from "@latticexyz/world/src/worldResourceTypes.sol"; -import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; - -// Import the systems to be deployed -import { IWorld } from "../src/codegen/world/IWorld.sol"; - -import { StorageSystem } from "../src/systems/StorageSystem/StorageSystem.sol"; -import { BucketSystem } from "../src/systems/StorageSystem/BucketSystem.sol"; -import { StoreAuthSystem } from "../src/systems/StorageSystem/StoreAuthSystem.sol"; -import { StoreProxySystem } from "../src/systems/StoreProxySystem/StoreProxySystem.sol"; -import { StoreLogicSystem } from "../src/systems/StorageSystem/StoreLogicSystem.sol"; -import { SmUtilsSystem } from "../src/systems/SmUtilsSystem.sol"; -import { AccessUtilsSystem } from "../src/systems/AccessUtilsSystem.sol"; -import { DEPLOYMENT_NAMESPACE } from "../src/systems/StorageSystem/Constants.sol"; - -// Import table schemas for registration -import { BucketedInventoryItem } from "../src/codegen/tables/BucketedInventoryItem.sol"; -import { BucketMetadata } from "../src/codegen/tables/BucketMetadata.sol"; -import { BucketConfig } from "../src/codegen/tables/BucketConfig.sol"; -import { InventoryBalances } from "../src/codegen/tables/InventoryBalances.sol"; -import { BucketOwners } from "../src/codegen/tables/BucketOwners.sol"; -import { BucketInventory } from "../src/codegen/tables/BucketInventory.sol"; - -/** - * @title InstallStorageManager - * @notice Script to install the complete StorageManager system into an existing MUD world - * @dev This script deploys all StorageManager systems and registers all required tables - * - * Usage: - * forge script InstallStorageManager --rpc-url $RPC_URL --broadcast --verify - * - * Environment Variables Required: - * - WORLD_ADDRESS: Address of the target MUD World - * - PRIVATE_KEY: Deployer private key - * - RPC_URL: RPC endpoint - * - CHAIN_ID: Target chain ID - */ -contract InstallStorageManager is Script { - // Storage Manager namespace - bytes14 constant NAMESPACE = DEPLOYMENT_NAMESPACE; - - // System names - bytes14 constant STORAGE_SYSTEM = "StorageSystem"; - bytes14 constant BUCKET_SYSTEM = "BucketSystem"; - bytes14 constant STORE_AUTH_SYSTEM = "StoreAuthSyste"; - bytes14 constant STORE_PROXY_SYSTEM = "StoreProxySyst"; - bytes14 constant STORE_LOGIC_SYSTEM = "StoreLogicSyst"; - bytes14 constant SM_UTILS_SYSTEM = "SmUtilsSystem"; - bytes14 constant ACCESS_UTILS_SYSTEM = "AccessUtilSyst"; - - IWorld world; - IStore store; - - address deployer; - - function run() external { - // Load configuration - address worldAddress = vm.envAddress("WORLD_ADDRESS"); - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - deployer = vm.addr(deployerPrivateKey); - - console.log("Installing StorageManager to world:", worldAddress); - console.log("Deployer address:", deployer); - - // Initialize world connection - world = IWorld(worldAddress); - StoreSwitch.setStoreAddress(worldAddress); - store = IStore(worldAddress); - - vm.startBroadcast(deployerPrivateKey); - // Ensure namespace exists and caller has authority - ensureNamespace(); - - // Step 1: Register all tables first - console.log("\n=== Registering Tables ==="); - registerTables(); - - // Step 2: Deploy and register all systems - console.log("\n=== Deploying Systems ==="); - deploySystems(); - - // Step 3: Verify installation - console.log("\n=== Verifying Installation ==="); - verifyInstallation(); - - vm.stopBroadcast(); - - console.log("\n=== Installation Complete ==="); - console.log("StorageManager successfully installed!"); - - // Print next steps - printNextSteps(); - } - - function ensureNamespace() internal { - console.log("Ensuring namespace is registered..."); - // registerNamespace is idempotent via try/catch - ResourceId namespaceResource = WorldResourceIdLib.encodeNamespace(DEPLOYMENT_NAMESPACE); - try world.registerNamespace(namespaceResource) { - console.log("Namespace registered."); - } catch { - console.log("Namespace already registered, continuing."); - } - } - - function registerIfNeeded( - ResourceId tableId, - bytes32 fieldLayout, - Schema keySchema, - Schema valueSchema, - string[] memory keyNames, - string[] memory fieldNames - ) internal { - // If table exists, verify schema matches; otherwise skip registration - try store.getKeySchema(tableId) returns (Schema existingKey) { - Schema existingValue = store.getValueSchema(tableId); - if ( - Schema.unwrap(existingKey) != Schema.unwrap(keySchema) || - Schema.unwrap(existingValue) != Schema.unwrap(valueSchema) - ) { - revert("Table already exists with different schema; bump DEPLOYMENT_NAMESPACE"); - } - console.log("Table already registered:", uint256(ResourceId.unwrap(tableId))); - return; - } catch { - // not registered yet - console.log("Not registered yet, registering table:", uint256(ResourceId.unwrap(tableId))); - } - store.registerTable({ - tableId: tableId, - fieldLayout: FieldLayout.wrap(fieldLayout), - keySchema: keySchema, - valueSchema: valueSchema, - keyNames: keyNames, - fieldNames: fieldNames - }); - } - - function registerTables() internal { - console.log("Registering BucketedInventoryItem table..."); - // BucketedInventoryItem.register(); - registerIfNeeded({ - tableId: BucketedInventoryItem._tableId, - fieldLayout: FieldLayout.unwrap(BucketedInventoryItem._fieldLayout), - keySchema: (BucketedInventoryItem._keySchema), - valueSchema: (BucketedInventoryItem._valueSchema), - keyNames: BucketedInventoryItem.getKeyNames(), - fieldNames: BucketedInventoryItem.getFieldNames() - }); - - console.log("Registering BucketMetadata table..."); - // BucketMetadata.register(); - registerIfNeeded({ - tableId: BucketMetadata._tableId, - fieldLayout: FieldLayout.unwrap(BucketMetadata._fieldLayout), - keySchema: BucketMetadata._keySchema, - valueSchema: BucketMetadata._valueSchema, - keyNames: BucketMetadata.getKeyNames(), - fieldNames: BucketMetadata.getFieldNames() - }); - - console.log("Registering BucketConfig table..."); - // BucketConfig.register(); - registerIfNeeded({ - tableId: BucketConfig._tableId, - fieldLayout: FieldLayout.unwrap(BucketConfig._fieldLayout), - keySchema: BucketConfig._keySchema, - valueSchema: BucketConfig._valueSchema, - keyNames: BucketConfig.getKeyNames(), - fieldNames: BucketConfig.getFieldNames() - }); - - console.log("Registering InventoryBalances table..."); - // InventoryBalances.register(); - registerIfNeeded({ - tableId: InventoryBalances._tableId, - fieldLayout: FieldLayout.unwrap(InventoryBalances._fieldLayout), - keySchema: InventoryBalances._keySchema, - valueSchema: InventoryBalances._valueSchema, - keyNames: InventoryBalances.getKeyNames(), - fieldNames: InventoryBalances.getFieldNames() - }); - - console.log("Registering BucketOwners table..."); - // BucketOwners.register(); - registerIfNeeded({ - tableId: BucketOwners._tableId, - fieldLayout: FieldLayout.unwrap(BucketOwners._fieldLayout), - keySchema: BucketOwners._keySchema, - valueSchema: BucketOwners._valueSchema, - keyNames: BucketOwners.getKeyNames(), - fieldNames: BucketOwners.getFieldNames() - }); - - console.log("Registering BucketInventory table..."); - // BucketInventory.register(); - registerIfNeeded({ - tableId: BucketInventory._tableId, - fieldLayout: FieldLayout.unwrap(BucketInventory._fieldLayout), - keySchema: BucketInventory._keySchema, - valueSchema: BucketInventory._valueSchema, - keyNames: BucketInventory.getKeyNames(), - fieldNames: BucketInventory.getFieldNames() - }); - - console.log("All tables registered successfully!"); - } - - function deploySystems() internal { - // Deploy StorageSystem - console.log("Deploying StorageSystem..."); - StorageSystem storageSystem = new StorageSystem(); - ResourceId storageSystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: STORAGE_SYSTEM - }); - world.registerSystem(storageSystemId, storageSystem, true); - console.log("StorageSystem deployed at:", address(storageSystem)); - - // Deploy BucketSystem - console.log("Deploying BucketSystem..."); - BucketSystem bucketSystem = new BucketSystem(); - ResourceId bucketSystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: BUCKET_SYSTEM - }); - world.registerSystem(bucketSystemId, bucketSystem, true); - console.log("BucketSystem deployed at:", address(bucketSystem)); - - // Deploy StoreAuthSystem - console.log("Deploying StoreAuthSystem..."); - StoreAuthSystem storeAuthSystem = new StoreAuthSystem(); - ResourceId storeAuthSystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: STORE_AUTH_SYSTEM - }); - world.registerSystem(storeAuthSystemId, storeAuthSystem, true); - console.log("StoreAuthSystem deployed at:", address(storeAuthSystem)); - - // Deploy StoreProxySystem - console.log("Deploying StoreProxySystem..."); - StoreProxySystem storeProxySystem = new StoreProxySystem(); - ResourceId storeProxySystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: STORE_PROXY_SYSTEM - }); - world.registerSystem(storeProxySystemId, storeProxySystem, true); - console.log("StoreProxySystem deployed at:", address(storeProxySystem)); - - // Deploy StoreLogicSystem - console.log("Deploying StoreLogicSystem..."); - StoreLogicSystem storeLogicSystem = new StoreLogicSystem(); - ResourceId storeLogicSystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: STORE_LOGIC_SYSTEM - }); - world.registerSystem(storeLogicSystemId, storeLogicSystem, true); - console.log("StoreLogicSystem deployed at:", address(storeLogicSystem)); - - // Deploy SmUtilsSystem - console.log("Deploying SmUtilsSystem..."); - SmUtilsSystem smUtilsSystem = new SmUtilsSystem(); - ResourceId smUtilsSystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: SM_UTILS_SYSTEM - }); - world.registerSystem(smUtilsSystemId, smUtilsSystem, true); - console.log("SmUtilsSystem deployed at:", address(smUtilsSystem)); - - // Deploy AccessUtilsSystem - console.log("Deploying AccessUtilsSystem..."); - AccessUtilsSystem accessUtilsSystem = new AccessUtilsSystem(); - ResourceId accessUtilsSystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: ACCESS_UTILS_SYSTEM - }); - world.registerSystem(accessUtilsSystemId, accessUtilsSystem, true); - console.log("AccessUtilsSystem deployed at:", address(accessUtilsSystem)); - - console.log("All systems deployed successfully!"); - } - - function verifyInstallation() internal view { - console.log("Verifying system registrations..."); - - // Check if systems are properly registered - ResourceId storageSystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: STORAGE_SYSTEM - }); - - // address systemAddress = world.getSystemAddress(storageSystemId); - // console.log("StorageSystem verified at:", systemAddress); - - // Additional verification for StoreProxySystem since it's critical - ResourceId storeProxySystemId = WorldResourceIdLib.encode({ - typeId: RESOURCE_SYSTEM, - namespace: NAMESPACE, - name: STORE_PROXY_SYSTEM - }); - - // address proxyAddress = world.getSystemAddress(storeProxySystemId); - // console.log("StoreProxySystem verified at:", proxyAddress); - - console.log("Installation verification complete!"); - } - - function printNextSteps() internal view { - console.log("\n=== Next Steps ==="); - console.log("1. Configure Smart Storage Unit (SSU) permissions:"); - console.log(" Run: forge script ConfigureSSU --rpc-url $RPC_URL --broadcast"); - console.log(""); - console.log("2. Create your first bucket:"); - console.log(' world.%s__createNestedBuckets(ssuId, "my-bucket");'); - console.log(""); - console.log("3. Grant StorageManager permissions to StoreProxySystem:"); - console.log(" - TRANSFER_FROM_EPHEMERAL_ROLE"); - console.log(" - TRANSFER_TO_EPHEMERAL_ROLE"); - console.log(" - CROSS_TRANSFER_TO_EPHEMERAL_ROLE"); - console.log(" - TRANSFER_TO_INVENTORY_ROLE"); - console.log(""); - console.log("4. Import StorageSystem in your project:"); - console.log(' import { storageSystem } from "@awar-dev/storage-manager/codegen/systems/StorageSystemLib";'); - console.log(""); - console.log("Available functions:"); - console.log(" - createNestedBuckets(smartObjectId, bucketName)"); - console.log(" - deposit(smartObjectId, bucketId, transferFromEphemeral, items)"); - console.log(" - withdraw(smartObjectId, bucketId, transferToEphemeral, items)"); - console.log(" - internalTransfer(smartObjectId, fromBucket, toBucket, items)"); - console.log(" - getBucketsMetadata(smartObjectId, bucketIds)"); - } -} diff --git a/packages/contracts/src/StorageManagerModule.sol b/packages/contracts/src/StorageManagerModule.sol new file mode 100644 index 0000000..863e874 --- /dev/null +++ b/packages/contracts/src/StorageManagerModule.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import { Module } from "@latticexyz/world/src/Module.sol"; +import { ResourceId, WorldResourceIdLib, WorldResourceIdInstance } from "@latticexyz/world/src/WorldResourceId.sol"; +import { RESOURCE_SYSTEM } from "@latticexyz/world/src/worldResourceTypes.sol"; +import { IWorld } from "./codegen/world/IWorld.sol"; + +// Systems +import { StorageSystem } from "./systems/StorageSystem/StorageSystem.sol"; +import { BucketSystem } from "./systems/StorageSystem/BucketSystem.sol"; +import { StoreAuthSystem } from "./systems/StorageSystem/StoreAuthSystem.sol"; +import { StoreProxySystem } from "./systems/StoreProxySystem/StoreProxySystem.sol"; +import { StoreLogicSystem } from "./systems/StorageSystem/StoreLogicSystem.sol"; +import { SmUtilsSystem } from "./systems/SmUtilsSystem.sol"; +import { AccessUtilsSystem } from "./systems/AccessUtilsSystem.sol"; + +// Tables (import the generated index to access all table libs) +import { BucketedInventoryItem, BucketMetadata, BucketConfig, InventoryBalances, BucketOwners, BucketInventory } from "./codegen/index.sol"; + +// Namespace constant +import { DEPLOYMENT_NAMESPACE } from "./systems/StorageSystem/Constants.sol"; + +contract StorageManagerModule is Module { + using WorldResourceIdInstance for ResourceId; + + // Pre-deploy systems once at module deployment time + StorageSystem private immutable storageSystem = new StorageSystem(); + BucketSystem private immutable bucketSystem = new BucketSystem(); + StoreAuthSystem private immutable storeAuthSystem = new StoreAuthSystem(); + StoreProxySystem private immutable storeProxySystem = new StoreProxySystem(); + StoreLogicSystem private immutable storeLogicSystem = new StoreLogicSystem(); + SmUtilsSystem private immutable smUtilsSystem = new SmUtilsSystem(); + AccessUtilsSystem private immutable accessUtilsSystem = new AccessUtilsSystem(); + + // Encoded namespace resource id + ResourceId private immutable namespaceResource = WorldResourceIdLib.encodeNamespace(DEPLOYMENT_NAMESPACE); + + function install(bytes memory) public override { + IWorld world = IWorld(_world()); + + // 1) Register namespace (reverts if already registered) + world.registerNamespace(namespaceResource); + + // 2) Register tables + BucketedInventoryItem.register(); + BucketMetadata.register(); + BucketConfig.register(); + InventoryBalances.register(); + BucketOwners.register(); + BucketInventory.register(); + + // Pre-compute system resource ids + ResourceId storageSystemResource = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: DEPLOYMENT_NAMESPACE, + name: bytes16("StorageSystem") + }); + ResourceId bucketSystemResource = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: DEPLOYMENT_NAMESPACE, + name: bytes16("BucketSystem") + }); + ResourceId storeAuthSystemResource = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: DEPLOYMENT_NAMESPACE, + name: bytes16("StoreAuthSystem") + }); + ResourceId storeProxySystemResource = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: DEPLOYMENT_NAMESPACE, + name: bytes16("StoreProxySystem") + }); + ResourceId storeLogicSystemResource = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: DEPLOYMENT_NAMESPACE, + name: bytes16("StoreLogicSystem") + }); + ResourceId smUtilsSystemResource = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: DEPLOYMENT_NAMESPACE, + name: bytes16("SmUtilsSystem") + }); + // Note: name must match mud.config.ts generated system lib name + ResourceId accessUtilsSystemResource = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: DEPLOYMENT_NAMESPACE, + name: bytes16("AccessUtilSystem") + }); + + // 3) Register systems (public access) + world.registerSystem(storageSystemResource, storageSystem, true); + world.registerSystem(bucketSystemResource, bucketSystem, true); + world.registerSystem(storeAuthSystemResource, storeAuthSystem, true); + world.registerSystem(storeProxySystemResource, storeProxySystem, true); + world.registerSystem(storeLogicSystemResource, storeLogicSystem, true); + world.registerSystem(smUtilsSystemResource, smUtilsSystem, true); + world.registerSystem(accessUtilsSystemResource, accessUtilsSystem, true); + + // 3.1) Register function selectors for all callable system functions + // StorageSystem + world.registerFunctionSelector(storageSystemResource, "deposit(uint256,bytes32,bool,(uint256,uint256)[])"); + world.registerFunctionSelector(storageSystemResource, "withdraw(uint256,bytes32,bool,(uint256,uint256)[])"); + world.registerFunctionSelector(storageSystemResource, "internalTransfer(uint256,bytes32,bytes32,(uint256,uint256)[])"); + world.registerFunctionSelector(storageSystemResource, "getSystemAddress()"); + + // BucketSystem + world.registerFunctionSelector(bucketSystemResource, "createNestedBuckets(uint256,string)"); + world.registerFunctionSelector(bucketSystemResource, "transferBucketToParent(uint256,bytes32,bytes32)"); + world.registerFunctionSelector(bucketSystemResource, "getCreateSystemAddress()"); + + // StoreAuthSystem (authorization helpers and config) + world.registerFunctionSelector(storeAuthSystemResource, "setAccessSystemId(uint256,bytes32,bytes32)"); + world.registerFunctionSelector(storeAuthSystemResource, "getCharacterTribeByAddress(address)"); + world.registerFunctionSelector(storeAuthSystemResource, "fetchAuthorizationSystemId(uint256,bytes32)"); + // Expected can* methods used by other systems via system libs + world.registerFunctionSelector(storeAuthSystemResource, "canDeposit(uint256,bytes32,address)"); + world.registerFunctionSelector(storeAuthSystemResource, "canWithdraw(uint256,bytes32,address)"); + world.registerFunctionSelector(storeAuthSystemResource, "canTransferBucket(uint256,bytes32,address)"); + + // StoreProxySystem (forwarders to EveWorld systems) + world.registerFunctionSelector(storeProxySystemResource, "getStoreProxyAddress()"); + world.registerFunctionSelector(storeProxySystemResource, "proxyTransferToEphemeral(uint256,address,(uint256,uint256)[])"); + world.registerFunctionSelector(storeProxySystemResource, "proxyTransferFromEphemeral(uint256,address,(uint256,uint256)[])"); + world.registerFunctionSelector(storeProxySystemResource, "proxyCrossTransferToEphemeral(uint256,address,address,(uint256,uint256)[])"); + world.registerFunctionSelector(storeProxySystemResource, "proxyTransferToInventory(uint256,uint256,(uint256,uint256)[])"); + + // StoreLogicSystem (internal ops invoked via world call) + world.registerFunctionSelector(storeLogicSystemResource, "_processDeposit(uint256,bytes32,(uint256,uint256))"); + world.registerFunctionSelector(storeLogicSystemResource, "_processWithdraw(uint256,bytes32,(uint256,uint256))"); + world.registerFunctionSelector(storeLogicSystemResource, "_processAggBucketsBalance(uint256,bytes32,bool,(uint256,uint256))"); + + // SmUtilsSystem (read helpers + batch checks) + world.registerFunctionSelector(smUtilsSystemResource, "deriveBucketId(uint256,string)"); + world.registerFunctionSelector(smUtilsSystemResource, "getPrimaryInventoryOwnerItems(uint256,address)"); + world.registerFunctionSelector(smUtilsSystemResource, "getEphemeralInventoryItems(uint256,address)"); + world.registerFunctionSelector(smUtilsSystemResource, "getBucketInventoryItems(uint256,bytes32)"); + world.registerFunctionSelector(smUtilsSystemResource, "getBucketsMetadata(uint256,bytes32[])"); + world.registerFunctionSelector(smUtilsSystemResource, "getBatchCanDeposit(uint256,bytes32[],address)"); + world.registerFunctionSelector(smUtilsSystemResource, "getBatchCanWithdraw(uint256,bytes32[],address)"); + world.registerFunctionSelector(smUtilsSystemResource, "getOwnerBalance(uint256,uint256)"); + world.registerFunctionSelector(smUtilsSystemResource, "getBucketsByOwnerAtSSU(uint256,address)"); + world.registerFunctionSelector(smUtilsSystemResource, "getBucketMetadata(uint256,bytes32)"); + world.registerFunctionSelector(smUtilsSystemResource, "getBucketMetadataChain(uint256,bytes32)"); + world.registerFunctionSelector(smUtilsSystemResource, "getBucketMetadataChainByName(uint256,string)"); + world.registerFunctionSelector(smUtilsSystemResource, "getItemTypeIds(uint256[])"); + + // AccessUtilsSystem + world.registerFunctionSelector(accessUtilsSystemResource, "hasRoles(bytes32[],address)"); + world.registerFunctionSelector(accessUtilsSystemResource, "getOwnersOf(uint256[])"); + + // 4) Transfer namespace ownership to the installer + world.transferOwnership(namespaceResource, _msgSender()); + } + + function installRoot(bytes memory encodedArgs) public override { + // Root install behaves the same; it has root permissions + install(encodedArgs); + } +} diff --git a/packages/contracts/src/codegen/systems/SmUtilsSystemLib.sol b/packages/contracts/src/codegen/systems/SmUtilsSystemLib.sol index beaa14f..05c0b7f 100644 --- a/packages/contracts/src/codegen/systems/SmUtilsSystemLib.sol +++ b/packages/contracts/src/codegen/systems/SmUtilsSystemLib.sol @@ -137,6 +137,10 @@ library SmUtilsSystemLib { return CallWrapper(self.toResourceId(), address(0)).getBucketMetadataChainByName(smartObjectId, bucketName); } + function getItemTypeIds(SmUtilsSystemType self, uint256[] calldata itemIds) internal view returns (uint256[] memory) { + return CallWrapper(self.toResourceId(), address(0)).getItemTypeIds(itemIds); + } + function deriveBucketId( CallWrapper memory self, uint256 smartObjectId, @@ -394,6 +398,24 @@ library SmUtilsSystemLib { return abi.decode(result, (BucketMetadataWithId[])); } + function getItemTypeIds( + CallWrapper memory self, + uint256[] calldata itemIds + ) internal view returns (uint256[] memory) { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert SmUtilsSystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall(_getItemTypeIds_uint256Array.getItemTypeIds, (itemIds)); + bytes memory worldCall = self.from == address(0) + ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) + : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); + (bool success, bytes memory returnData) = address(_world()).staticcall(worldCall); + if (!success) revertWithBytes(returnData); + + bytes memory result = abi.decode(returnData, (bytes)); + return abi.decode(result, (uint256[])); + } + function deriveBucketId( RootCallWrapper memory self, uint256 smartObjectId, @@ -561,6 +583,16 @@ library SmUtilsSystemLib { return abi.decode(result, (BucketMetadataWithId[])); } + function getItemTypeIds( + RootCallWrapper memory self, + uint256[] calldata itemIds + ) internal view returns (uint256[] memory) { + bytes memory systemCall = abi.encodeCall(_getItemTypeIds_uint256Array.getItemTypeIds, (itemIds)); + + bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); + return abi.decode(result, (uint256[])); + } + function callFrom(SmUtilsSystemType self, address from) internal pure returns (CallWrapper memory) { return CallWrapper(self.toResourceId(), from); } @@ -647,6 +679,10 @@ interface _getBucketMetadataChainByName_uint256_string { function getBucketMetadataChainByName(uint256 smartObjectId, string memory bucketName) external; } +interface _getItemTypeIds_uint256Array { + function getItemTypeIds(uint256[] calldata itemIds) external; +} + using SmUtilsSystemLib for SmUtilsSystemType global; using SmUtilsSystemLib for CallWrapper global; using SmUtilsSystemLib for RootCallWrapper global; diff --git a/packages/contracts/src/codegen/world/ISmUtilsSystem.sol b/packages/contracts/src/codegen/world/ISmUtilsSystem.sol index b6be015..2bad7bd 100644 --- a/packages/contracts/src/codegen/world/ISmUtilsSystem.sol +++ b/packages/contracts/src/codegen/world/ISmUtilsSystem.sol @@ -68,4 +68,6 @@ interface ISmUtilsSystem { uint256 smartObjectId, string memory bucketName ) external view returns (BucketMetadataWithId[] memory); + + function sm_v0_2_0__getItemTypeIds(uint256[] calldata itemIds) external view returns (uint256[] memory); } diff --git a/packages/contracts/src/systems/SmUtilsSystem.sol b/packages/contracts/src/systems/SmUtilsSystem.sol index 47e6207..78e4a06 100644 --- a/packages/contracts/src/systems/SmUtilsSystem.sol +++ b/packages/contracts/src/systems/SmUtilsSystem.sol @@ -6,6 +6,7 @@ import { InventoryItemParams } from "@eveworld/world-v2/src/namespaces/evefronti import { InventoryItem } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/InventoryItem.sol"; import { EphemeralInventory } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/EphemeralInventory.sol"; import { EphemeralInvItem } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/EphemeralInvItem.sol"; +import { EntityRecord } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/EntityRecord.sol"; import { InventoryBalances } from "../codegen/tables/InventoryBalances.sol"; import { storeAuthSystem } from "../codegen/systems/StoreAuthSystemLib.sol"; @@ -20,6 +21,12 @@ import { SharedUtils, BucketMetadataWithId } from "./StorageSystem/utils.sol"; contract SmUtilsSystem is System { using Bytes32StringPacker for string; + function incrementUnsafe(uint256 i) private pure returns (uint256) { + unchecked { + return i + 1; + } + } + function deriveBucketId(uint256 smartObjectId, string memory bucketName) public pure returns (bytes32) { return bytes32(keccak256(abi.encode(smartObjectId, bucketName.pack()))); } @@ -220,4 +227,16 @@ contract SmUtilsSystem is System { bytes32 bucketId = SharedUtils.composeBucketId(smartObjectId, bucketName); return getBucketMetadataChain(smartObjectId, bucketId); } + + /** + * @dev - Get the typeIds of all specified itemIds + */ + function getItemTypeIds(uint256[] calldata itemIds) public view returns (uint256[] memory) { + uint256[] memory typeIds = new uint256[](itemIds.length); + for (uint i = 0; i < itemIds.length; ) { + typeIds[i] = EntityRecord.getTypeId(itemIds[i]); + i = incrementUnsafe(i); + } + return typeIds; + } } diff --git a/packages/contracts/src/systems/StorageSystem/StoreLogicSystem.sol b/packages/contracts/src/systems/StorageSystem/StoreLogicSystem.sol index 0154353..a516e1e 100644 --- a/packages/contracts/src/systems/StorageSystem/StoreLogicSystem.sol +++ b/packages/contracts/src/systems/StorageSystem/StoreLogicSystem.sol @@ -51,9 +51,9 @@ contract StoreLogicSystem is System { InventoryItemParams memory item ) external { if (!InventoryBalances.getExists(smartObjectId, item.smartObjectId)) { - if (isWithdrawal) { - revert ItemAggregateNotFound(); - } + if (isWithdrawal) { + revert ItemAggregateNotFound(); + } // create a new entry in the InventoryBalances table for the item InventoryBalances.set(smartObjectId, item.smartObjectId, true, uint64(item.quantity)); } else { diff --git a/packages/contracts/store/TaskTests/Task.t.sol b/packages/contracts/store/TaskTests/Task.t.sol deleted file mode 100644 index faafe07..0000000 --- a/packages/contracts/store/TaskTests/Task.t.sol +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import "forge-std/Test.sol"; -import { MudTest } from "@latticexyz/world/test/MudTest.t.sol"; -import { IWorld } from "@world/IWorld.sol"; -import { Tasklist, TasklistData } from "@store/index.sol"; -import { TaskStatus } from "@store/common.sol"; -import { TaskSystem } from "@systems/Tasklist/TaskSystem.sol"; -import { SetupTest } from "../SetupTest.t.sol"; -import "@systems/Tasklist/Errors.sol"; - -contract TaskTest is SetupTest { - address private creator = address(1); - address private assignee = address(2); - address private nonAuthorized = address(3); - string private initialDescription = "Initial task description"; - uint256 private initialDeadline = block.timestamp + 1 days; - uint256 private taskId; - - TasklistData task; - TasklistData updatedTask; - TasklistData completedTask; - - function setUp() public override { - super.setUp(); - vm.prank(creator); - taskId = taskWorld.TASK__createTask(assignee, initialDescription, initialDeadline); - } - - function testCreateTask() public { - task = Tasklist.get(taskId); - assertEq(task.creator, creator, "Creator address mismatch"); - assertEq(task.assignee, assignee, "Assignee address mismatch"); - assertEq(task.description, initialDescription, "Description mismatch"); - assertEq(uint256(task.status), uint256(TaskStatus.OPEN), "Initial status should be Open"); - assertEq(task.deadline, initialDeadline, "Deadline mismatch"); - assertEq(task.timestamp, block.timestamp, "Timestamp mismatch"); - } - - function testUpdateTaskAssignee() public { - testCreateTask(); - - address newAssignee = address(4); - - vm.prank(creator); - taskWorld.TASK__updateTaskAssignee(taskId, newAssignee); - - updatedTask = Tasklist.get(taskId); - assertEq(updatedTask.assignee, newAssignee, "Assignee not updated"); - } - - function testUpdateTaskDeadline() public { - uint256 newDeadline = block.timestamp + 2 days; - - vm.prank(creator); - taskWorld.TASK__updateTaskDeadline(taskId, newDeadline); - - updatedTask = Tasklist.get(taskId); - assertEq(updatedTask.deadline, newDeadline, "Deadline not updated"); - } - - function testUpdateTaskDescription() public { - string memory newDescription = "Updated description"; - - vm.prank(creator); - taskWorld.TASK__updateTaskDescription(taskId, newDescription); - - updatedTask = Tasklist.get(taskId); - assertEq(updatedTask.description, newDescription, "Description not updated"); - } - - function testCompleteTaskAsCreator() public { - vm.prank(creator); - taskWorld.TASK__completeTask(taskId); - - completedTask = Tasklist.get(taskId); - assertEq(uint256(completedTask.status), uint256(TaskStatus.CLOSED), "Task not completed"); - } - - function testNonCreatorCannotUpdateTask() public { - vm.prank(nonAuthorized); - vm.expectRevert(Unauthorized.selector); - taskWorld.TASK__updateTaskAssignee(taskId, address(4)); - } - - function testNonAuthorizedCannotCompleteTask() public { - vm.prank(nonAuthorized); - vm.expectRevert(Unauthorized.selector); - taskWorld.TASK__completeTask(taskId); - } - - function testUpdateNonExistentTask() public { - uint256 invalidTaskId = uint256(keccak256("invalid")); - vm.prank(creator); - vm.expectRevert(TaskNotFound.selector); - taskWorld.TASK__updateTaskAssignee(invalidTaskId, address(4)); - } - - function testCompleteNonExistentTask() public { - uint256 invalidTaskId = uint256(keccak256("invalid")); - vm.prank(creator); - vm.expectRevert(TaskNotFound.selector); - taskWorld.TASK__completeTask(invalidTaskId); - } - - function testCreateTaskWithInvalidAssignee() public { - vm.prank(creator); - vm.expectRevert(InvalidAssignee.selector); - taskWorld.TASK__createTask(address(0), "Invalid task", block.timestamp + 1 days); - } - - function testCreateTaskWithInvalidDeadline() public { - vm.prank(creator); - vm.expectRevert(InvalidDeadline.selector); - taskWorld.TASK__createTask(assignee, "Invalid task", block.timestamp - 1); - } - - function testUpdateTaskWithInvalidAssignee() public { - vm.prank(creator); - vm.expectRevert(InvalidAssignee.selector); - taskWorld.TASK__updateTaskAssignee(taskId, address(0)); - } - - function testUpdateTaskWithInvalidDeadline() public { - vm.prank(creator); - vm.expectRevert(InvalidDeadline.selector); - taskWorld.TASK__updateTaskDeadline(taskId, block.timestamp - 1); - } -} diff --git a/packages/contracts/store/Tasklist/Constants.sol b/packages/contracts/store/Tasklist/Constants.sol deleted file mode 100644 index 527d69d..0000000 --- a/packages/contracts/store/Tasklist/Constants.sol +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.21; - -bytes14 constant DEPLOYMENT_NAMESPACE = "TASK"; - diff --git a/packages/contracts/store/Tasklist/Errors.sol b/packages/contracts/store/Tasklist/Errors.sol deleted file mode 100644 index 1e3100e..0000000 --- a/packages/contracts/store/Tasklist/Errors.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.21; - -// Custom errors for TaskSystem -error Unauthorized(); -error InvalidAssignee(); -error InvalidDeadline(); -error TaskNotFound(); diff --git a/packages/contracts/store/Tasklist/TaskSystem.sol b/packages/contracts/store/Tasklist/TaskSystem.sol deleted file mode 100644 index cbbc584..0000000 --- a/packages/contracts/store/Tasklist/TaskSystem.sol +++ /dev/null @@ -1,91 +0,0 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity >=0.8.24; - -// import { System } from "@latticexyz/world/src/System.sol"; -// import { Tasklist, TasklistData } from "@store/index.sol"; -// import { TaskStatus } from "@store/common.sol"; -// import "./Errors.sol"; - -// contract TaskSystem is System { -// event TaskCreated( -// uint256 indexed taskId, -// address indexed creator, -// address indexed assignee, -// string description, -// uint256 deadline, -// uint256 timestamp -// ); - -// event TaskUpdated(uint256 indexed taskId, address newAssignee, string newDescription, uint256 newDeadline); -// event TaskCompleted(uint256 indexed taskId); - -// modifier onlyCreator(uint256 taskId) { -// TasklistData memory task = Tasklist.get(taskId); -// if (task.creator != _msgSender()) revert Unauthorized(); -// _; -// } - -// modifier onlyExistentTask(uint256 taskId) { -// TasklistData memory task = Tasklist.get(taskId); -// if (task.creator == address(0)) revert TaskNotFound(); -// if (task.assignee == address(0)) revert InvalidAssignee(); -// if (task.deadline <= task.timestamp) revert InvalidDeadline(); - -// _; -// } - -// function createTask(address assignee, string memory description, uint256 deadline) public returns (uint256 taskId) { -// if (assignee == address(0)) revert InvalidAssignee(); -// if (deadline <= block.timestamp) revert InvalidDeadline(); - -// taskId = uint256(keccak256(abi.encode(description, deadline, _msgSender(), block.timestamp))); -// Tasklist.set( -// taskId, -// TasklistData({ -// creator: _msgSender(), -// assignee: assignee, -// description: description, -// timestamp: block.timestamp, -// deadline: deadline, -// status: TaskStatus.OPEN -// }) -// ); -// emit TaskCreated(taskId, _msgSender(), assignee, description, deadline, block.timestamp); - -// return taskId; -// } - -// function updateTaskAssignee(uint256 taskId, address newAssignee) public onlyExistentTask(taskId) onlyCreator(taskId) { -// TasklistData memory task = Tasklist.get(taskId); -// if (newAssignee == address(0)) revert InvalidAssignee(); - -// Tasklist.setAssignee(taskId, newAssignee); - -// emit TaskUpdated(taskId, newAssignee, task.description, task.deadline); -// } - -// function updateTaskDeadline(uint256 taskId, uint256 newDeadline) public onlyExistentTask(taskId) onlyCreator(taskId) { -// TasklistData memory task = Tasklist.get(taskId); -// if (newDeadline <= task.timestamp) revert InvalidDeadline(); - -// Tasklist.setDeadline(taskId, newDeadline); - -// emit TaskUpdated(taskId, task.assignee, task.description, newDeadline); -// } - -// function updateTaskDescription( -// uint256 taskId, -// string memory newDescription -// ) public onlyExistentTask(taskId) onlyCreator(taskId) { -// TasklistData memory task = Tasklist.get(taskId); - -// Tasklist.setDescription(taskId, newDescription); -// emit TaskUpdated(taskId, task.assignee, newDescription, task.deadline); -// } - -// function completeTask(uint256 taskId) public onlyExistentTask(taskId) onlyCreator(taskId) { -// Tasklist.setStatus(taskId, TaskStatus.CLOSED); - -// emit TaskCompleted(taskId); -// } -// } diff --git a/packages/contracts/store/script/PostDeploy.s.sol b/packages/contracts/store/script/PostDeploy.s.sol deleted file mode 100644 index 9f7e2cf..0000000 --- a/packages/contracts/store/script/PostDeploy.s.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { Script } from "forge-std/Script.sol"; -import { console } from "forge-std/console.sol"; -import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; - -import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol"; - - -contract PostDeploy is Script { - function run(address worldAddress) external { - // Specify a store so that you can use tables directly in PostDeploy - // StoreSwitch.setStoreAddress(worldAddress); - // IBaseWorld world = IBaseWorld(worldAddress); - - // Load the private key from the `PRIVATE_KEY` environment variable (in .env) - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - // Start broadcasting transactions from the deployer account - - vm.startBroadcast(deployerPrivateKey); - vm.stopBroadcast(); - } -} diff --git a/packages/contracts/store/script/Tasks/CompleteTask.s.sol b/packages/contracts/store/script/Tasks/CompleteTask.s.sol deleted file mode 100644 index a4fff26..0000000 --- a/packages/contracts/store/script/Tasks/CompleteTask.s.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { Script } from "node_modules/forge-std/src/Script.sol"; -import { console } from "node_modules/forge-std/src/console.sol"; -import { StoreSwitch } from "node_modules/@latticexyz/store/src/StoreSwitch.sol"; -import { taskSystem } from "../../src/codegen/systems/TaskSystemLib.sol"; - -contract CompleteTask is Script { - function run( - address worldAddress, - uint256 taskId - ) external { - StoreSwitch.setStoreAddress(worldAddress); - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - vm.startBroadcast(deployerPrivateKey); - taskSystem.completeTask(taskId); - console.log("Completed task with ID:", taskId); - vm.stopBroadcast(); - } -} diff --git a/packages/contracts/store/script/Tasks/CreateTask.s.sol b/packages/contracts/store/script/Tasks/CreateTask.s.sol deleted file mode 100644 index 8dbad56..0000000 --- a/packages/contracts/store/script/Tasks/CreateTask.s.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { Script } from "node_modules/forge-std/src/Script.sol"; -import { console } from "node_modules/forge-std/src/console.sol"; -import { StoreSwitch } from "node_modules/@latticexyz/store/src/StoreSwitch.sol"; -import { taskSystem } from "../../src/codegen/systems/TaskSystemLib.sol"; - -contract CreateTask is Script { - function run( - address worldAddress, - address assignee, - string memory description, - uint256 deadline - ) external { - StoreSwitch.setStoreAddress(worldAddress); - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - vm.startBroadcast(deployerPrivateKey); - uint256 taskId = taskSystem.createTask( - assignee, - description, - deadline - ); - console.logString("Created task with ID:"); - console.logUint(taskId); - vm.stopBroadcast(); - } -} diff --git a/packages/contracts/store/script/Tasks/UpdateTaskAssignee.s.sol b/packages/contracts/store/script/Tasks/UpdateTaskAssignee.s.sol deleted file mode 100644 index e562b99..0000000 --- a/packages/contracts/store/script/Tasks/UpdateTaskAssignee.s.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { Script } from "node_modules/forge-std/src/Script.sol"; -import { console } from "node_modules/forge-std/src/console.sol"; -import { StoreSwitch } from "node_modules/@latticexyz/store/src/StoreSwitch.sol"; -import { taskSystem } from "../../src/codegen/systems/TaskSystemLib.sol"; - -contract UpdateTaskAssignee is Script { - function run( - address worldAddress, - uint256 taskId, - address newAssignee - ) external { - StoreSwitch.setStoreAddress(worldAddress); - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - vm.startBroadcast(deployerPrivateKey); - taskSystem.updateTaskAssignee(taskId, newAssignee); - console.log("Updated task assignee for task ID:", taskId); - vm.stopBroadcast(); - } -} diff --git a/packages/contracts/store/script/Tasks/UpdateTaskDeadline.s.sol b/packages/contracts/store/script/Tasks/UpdateTaskDeadline.s.sol deleted file mode 100644 index 30f6577..0000000 --- a/packages/contracts/store/script/Tasks/UpdateTaskDeadline.s.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { Script } from "node_modules/forge-std/src/Script.sol"; -import { console } from "node_modules/forge-std/src/console.sol"; -import { StoreSwitch } from "node_modules/@latticexyz/store/src/StoreSwitch.sol"; -import { taskSystem } from "../../src/codegen/systems/TaskSystemLib.sol"; - -contract UpdateTaskDeadline is Script { - function run( - address worldAddress, - uint256 taskId, - uint256 newDeadline - ) external { - StoreSwitch.setStoreAddress(worldAddress); - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - vm.startBroadcast(deployerPrivateKey); - taskSystem.updateTaskDeadline(taskId, newDeadline); - console.log("Updated task deadline for task ID:", taskId); - vm.stopBroadcast(); - } -} diff --git a/packages/contracts/store/script/Tasks/UpdateTaskDescription.s.sol b/packages/contracts/store/script/Tasks/UpdateTaskDescription.s.sol deleted file mode 100644 index 3d8fbd8..0000000 --- a/packages/contracts/store/script/Tasks/UpdateTaskDescription.s.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { Script } from "node_modules/forge-std/src/Script.sol"; -import { console } from "node_modules/forge-std/src/console.sol"; -import { StoreSwitch } from "node_modules/@latticexyz/store/src/StoreSwitch.sol"; -import { taskSystem } from "../../src/codegen/systems/TaskSystemLib.sol"; - -contract UpdateTaskDescription is Script { - function run( - address worldAddress, - uint256 taskId, - string memory newDescription - ) external { - StoreSwitch.setStoreAddress(worldAddress); - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - vm.startBroadcast(deployerPrivateKey); - taskSystem.updateTaskDescription(taskId, newDescription); - console.log("Updated task description for task ID:", taskId); - vm.stopBroadcast(); - } -} From b697eaec18df04c171e72fcdce92e29aaa83c0f1 Mon Sep 17 00:00:00 2001 From: blurpesec Date: Thu, 28 Aug 2025 12:24:12 -0700 Subject: [PATCH 2/3] fix: deposit/withdraw when transferrer is a system --- packages/contracts/package.json | 3 +- .../systems/StorageSystem/StorageSystem.sol | 9 +- .../test/StorageManager/MockTest.t.sol | 0 .../ProxyDepositorSystemTest.t.sol | 83 ++++++++++++++ .../StoreAuthDelegatedAccessTest.t.sol | 70 ++++++++++++ .../StorageManagerProxyDepositorSystem.sol | 32 ++++++ .../contracts/test/mocks/TestAccessSystem.sol | 105 ++++++++++++++++++ 7 files changed, 297 insertions(+), 5 deletions(-) delete mode 100644 packages/contracts/test/StorageManager/MockTest.t.sol create mode 100644 packages/contracts/test/StorageManager/ProxyDepositorSystemTest.t.sol create mode 100644 packages/contracts/test/StorageManager/StoreAuthDelegatedAccessTest.t.sol create mode 100644 packages/contracts/test/mocks/StorageManagerProxyDepositorSystem.sol create mode 100644 packages/contracts/test/mocks/TestAccessSystem.sol diff --git a/packages/contracts/package.json b/packages/contracts/package.json index f02e346..891df54 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -25,8 +25,7 @@ "coverage": ". ./.env.local && forge coverage --ir-minimum --fork-url $RPC_URL -vvvv", "configure-ssu": ". ./.env && pnpm forge script ./script/ConfigureSSU.s.sol:ConfigureSSU --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID --sig \"run()\" $WORLD_ADDRESS", "create-nested-bucket": ". ./.env && pnpm forge script ./script/CreateNestedBucket.s.sol:CreateNestedBucket --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID --sig \"run(string)\" $WORLD_ADDRESS", - "install:storage-manager": ". ./.env.local && pnpm forge script ./scripts/InstallStorageManager.s.sol:InstallStorageManager --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID -vvvv", - "pretest": "pnpm run install:storage-manager" + "install:storage-manager": ". ./.env.local && pnpm forge script ./scripts/InstallStorageManager.s.sol:InstallStorageManager --broadcast --rpc-url $RPC_URL --chain-id $CHAIN_ID -vvvv" }, "publishConfig": { "access": "public" diff --git a/packages/contracts/src/systems/StorageSystem/StorageSystem.sol b/packages/contracts/src/systems/StorageSystem/StorageSystem.sol index bee2d89..838b9f1 100644 --- a/packages/contracts/src/systems/StorageSystem/StorageSystem.sol +++ b/packages/contracts/src/systems/StorageSystem/StorageSystem.sol @@ -4,6 +4,7 @@ import { InventoryItemParams } from "@eveworld/world-v2/src/namespaces/evefronti import { InventoryItem } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/InventoryItem.sol"; import { OwnershipByObject } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/OwnershipByObject.sol"; import { System } from "@latticexyz/world/src/System.sol"; +import { IWorldWithContext } from "@eveworld/smart-object-framework-v2/src/IWorldWithContext.sol"; import { storeAuthSystem } from "../../codegen/systems/StoreAuthSystemLib.sol"; import { storeLogicSystem } from "../../codegen/systems/StoreLogicSystemLib.sol"; @@ -46,6 +47,7 @@ contract StorageSystem is System { if (!storeAuthSystem.canDeposit(smartObjectId, bucketId, _msgSender())) { revert UnauthorizedDeposit(); } + (, , address transferrer, ) = IWorldWithContext(_world()).getWorldCallContext(1); // for each item in transferItems, check if the item exists in the BucketedInventoryItem table for the bucketId // if it does, transfer the item from the ephemeral inventory to the primary inventory // if it doesn't, create a new entry in the BucketedInventoryItem table for the item and transfer @@ -54,7 +56,7 @@ contract StorageSystem is System { InventoryItemParams memory item = transferItems[i]; // if is depositing from primary inventory, check if the item has a net quantity in the primary inventory (i.e - not already allocated to a bucket) if (useOwnerInventory) { - if (_msgSender() != OwnershipByObject.getAccount(smartObjectId)) { + if (transferrer != OwnershipByObject.getAccount(smartObjectId)) { revert UnauthorizedDepositFromOwnerInventory(); } uint256 primaryInventoryQuantity = InventoryItem.getQuantity(smartObjectId, item.smartObjectId); @@ -70,7 +72,7 @@ contract StorageSystem is System { } // transfer the items from the ephemeral inventory to the primary inventory if (!useOwnerInventory) { - storeProxySystem.proxyTransferFromEphemeral(smartObjectId, _msgSender(), transferItems); + storeProxySystem.proxyTransferFromEphemeral(smartObjectId, transferrer, transferItems); } } @@ -83,6 +85,7 @@ contract StorageSystem is System { if (!storeAuthSystem.canWithdraw(smartObjectId, bucketId, _msgSender())) { revert UnauthorizedWithdraw(); } + (, , address transferrer, ) = IWorldWithContext(_world()).getWorldCallContext(1); for (uint i = 0; i < transferItems.length; ) { InventoryItemParams memory item = transferItems[i]; @@ -97,7 +100,7 @@ contract StorageSystem is System { i = unsafe_increment(i); } if (!useOwnerInventory) { - storeProxySystem.proxyTransferToEphemeral(smartObjectId, _msgSender(), transferItems); + storeProxySystem.proxyTransferToEphemeral(smartObjectId, transferrer, transferItems); } } diff --git a/packages/contracts/test/StorageManager/MockTest.t.sol b/packages/contracts/test/StorageManager/MockTest.t.sol deleted file mode 100644 index e69de29..0000000 diff --git a/packages/contracts/test/StorageManager/ProxyDepositorSystemTest.t.sol b/packages/contracts/test/StorageManager/ProxyDepositorSystemTest.t.sol new file mode 100644 index 0000000..9dd5eb5 --- /dev/null +++ b/packages/contracts/test/StorageManager/ProxyDepositorSystemTest.t.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol"; +import { WorldResourceIdLib } from "@latticexyz/world/src/WorldResourceId.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; +import { RESOURCE_SYSTEM } from "@latticexyz/world/src/worldResourceTypes.sol"; +import { SystemRegistry } from "@latticexyz/world/src/codegen/tables/SystemRegistry.sol"; + +import { EphemeralInvItem } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/EphemeralInvItem.sol"; +import { InventoryItem } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/tables/InventoryItem.sol"; +import { InventoryItemParams } from "@eveworld/world-v2/src/namespaces/evefrontier/systems/inventory/types.sol"; +import { EphemeralInteractSystemLib, ephemeralInteractSystem } from "@eveworld/world-v2/src/namespaces/evefrontier/codegen/systems/EphemeralInteractSystemLib.sol"; + +import { BucketedInventoryItem } from "../../src/codegen/tables/BucketedInventoryItem.sol"; +import { storeAuthSystem } from "../../src/codegen/systems/StoreAuthSystemLib.sol"; +import { StorageManagerProxyDepositorSystem } from "../mocks/StorageManagerProxyDepositorSystem.sol"; +import { TestAccessSystem } from "../mocks/TestAccessSystem.sol"; +import { SetupTestWithBucketsTest } from "../SetupTestWithBucketsTest.t.sol"; + +contract ProxyDepositorSystemTest is SetupTestWithBucketsTest { + ResourceId private proxySystemId; + + function setUp() public override { + super.setUp(); + + // Deploy and register the proxy depositor system under a dedicated namespace + vm.startPrank(admin); + bytes14 NS = "proxy_deposit"; + ResourceId nsRes = WorldResourceIdLib.encodeNamespace(NS); + try IBaseWorld(worldAddress).registerNamespace(nsRes) {} catch {} + + StorageManagerProxyDepositorSystem proxy = new StorageManagerProxyDepositorSystem(); + proxySystemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: NS, name: "Depositor" }); + IBaseWorld(worldAddress).registerSystem(proxySystemId, proxy, true); + + // Register a permissive access system and set it for this bucket so proxy system can be the caller + TestAccessSystem access = new TestAccessSystem(); + ResourceId accessSystemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: NS, name: "TestAccessSystem" }); + IBaseWorld(worldAddress).registerSystem(accessSystemId, access, true); + // Sanity: ensure registry maps to the id + ResourceId fetched = SystemRegistry.getSystemId(address(access)); + require(ResourceId.unwrap(fetched) == ResourceId.unwrap(accessSystemId), "access id mismatch"); + storeAuthSystem.setAccessSystemId(ssuId, bucketId, accessSystemId); + + // Ensure ephemeral transfer-from is authorized for the store proxy (already done in base), keep as-is + // ephemeralInteractSystem.setTransferFromEphemeralAccess(ssuId, storeProxySystemAddress, true); + + vm.stopPrank(); + } + + function testProxyDepositFromEphemeral() public { + // Prepare a small deposit sourced from player's ephemeral inventory + uint64 qty = 7; + InventoryItemParams[] memory items = new InventoryItemParams[](1); + items[0] = InventoryItemParams({ smartObjectId: itemId, quantity: qty }); + + uint64 ephBefore = uint64(EphemeralInvItem.getQuantity(ssuId, player, itemId)); + uint64 bucketBefore = uint64(BucketedInventoryItem.getQuantity(bucketId, itemId)); + uint64 primaryBefore = uint64(InventoryItem.getQuantity(ssuId, itemId)); + + // Call the proxy system via the world to preserve player as _msgSender at the world layer, + // but StorageSystem will receive this system as the caller, which is allowed by TestAccessSystem. + vm.startPrank(player); + IBaseWorld(worldAddress).callFrom( + player, + proxySystemId, + abi.encodeCall(StorageManagerProxyDepositorSystem.depositFromEphemeral, (ssuId, bucketId, items)) + ); + vm.stopPrank(); + + uint64 ephAfter = uint64(EphemeralInvItem.getQuantity(ssuId, player, itemId)); + uint64 bucketAfter = uint64(BucketedInventoryItem.getQuantity(bucketId, itemId)); + uint64 primaryAfter = uint64(InventoryItem.getQuantity(ssuId, itemId)); + + assertEq(ephAfter, ephBefore - qty, "Ephemeral balance should decrease by qty"); + assertEq(bucketAfter, bucketBefore + qty, "Bucket balance should increase by qty"); + assertEq(primaryAfter, primaryBefore + qty, "Primary inventory should increase by qty"); + } +} diff --git a/packages/contracts/test/StorageManager/StoreAuthDelegatedAccessTest.t.sol b/packages/contracts/test/StorageManager/StoreAuthDelegatedAccessTest.t.sol new file mode 100644 index 0000000..d8a4efa --- /dev/null +++ b/packages/contracts/test/StorageManager/StoreAuthDelegatedAccessTest.t.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import { SystemRegistry } from "@latticexyz/world/src/codegen/tables/SystemRegistry.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; +import { WorldResourceIdLib } from "@latticexyz/world/src/WorldResourceId.sol"; +import { RESOURCE_SYSTEM } from "@latticexyz/world/src/worldResourceTypes.sol"; +import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol"; + +import { SetupTestWithBucketsTest } from "../SetupTestWithBucketsTest.t.sol"; +import { storeAuthSystem } from "../../src/codegen/systems/StoreAuthSystemLib.sol"; +import { BucketMetadata } from "../../src/codegen/tables/BucketMetadata.sol"; +import { TestAccessSystem } from "../mocks/TestAccessSystem.sol"; + +contract StoreAuthDelegatedAccessTest is SetupTestWithBucketsTest { + // Use a dedicated test namespace to avoid ownership issues + bytes14 constant TEST_NS = "test_access"; + + function setUp() public override { + super.setUp(); + // Ensure test namespace exists (idempotent) + ResourceId nsRes = WorldResourceIdLib.encodeNamespace(TEST_NS); + vm.startPrank(admin); + try IBaseWorld(worldAddress).registerNamespace(nsRes) { + // namespace registered + } catch { + // already registered; continue + } + + // Deploy custom access system + TestAccessSystem access = new TestAccessSystem(); + + // Register the system under the test namespace + ResourceId accessSystemId = WorldResourceIdLib.encode({ + typeId: RESOURCE_SYSTEM, + namespace: TEST_NS, + name: "TestAccessSystem" + }); + + IBaseWorld(worldAddress).registerSystem(accessSystemId, access, true); + vm.stopPrank(); + + // Validate registry mapping and set on the target bucket + ResourceId fetchedId = SystemRegistry.getSystemId(address(access)); + assertEq(ResourceId.unwrap(fetchedId), ResourceId.unwrap(accessSystemId), "SystemRegistry id mismatch"); + + // Only bucket owner (admin) can set the access system id + vm.startPrank(admin); + storeAuthSystem.setAccessSystemId(ssuId, bucketId, accessSystemId); + vm.stopPrank(); + + // Now canDeposit/canWithdraw should be delegated to TestAccessSystem, which returns true + bool canDep = storeAuthSystem.canDeposit(ssuId, bucketId, player); + assertTrue(canDep, "Expected delegated canDeposit to return true"); + + bool canW = storeAuthSystem.canWithdraw(ssuId, bucketId, player); + assertFalse(canW, "Expected delegated canWithdraw to return false since TestAccessSystem is a drop-only system"); + + // canTransferBucket is delegated and returns false in TestAccessSystem + bool canTransfer = storeAuthSystem.canTransferBucket(ssuId, bucketId, player); + assertFalse(canTransfer, "Expected delegated canTransferBucket to return false"); + } + + function testRegisterDelegatedAccessSystemAndAuthorize() public { + + } +} diff --git a/packages/contracts/test/mocks/StorageManagerProxyDepositorSystem.sol b/packages/contracts/test/mocks/StorageManagerProxyDepositorSystem.sol new file mode 100644 index 0000000..713e860 --- /dev/null +++ b/packages/contracts/test/mocks/StorageManagerProxyDepositorSystem.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import { System } from "@latticexyz/world/src/System.sol"; +import { InventoryItemParams } from "@eveworld/world-v2/src/namespaces/evefrontier/systems/inventory/types.sol"; + +import { storageSystem } from "../../src/codegen/systems/StorageSystemLib.sol"; + + +// A simple system that owns interactions with StorageManager by proxying deposits +// to the underlying StorageSystem. This allows buckets to delegate access to this +// system ID and gate who can initiate deposits via StoreAuthSystem policies. +contract StorageManagerProxyDepositorSystem is System { + // Deposit items sourced from the caller's ephemeral inventory into a bucket + function depositFromEphemeral( + uint256 smartObjectId, + bytes32 bucketId, + InventoryItemParams[] memory items + ) public { + storageSystem.deposit(smartObjectId, bucketId, false, items); + } + + // Deposit items sourced from the owner's primary inventory into a bucket + // Caller must be the owner of the smartObjectId per StorageSystem checks + function depositFromOwner( + uint256 smartObjectId, + bytes32 bucketId, + InventoryItemParams[] memory items + ) public { + storageSystem.deposit(smartObjectId, bucketId, true, items); + } +} diff --git a/packages/contracts/test/mocks/TestAccessSystem.sol b/packages/contracts/test/mocks/TestAccessSystem.sol new file mode 100644 index 0000000..1ac4865 --- /dev/null +++ b/packages/contracts/test/mocks/TestAccessSystem.sol @@ -0,0 +1,105 @@ +pragma solidity ^0.8.24; + +import { console } from "forge-std/console.sol"; +import { ResourceId, WorldResourceIdInstance } from "@latticexyz/world/src/WorldResourceId.sol"; +import { System } from "@latticexyz/world/src/System.sol"; +import { IWorldWithContext } from "@eveworld/smart-object-framework-v2/src/IWorldWithContext.sol"; +import { SmartObjectFramework } from "@eveworld/smart-object-framework-v2/src/inherit/SmartObjectFramework.sol"; +import { CallAccess } from "@eveworld/smart-object-framework-v2/src/namespaces/evefrontier/codegen/tables/CallAccess.sol"; + + +contract TestAccessSystem is SmartObjectFramework { + // This system is used to manage access to the store's bucket. + // It should adhere to @awar-dev/storage-manager's delegated + // access control standard (v0.2.0). + + /** + * @notice Check if the sender can deposit into a bucket (for dex - we want this to be locked down to be true + * @param smartObjectId The id of the smart object + * @param bucketId The id of the bucket to check access for + * @param sender The address of the sender + * @return bool True if the sender can deposit, false otherwise + * @dev This function should be called by the test system to check if a deposit is allowed. + * It should return true if the sender is allowed to deposit into the bucket + * and false otherwise. The access control logic that calls this should be implemented in the StoreAuthSystem. + */ + function canDeposit(uint256 smartObjectId, bytes32 bucketId, address sender) public view context returns (bool) { + // iterate through each of the current world call count - find it's address and log it + if has a system, log the system too + uint256 currentCallCount = IWorldWithContext(_world()).getWorldCallCount(); + if (currentCallCount < 2) { + return false; + } + // for (uint i = 1; i <= currentCallCount; i++) { + // (ResourceId sysid, bytes4 fnid, address msgSender, ) = IWorldWithContext(_world()).getWorldCallContext(i); + // console.log("Call Context - Index:"); + // console.logUint(i); + // console.log(i); + // // Log the address of the system that made the call, it's systemId, selector, and sender and then determine it's name by decodig the ResourceId + // // address selectedCallSystemAddress = world.getSystemAddress(selectedCallSystemId); + // // console.log("Call Context - System Address:", selectedCallSystemAddress); + // // console.log("Call Context - System ID:", selectedCallSystemId); + // console.log("Call Context - System Name:"); + // console.logBytes16(WorldResourceIdInstance.getName(sysid)); + // console.log(WorldResourceIdInstance.toString(sysid)); + // // console.log("Call Context - Selector:", selectedCallSelector); + // // console.log("Call Context - Sender:", selectedCallSender); + // // console.log("Call Context - Value:", selectedCallValue); + // console.log("Call Context - Msg Sender:", msgSender); + // } + // console.log("Retrying with exact check"); + (, , /*ResourceId sysid, bytes4 fnid, */ address msgSender, ) = IWorldWithContext(_world()).getWorldCallContext( + currentCallCount - 2 + ); + // console.log("Call Context - System Name:"); + // console.logBytes16(WorldResourceIdInstance.getName(sysid)); + // console.log(WorldResourceIdInstance.toString(sysid)); + // // console.log("Call Context - Selector:", selectedCallSelector); + // // console.log("Call Context - Sender:", selectedCallSender); + // // console.log("Call Context - Value:", selectedCallValue); + // console.log("Call Context - Msg Sender:", msgSender); + // if (msgSender == address(orderbookDexSystem.getAddress())) { + // // Allow the test system to deposit into the bucket + // return true; + // } + return true; + } + + /** + * @notice Check if the sender can withdraw from a bucket (for dex - we want this to be locked down to only the test system) + * @param smartObjectId The id of the smart object + * @param bucketId The id of the bucket to check access for + * @param sender The address of the sender + * @return bool True if the sender can withdraw, false otherwise + * @dev This function should be called by the test system to check if a withdrawal is allowed. + * It should return true if the sender is allowed to withdraw from the bucket + * and false otherwise. The access control logic that calls this should be implemented in the StoreAuthSystem. + */ + function canWithdraw(uint256 smartObjectId, bytes32 bucketId, address sender) public view context returns (bool) { + uint256 currentCallCount = IWorldWithContext(_world()).getWorldCallCount(); + if (currentCallCount < 2) { + return false; + } + (ResourceId sysid, bytes4 fnid, address msgSender, ) = IWorldWithContext(_world()).getWorldCallContext( + currentCallCount - 2 + ); + // if (msgSender == address(orderbookDexSystem.getAddress())) { + // // Allow the test system to withdraw from the bucket + // return true; + // } + return false; + } + + /** + * @notice Check if the sender can transfer a bucket to a different parent + * @param smartObjectId The id of the smart object + * @param bucketId The id of the bucket to check access for + * @param sender The address of the sender + * @return bool True if the sender can transfer the bucket, false otherwise + * @dev This function should be called by the test system to check if a transfer of the bucket is allowed. + * It should return false always + */ + function canTransferBucket(uint256 smartObjectId, bytes32 bucketId, address sender) public pure returns (bool) { + // Allow no one to transfer buckets except the test system + return false; + } +} From 5b40a56f01a9067126bbea17302a485c95e4b8b9 Mon Sep 17 00:00:00 2001 From: blurpesec Date: Thu, 28 Aug 2025 12:25:40 -0700 Subject: [PATCH 3/3] chore: iterated ver --- packages/contracts/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 891df54..b0905ab 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -4,7 +4,7 @@ "name": "blurpesec", "email": "hahn.michael.f@gmail.com" }, - "version": "0.2.2", + "version": "0.2.3", "private": false, "license": "MIT", "scripts": {