Primodium Contracts
Primodium contracts conform to the open MUD standard (opens in a new tab). The entry point to all smart contracts is a single world (opens in a new tab) contract, with logic stored in system (opens in a new tab) contracts and data stored in table (opens in a new tab) contracts.
Primodium contracts are primarily written in Solidity (opens in a new tab) and deployable to any environment compatible with the Ethereum virtual machine (opens in a new tab).
Introduction
All Primodium contracts are available in the
/packages/contracts
(opens in a new tab)
directory in the
@primodiumxyz/primodium
(opens in a new tab)
monorepo.
Overview
These contracts are separated into two main directories: libraries (opens in a new tab) and systems (opens in a new tab). The libraries are used to define core logic that is used across systems, which are more opinionated and specific to a component of the game.
All of these get "compiled" into a codegen
directory, which is internally used
for actually updating the game state. The generated codegen
is available in
the
@primodiumxyz/contracts (opens in a new tab)
package and referenced by external smart contracts to interact with the game
state.
The package also includes TypeScript utilities for generating terrains, tables and prototypes (opens in a new tab).
The main entry point for the package is mud.config.ts (opens in a new tab), which houses the tables and world inputs, and it also exports various constants, enums and prototype configurations (opens in a new tab) for usage from other packages.
The actual configuration—applying the initial prototype configuration (opens in a new tab) to the game state—is done in the PostDeploy (opens in a new tab) script, ran after the contracts are deployed.
Installation
Follow the README in the root of the monorepo to install the necessary dependencies and configure the environment.
This package needs its own .env
file for specifying the deployer's private
key:
# From this directory:
# The default anvil private key
echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" >> .env
Structure
broadcast - "History of transactions ran from the scripts (ignored by git)"
cache - "Foundry cache (ignored by git)"
config - "Prototype and terrain configuration for initial game state"
deploys - "History of deployments (ignored by git)"
out - "Built ABIs for all systems (ignored by git)"
script - "Additional scripts for after-deployment setup"
src - "Source files"
├── codegen - "MUD-generated Solidity files"
├── hooks - "Hooks for internal logic"
├── libraries - "Core logic for the game"
└── systems - "Core logic applied to game systems"
test - "Test files"
ts - "TypeScript utilities for generating terrains, tables and prototypes"
Development
Building
To build the contracts, run:
pnpm build
This will run the following commands sequentially:
pnpm run build:lib # Generates source contracts in codegen and terrain
pnpm run build:mud # Generates prototypes and compiles contracts
pnpm run build:abi-ts # Generates TypeScript bindings for the contracts
Testing
To test the contracts, run:
pnpm test
This will build the contracts and run the tests with MUD.
If you want to test a specific contract and skip build, you can run:
pnpm mud test --skipBuild --forgeOptions='--mc <contract_name>'
Usage
Generally, you should refer directly to the MUD documentation (opens in a new tab) for more information on how to modify the MUD config, add systems, etc.
If you would like to add an extension to the game, you can directly refer to the dedicated package in this monorepo (opens in a new tab).
You can directly add a system or library in their respective directories, and they will be included in the codegen in the next build.
For tables, you can directly add them in the
mud.config.ts
(opens in a new tab)
file with their schema, and they will be available in the client with TypeScript
bindings.
If this is a prototype table (P_<table_name>
), you can add a prototype
configuration (or settings) in the
prototypeConfig.ts
(opens in a new tab)
file, and it will be applied to the game state when the contracts are deployed.
A note during development; the DevSystem
will expose direct table access.
Meaning that you can directly modify the state for any table at a low level from
the client. For instance:
// To set some data on a table:
DevSystem.devSetRecord(tableId, key, data, valueSchema);
// To remove a record:
DevSystem.devDeleteRecord(tableId, key, valueSchema);
Deployment
For deployment instructions, see the README (opens in a new tab) in the root of the monorepo.