Skip to content

Commit

Permalink
[gms-1004][chore] add comments to contracts (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonzwli authored Aug 28, 2023
1 parent 620be0f commit c28881c
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 144 deletions.
231 changes: 132 additions & 99 deletions contracts/token/erc721/abstract/ERC721Hybrid.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
uint256 private _idMintTotalSupply = 0;

/// @dev A mapping of tokens ids before the threshold that have been burned to prevent re-minting
//mapping(uint256 => bool) public _burnedTokens;

BitMaps.BitMap private _burnedTokens;

/// @dev A singular batch transfer request
Expand All @@ -33,47 +31,68 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
uint256[] tokenIds;
}

/// @dev A singular safe burn request.
struct IDBurn {
address owner;
uint256[] tokenIds;
}

/// @dev A singular Mint by quantity request
struct Mint {
address to;
uint256 quantity;
}

/// @dev A singular Mint by id request
struct IDMint {
address to;
uint256[] tokenIds;
}

constructor(
string memory name_,
string memory symbol_
) ERC721(name_, symbol_) ERC721Psi(name_, symbol_) {}

/** @dev returns the threshold that divides tokens that are minted by id and
* minted by quantity
**/
function bulkMintThreshold() public pure virtual returns (uint256) {
return 2**64;
}

/// @dev returns the startTokenID for the minting by quantity section of the contract
function _startTokenId() internal pure virtual override(ERC721Psi) returns (uint256) {
return bulkMintThreshold();
}

// Optimised minting functions
struct Mint {
address to;
uint256 quantity;
}

/// @dev mints number of tokens specified to the address given via erc721psi
function _mintByQuantity(address to, uint256 quantity) internal {
ERC721Psi._mint(to, quantity);
}

/// @dev safe mints number of tokens specified to the address given via erc721psi
function _safeMintByQuantity(address to, uint256 quantity) internal {
ERC721Psi._safeMint(to, quantity);
}

/// @dev mints number of tokens specified to a multiple specified addresses via erc721psi
function _mintBatchByQuantity(Mint[] memory mints) internal {
for (uint i = 0; i < mints.length; i++) {
Mint memory m = mints[i];
_mintByQuantity(m.to, m.quantity);
}
}

/// @dev safe mints number of tokens specified to a multiple specified addresses via erc721psi
function _safeMintBatchByQuantity(Mint[] memory mints) internal {
for (uint i = 0; i < mints.length; i++) {
Mint memory m = mints[i];
_safeMintByQuantity(m.to, m.quantity);
}
}

