Contracts

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.