75 lines
2.9 KiB
Solidity
75 lines
2.9 KiB
Solidity
|
// SPDX-License-Identifier: CC0-1.0
|
||
|
|
||
|
pragma solidity ^0.8.0;
|
||
|
|
||
|
import "./ERC3525.sol";
|
||
|
import "./interface/IERC3525SlotApprovable.sol";
|
||
|
|
||
|
abstract contract ERC3525SlotApprovable is ERC3525, IERC3525SlotApprovable {
|
||
|
// @dev owner => slot => operator => approved
|
||
|
mapping(address => mapping(uint256 => mapping(address => bool)))
|
||
|
private _slotApprovals;
|
||
|
|
||
|
function setApprovalForSlot( address owner_, uint256 slot_, address operator_, bool approved_) external payable virtual override {
|
||
|
require(
|
||
|
_msgSender() == owner_ || isApprovedForAll(owner_, _msgSender()),
|
||
|
"ERC3525SlotApprovable: caller is not owner nor approved for all"
|
||
|
);
|
||
|
_setApprovalForSlot(owner_, slot_, operator_, approved_);
|
||
|
}
|
||
|
|
||
|
function isApprovedForSlot( address owner_, uint256 slot_, address operator_) public view virtual override returns (bool) {
|
||
|
return _slotApprovals[owner_][slot_][operator_];
|
||
|
}
|
||
|
|
||
|
function approve(address to_, uint256 tokenId_) public virtual override(IERC721, ERC721) {
|
||
|
address owner = ERC721.ownerOf(tokenId_);
|
||
|
uint256 slot = ERC3525.slotOf(tokenId_);
|
||
|
require(to_ != owner, "ERC3525: approval to current owner");
|
||
|
|
||
|
require(
|
||
|
_msgSender() == owner ||
|
||
|
ERC721.isApprovedForAll(owner, _msgSender()) ||
|
||
|
ERC3525SlotApprovable.isApprovedForSlot(
|
||
|
owner,
|
||
|
slot,
|
||
|
_msgSender()
|
||
|
),
|
||
|
"ERC3525: caller is not owner nor approved"
|
||
|
);
|
||
|
|
||
|
_approve(to_, tokenId_);
|
||
|
}
|
||
|
|
||
|
function approve(uint256 tokenId_, address to_, uint256 value_) external payable virtual override(IERC3525, ERC3525) {
|
||
|
address owner = ERC721.ownerOf(tokenId_);
|
||
|
require(to_ != owner, "ERC3525: approval to current owner");
|
||
|
|
||
|
require(
|
||
|
_isApprovedOrOwner(_msgSender(), tokenId_),
|
||
|
"ERC3525: caller is not owner nor approved"
|
||
|
);
|
||
|
|
||
|
_approveValue(tokenId_, to_, value_);
|
||
|
}
|
||
|
|
||
|
function _setApprovalForSlot( address owner_, uint256 slot_, address operator_, bool approved_) internal virtual {
|
||
|
require(owner_ != operator_, "ERC3525SlotApprovable: approve to owner");
|
||
|
_slotApprovals[owner_][slot_][operator_] = approved_;
|
||
|
emit ApprovalForSlot(owner_, slot_, operator_, approved_);
|
||
|
}
|
||
|
|
||
|
function _isApprovedOrOwner(address operator_, uint256 tokenId_) internal view virtual override returns (bool) {
|
||
|
require(
|
||
|
_exists(tokenId_),
|
||
|
"ERC3525: operator query for nonexistent token"
|
||
|
);
|
||
|
address owner = ERC721.ownerOf(tokenId_);
|
||
|
uint256 slot = ERC3525.slotOf(tokenId_);
|
||
|
return (operator_ == owner ||
|
||
|
getApproved(tokenId_) == operator_ ||
|
||
|
ERC721.isApprovedForAll(owner, operator_) ||
|
||
|
ERC3525SlotApprovable.isApprovedForSlot(owner, slot, operator_));
|
||
|
}
|
||
|
}
|