/// @dev mints by id to a specified address via erc721
function _mintByID(address to, uint256 tokenId) internal {
if (tokenId >= bulkMintThreshold()){
revert IImmutableERC721IDAboveThreshold(tokenId);
Expand All @@ -86,6 +105,7 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
_idMintTotalSupply++;
}

/// @dev safe mints by id to a specified address via erc721
function _safeMintByID(address to, uint256 tokenId) internal {
if (tokenId >= bulkMintThreshold()){
revert IImmutableERC721IDAboveThreshold(tokenId);
Expand All @@ -98,43 +118,80 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
_idMintTotalSupply++;
}

/// @dev mints multiple tokens by id to a specified address via erc721
function _mintBatchByID(address to, uint256[] memory tokenIds) internal {
for (uint i = 0; i < tokenIds.length; i++) {
_mintByID(to, tokenIds[i]);
}
}

/// @dev safe mints multiple tokens by id to a specified address via erc721
function _safeMintBatchByID(address to, uint256[] memory tokenIds) internal {
for (uint i = 0; i < tokenIds.length; i++) {
_safeMintByID(to, tokenIds[i]);
}
}

struct IDMint {
address to;
uint256[] tokenIds;
}

/// @dev mints multiple tokens by id to multiple specified addresses via erc721
function _mintBatchByIDToMultiple(IDMint[] memory mints) internal {
for (uint i = 0; i < mints.length; i++) {
IDMint memory m = mints[i];
_mintBatchByID(m.to, m.tokenIds);
}
}

/// @dev safe mints multiple tokens by id to multiple specified addresses via erc721
function _safeMintBatchByIDToMultiple(IDMint[] memory mints) internal {
for (uint i = 0; i < mints.length; i++) {
IDMint memory m = mints[i];
_safeMintBatchByID(m.to, m.tokenIds);
}
}

/// @dev checks to see if tokenID exists in the collection
function exists(uint256 tokenId) public view virtual returns (bool) {
return _exists(tokenId);
}

// Overwritten functions from ERC721/ERC721Psi with split routing
/// @dev allows caller to burn a token by id
function burn(uint256 tokenId) public virtual {
if (!_isApprovedOrOwner(_msgSender(), tokenId)) {
revert IImmutableERC721NotOwnerOrOperator(tokenId);
}
_burn(tokenId);
}

/// @dev allows caller to burn multiple tokens by id
function burnBatch(uint256[] calldata tokenIDs) external {
for (uint i = 0; i < tokenIDs.length; i++) {
burn(tokenIDs[i]);
}
}

/// @dev Burn a token, checking the owner of the token against the parameter first.
function safeBurn(address owner, uint256 tokenId) public virtual {
address currentOwner = ownerOf(tokenId);
if (currentOwner != owner) {
revert IImmutableERC721MismatchedTokenOwner(tokenId, currentOwner);
}

burn(tokenId);
}

/// @dev Burn a batch of tokens, checking the owner of each token first.
function _safeBurnBatch(IDBurn[] memory burns) internal {
for (uint i = 0; i < burns.length; i++) {
IDBurn memory b = burns[i];
for (uint j = 0; j < b.tokenIds.length; j++) {
safeBurn(b.owner, b.tokenIds[j]);
}
}
}

/** @dev All methods below are overwritten functions from ERC721/ERC721Psi with split routing
* if the token id in the param is below the threshold the erc721 method is invoked. Else
* the erc721psi method is invoked. They then behave like their specified ancestors methods.
**/

function _exists(uint256 tokenId) internal view virtual override(ERC721, ERC721PsiBurnable) returns (bool) {
if (tokenId < bulkMintThreshold()) {
Expand All @@ -158,6 +215,9 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
return ERC721Psi.ownerOf(tokenId);
}

/** @dev burn a token by id, if the token is below the threshold it is burned via erc721
* additional tracking is added for erc721 to prevent re-minting
**/
function _burn(uint256 tokenId) internal virtual override(ERC721, ERC721PsiBurnable) {
if (tokenId < bulkMintThreshold()) {
ERC721._burn(tokenId);
Expand All @@ -168,64 +228,88 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
}
}

function burn(uint256 tokenId) public virtual {
if (!_isApprovedOrOwner(_msgSender(), tokenId)) {
revert IImmutableERC721NotOwnerOrOperator(tokenId);
function _approve(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721._approve(to, tokenId);
}
_burn(tokenId);
return ERC721Psi._approve(to, tokenId);
}

function burnBatch(uint256[] calldata tokenIDs) external {
for (uint i = 0; i < tokenIDs.length; i++) {
burn(tokenIDs[i]);
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual override(ERC721, ERC721Psi) returns (bool) {
if (tokenId < bulkMintThreshold()) {
return ERC721._isApprovedOrOwner(spender, tokenId);
}
return ERC721Psi._isApprovedOrOwner(spender, tokenId);
}

/// @dev Burn a token, checking the owner of the token against the parameter first.
function safeBurn(address owner, uint256 tokenId) public virtual {
address currentOwner = ownerOf(tokenId);
if (currentOwner != owner) {
revert IImmutableERC721MismatchedTokenOwner(tokenId, currentOwner);
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721._safeTransfer(from, to, tokenId, _data);
}
return ERC721Psi._safeTransfer(from, to, tokenId, _data);
}

burn(tokenId);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721.safeTransferFrom(from, to, tokenId, _data);
}
return ERC721Psi.safeTransferFrom(from, to, tokenId, _data);
}

/// @dev A singular safe burn request.
struct IDBurn {
address owner;
uint256[] tokenIds;
function isApprovedForAll(address owner, address operator) public view virtual override(ERC721, ERC721Psi) returns (bool) {
return ERC721.isApprovedForAll(owner, operator);
}

/// @dev Burn a batch of tokens, checking the owner of each token first.
function _safeBurnBatch(IDBurn[] memory burns) internal {
for (uint i = 0; i < burns.length; i++) {
IDBurn memory b = burns[i];
for (uint j = 0; j < b.tokenIds.length; j++) {
safeBurn(b.owner, b.tokenIds[j]);
}
function getApproved(uint256 tokenId) public view virtual override(ERC721, ERC721Psi) returns (address) {
if (tokenId < bulkMintThreshold()) {
return ERC721.getApproved(tokenId);
}
return ERC721Psi.getApproved(tokenId);
}

function approve(address to, uint256 tokenId) public virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721.approve(to, tokenId);
}
return ERC721Psi.approve(to, tokenId);
}

function transferFrom(address from, address to, uint256 tokenId) public virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721.transferFrom(from, to, tokenId);
}
return ERC721Psi.transferFrom(from, to, tokenId);
}

/// @dev overriding erc721 and erc721psi _safemint, super calls the `_safeMint` method of
/// the erc721 implementation due to inheritance linearisation
/** @dev methods below are overwritten to always invoke the erc721 equivalent due to linearisation
they do not get invoked by any minting methods in this contract and are only overwritten to satisfy
the compiler
*/

/** @dev overriding erc721 and erc721psi _safemint, super calls the `_safeMint` method of
* the erc721 implementation due to inheritance linearisation
**/
function _safeMint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Psi) {
super._safeMint(to, tokenId);
}

/// @dev overriding erc721 and erc721psi _safemint, super calls the `_safeMint` method of
/// the erc721 implementation due to inheritance linearisation
/** @dev overriding erc721 and erc721psi _safemint, super calls the `_safeMint` method of
* the erc721 implementation due to inheritance linearisation
**/
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual override(ERC721, ERC721Psi) {
super._safeMint(to, tokenId, _data);
}

/// @dev overriding erc721 and erc721psi _safemint, super calls the `_mint` method of
/// the erc721 implementation due to inheritance linearisation
/** @dev overriding erc721 and erc721psi _safemint, super calls the `_mint` method of
* the erc721 implementation due to inheritance linearisation
**/
function _mint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Psi) {
super._mint(to, tokenId);
}

// Overwritten functions with combined implementations
/** @dev Overwritten functions with combined implementations, supply for the collection is summed as they
* are tracked differently by each minting strategy
**/

function balanceOf(address owner) public view virtual override(ERC721, ERC721Psi) returns (uint) {
return ERC721.balanceOf(owner) + ERC721Psi.balanceOf(owner);
Expand All @@ -235,7 +319,9 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
return ERC721PsiBurnable.totalSupply() + _idMintTotalSupply;
}

// Overwritten functions with direct routing
/** @dev Overwritten functions with direct routing. The metadata of the collect remains the same regardless
* of the minting strategy used for the tokenID
**/

function tokenURI(uint256 tokenId) public view virtual override(ERC721, ERC721Psi) returns (string memory) {
return ERC721.tokenURI(tokenId);
Expand All @@ -257,64 +343,11 @@ abstract contract ERC721Hybrid is ERC721PsiBurnable, ERC721, IImmutableERC721Err
return ERC721._baseURI();
}

function _approve(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721._approve(to, tokenId);
}
return ERC721Psi._approve(to, tokenId);
}

