소스 검색

Align ERC721 Receiver with current ERC721 standard. (#1047)

* Align ERC721 Receiver with current ERC721 standard.
Adds a second address field to onERC721Received
onERC721Received(address,address,uint256,bytes)
Updates the function signature to 0x150b7a02 from 0xf0b9e5ba

* Add _operator to onERC721Received

* Fix error caused by formatOnSave

* Fixed comments on ERC721Receiver
Removed "Must use 50,000 gas or less"
Corrected the function signature
Paul Barclay 7 년 전
부모
커밋
7d8e3ca8b2

+ 6 - 3
contracts/mocks/ERC721ReceiverMock.sol

@@ -8,7 +8,8 @@ contract ERC721ReceiverMock is ERC721Receiver {
   bool reverts;
 
   event Received(
-    address _address,
+    address _operator,
+    address _from,
     uint256 _tokenId,
     bytes _data,
     uint256 _gas
@@ -20,7 +21,8 @@ contract ERC721ReceiverMock is ERC721Receiver {
   }
 
   function onERC721Received(
-    address _address,
+    address _operator,
+    address _from,
     uint256 _tokenId,
     bytes _data
   )
@@ -29,7 +31,8 @@ contract ERC721ReceiverMock is ERC721Receiver {
   {
     require(!reverts);
     emit Received(
-      _address,
+      _operator,
+      _from,
       _tokenId,
       _data,
       gasleft() // msg.gas was deprecated in solidityv0.4.21

+ 5 - 5
contracts/token/ERC721/ERC721BasicToken.sol

@@ -36,9 +36,9 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
   using SafeMath for uint256;
   using AddressUtils for address;
 
-  // Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
+  // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
   // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
-  bytes4 private constant ERC721_RECEIVED = 0xf0b9e5ba;
+  bytes4 private constant ERC721_RECEIVED = 0x150b7a02;
 
   // Mapping from token ID to owner
   mapping (uint256 => address) internal tokenOwner;
@@ -194,7 +194,7 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
    * @dev Safely transfers the ownership of a given token ID to another address
    * If the target address is a contract, it must implement `onERC721Received`,
    * which is called upon a safe transfer, and return the magic value
-   * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; otherwise,
+   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
    * the transfer is reverted.
    *
    * Requires the msg sender to be the owner, approved, or operator
@@ -218,7 +218,7 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
    * @dev Safely transfers the ownership of a given token ID to another address
    * If the target address is a contract, it must implement `onERC721Received`,
    * which is called upon a safe transfer, and return the magic value
-   * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; otherwise,
+   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
    * the transfer is reverted.
    * Requires the msg sender to be the owner, approved, or operator
    * @param _from current owner of the token
@@ -346,7 +346,7 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
       return true;
     }
     bytes4 retval = ERC721Receiver(_to).onERC721Received(
-      _from, _tokenId, _data);
+      msg.sender, _from, _tokenId, _data);
     return (retval == ERC721_RECEIVED);
   }
 }

+ 1 - 1
contracts/token/ERC721/ERC721Holder.sol

@@ -4,7 +4,7 @@ import "./ERC721Receiver.sol";
 
 
 contract ERC721Holder is ERC721Receiver {
-  function onERC721Received(address, uint256, bytes) public returns(bytes4) {
+  function onERC721Received(address, address, uint256, bytes) public returns(bytes4) {
     return ERC721_RECEIVED;
   }
 }

+ 8 - 6
contracts/token/ERC721/ERC721Receiver.sol

@@ -9,24 +9,26 @@ pragma solidity ^0.4.24;
 contract ERC721Receiver {
   /**
    * @dev Magic value to be returned upon successful reception of an NFT
-   *  Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`,
+   *  Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,
    *  which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
    */
-  bytes4 internal constant ERC721_RECEIVED = 0xf0b9e5ba;
+  bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;
 
   /**
    * @notice Handle the receipt of an NFT
    * @dev The ERC721 smart contract calls this function on the recipient
    * after a `safetransfer`. This function MAY throw to revert and reject the
-   * transfer. This function MUST use 50,000 gas or less. Return of other
-   * than the magic value MUST result in the transaction being reverted.
+   * transfer. Return of other than the magic value MUST result in the 
+   * transaction being reverted.
    * Note: the contract address is always the message sender.
-   * @param _from The sending address
+   * @param _operator The address which called `safeTransferFrom` function
+   * @param _from The address which previously owned the token
    * @param _tokenId The NFT identifier which is being transfered
    * @param _data Additional data with no specified format
-   * @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
+   * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    */
   function onERC721Received(
+    address _operator,
     address _from,
     uint256 _tokenId,
     bytes _data

+ 14 - 2
test/token/ERC721/ERC721BasicToken.behaviour.js

@@ -18,7 +18,7 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
   const unknownTokenId = 3;
   const creator = accounts[0];
   const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
-  const RECEIVER_MAGIC_VALUE = '0xf0b9e5ba';
+  const RECEIVER_MAGIC_VALUE = '0x150b7a02';
 
   describe('like an ERC721BasicToken', function () {
     beforeEach(async function () {
@@ -280,7 +280,19 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
               result.receipt.logs.length.should.be.equal(2);
               const [log] = decodeLogs([result.receipt.logs[1]], ERC721Receiver, this.receiver.address);
               log.event.should.be.eq('Received');
-              log.args._address.should.be.equal(owner);
+              log.args._operator.should.be.equal(owner);
+              log.args._from.should.be.equal(owner);
+              log.args._tokenId.toNumber().should.be.equal(tokenId);
+              log.args._data.should.be.equal(data);
+            });
+
+            it('should call onERC721Received from approved', async function () {
+              const result = await transferFun.call(this, owner, this.to, tokenId, { from: approved });
+              result.receipt.logs.length.should.be.equal(2);
+              const [log] = decodeLogs([result.receipt.logs[1]], ERC721Receiver, this.receiver.address);
+              log.event.should.be.eq('Received');
+              log.args._operator.should.be.equal(approved);
+              log.args._from.should.be.equal(owner);
               log.args._tokenId.toNumber().should.be.equal(tokenId);
               log.args._data.should.be.equal(data);
             });