Skip to content

Instantly share code, notes, and snippets.

@BenFaruna
Last active February 15, 2024 16:45
Show Gist options
  • Save BenFaruna/24f18fb4286b91abcf4b132e9f7a6d7a to your computer and use it in GitHub Desktop.
Save BenFaruna/24f18fb4286b91abcf4b132e9f7a6d7a to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceID) external pure returns (bool);
}
interface IERC721 is IERC165 {
function balanceOf(address _owner) external view returns (uint _balance);
function ownerOf(uint _tokenId) external view returns (address _owner);
function safeTransferFrom(address _from, address _to, uint _tokenId) external payable;
function safeTransferFrom(
address _from,
address _to,
uint _tokenId,
bytes calldata _data
) external payable;
function transferFrom(address _from, address _to, uint _tokenId) external payable;
function approve(address _to, uint _tokenId) external;
function getApproved(uint _tokenId) external view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(
address _owner,
address _operator
) external view returns (bool);
}
interface IERC721Receiver {
function onERC721Received(
address _operator,
address _from,
uint _tokenId,
bytes calldata _data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./interface/IERC721.sol";
contract ERC721 is IERC721 {
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
event Approval(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
mapping(uint => address) internal _ownerOf;
mapping(address => uint) internal _balanceOf;
mapping(uint => address) internal _approvals;
mapping(address => mapping(address => bool)) public isApprovedForAll;
function supportsInterface(
bytes4 interfaceID
) external pure returns (bool) {
return
interfaceID == type(IERC721).interfaceId ||
interfaceID == type(IERC165).interfaceId;
}
function ownerOf(uint tokenId) external view returns (address) {
require(
_ownerOf[tokenId] != address(0),
"NftContract: owner query for nonexistent token"
);
return _ownerOf[tokenId];
}
function balanceOf(address owner) external view returns (uint) {
require(
owner != address(0),
"NftContract: balance query for the zero address"
);
return _balanceOf[owner];
}
function safeTransferFrom(
address _from,
address _to,
uint _tokenId
) external payable {
_transferFrom(_from, _to, _tokenId);
require(
_to.code.length == 0 ||
IERC721Receiver(_to).onERC721Received(
msg.sender,
_from,
_tokenId,
""
) ==
bytes4(
keccak256("onERC721Received(address,address,uint256,bytes)")
),
"unsafe receiver"
);
}
function safeTransferFrom(
address _from,
address _to,
uint _tokenId,
bytes calldata _data
) external payable {
_transferFrom(_from, _to, _tokenId);
require(
_to.code.length == 0 ||
IERC721Receiver(_to).onERC721Received(
msg.sender,
_from,
_tokenId,
_data
) ==
bytes4(
keccak256("onERC721Received(address,address,uint256,bytes)")
),
"unsafe receiver"
);
}
function transferFrom(
address _from,
address _to,
uint _tokenId
) external payable {
_transferFrom(_from, _to, _tokenId);
}
function _transferFrom(address _from, address _to, uint _tokenId) internal {
require(
_from != address(0),
"NftContract: transfer from the zero address"
);
require(_to != address(0), "NftContract: transfer to the zero address");
require(
_ownerOf[_tokenId] == _from,
"NftContract: transfer of token that is not owner"
);
require(
msg.sender == _from ||
_approvals[_tokenId] == msg.sender ||
isApprovedForAll[_from][msg.sender],
"NftContract: transfer caller is not owner nor approved"
);
_balanceOf[_from]--;
_balanceOf[_to]++;
_ownerOf[_tokenId] = _to;
delete _approvals[_tokenId];
emit Transfer(_from, _to, _tokenId);
}
function approve(address _to, uint _tokenId) external {
address owner = _ownerOf[_tokenId];
require(
msg.sender == owner || isApprovedForAll[owner][msg.sender],
"NftContract: approve caller is not owner"
);
_approvals[_tokenId] = _to;
}
function getApproved(
uint _tokenId
) external view returns (address _operator) {
require(
_ownerOf[_tokenId] != address(0),
"NftContract: approved query for nonexistent token"
);
return _approvals[_tokenId];
}
function setApprovalForAll(address _operator, bool _approved) external {
require(_operator != msg.sender, "NftContract: approve to caller");
require(
_operator != address(0),
"NftContract: approve to the zero address"
);
isApprovedForAll[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}
function _mint(address to, uint id) internal {
require(to != address(0), "mint to zero address");
require(_ownerOf[id] == address(0), "already minted");
_balanceOf[to]++;
_ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
function _burn(uint id) internal {
address owner = _ownerOf[id];
require(owner != address(0), "not minted");
_balanceOf[owner] -= 1;
delete _ownerOf[id];
delete _approvals[id];
emit Transfer(owner, address(0), id);
}
}
contract BfaNft is ERC721 {
function mint(address to, uint id) external {
_mint(to, id);
}
function burn(uint id) external {
require(msg.sender == _ownerOf[id], "not owner");
_burn(id);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment