Source for Primodium System Interfaces
@primodiumxyz/contracts/src/codegen/world
(opens in a new tab): Generated Solidity interfaces for each publicly-accessible system.
Primodium Systems in World Extensions
There are two ways to reference Primodium systems in a world extension:
- Install the
@primodiumxyz/contracts
package and import the system interfaces directly. - Copy the system interfaces to your world extension project and import them from there.
Installing the @primodiumxyz/contracts
package
If your world extension is a Foundry (opens in a new tab) project, you
can install the @primodiumxyz/contracts
package as a dependency. In the root
directory of your world extension project, run the following command:
pnpm install @primodiumxyz/contracts
Make sure the project's foundry.toml
references node_modules
as a package
directory.
[profile.default]
# ...
allow_paths = [
# pnpm symlinks to the project root's node_modules
"../../node_modules",
# template uses linked mud packages from within the mud monorepo
"../../../../packages",
# projects created from this template and using linked mud packages
"../../../mud/packages",
]
#...
Then, update remappings.txt
to point to the installed package. For example, if
you are using the @primodiumxyz/contracts
package in a world extension, update
the remappings.txt
file as follows:
primodium=node_modules/@primodiumxyz/contracts/src/codegen/
The ReadDemo
world extension example references
system interfaces directly from @primodiumxyz/contracts
. The following snipped
highlights lines on how to import and reference the Home
table.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.24;
import { System } from "@latticexyz/world/src/System.sol";
import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol";
import { Home } from "primodium/tables/Home.sol";
import { Level } from "primodium/tables/Level.sol";
// We're building a System, to extend the System contract
contract ReadDemoSystem is System {
function readMainBaseLevel() public returns (uint32) {
// we want to read from the Primodium World, not the Extension World
StoreSwitch.setStoreAddress(_world());
// Get the players ID
// msg.sender in this case will be the World. We want the player instead.
// use _msgSender() to get the address of the player calling the function
bytes32 playerEntity = bytes32(uint256(uint160(_msgSender())));
// Home.get is dual purpose. Using it on a player ID returns their home asteroid ID
// Using it on an asteroid ID returns the base building ID of that asteroid
// get the ID of the players home base asteroid
bytes32 asteroidEntity = Home.get(playerEntity);
// get the ID of the base building on the players home base asteroid
bytes32 baseEntity = Home.get(asteroidEntity);
// get and return the level of the base building
return uint32(Level.get(baseEntity));
}
}
Directly Referencing System Interfaces
The BuildingUpgradeBounty
world
extension example requires a reference to functions in the Primodium
UpgradeBuildingSystem
, which handles building upgrades. The following steps
demonstrate how to reference the UpgradeBuildingSystem
in a world extension
and successfully its function upgradeBuilding()
.
First, copy the following folders to your Primodium extension project:
@primodiumxyz/contracts/src/codegen/world
(opens in a new tab): contains references to all system interfaces.@primodiumxyz/contracts/src/codegen/common.sol
(opens in a new tab): contains generated Solidity enums and structs for common types.
In the BuildingUpgradeBounty
example, the above files are copied to
/examples/BuildingUpgradeBounty/packages/contracts/src/primodium-codegen
(opens in a new tab).
Locate the function you want to call in the generated system interfaces. In this
case, we want to call the upgrade Pri_11__upgradeBuilding()
, whose function
signature is obtained from the generated IUpgradeBuildingSystem
.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.24;
/* Autogenerated file. Do not edit manually. */
/**
* @title IUpgradeBuildingSystem
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @dev This interface is automatically generated from the corresponding system contract. Do not edit manually.
*/
interface IUpgradeBuildingSystem {
function Pri_11__upgradeBuilding(bytes32 buildingEntity) external;
}
The upgradeBuilding()
function in BuildSystem
can then be called as follows,
with UpgradeBuildingS
being the system ID of the Primodium
UpgradeBuildingSystem
cut off at 16 bytes. See
footguns for more details.
import { IWorld as IPrimodiumWorld } from "../primodium-codegen/world/IWorld.sol";
contract UpgrBounSystem is System {
/**
* @dev Upgrades a specified building using the bounty published by the given address.
* @param bountyPublisherAddress The address of the bounty publisher.
* @param buildingEntityParam The building to upgrade.
* @return newBuildingEntity The new building entity.
*/
function upgradeForBounty(
address bountyPublisherAddress,
bytes32 buildingEntityParam
) public returns (bytes memory newBuildingEntity) {
// ...
// Call the upgradeBuilding function from the World contract
ResourceId upgradeBuildingSystemId = WorldResourceIdLib.encode(RESOURCE_SYSTEM, PRIMODIUM_NAMESPACE, "UpgradeBuildingS");
newBuildingEntity = IPrimodiumWorld(_world()).callFrom(
bountyPublisherAddress,
upgradeBuildingSystemId,
abi.encodeWithSignature("upgradeBuilding(bytes32)", buildingEntity)
);
// ...
}
}