Skip to content

Commit

Permalink
Agent: add ERC721Receiver support (aragon#1058)
Browse files Browse the repository at this point in the history
* Agent: add ERC721Receiver support

* Lint

* Test

* Address review comments

* cosmetic: small whitespace changes

Co-authored-by: Brett Sun <qisheng.brett.sun@gmail.com>
  • Loading branch information
izqui and sohkai committed Mar 11, 2020
1 parent 940efd5 commit abe759f
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 14 deletions.
37 changes: 23 additions & 14 deletions apps/agent/contracts/Agent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ pragma solidity 0.4.24;
import "./SignatureValidator.sol";
import "./standards/IERC165.sol";
import "./standards/ERC1271.sol";
import "./standards/IERC721Receiver.sol";

import "@aragon/apps-vault/contracts/Vault.sol";

import "@aragon/os/contracts/common/IForwarder.sol";


contract Agent is IERC165, ERC1271Bytes, IForwarder, IsContract, Vault {
contract Agent is IERC165, IERC721Receiver, ERC1271Bytes, IForwarder, IsContract, Vault {
/* Hardcoded constants to save gas
bytes32 public constant EXECUTE_ROLE = keccak256("EXECUTE_ROLE");
bytes32 public constant SAFE_EXECUTE_ROLE = keccak256("SAFE_EXECUTE_ROLE");
Expand All @@ -35,6 +36,7 @@ contract Agent is IERC165, ERC1271Bytes, IForwarder, IsContract, Vault {
uint256 public constant PROTECTED_TOKENS_CAP = 10;

bytes4 private constant ERC165_INTERFACE_ID = 0x01ffc9a7;
bytes4 private constant ERC721_RECEIVED_INTERFACE_ID = 0x150b7a02; // bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))

string private constant ERROR_TARGET_PROTECTED = "AGENT_TARGET_PROTECTED";
string private constant ERROR_PROTECTED_TOKENS_MODIFIED = "AGENT_PROTECTED_TOKENS_MODIFIED";
Expand All @@ -56,6 +58,7 @@ contract Agent is IERC165, ERC1271Bytes, IForwarder, IsContract, Vault {
event RemoveProtectedToken(address indexed token);
event PresignHash(address indexed sender, bytes32 indexed hash);
event SetDesignatedSigner(address indexed sender, address indexed oldSigner, address indexed newSigner);
event ReceiveERC721(address indexed token, address indexed operator, address indexed from, uint256 tokenId, bytes data);

/**
* @notice Execute '`@radspec(_target, _data)`' on `_target``_ethValue == 0 ? '' : ' (Sending ' + @tokenAmount(0x0000000000000000000000000000000000000000, _ethValue) + ')'`
Expand Down Expand Up @@ -197,6 +200,12 @@ contract Agent is IERC165, ERC1271Bytes, IForwarder, IsContract, Vault {
emit SetDesignatedSigner(msg.sender, oldDesignatedSigner, _designatedSigner);
}

function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns (bytes4) {
emit ReceiveERC721(msg.sender, _operator, _from, _tokenId, _data);

return ERC721_RECEIVED_INTERFACE_ID;
}

// Forwarding fns

/**
Expand All @@ -208,6 +217,19 @@ contract Agent is IERC165, ERC1271Bytes, IForwarder, IsContract, Vault {
return true;
}

/**
* @notice Tells whether this contract supports a given ERC-165 interface
* @dev Implements conformance to ERC-165
* @param _interfaceId Interface bytes to check
* @return True if this contract supports the interface
*/
function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
return
_interfaceId == ERC1271_INTERFACE_ID ||
_interfaceId == ERC721_RECEIVED_INTERFACE_ID ||
_interfaceId == ERC165_INTERFACE_ID;
}

/**
* @notice Execute the script as the Agent app
* @dev IForwarder interface conformance. Forwards any token holder action.
Expand All @@ -233,19 +255,6 @@ contract Agent is IERC165, ERC1271Bytes, IForwarder, IsContract, Vault {
return canPerform(_sender, RUN_SCRIPT_ROLE, arr(_getScriptACLParam(_evmScript)));
}

// ERC-165 conformance

/**
* @notice Tells whether this contract supports a given ERC-165 interface
* @param _interfaceId Interface bytes to check
* @return True if this contract supports the interface
*/
function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
return
_interfaceId == ERC1271_INTERFACE_ID ||
_interfaceId == ERC165_INTERFACE_ID;
}

// ERC-1271 conformance

/**
Expand Down
20 changes: 20 additions & 0 deletions apps/agent/contracts/standards/IERC721Receiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pragma solidity 0.4.24;


interface IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer.
* Note: the ERC721 contract address is always the message sender.
* @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 transferred
* @param data Additional data with no specified format
* @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes data) external returns (bytes4);
}
5 changes: 5 additions & 0 deletions apps/agent/test/agent_shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module.exports = (
const NO_DATA = '0x'
const ERC165_SUPPORT_INVALID_ID = '0xffffffff'
const ERC165_SUPPORT_INTERFACE_ID = '0x01ffc9a7'
const ERC721_RECEIVED_INTERFACE_ID = '0x150b7a02'

const AgentLike = artifacts.require(agentName)

Expand Down Expand Up @@ -759,6 +760,10 @@ module.exports = (
assert.isTrue(await agent.supportsInterface(ERC1271_INTERFACE_ID))
})

it('supports ERC721Receiver interface', async () => {
assert.isTrue(await agent.supportsInterface(ERC721_RECEIVED_INTERFACE_ID))
})

it('doesn\'t support any other interface', async () => {
assert.isFalse(await agent.supportsInterface('0x12345678'))
assert.isFalse(await agent.supportsInterface('0x'))
Expand Down

0 comments on commit abe759f

Please sign in to comment.