Upgrading worlds
The System
s can be upgraded without changing the underlying World
code, using mud deploy --worldAddress
.
However, you can also upgrade the World
contract itself if the World
was deployed behind a proxy.
This allows you to upgrade to a future version of MUD, but adds some gas overhead for all calls (due to one more level of indirection).
Making an upgradeable World
To make a World
upgradeable, edit the mud.config.ts
file and set deploy.upgradeableWorldImplementation
to true
.
import { defineWorld } from "@latticexyz/world";
export default defineWorld({
deploy: {
upgradeableWorldImplementation: true,
},
tables: {
Counter: {
schema: {
value: "uint32",
},
key: [],
},
},
});
Testing if upgrades are possible
As per ERC-1967 (opens in a new tab), the storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
stores the address of the contract implementation in a proxy.
So to identify if a World
is deployed behind a proxy run these commands:
WORLD_ADDRESS=0xbe6b85dc88f969e45d8d8ae128c5a9c9744d6464
cast implementation $WORLD_ADDRESS
If the answer is anything other than zero, the World
is behind a proxy and can be upgraded.
Performing an upgrade
To upgrade the World
use these steps in a package/contracts
directory:
-
Edit
.env
to addWORLD_ADDRESS
with the address displayed by MUD Dev Tools. For example, you might want to use this file:.env# This .env file is for demonstration purposes only. # # This should usually be excluded via .gitignore and the env vars attached to # your deployment environment, but we're including this here for ease of local # development. Please do not commit changes to this file! # # Enable debug logs for MUD CLI DEBUG=mud:* # # Anvil default private key: PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 WORLD_ADDRESS=0xbe6b85dc88f969e45d8d8ae128c5a9c9744d6464
-
Create this script in
scripts/UpgradeWorld.s.sol
.UpgradeWorld.s.sol// SPDX-License-Identifier: MIT pragma solidity >=0.8.24; import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; import { World } from "@latticexyz/world/src/World.sol"; import { WorldProxy } from "@latticexyz/world/src/WorldProxy.sol"; contract SetImplementation is Script { function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); address proxyAddress = vm.envAddress("WORLD_ADDRESS"); // Deploy new world implementation World newWorld = new World(); console.log("proxy:", proxyAddress); console.log("new World:", address(newWorld)); WorldProxy(payable(proxyAddress)).setImplementation(address(newWorld)); vm.stopBroadcast(); } }
-
Run the script.
forge script script/UpgradeWorld.s.sol --rpc-url http://localhost:8545 --broadcast
-
See the new address.
source .env cast implementation $WORLD_ADDRESS