Skip to content
Technical Reference

MultiOwnable

Hash-verified 0xd5bc09d5…bd7720
Source details
Property Value
Keccak256 Hash 0xd5bc09d51ea952718d51fc0c347aad20278f6a1c7a0fda63e40ea9317fbd7720
Source URL https://raw.githubusercontent.com/busytoby/atropa_pulsechain/58607494f7741b80525953e4a85bc99e66fd20fc/solidity/dysnomia/lib/multiownable.sol
Source Revision 58607494f7741b80525953e4a85bc99e66fd20fc
Source Status Canonical source snapshot; deployed bytecode equivalence is only established where a deployment record says so.
Compiler solc 0.8.21; optimizer enabled with 200 runs
Compiler Configuration {"evmVersion":"compiler-default","optimizer":{"enabled":true,"runs":200},"version":"0.8.21+commit.d9974bed.Linux.g++"}
Compilation Closure Hash 0x6c094bbab1cc9c0e942bb850c4564398cdd185bc10d7c1058d515c47603e2725
Compilation Closure Files 1
Hash Generated 2026-09-14T19:34:21Z

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.

  • Kind: Abstract Contract
  • License: Sharia
  • Solidity: ^0.8.21
  • Source: lib/multiownable.sol

No base contracts; this contract has no parents.

None (root of its hierarchy).

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
Variable Type Visibility Mutability Initial Value NatSpec
_owners mapping(address => bool) private mutable ``
Modifier Parameters NatSpec
onlyOwners (none)
Event Parameters Anonymous NatSpec
OwnershipUpdate address indexed newOwner, bool indexed state no
Error Parameters NatSpec
OwnableUnauthorizedAccount address origin, address account, address what
OwnableInvalidOwner address origin, address owner, address what
constructorconstructor
constructor(address initialOwner)
  • Parameters: address initialOwner
ownerfunction
function owner() external view virtual returns (address)

A callable deployment has not been resolved for this reference.

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

A callable deployment has not been resolved for this reference.

  • Visibility: public
  • State Mutability: view
  • Virtual: yes
  • Parameters: address cOwner
  • Returns: bool
renounceOwnershipfunction
function renounceOwnership(address toRemove) public virtual onlyOwners

A callable deployment has not been resolved for this reference.

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

A callable deployment has not been resolved for this reference.

  • Visibility: public
  • Virtual: yes
  • Modifiers: onlyOwners
  • Parameters: address newOwner
_checkOwnerfunction
function _checkOwner() internal view virtual
  • Visibility: internal
  • State Mutability: view
  • Virtual: yes
_changeOwnershipfunction
function _changeOwnership(address cOwner, bool cState) internal virtual
  • Visibility: internal
  • Virtual: yes
  • Parameters: address cOwner, bool cState
modifier onlyOwners() {
_checkOwner();
_;
}
  • Description: Restricts function access to owners only
  • Checks: Both msg.sender AND tx.origin - allows if either is an owner
  • DYSNOMIA - All tokens inherit this
  • Every contract in the ecosystem

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

Constructor requires a non-zero initial owner:

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

Owners cannot be enumerated through a getter. owner(address) checks one candidate, while owner() returns the contract address. Reconstruct the set from OwnershipUpdate events when a complete owner list is needed.

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);
}
}
  • 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





The compiled ABI below is produced by solc 0.8.21 from the exact source bytes recorded in Source details. Consumers can paste it directly into ethers/web3/viem.

Click to expand JSON ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "origin",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "what",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "origin",
"type": "address"
},
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "what",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "bool",
"name": "state",
"type": "bool"
}
],
"name": "OwnershipUpdate",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "addOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "cOwner",
"type": "address"
}
],
"name": "owner",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "toRemove",
"type": "address"
}
],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]