Skip to content
Player's Guide

MultiOwnable — Shared Control

One-line pitch: MultiOwnable lets a contract have many owners instead of just one. Every owner has equal admin power. This is the pattern every token in Dysnomia inherits.

Standard OpenZeppelin Ownable has one owner. MultiOwnable flips that to a set of authorized addresses. The onlyOwners modifier gates any privileged function; any address in _owners passes.

This isn’t just a convenience — the whole Dysnomia system depends on contracts being able to add each other as owners. That’s how LAU gives VOID permission to mint for it, how WAR gets permission to mint H2O, and so on.

  • Closest analogy: a joint bank account — any signer can transact.
  • Or: OpenZeppelin’s AccessControl (a role-based extension with multiple admins).
  • Or: a Safe with 1-of-N threshold — any owner can solo-sign.
Dysnomia term What it maps to
MultiOwnable Base class for “set of owners”
_owners The mapping address → bool
onlyOwners Modifier — reverts unless caller is in _owners
OwnershipUpdate Event fired when owners are added/removed
owner(address) Tests one address against the owner mapping
owner() Returns the contract’s own address; it does not enumerate or identify a current owner
  • Understand it’s there — every token you interact with is MultiOwnable.
  • Don’t give ownership to random addresses — an owner has total power over that token.
  • Normal actions (transfer, approve, Purchase/Redeem) don’t require ownership; only admin-level operations do.

Use these calls here. Simulations preview the current state; each confirmed call is a separate transaction.

LAUResolve your player or venue above the call forms.
LAU.owner(address cOwner)Read

Open this function to load its call form.

QINGResolve your player or venue above the call forms.
QING.owner(address cOwner)Read

Open this function to load its call form.

  • Cost: none directly.
  • Reward: none — it’s infrastructure.
  • To add/remove an owner, you must already be an owner.
  • onlyOwners accepts either msg.sender or tx.origin when that exact address is in the mapping. Ownership held by a separate LAU does not automatically authorize its wallet on another contract.

Inherited by every token in the system — DYSNOMIA, DYSNOMIA V2, and through them, everything else.

Q: Why not just use Ownable? A: Because game contracts need to call privileged functions on each other. If there’s only one owner, you can’t do that without an EOA in the middle.

Q: Can I become a co-owner of a public token? A: Only if an existing owner adds you. In practice, ownership is set up at deployment and rarely modified.

Q: How do I list every owner? A: Replay OwnershipUpdate events and apply them in order. owner(address) verifies one candidate; owner() always returns the contract address in this implementation.

Q: What if all owners are removed? A: The contract becomes un-admin’d. Most contracts in Dysnomia maintain at least one owner specifically to avoid this bricking scenario.


Want the Solidity? The contract reference lives at technical/docs/lib/MULTIOWNABLE.md.