Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft EIP 1820 #1677

Merged
merged 14 commits into from
Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 2.3.0 (unreleased)
### New features:
* `ERC1820`: added support for interacting with the [ERC1820](https://eips.ethereum.org/EIPS/eip-1820) registry contract (`IERC1820Registry`), as well as base contracts that can be registered as implementers there. ([#1677](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1677))

## 2.2.0 (unreleased)

### New features:
Expand Down
25 changes: 25 additions & 0 deletions contracts/drafts/ERC1820.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pragma solidity ^0.5.2;

import "./IERC1820.sol";

/**
* Inherit from this contract and call _registerInterfaceForAddress to allow for contracts to be registered in the
nventuro marked this conversation as resolved.
Show resolved Hide resolved
nventuro marked this conversation as resolved.
Show resolved Hide resolved
* ERC1820 registry.
*/
contract ERC1820 is IERC1820 {
nventuro marked this conversation as resolved.
Show resolved Hide resolved
bytes32 constant private ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC"));

mapping(bytes32 => mapping(address => bool)) private _supportedInterfaces;

function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32) {
return _implementsInterfaceForAddress(interfaceHash, account) ? ERC1820_ACCEPT_MAGIC : bytes32(0x00);
}

function _implementsInterfaceForAddress(bytes32 interfaceHash, address account) internal view returns (bool) {
nventuro marked this conversation as resolved.
Show resolved Hide resolved
return _supportedInterfaces[interfaceHash][account];
}

function _registerInterfaceForAddress(bytes32 interfaceHash, address account) internal {
_supportedInterfaces[interfaceHash][account] = true;
}
}
17 changes: 17 additions & 0 deletions contracts/drafts/IERC1820.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pragma solidity ^0.5.2;

/**
* @title IERC1820
* Interface for contracts that will be registered as implementers in the ERC1820 registry.
* @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820
*/
interface IERC1820 {
/**
* @notice Indicates whether the contract implements the interface `interfaceHash` for the address `account` or
* not.
* @param interfaceHash keccak256 hash of the name of the interface
* @param account Address for which the contract will implement the interface
* @return ERC1820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `account`.
*/
function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32);
}
90 changes: 90 additions & 0 deletions contracts/drafts/IERC1820Registry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
pragma solidity ^0.5.2;

/**
* @title ERC1820 Pseudo-introspection Registry Contract
* @author Jordi Baylina and Jacques Dafflon
* @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820
*/
interface IERC1820Registry {
nventuro marked this conversation as resolved.
Show resolved Hide resolved
/**
* @notice Sets the contract which implements a specific interface for an address.
* Only the manager defined for that address can set it.
* (Each address is the manager for itself until it sets a new manager.)
* @param account Address for which to set the interface.
* (If 'account' is the zero address then 'msg.sender' is assumed.)
* @param interfaceHash Keccak256 hash of the name of the interface as a string.
* E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface.
* @param implementer Contract address implementing `interfaceHash` for `account.address()`.
*/
function setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external;

/**
* @notice Sets `newManager.address()` as manager for `account.address()`.
* The new manager will be able to call 'setInterfaceImplementer' for `account.address()`.
* @param account Address for which to set the new manager.
* @param newManager Address of the new manager for `addr.address()`.
* (Pass '0x0' to reset the manager to `account.address()`.)
*/
function setManager(address account, address newManager) external;

/**
* @notice Updates the cache with whether the contract implements an ERC165 interface or not.
* @param account Address of the contract for which to update the cache.
* @param interfaceId ERC165 interface for which to update the cache.
*/
function updateERC165Cache(address account, bytes4 interfaceId) external;

/**
* @notice Get the manager of an address.
* @param account Address for which to return the manager.
* @return Address of the manager for a given address.
*/
function getManager(address account) external view returns (address);

/**
* @notice Query if an address implements an interface and through which contract.
* @param account Address being queried for the implementer of an interface.
* (If 'account' is the zero address then 'msg.sender' is assumed.)
* @param interfaceHash Keccak256 hash of the name of the interface as a string.
* E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface.
* @return The address of the contract which implements the interface `interfaceHash` for `account.address()`
* or '0' if `account.address()` did not register an implementer for this interface.
*/
function getInterfaceImplementer(address account, bytes32 interfaceHash) external view returns (address);

/**
* @notice Checks whether a contract implements an ERC165 interface or not.
* If the result is not cached a direct lookup on the contract address is performed.
* If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling
* 'updateERC165Cache' with the contract address.
* @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check.
* @return True if `account.address()` implements `interfaceId`, false otherwise.
*/
function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);

/**
* @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.
* @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check.
* @return True if `account.address()` implements `interfaceId`, false otherwise.
*/
function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);

/**
* @notice Compute the keccak256 hash of an interface given its name.
* @param interfaceName Name of the interface.
* @return The keccak256 hash of an interface name.
*/
function interfaceHash(string calldata interfaceName) external pure returns (bytes32);

/**
* @notice Indicates a contract is the `implementer` of `interfaceHash` for `account`.
*/
event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);

/**
* @notice Indicates `newManager` is the address of the new manager for `account`.
*/
event ManagerChanged(address indexed account, address indexed newManager);
}
13 changes: 13 additions & 0 deletions contracts/mocks/ERC1820Mock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pragma solidity ^0.5.2;

import "../drafts/ERC1820.sol";

contract ERC1820Mock is ERC1820 {
function implementsInterfaceForAddress(bytes32 interfaceHash, address account) public view returns (bool) {
return _implementsInterfaceForAddress(interfaceHash, account);
}

function registerInterfaceForAddress(bytes32 interfaceHash, address account) public {
_registerInterfaceForAddress(interfaceHash, account);
}
}
Loading