Does giving approval to a marketplace allow the marketplace contract deployer to move assets if they so wished?

  • It depends on the contract implementation. As said by cryptovale the more common OpenZeppelin allows the operator to transfer to token to anyone (including himself).
    – Ismael
    Aug 14, 2022 at 18:28

1 Answer 1


Let's check a standard implementation by OpenZeppelin:

   function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes memory data
) public virtual override {
    require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
    _safeTransfer(from, to, tokenId, data);

This is taken from here: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol#L175

This line

require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");

uses the function "_isApprovedOrOwner" with the msg.sender and the tokenId. Let's have a look at this function:

 * @dev Returns whether `spender` is allowed to manage `tokenId`.
 * Requirements:
 * - `tokenId` must exist.
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
    address owner = ERC721.ownerOf(tokenId);
    return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);

Reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol#L226

Here, the function checks with a function "isApprovedForAll". Let's check that as well:

 * @dev See {IERC721-isApprovedForAll}.
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
    return _operatorApprovals[owner][operator];

Reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol#L140

That function uses a mapping "_operatorApprovals" which is defined as:

// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;

This means, that an owner can approve an operator to move any token in ownership by the owner.

Let's have a final look at the famous "setApprovalForAll":

 * @dev Approve `operator` to operate on all of `owner` tokens
 * Emits an {ApprovalForAll} event.
function _setApprovalForAll(
    address owner,
    address operator,
    bool approved
) internal virtual {
    require(owner != operator, "ERC721: approve to caller");
    _operatorApprovals[owner][operator] = approved;
    emit ApprovalForAll(owner, operator, approved);

Reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol#L363

There it is:

_operatorApprovals[owner][operator] = approved;

This is the part, where the mapping between the owner and the operator is set to "true". Which means that the function call to "isApprovedOrOwner" will return true, allowing that caller to transfer any token of the owner.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.