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

Add ERC721 diamond #68

Merged
merged 9 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
383 changes: 383 additions & 0 deletions contracts/diamond/tokens/ERC721/DiamondERC721.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,383 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {DiamondERC721Storage} from "./DiamondERC721Storage.sol";

/**
* @notice This is modified version of OpenZeppelin's ERC721 contract to be used as a Storage contract
* by the Diamond Standard.
*/
contract DiamondERC721 is DiamondERC721Storage {
using Address for address;

/**
* @notice Sets the values for {name} and {symbol}.
*/
function __DiamondERC721_init(

Check warning on line 20 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L20

Added line #L20 was not covered by tests
string memory name_,
string memory symbol_
) internal onlyInitializing(DIAMOND_ERC721_STORAGE_SLOT) {
DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 24 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L24

Added line #L24 was not covered by tests

_erc721Storage.name = name_;
_erc721Storage.symbol = symbol_;

Check warning on line 27 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L26-L27

Added lines #L26 - L27 were not covered by tests
}

/**
* @inheritdoc IERC721
*/
function approve(address to_, uint256 tokenId_) public virtual override {
address owner_ = ownerOf(tokenId_);

Check warning on line 34 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L33-L34

Added lines #L33 - L34 were not covered by tests
require(to_ != owner_, "ERC721: approval to current owner");

require(
msg.sender == owner_ || isApprovedForAll(owner_, msg.sender),
"ERC721: approve caller is not token owner or approved for all"
);

_approve(to_, tokenId_);

Check warning on line 42 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L42

Added line #L42 was not covered by tests
}

/**
* @inheritdoc IERC721
*/
function setApprovalForAll(address operator_, bool approved_) public virtual override {
_setApprovalForAll(msg.sender, operator_, approved_);

Check warning on line 49 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L48-L49

Added lines #L48 - L49 were not covered by tests
}

/**
* @inheritdoc IERC721
*/
function transferFrom(address from_, address to_, uint256 tokenId_) public virtual override {

Check warning on line 55 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L55

Added line #L55 was not covered by tests
//solhint-disable-next-line max-line-length
Arvolear marked this conversation as resolved.
Show resolved Hide resolved
require(
_isApprovedOrOwner(msg.sender, tokenId_),
"ERC721: caller is not token owner or approved"
);

_transfer(from_, to_, tokenId_);

Check warning on line 62 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L62

Added line #L62 was not covered by tests
}

/**
* @inheritdoc IERC721
*/
function safeTransferFrom(

Check warning on line 68 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L68

Added line #L68 was not covered by tests
address from_,
address to_,
uint256 tokenId_
) public virtual override {
safeTransferFrom(from_, to_, tokenId_, "");

Check warning on line 73 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L73

Added line #L73 was not covered by tests
}

/**
* @inheritdoc IERC721
*/
function safeTransferFrom(

Check warning on line 79 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L79

Added line #L79 was not covered by tests
address from_,
address to_,
uint256 tokenId_,
bytes memory data_
) public virtual override {
require(
_isApprovedOrOwner(msg.sender, tokenId_),
"ERC721: caller is not token owner or approved"
);

_safeTransfer(from_, to_, tokenId_, data_);

Check warning on line 90 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L90

Added line #L90 was not covered by tests
}

/**
* @notice Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*/
function _safeTransfer(

Check warning on line 97 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L97

Added line #L97 was not covered by tests
address from_,
address to_,
uint256 tokenId_,
bytes memory data_
) internal virtual {
_transfer(from_, to_, tokenId_);

Check warning on line 103 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L103

Added line #L103 was not covered by tests

require(
_checkOnERC721Received(from_, to_, tokenId_, data_),
"ERC721: transfer to non ERC721Receiver implementer"
);
}

/**
* @notice Safely mints `tokenId` and transfers it to `to`.
*/
function _safeMint(address to_, uint256 tokenId_) internal virtual {
_safeMint(to_, tokenId_, "");

Check warning on line 115 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L114-L115

Added lines #L114 - L115 were not covered by tests
}

/**
* @notice Same as _safeMint, with an additional `data` parameter.
*/
function _safeMint(address to_, uint256 tokenId_, bytes memory data_) internal virtual {
_mint(to_, tokenId_);

Check warning on line 122 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L121-L122

Added lines #L121 - L122 were not covered by tests

require(
_checkOnERC721Received(address(0), to_, tokenId_, data_),
"ERC721: transfer to non ERC721Receiver implementer"
);
}

/**
* @notice Mints `tokenId` and transfers it to `to`.
*/
function _mint(address to_, uint256 tokenId_) internal virtual {

Check warning on line 133 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L133

Added line #L133 was not covered by tests
require(to_ != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId_), "ERC721: token already minted");

_beforeTokenTransfer(address(0), to_, tokenId_, 1);

Check warning on line 137 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L137

Added line #L137 was not covered by tests

// Check that tokenId was not minted by `_beforeTokenTransfer` hook
require(!_exists(tokenId_), "ERC721: token already minted");

DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 142 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L142

Added line #L142 was not covered by tests

unchecked {

Check warning on line 144 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L144

Added line #L144 was not covered by tests
// Will not overflow unless all 2**256 token ids are minted to the same owner.
// Given that tokens are minted one by one, it is impossible in practice that
// this ever happens. Might change if we allow batch minting.
// The ERC fails to describe this case.
Arvolear marked this conversation as resolved.
Show resolved Hide resolved
_erc721Storage.balances[to_] += 1;

Check warning on line 149 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L149

Added line #L149 was not covered by tests
}

_erc721Storage.owners[tokenId_] = to_;

Check warning on line 152 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L152

Added line #L152 was not covered by tests

emit Transfer(address(0), to_, tokenId_);

Check warning on line 154 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L154

Added line #L154 was not covered by tests

_afterTokenTransfer(address(0), to_, tokenId_, 1);

Check warning on line 156 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L156

Added line #L156 was not covered by tests
}

/**
* @notice Destroys `tokenId`.
*/
function _burn(uint256 tokenId_) internal virtual {
address owner_ = ownerOf(tokenId_);

Check warning on line 163 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L162-L163

Added lines #L162 - L163 were not covered by tests

_beforeTokenTransfer(owner_, address(0), tokenId_, 1);

Check warning on line 165 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L165

Added line #L165 was not covered by tests

// Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
owner_ = ownerOf(tokenId_);

Check warning on line 168 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L168

Added line #L168 was not covered by tests

DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 170 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L170

Added line #L170 was not covered by tests

// Clear approvals
delete _erc721Storage.tokenApprovals[tokenId_];

Check warning on line 173 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L173

Added line #L173 was not covered by tests

unchecked {

Check warning on line 175 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L175

Added line #L175 was not covered by tests
// Cannot overflow, as that would require more tokens to be burned/transferred
// out than the owner initially received through minting and transferring in.
Arvolear marked this conversation as resolved.
Show resolved Hide resolved
_erc721Storage.balances[owner_] -= 1;

Check warning on line 178 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L178

Added line #L178 was not covered by tests
}

delete _erc721Storage.owners[tokenId_];

Check warning on line 181 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L181

Added line #L181 was not covered by tests

emit Transfer(owner_, address(0), tokenId_);

Check warning on line 183 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L183

Added line #L183 was not covered by tests

_afterTokenTransfer(owner_, address(0), tokenId_, 1);

Check warning on line 185 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L185

Added line #L185 was not covered by tests
}

/**
* @notice Transfers `tokenId` from `from` to `to`.
*/
function _transfer(address from_, address to_, uint256 tokenId_) internal virtual {

Check warning on line 191 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L191

Added line #L191 was not covered by tests
require(ownerOf(tokenId_) == from_, "ERC721: transfer from incorrect owner");
require(to_ != address(0), "ERC721: transfer to the zero address");

_beforeTokenTransfer(from_, to_, tokenId_, 1);

Check warning on line 195 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L195

Added line #L195 was not covered by tests

// Check that tokenId was not transferred by `_beforeTokenTransfer` hook
require(ownerOf(tokenId_) == from_, "ERC721: transfer from incorrect owner");

DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 200 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L200

Added line #L200 was not covered by tests

// Clear approvals from the previous owner
delete _erc721Storage.tokenApprovals[tokenId_];

Check warning on line 203 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L203

Added line #L203 was not covered by tests

unchecked {

Check warning on line 205 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L205

Added line #L205 was not covered by tests
// `_balances[from]` cannot overflow for the same reason as described in `_burn`:
// `from`'s balance is the number of token held, which is at least one before the current
// transfer.
// `_balances[to]` could overflow in the conditions described in `_mint`. That would require
// all 2**256 token ids to be minted, which in practice is impossible.
Arvolear marked this conversation as resolved.
Show resolved Hide resolved
_erc721Storage.balances[from_] -= 1;
_erc721Storage.balances[to_] += 1;

Check warning on line 212 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L211-L212

Added lines #L211 - L212 were not covered by tests
}

_getErc721Storage().owners[tokenId_] = to_;

Check warning on line 215 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L215

Added line #L215 was not covered by tests

emit Transfer(from_, to_, tokenId_);

Check warning on line 217 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L217

Added line #L217 was not covered by tests

_afterTokenTransfer(from_, to_, tokenId_, 1);

Check warning on line 219 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L219

Added line #L219 was not covered by tests
}

/**
* @notice Approve `to` to operate on `tokenId`.
*/
function _approve(address to_, uint256 tokenId_) internal virtual {
_getErc721Storage().tokenApprovals[tokenId_] = to_;

Check warning on line 226 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L225-L226

Added lines #L225 - L226 were not covered by tests

emit Approval(ownerOf(tokenId_), to_, tokenId_);

Check warning on line 228 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L228

Added line #L228 was not covered by tests
}

/**
* @notice Approve `operator` to operate on all of `owner` tokens.
*/
function _setApprovalForAll(

Check warning on line 234 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L234

Added line #L234 was not covered by tests
address owner_,
address operator_,
bool approved_
) internal virtual {
require(owner_ != operator_, "ERC721: approve to caller");

_getErc721Storage().operatorApprovals[owner_][operator_] = approved_;

Check warning on line 241 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L241

Added line #L241 was not covered by tests

emit ApprovalForAll(owner_, operator_, approved_);

Check warning on line 243 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L243

Added line #L243 was not covered by tests
}

