DCIPs/assets/eip-4671/ERC4671Delegate.sol

99 lines
4.0 KiB
Solidity

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./ERC4671.sol";
import "./IERC4671Delegate.sol";
abstract contract ERC4671Delegate is ERC4671, IERC4671Delegate {
// Mapping from operator to list of owners
mapping (address => mapping(address => bool)) _allowed;
/// @notice Grant one-time minting right to `operator` for `owner`
/// An allowed operator can call the function to transfer rights.
/// @param operator Address allowed to mint a token
/// @param owner Address for whom `operator` is allowed to mint a token
function delegate(address operator, address owner) public virtual override {
_delegateAsDelegateOrCreator(operator, owner, _isCreator());
}
/// @notice Grant one-time minting right to a list of `operators` for a corresponding list of `owners`
/// An allowed operator can call the function to transfer rights.
/// @param operators Addresses allowed to mint a token
/// @param owners Addresses for whom `operators` are allowed to mint a token
function delegateBatch(address[] memory operators, address[] memory owners) public virtual override {
require(operators.length == owners.length, "operators and owners must have the same length");
bool isCreator = _isCreator();
for (uint i=0; i<operators.length; i++) {
_delegateAsDelegateOrCreator(operators[i], owners[i], isCreator);
}
}
/// @notice Mint a token. Caller must have the right to mint for the owner.
/// @param owner Address for whom the token is minted
function mint(address owner) public virtual override {
_mintAsDelegateOrCreator(owner, _isCreator());
}
/// @notice Mint tokens to multiple addresses. Caller must have the right to mint for all owners.
/// @param owners Addresses for whom the tokens are minted
function mintBatch(address[] memory owners) public virtual override {
bool isCreator = _isCreator();
for (uint i=0 ; i<owners.length; i++) {
_mintAsDelegateOrCreator(owners[i], isCreator);
}
}
/// @notice Get the issuer of a token
/// @param tokenId Identifier of the token
/// @return Address who minted `tokenId`
function issuerOf(uint256 tokenId) public view virtual override returns (address) {
return _getTokenOrRevert(tokenId).issuer;
}
/// @notice Check if an operator is a delegate for a given address
/// @param operator Address of the operator
/// @param owner Address of the token's owner
/// @return True if the `operator` is a delegate for `owner`, false otherwise
function isDelegate(address operator, address owner) public view virtual returns (bool) {
return _allowed[operator][owner];
}
/// @notice Check if you are a delegate for a given address
/// @param owner Address of the token's owner
/// @return True if the caller is a delegate for `owner`, false otherwise
function isDelegateOf(address owner) public view virtual returns (bool) {
return isDelegate(msg.sender, owner);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC4671) returns (bool) {
return
interfaceId == type(IERC4671Delegate).interfaceId ||
super.supportsInterface(interfaceId);
}
function _delegateAsDelegateOrCreator(address operator, address owner, bool isCreator) private {
require(
isCreator || _allowed[msg.sender][owner],
"Only contract creator or allowed operator can delegate"
);
if (!isCreator) {
_allowed[msg.sender][owner] = false;
}
_allowed[operator][owner] = true;
}
function _mintAsDelegateOrCreator(address owner, bool isCreator) private {
require(
isCreator || _allowed[msg.sender][owner],
"Only contract creator or allowed operator can mint"
);
if (!isCreator) {
_allowed[msg.sender][owner] = false;
}
_mint(owner);
}
}