function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual override(ERC721, ERC721Psi) returns (bool) {
if (tokenId < bulkMintThreshold()) {
return ERC721._isApprovedOrOwner(spender, tokenId);
}
return ERC721Psi._isApprovedOrOwner(spender, tokenId);
}

function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721._safeTransfer(from, to, tokenId, _data);
}
return ERC721Psi._safeTransfer(from, to, tokenId, _data);
}

function setApprovalForAll(address operator, bool approved) public virtual override(ERC721, ERC721Psi) {
return ERC721.setApprovalForAll(operator, approved);
}

function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override(ERC721, ERC721Psi) {
safeTransferFrom(from, to, tokenId, "");
}

function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721.safeTransferFrom(from, to, tokenId, _data);
}
return ERC721Psi.safeTransferFrom(from, to, tokenId, _data);
}

function isApprovedForAll(address owner, address operator) public view virtual override(ERC721, ERC721Psi) returns (bool) {
return ERC721.isApprovedForAll(owner, operator);
}

function getApproved(uint256 tokenId) public view virtual override(ERC721, ERC721Psi) returns (address) {
if (tokenId < bulkMintThreshold()) {
return ERC721.getApproved(tokenId);
}
return ERC721Psi.getApproved(tokenId);
}

function approve(address to, uint256 tokenId) public virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721.approve(to, tokenId);
}
return ERC721Psi.approve(to, tokenId);
}

function transferFrom(address from, address to, uint256 tokenId) public virtual override(ERC721, ERC721Psi) {
if (tokenId < bulkMintThreshold()) {
return ERC721.transferFrom(from, to, tokenId);
}
return ERC721Psi.transferFrom(from, to, tokenId);
}
}
Loading

0 comments on commit c28881c

Please sign in to comment.