/**
* @notice Function to check if the 'to' can receive token.
* The call is not executed if the target address is not a contract.
*/
function _checkOnERC721Received(

Check warning on line 250 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L250

Added line #L250 was not covered by tests
address from_,
address to_,
uint256 tokenId_,
bytes memory data_
) private returns (bool) {
if (to_.isContract()) {
try IERC721Receiver(to_).onERC721Received(msg.sender, from_, tokenId_, data_) returns (

Check warning on line 257 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L257

Added line #L257 was not covered by tests
bytes4 retval
) {
return retval == IERC721Receiver.onERC721Received.selector;

Check warning on line 260 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L260

Added line #L260 was not covered by tests
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");

Check warning on line 263 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L263

Added line #L263 was not covered by tests
} else {
// @solidity memory-safe-assembly
assembly {

Check warning on line 266 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L266

Added line #L266 was not covered by tests
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;

Check warning on line 272 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L272

Added line #L272 was not covered by tests
}
}

/**
* @notice Hook that is called before any token transfer. This includes minting and burning.
*/
function _beforeTokenTransfer(

Check warning on line 279 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L279

Added line #L279 was not covered by tests
address from_,
address to_,
uint256 firstTokenId_,
uint256 batchSize_
) internal virtual {
if (batchSize_ > 1) {
// Will only trigger during construction. Batch transferring (minting) is not available afterwards.
revert("ERC721Enumerable: consecutive transfers not supported");

Check warning on line 287 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L287

Added line #L287 was not covered by tests
}

uint256 tokenId_ = firstTokenId_;

Check warning on line 290 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L290

Added line #L290 was not covered by tests

if (from_ == address(0)) {
_addTokenToAllTokensEnumeration(tokenId_);

Check warning on line 293 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L293

Added line #L293 was not covered by tests
} else if (from_ != to_) {
_removeTokenFromOwnerEnumeration(from_, tokenId_);

Check warning on line 295 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L295

Added line #L295 was not covered by tests
}

if (to_ == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId_);

Check warning on line 299 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L299

Added line #L299 was not covered by tests
} else if (to_ != from_) {
_addTokenToOwnerEnumeration(to_, tokenId_);

Check warning on line 301 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L301

Added line #L301 was not covered by tests
}
}

/**
* @notice Hook that is called after any token transfer. This includes minting and burning.
*/
function _afterTokenTransfer(

Check warning on line 308 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L308

Added line #L308 was not covered by tests
address from_,
address to_,
uint256 firstTokenId_,
uint256 batchSize_
) internal virtual {}

/**
* @notice Private function to add a token to ownership-tracking data structures.
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 319 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L318-L319

Added lines #L318 - L319 were not covered by tests

uint256 length_ = balanceOf(to);
_erc721Storage.ownedTokens[to][length_] = tokenId;
_erc721Storage.ownedTokensIndex[tokenId] = length_;

Check warning on line 323 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L321-L323

Added lines #L321 - L323 were not covered by tests
}

/**
* @notice Private function to add a token to token tracking data structures.
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 330 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L329-L330

Added lines #L329 - L330 were not covered by tests

_erc721Storage.allTokensIndex[tokenId] = _erc721Storage.allTokens.length;
_erc721Storage.allTokens.push(tokenId);

Check warning on line 333 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L332-L333

Added lines #L332 - L333 were not covered by tests
}

/**
* @dev Private function to remove a token from ownership-tracking data structures.
Arvolear marked this conversation as resolved.
Show resolved Hide resolved
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 340 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L339-L340

Added lines #L339 - L340 were not covered by tests
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
Arvolear marked this conversation as resolved.
Show resolved Hide resolved
// then delete the last slot (swap and pop).

uint256 lastTokenIndex_ = balanceOf(from) - 1;
uint256 tokenIndex_ = _erc721Storage.ownedTokensIndex[tokenId];

Check warning on line 345 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L344-L345

Added lines #L344 - L345 were not covered by tests

// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex_ != lastTokenIndex_) {
uint256 lastTokenId = _erc721Storage.ownedTokens[from][lastTokenIndex_];

Check warning on line 349 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L349

Added line #L349 was not covered by tests

_erc721Storage.ownedTokens[from][tokenIndex_] = lastTokenId; // Move the last token to the slot of the to-delete token
_erc721Storage.ownedTokensIndex[lastTokenId] = tokenIndex_; // Update the moved token's index

Check warning on line 352 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L351-L352

Added lines #L351 - L352 were not covered by tests
}

// This also deletes the contents at the last position of the array
delete _erc721Storage.ownedTokensIndex[tokenId];
delete _erc721Storage.ownedTokens[from][lastTokenIndex_];

Check warning on line 357 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L356-L357

Added lines #L356 - L357 were not covered by tests
}

/**
* @dev Private function to remove a token from token tracking data structures.
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
DERC721Storage storage _erc721Storage = _getErc721Storage();

Check warning on line 364 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L363-L364

Added lines #L363 - L364 were not covered by tests
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).

uint256 lastTokenIndex_ = _erc721Storage.allTokens.length - 1;
uint256 tokenIndex_ = _erc721Storage.allTokensIndex[tokenId];

Check warning on line 369 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L368-L369

Added lines #L368 - L369 were not covered by tests

// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId_ = _erc721Storage.allTokens[lastTokenIndex_];

Check warning on line 374 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L374

Added line #L374 was not covered by tests

_erc721Storage.allTokens[tokenIndex_] = lastTokenId_; // Move the last token to the slot of the to-delete token
_erc721Storage.allTokensIndex[lastTokenId_] = tokenIndex_; // Update the moved token's index

Check warning on line 377 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L376-L377

Added lines #L376 - L377 were not covered by tests

// This also deletes the contents at the last position of the array
delete _erc721Storage.allTokensIndex[tokenId];
_erc721Storage.allTokens.pop();

Check warning on line 381 in contracts/diamond/tokens/ERC721/DiamondERC721.sol

View check run for this annotation

Codecov / codecov/patch

contracts/diamond/tokens/ERC721/DiamondERC721.sol#L380-L381

Added lines #L380 - L381 were not covered by tests
}
}
Loading