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 Wrapper #3863

Merged
merged 38 commits into from
Feb 9, 2023
Merged

Conversation

ernestognw
Copy link
Member

@ernestognw ernestognw commented Dec 7, 2022

Fixes LIB-647

PR Checklist

  • Tests
  • Documentation
  • Changelog entry

@TrejGun
Copy link

TrejGun commented Dec 26, 2022

this definitely should be extended to support erc20 and erc1155

@ernestognw
Copy link
Member Author

this definitely should be extended to support erc20 and erc1155

ERC20Wrapper already exists.

The case for ERC1155 might need more discussion imo.

@TrejGun
Copy link

TrejGun commented Dec 27, 2022

I mean erc721 wrapper for erc20

@Amxx
Copy link
Collaborator

Amxx commented Jan 3, 2023

I would add a "onERC721Received" hook, so you can wrap by doing a safeTransfer to this.

function onERC721Received(address, address from, uint256 tokenId, bytes calldata data) external returns (bytes4) {
    require(msg.sender == address(underlying));
    _safeMint(data.length == 0 ? from : abi.decode(data, (address)), tokenIds);
    return IERC721Receiver.onERC721Received.selector;
}

@ernestognw
Copy link
Member Author

ernestognw commented Jan 4, 2023

I would add a "onERC721Received" hook, so you can wrap by doing a safeTransfer to this.

function onERC721Received(address, address from, uint256 tokenId, bytes calldata data) external returns (bytes4) {
    require(msg.sender == address(underlying));
    _safeMint(data.length == 0 ? from : abi.decode(data, (address)), tokenIds);
    return IERC721Receiver.onERC721Received.selector;
}

Not sure about this. It'll require to use transferFrom() inside depositFor instead of safeTransferFrom(), otherwise _safeMint will be called twice. We'll be exposing our users to the same reason why there's no transfer() in the ERC721.

Also, if we decide to only keep onERC721Received, we'll lose the batch minting allowed in depositFor.

What do you think?

@Amxx
Copy link
Collaborator

Amxx commented Jan 4, 2023

I would add a "onERC721Received" hook, so you can wrap by doing a safeTransfer to this.

function onERC721Received(address, address from, uint256 tokenId, bytes calldata data) external returns (bytes4) {
    require(msg.sender == address(underlying));
    _safeMint(data.length == 0 ? from : abi.decode(data, (address)), tokenIds);
    return IERC721Receiver.onERC721Received.selector;
}

Not sure about this. It'll require to use _transfer() inside depositFor instead of safeTransferFrom(), otherwise _safeMint will be called twice. We'll be exposing our users to the same reason why there's no transfer() in the ERC721.

Also, if we decide to only keep onERC721Received, we'll lose the batch minting allowed in depositFor.

What do you think?

If we add this hook, we can keep safeTransfer in the depositFor function, with the right "data", and remove the _safeMint from deposit. The mint will be handled by the hook.

@Amxx
Copy link
Collaborator

Amxx commented Jan 4, 2023

function depositFor(address account, uint256[] memory tokenIds) public virtual returns (bool) {
    bytes memory data = abi.encode(account);
    for (uint256 i = 0; i < tokenIds.length; ++i) {
        underlying.safeTransferFrom(_msgSender(), address(this), tokenIds[i], data); // This will trigger the hook
    }
    return true;
}

// The hook will mint
function onERC721Received(address, address from, uint256 tokenId, bytes calldata data) external returns (bytes4) {
    require(msg.sender == address(underlying));
    _safeMint(data.length == 0 ? from : abi.decode(data, (address)), tokenIds);
    return IERC721Receiver.onERC721Received.selector;
}

@Amxx
Copy link
Collaborator

Amxx commented Jan 4, 2023

OR, we can use "unsafeTransfer" in deposit, which is ok because we know the receiver is able to handle NFTs

Either option is good IMO.

I really think having the hook brings some value.

@ernestognw
Copy link
Member Author

// The hook will mint
function onERC721Received(address, address from, uint256 tokenId, bytes calldata data) external returns (bytes4) {
require(msg.sender == address(underlying));
_safeMint(data.length == 0 ? from : abi.decode(data, (address)), tokenIds);
return IERC721Receiver.onERC721Received.selector;
}

I have to admit I'm a fan of this solution. So I'll go for it.

Before implementing, I wonder, is there a case for keeping _recover? EIP-721 requires every application/wallet/holder to implement onERC721Received so _recover won't be necessary if this is used for a compliant ERC721.

@ernestognw
Copy link
Member Author

I have to admit I'm a fan of this solution. So I'll go for it.

Before implementing, I wonder, is there a case for keeping _recover? EIP-721 requires every application/wallet/holder to implement onERC721Received so _recover won't be necessary if this is used for a compliant ERC721.

For the record, transferFrom is standard behavior and doesn't enforce onERC721Received check, so _recover should be kept for general unsafe transfers.

@frangio frangio changed the title Feature: ERC721 Wrapper Add ERC721 Wrapper Feb 3, 2023
1 Outdated Show resolved Hide resolved
contracts/token/ERC721/extensions/ERC721Wrapper.sol Outdated Show resolved Hide resolved
contracts/token/ERC721/extensions/ERC721Wrapper.sol Outdated Show resolved Hide resolved
frangio
frangio previously approved these changes Feb 7, 2023
Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@frangio frangio requested a review from Amxx February 7, 2023 23:31
Copy link
Collaborator

@Amxx Amxx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is your second approval :

@ernestognw ernestognw merged commit 94cd8ef into OpenZeppelin:master Feb 9, 2023
@ernestognw ernestognw deleted the feature/erc721-wrapper branch February 15, 2023 02:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants