Skip to content

Commit

Permalink
fix: allow overriding preset components, replace Owned interface with…
Browse files Browse the repository at this point in the history
… IERC173, fix IComponent interface (#239)

* refactor(std-contracts): better inheritance for component presets

* feat(solecs): use IERC173 instead of IOwned, update IComponent

Co-authored-by: alvarius <89248902+alvrs@users.noreply.github.com>
  • Loading branch information
dk1a and alvrs committed Nov 25, 2022
1 parent 42fd678 commit ae3983b
Show file tree
Hide file tree
Showing 35 changed files with 147 additions and 107 deletions.
15 changes: 11 additions & 4 deletions packages/solecs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ Everyone has read access.
For convenience the component implementation in `solecs` also includes a reverse mapping from `keccak256(value)` to set of entities with this value, but this is not strictly required and might change in a future release.

```solidity
interface IComponent is IOwned {
function transferOwnership(address newOwner) external;
interface IComponent is IERC173 {
/** Return the keys and value types of the schema of this component. */
function getSchema() external pure returns (string[] memory keys, LibTypes.SchemaValue[] memory values);
function set(uint256 entity, bytes memory value) external;
Expand All @@ -91,6 +92,12 @@ interface IComponent is IOwned {
function getEntities() external view returns (uint256[] memory);
function getEntitiesWithValue(bytes memory value) external view returns (uint256[] memory);
function registerIndexer(address indexer) external;
function authorizeWriter(address writer) external;
function unauthorizeWriter(address writer) external;
}
```
Expand Down Expand Up @@ -159,9 +166,9 @@ System are contracts with a single `execute` function.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "./IOwned.sol";
import "./IERC173.sol";
interface ISystem is IOwned {
interface ISystem is IERC173 {
function execute(bytes memory arguments) external returns (bytes memory);
}
Expand Down
47 changes: 23 additions & 24 deletions packages/solecs/src/BareComponent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ abstract contract BareComponent is IComponent {
* @param newOwner Address of the new owner.
*/
function transferOwnership(address newOwner) public override onlyOwner {
emit OwnershipTransferred(_owner, newOwner);
writeAccess[msg.sender] = false;
_owner = newOwner;
writeAccess[newOwner] = true;
Expand All @@ -77,29 +78,6 @@ abstract contract BareComponent is IComponent {
IWorld(world).registerComponent(address(this), id);
}

/**
* Grant write access to this component to the given address.
* Can only be called by the owner of this component.
* @param writer Address to grant write access to.
*/
function authorizeWriter(address writer) public override onlyOwner {
writeAccess[writer] = true;
}

/**
* Revoke write access to this component to the given address.
* Can only be called by the owner of this component.
* @param writer Address to revoke write access .
*/
function unauthorizeWriter(address writer) public override onlyOwner {
delete writeAccess[writer];
}

/**
* Return the keys and value types of the schema of this component.
*/
function getSchema() public pure virtual returns (string[] memory keys, LibTypes.SchemaValue[] memory values);

/**
* Set the given component value for the given entity.
* Registers the update in the World contract.
Expand Down Expand Up @@ -138,18 +116,39 @@ abstract contract BareComponent is IComponent {
return entityToValue[entity];
}

/** Not implemented in BareComponent */
function getEntities() public view virtual override returns (uint256[] memory) {
revert BareComponent__NotImplemented();
}

/** Not implemented in BareComponent */
function getEntitiesWithValue(bytes memory) public view virtual override returns (uint256[] memory) {
revert BareComponent__NotImplemented();
}

function registerIndexer(address) external virtual {
/** Not implemented in BareComponent */
function registerIndexer(address) external virtual override {
revert BareComponent__NotImplemented();
}

/**
* Grant write access to this component to the given address.
* Can only be called by the owner of this component.
* @param writer Address to grant write access to.
*/
function authorizeWriter(address writer) public override onlyOwner {
writeAccess[writer] = true;
}

/**
* Revoke write access to this component to the given address.
* Can only be called by the owner of this component.
* @param writer Address to revoke write access .
*/
function unauthorizeWriter(address writer) public override onlyOwner {
delete writeAccess[writer];
}

/**
* Set the given component value for the given entity.
* Registers the update in the World contract.
Expand Down
8 changes: 5 additions & 3 deletions packages/solecs/src/Component.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,24 @@ abstract contract Component is BareComponent {
}

/**
* @inheritdoc BareComponent
* Get a list of all entities that have a value in this component.
*/
function getEntities() public view virtual override returns (uint256[] memory) {
return entities.getItems();
}

/**
* @inheritdoc BareComponent
* Get a list of all entities that have the specified value in this component.
* @param value Abi-encoded value to get the list of entities with this value for.
*/
function getEntitiesWithValue(bytes memory value) public view virtual override returns (uint256[] memory) {
// Return all entities with this component value
return valueToEntities.getItems(uint256(keccak256(value)));
}

/**
* @inheritdoc BareComponent
* Register a new indexer that gets notified when a component value is set.
* @param indexer Address of the indexer to notify when a component value is set.
*/
function registerIndexer(address indexer) external virtual override onlyWriter {
indexers.push(IEntityIndexer(indexer));
Expand Down
7 changes: 6 additions & 1 deletion packages/solecs/src/PayableSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ abstract contract PayableSystem is IPayableSystem {
world = _world;
}

function owner() public view returns (address) {
function owner() public view override returns (address) {
return _owner;
}

function transferOwnership(address newOwner) public override onlyOwner {
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
7 changes: 6 additions & 1 deletion packages/solecs/src/System.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ abstract contract System is ISystem {
world = _world;
}

function owner() public view returns (address) {
function owner() public view override returns (address) {
return _owner;
}

function transferOwnership(address newOwner) public override onlyOwner {
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
6 changes: 3 additions & 3 deletions packages/solecs/src/components/Uint256Component.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ contract Uint256Component is Component, IUint256Component {
values[0] = LibTypes.SchemaValue.UINT256;
}

function set(uint256 entity, uint256 value) public {
function set(uint256 entity, uint256 value) public virtual {
set(entity, abi.encode(value));
}

function getValue(uint256 entity) public view returns (uint256) {
function getValue(uint256 entity) public view virtual returns (uint256) {
uint256 value = abi.decode(getRawValue(entity), (uint256));
return value;
}

function getEntitiesWithValue(uint256 value) public view returns (uint256[] memory) {
function getEntitiesWithValue(uint256 value) public view virtual returns (uint256[] memory) {
return getEntitiesWithValue(abi.encode(value));
}
}
10 changes: 7 additions & 3 deletions packages/solecs/src/interfaces/IComponent.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import "./IOwned.sol";
import { IERC173 } from "./IERC173.sol";
import { LibTypes } from "../LibTypes.sol";

interface IComponent is IOwned {
function transferOwnership(address newOwner) external;
interface IComponent is IERC173 {
/** Return the keys and value types of the schema of this component. */
function getSchema() external pure returns (string[] memory keys, LibTypes.SchemaValue[] memory values);

function set(uint256 entity, bytes memory value) external;

Expand All @@ -18,6 +20,8 @@ interface IComponent is IOwned {

function getEntitiesWithValue(bytes memory value) external view returns (uint256[] memory);

function registerIndexer(address indexer) external;

function authorizeWriter(address writer) external;

function unauthorizeWriter(address writer) external;
Expand Down
24 changes: 24 additions & 0 deletions packages/solecs/src/interfaces/IERC173.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

/**
* @title ERC-173 Contract ownership standard
* @dev see https://eips.ethereum.org/EIPS/eip-173
*/
interface IERC173 {
/** @dev This emits when ownership of a contract changes. */
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

/**
* @notice Get the address of the owner
* @return The address of the owner.
*/
function owner() external view returns (address);

/**
* @notice Set the address of the new owner of the contract
* @dev Set _newOwner to address(0) to renounce any ownership.
* @param _newOwner The address of the new owner of the contract
*/
function transferOwnership(address _newOwner) external;
}
6 changes: 0 additions & 6 deletions packages/solecs/src/interfaces/IOwned.sol

This file was deleted.

4 changes: 2 additions & 2 deletions packages/solecs/src/interfaces/IPayableSystem.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import "./IOwned.sol";
import "./IERC173.sol";

// The minimum requirement for a system is to have an `execute` function.
// For convenience having an `executeTyped` function with typed arguments is recommended.
interface IPayableSystem is IOwned {
interface IPayableSystem is IERC173 {
function execute(bytes memory arguments) external payable returns (bytes memory);
}
4 changes: 2 additions & 2 deletions packages/solecs/src/interfaces/ISystem.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import "./IOwned.sol";
import "./IERC173.sol";

// The minimum requirement for a system is to have an `execute` function.
// For convenience having an `executeTyped` function with typed arguments is recommended.
interface ISystem is IOwned {
interface ISystem is IERC173 {
function execute(bytes memory arguments) external returns (bytes memory);
}
4 changes: 2 additions & 2 deletions packages/solecs/src/systems/RegisterSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity >=0.8.0;
import { ISystem } from "../interfaces/ISystem.sol";
import { IWorld } from "../interfaces/IWorld.sol";
import { IOwned } from "../interfaces/IOwned.sol";
import { IERC173 } from "../interfaces/IERC173.sol";
import { IUint256Component } from "../interfaces/IUint256Component.sol";
import { addressToEntity, entityToAddress, getAddressById } from "../utils.sol";
import { systemsComponentId } from "../constants.sol";
Expand Down Expand Up @@ -52,7 +52,7 @@ contract RegisterSystem is System {

require(
entitiesWithId.length == 0 ||
(entitiesWithId.length == 1 && IOwned(entityToAddress(entitiesWithId[0])).owner() == msgSender),
(entitiesWithId.length == 1 && IERC173(entityToAddress(entitiesWithId[0])).owner() == msgSender),
"id already registered and caller not owner"
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ contract AddressBareComponent is BareComponent {
values[0] = LibTypes.SchemaValue.UINT256;
}

function set(uint256 entity, address value) public {
function set(uint256 entity, address value) public virtual {
set(entity, abi.encode(value));
}

function getValue(uint256 entity) public view returns (address) {
function getValue(uint256 entity) public view virtual returns (address) {
address value = abi.decode(getRawValue(entity), (address));
return value;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/std-contracts/src/components/AddressComponent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ contract AddressComponent is Component {
values[0] = LibTypes.SchemaValue.UINT256;
}

function set(uint256 entity, address value) public {
function set(uint256 entity, address value) public virtual {
set(entity, abi.encode(value));
}

function getValue(uint256 entity) public view returns (address) {
function getValue(uint256 entity) public view virtual returns (address) {
address value = abi.decode(getRawValue(entity), (address));
return value;
}

function getEntitiesWithValue(address value) public view returns (uint256[] memory) {
function getEntitiesWithValue(address value) public view virtual returns (uint256[] memory) {
return getEntitiesWithValue(abi.encode(value));
}
}
4 changes: 2 additions & 2 deletions packages/std-contracts/src/components/BoolBareComponent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ contract BoolBareComponent is BareComponent {
values[0] = LibTypes.SchemaValue.BOOL;
}

function set(uint256 entity) public {
function set(uint256 entity) public virtual {
set(entity, abi.encode(true));
}

function getValue(uint256 entity) public view returns (bool) {
function getValue(uint256 entity) public view virtual returns (bool) {
bool value = abi.decode(getRawValue(entity), (bool));
return value;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/std-contracts/src/components/BoolComponent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ contract BoolComponent is Component {
set(entity, abi.encode(true));
}

function getValue(uint256 entity) public view returns (bool) {
function getValue(uint256 entity) public view virtual returns (bool) {
bool value = abi.decode(getRawValue(entity), (bool));
return value;
}

function getEntitiesWithValue(bool value) public view returns (uint256[] memory) {
function getEntitiesWithValue(bool value) public view virtual returns (uint256[] memory) {
return getEntitiesWithValue(abi.encode(value));
}
}
4 changes: 2 additions & 2 deletions packages/std-contracts/src/components/CoordBareComponent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ contract CoordBareComponent is BareComponent {
values[1] = LibTypes.SchemaValue.INT32;
}

function set(uint256 entity, Coord calldata value) public {
function set(uint256 entity, Coord calldata value) public virtual {
set(entity, abi.encode(value));
}

function getValue(uint256 entity) public view returns (Coord memory) {
function getValue(uint256 entity) public view virtual returns (Coord memory) {
(int32 x, int32 y) = abi.decode(getRawValue(entity), (int32, int32));
return Coord(x, y);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/std-contracts/src/components/CoordComponent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ contract CoordComponent is Component {
values[1] = LibTypes.SchemaValue.INT32;
}

function set(uint256 entity, Coord calldata value) public {
function set(uint256 entity, Coord calldata value) public virtual {
set(entity, abi.encode(value));
}

function getValue(uint256 entity) public view returns (Coord memory) {
function getValue(uint256 entity) public view virtual returns (Coord memory) {
(int32 x, int32 y) = abi.decode(getRawValue(entity), (int32, int32));
return Coord(x, y);
}

function getEntitiesWithValue(Coord calldata coord) public view returns (uint256[] memory) {
function getEntitiesWithValue(Coord calldata coord) public view virtual returns (uint256[] memory) {
return getEntitiesWithValue(abi.encode(coord));
}
}
Loading

0 comments on commit ae3983b

Please sign in to comment.