Skip to content

MultiOwnable

Overview

MultiOwnable is an abstract contract providing multi-owner access control. Unlike OpenZeppelin's Ownable which has a single owner, MultiOwnable allows multiple addresses to have owner privileges simultaneously.

Inheritance Chain (C3 Linearized)

No base contracts; this contract has no parents.

Immediate Parents

None (root of its hierarchy).

What This Means For Players

Plain English Summary: MultiOwnable allows shared control - it lets multiple people manage the same thing. Instead of having just one admin, a contract can have many admins who all have equal power. This is essential for the Dysnomia ecosystem where game contracts need to interact with each other.

Real-World Analogy: Think of a shared bank account that has multiple signatories. Any of the signatories can make transactions - you don't need everyone to approve. MultiOwnable works the same way: if you're on the list of owners, you can control the contract.

How It Affects Your Gameplay: - Shared access - Your LAU, SHIO, and other tokens may have multiple owners (you + game contracts) - Chain of trust - Game contracts add each other as owners to enable coordination - Revocable - Owners can be added or removed by existing owners

State Variables

Variable Type Visibility Mutability Initial Value NatSpec
_owners mapping(address => bool) private mutable ``

Modifiers

Modifier Parameters NatSpec
onlyOwners (none)

Events

Event Parameters Anonymous NatSpec
OwnershipUpdate address indexed newOwner, bool indexed state no

Errors

Error Parameters NatSpec
OwnableUnauthorizedAccount address origin, address account, address what
OwnableInvalidOwner address origin, address owner, address what

Constructor

constructor

constructor(address initialOwner)
  • Parameters: address initialOwner

Functions

External & Public

owner

function owner() external view virtual returns (address)
  • Visibility: external
  • State Mutability: view
  • Virtual: yes
  • Returns: address

owner

function owner(address cOwner) public view virtual returns (bool)
  • Visibility: public
  • State Mutability: view
  • Virtual: yes
  • Parameters: address cOwner
  • Returns: bool

renounceOwnership

function renounceOwnership(address toRemove) public virtual onlyOwners
  • Visibility: public
  • Virtual: yes
  • Modifiers: onlyOwners
  • Parameters: address toRemove

addOwner

function addOwner(address newOwner) public virtual onlyOwners
  • Visibility: public
  • Virtual: yes
  • Modifiers: onlyOwners
  • Parameters: address newOwner

Internal

_checkOwner

function _checkOwner() internal view virtual
  • Visibility: internal
  • State Mutability: view
  • Virtual: yes

_changeOwnership

function _changeOwnership(address cOwner, bool cState) internal virtual
  • Visibility: internal
  • Virtual: yes
  • Parameters: address cOwner, bool cState

Modifier

onlyOwners

modifier onlyOwners() {
    _checkOwner();
    _;
}
- Description: Restricts function access to owners only - Checks: Both msg.sender AND tx.origin - allows if either is an owner

Contract Interactions

Depended On By

  • DYSNOMIA - All tokens inherit this
  • Every contract in the ecosystem

Special Mechanisms

Dual Sender Check

The _checkOwner function checks both:

if (!owner(msg.sender) && !owner(tx.origin)) {
    revert OwnableUnauthorizedAccount(...);
}

This allows: - Direct calls from owner addresses - Calls through contracts where tx.origin is an owner - Factory patterns where the deploying contract is trusted

Initial Owner

Constructor requires a non-zero initial owner:

constructor(address initialOwner) {
    if (initialOwner == address(0)) {
        revert OwnableInvalidOwner(...);
    }
    _changeOwnership(initialOwner, true);
}

No Enumeration

Unlike some implementations, owners cannot be enumerated. You can only check if a specific address is an owner. This is a gas optimization trade-off.

Usage Pattern

contract MyContract is MultiOwnable {
    constructor() MultiOwnable(msg.sender) {}

    function adminFunction() public onlyOwners {
        // Only owners can call this
    }

    function addAdmin(address newAdmin) public onlyOwners {
        addOwner(newAdmin);
    }
}

Security Considerations

  • Any owner can add new owners
  • Any owner can remove any owner (including themselves)
  • No protection against removing all owners
  • tx.origin check enables some use cases but has known security implications
  • Consider carefully before using in high-security contexts





Contract Verification

Property Value
Keccak256 Hash 0xd5bc09d51ea952718d51fc0c347aad20278f6a1c7a0fda63e40ea9317fbd7720
Source URL https://raw.githubusercontent.com/busytoby/atropa_pulsechain/main/solidity/dysnomia/lib/multiownable.sol
Hash Generated 2026-04-17T20:48:16Z