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.
- License: Sharia
- Solidity: ^0.8.21
- Type: Abstract Contract
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 | Description |
|---|---|---|---|
| _owners | mapping(address => bool) | private | Tracks owner status per address |
Read Functions¶
owner (address check)¶
- Access:public view
- Parameters:
- cOwner (address): Address to check
- Returns:
- bool: True if address is in the _owners mapping
- Description: Checks if an address has owner privileges.
- Logic Flow:
1. Return _owners[cOwner]
- In Plain English: Check if an address has admin rights on this contract. Returns true if they're on the owners list.
owner (contract address)¶
- Access:external view
- Returns:
- address: Returns address(this) (the contract itself)
- Description: Compatibility function that returns the contract's own address for owner checks.
- In Plain English: Returns the contract's address for compatibility with code that expects a single owner.
Write Functions¶
addOwner¶
- Access:onlyOwners
- Parameters:
- newOwner (address): Address to add as owner
- Description: Adds a new address to the owners set.
- Logic Flow:
1. Validate: if(newOwner == address(0)) revert OwnableInvalidOwner
2. Call: _changeOwnership(newOwner, true)
- Side Effects: Updates _owners mapping; emits OwnershipUpdate event
- In Plain English: Give admin powers to a new address. Once added, they can manage the contract just like existing owners. Cannot add the zero address.
renounceOwnership¶
- Access:onlyOwners
- Parameters:
- toRemove (address): Address to remove from owners
- Description: Removes an address from the owners set.
- Logic Flow:
1. Call: _changeOwnership(toRemove, false)
- Side Effects: Updates _owners mapping; emits OwnershipUpdate event
- In Plain English: Remove admin powers from an address. Any owner can remove any other owner (or themselves) from the list.
Modifier¶
onlyOwners¶
- Description: Restricts function access to owners only - Checks: Both msg.sender AND tx.origin - allows if either is an ownerEvents¶
| Event | Parameters | Description |
|---|---|---|
| OwnershipUpdate | newOwner (indexed), state (indexed) | Emitted when ownership changes |
Errors¶
| Error | Parameters | Description |
|---|---|---|
| OwnableUnauthorizedAccount | origin, account, what | Caller is not an owner |
| OwnableInvalidOwner | origin, owner, what | Invalid owner address (zero) |
Internal Functions¶
_checkOwner¶
- Description: Verifies msg.sender or tx.origin is an owner, reverts otherwise_changeOwnership¶
- Parameters: -cOwner: Address to modify
- cState: New ownership state (true = owner, false = not owner)
- Description: Internal function to modify ownership mapping
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:
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-02-08T00:29:08Z |