I'm looking at OpenZeppelin's implementation of an ERC721 token and I'm lost at what the difference is between an approved address and an operator address.

Here's a code snippet:

/// @dev Checks msg.sender can transfer a token, by being owner, approved, or operator
/// @param _tokenId uint256 ID of the token to validate
modifier canTransfer(uint256 _tokenId) {
    require(isApprovedOrOwner(msg.sender, _tokenId));

Could someone explain to me what the key differences are?
Included examples would be very helpful.


Here's the relevant code:

   * @dev Returns whether the given spender can transfer a given token ID
   * @param _spender address of the spender to query
   * @param _tokenId uint256 ID of the token to be transferred
   * @return bool whether the msg.sender is approved for the given token ID,
   *  is an operator of the owner, or is the owner of the token
  function isApprovedOrOwner(
    address _spender,
    uint256 _tokenId
    returns (bool)
    address owner = ownerOf(_tokenId);
    // Disable solium check because of
    // https://github.com/duaraghav8/Solium/issues/175
    // solium-disable-next-line operator-whitespace
    return (
      _spender == owner ||
      getApproved(_tokenId) == _spender ||
      isApprovedForAll(owner, _spender)

First check is whether the person wanting to spend the token is its owner (from the call to ownerOf()):

_spender == owner ||

Relevant mapping is:

// Mapping from token ID to owner
mapping (uint256 => address) internal tokenOwner;

If not, we jump to the next check, which is whether the address of the spender has been approved by the owner to have control over that particular token ID. (So here the delegation is by reference to the token. i.e. The spender has permission for this particular token.)

getApproved(_tokenId) == _spender ||

Relevant mapping is:

// Mapping from token ID to approved address
mapping (uint256 => address) internal tokenApprovals;

If not, and even if the spender isn't the owner or has the single token approval, then they might be in the approved operator list. (In this case the delegation is via reference to the token's owner. i.e. The spender is allowed to "operate" in place of the owner, over any tokens they own.)

isApprovedForAll(owner, _spender)


// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) internal operatorApprovals;
  • Ok so essentially an appoved address is one that is allowed to have control over individual token(s). While an operator address is one that is allowed to control every token the owner owns? – John DeBord May 17 '18 at 23:34
  • Yep, that's correct :-) – Richard Horrocks May 18 '18 at 5:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.