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

onERC721Received #443

Open
sayedex opened this issue Jan 12, 2023 · 15 comments
Open

onERC721Received #443

sayedex opened this issue Jan 12, 2023 · 15 comments

Comments

@sayedex
Copy link

sayedex commented Jan 12, 2023

when i try to rcv my erc721 from null address on my contract onERC721Received its not working

@Vectorized
Copy link
Collaborator

Can you share your code?

@sayedex
Copy link
Author

sayedex commented Jan 12, 2023

contract NftMinterA is IERC721Receiver{

address public admin;
mapping(address => uint256[]) private tokenIdsByContract;

constructor(address _admin) {
    admin = _admin;
}

function mint(
    address nft,
    bytes calldata param
    ) external payable {
    (bool success, ) = nft.call{value: msg.value}(param);
    require(success);
}


function transfer(address nft) external {
    uint256[] memory _tokenIds = tokenIdsByContract[nft];
    uint256 _length = _tokenIds.length;

    for (uint256 i = 0; i < _length; i++ ) {
        IERC721(nft).transferFrom(address(this), admin, _tokenIds[i]);
    }
    delete tokenIdsByContract[nft];
}
function onERC721Received(
    address,
    address,
    uint256 _tokenId,
    bytes memory
) public virtual override returns (bytes4) {
    tokenIdsByContract[msg.sender].push(_tokenId);
    return this.onERC721Received.selector;
}

function tokenIdsByNFT(address nft) external view returns(uint256[] memory){
    return tokenIdsByContract[nft];
}

}

@Vectorized
Copy link
Collaborator

Why are you calling call instead of mintTo(address to, uint256 quantity) on the nft contract?

@sayedex
Copy link
Author

sayedex commented Jan 12, 2023

its a subcontract bro! it will be deployed by facotory contract but my question is all about onERC721Received how can i work it to be true?

@Vectorized
Copy link
Collaborator

Need to see the code of your NFT contract too.

@sayedex
Copy link
Author

sayedex commented Jan 13, 2023

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol

// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**

  • @dev Interface of the ERC165 standard, as defined in the
  • https://eips.ethereum.org/EIPS/eip-165[EIP].
  • Implementers can declare support of contract interfaces, which can then be
  • queried by others ({ERC165Checker}).
  • For an implementation, see {ERC165}.
    */

interface IERC721AMock {
function safeMint(address to, uint256 quantity) external;
}
interface ERC721A__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}

interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* interfaceId. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol

// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

/**

  • @dev Required interface of an ERC721 compliant contract.
    /
    interface IERC721 is IERC165 {
    /
    *

    • @dev Emitted when tokenId token is transferred from from to to.
      */
      event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**

    • @dev Emitted when owner enables approved to manage the tokenId token.
      */
      event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**

    • @dev Emitted when owner enables or disables (approved) operator to manage all of its assets.
      */
      event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**

    • @dev Returns the number of tokens in owner's account.
      */
      function balanceOf(address owner) external view returns (uint256 balance);

    /**

    • @dev Returns the owner of the tokenId token.
    • Requirements:
      • tokenId must exist.
        */
        function ownerOf(uint256 tokenId) external view returns (address owner);

    /**

    • @dev Safely transfers tokenId token from from to to.
    • Requirements:
      • from cannot be the zero address.
      • to cannot be the zero address.
      • tokenId token must exist and be owned by from.
      • If the caller is not from, it must be approved to move this token by either {approve} or {setApprovalForAll}.
      • If to refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    • Emits a {Transfer} event.
      */
      function safeTransferFrom(
      address from,
      address to,
      uint256 tokenId,
      bytes calldata data
      ) external;

    /**

    • @dev Safely transfers tokenId token from from to to, checking first that contract recipients
    • are aware of the ERC721 protocol to prevent tokens from being forever locked.
    • Requirements:
      • from cannot be the zero address.
      • to cannot be the zero address.
      • tokenId token must exist and be owned by from.
      • If the caller is not from, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
      • If to refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    • Emits a {Transfer} event.
      */
      function safeTransferFrom(
      address from,
      address to,
      uint256 tokenId
      ) external;

    /**

    • @dev Transfers tokenId token from from to to.
    • WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
    • Requirements:
      • from cannot be the zero address.
      • to cannot be the zero address.
      • tokenId token must be owned by from.
      • If the caller is not from, it must be approved to move this token by either {approve} or {setApprovalForAll}.
    • Emits a {Transfer} event.
      */
      function transferFrom(
      address from,
      address to,
      uint256 tokenId
      ) external;

    /**

    • @dev Gives permission to to to transfer tokenId token to another account.
    • The approval is cleared when the token is transferred.
    • Only a single account can be approved at a time, so approving the zero address clears previous approvals.
    • Requirements:
      • The caller must own the token or be an approved operator.
      • tokenId must exist.
    • Emits an {Approval} event.
      */
      function approve(address to, uint256 tokenId) external;

    /**

    • @dev Approve or remove operator as an operator for the caller.
    • Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
    • Requirements:
      • The operator cannot be the caller.
    • Emits an {ApprovalForAll} event.
      */
      function setApprovalForAll(address operator, bool _approved) external;

    /**

    • @dev Returns the account approved for tokenId token.
    • Requirements:
      • tokenId must exist.
        */
        function getApproved(uint256 tokenId) external view returns (address operator);

    /**

    • @dev Returns if the operator is allowed to manage all of the assets of owner.
    • See {setApprovalForAll}
      */
      function isApprovedForAll(address owner, address operator) external view returns (bool);
      }

// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol

// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**

  • @title ERC721 token receiver interface
  • @dev Interface for any contract that wants to support safeTransfers
  • from ERC721 asset contracts.
    /
    interface IERC721Receiver {
    /
    *
    • @dev Whenever an {IERC721} tokenId token is transferred to this contract via {IERC721-safeTransferFrom}
    • by operator from from, this function is called.
    • It must return its Solidity selector to confirm the token transfer.
    • If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
    • The selector can be obtained in Solidity with IERC721Receiver.onERC721Received.selector.
      */
      function onERC721Received(
      address operator,
      address from,
      uint256 tokenId,
      bytes calldata data
      ) external returns (bytes4);
      }

// File: contracts/nft_minter.sol

pragma solidity ^0.8.0;

contract NftMinter is ERC721A__IERC721Receiver{

address public admin;
uint public sayed = 5;
mapping(address => uint256[]) private tokenIdsByContract;

constructor(address _admin) {
    admin = _admin;
}

function mint(
    address nft,
    bytes calldata param
    ) external payable {
    (bool success, ) = nft.call{value: msg.value}(param);
    require(success);
}
 function _mint(
    address nft,
    bytes calldata param
    ) external payable {
    (bool success, ) = nft.call(param);
    require(success);
}

function transfer(address nft) external {
    uint256[] memory _tokenIds = tokenIdsByContract[nft];
    uint256 _length = _tokenIds.length;

    for (uint256 i = 0; i < _length; i++ ) {
        IERC721(nft).transferFrom(address(this), admin, _tokenIds[i]);
    }
    delete tokenIdsByContract[nft];
}

function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes memory data
) public override returns (bytes4) {
tokenIdsByContract[msg.sender].push(tokenId);
return this.onERC721Received.selector;
}

function tokenIdsByNFT(address nft) external view returns(uint256[] memory){
    return tokenIdsByContract[nft];
}

function Givescon() pure public returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}

}

contract NftMinterA is IERC721Receiver{

address public admin;
mapping(address => uint256[]) private tokenIdsByContract;

constructor(address _admin) {
    admin = _admin;
}

function mint(
    address nft,
    bytes calldata param
    ) external payable {
    (bool success, ) = nft.call{value: msg.value}(param);
    require(success);
}


function transfer(address nft) external {
    uint256[] memory _tokenIds = tokenIdsByContract[nft];
    uint256 _length = _tokenIds.length;

    for (uint256 i = 0; i < _length; i++ ) {
        IERC721(nft).transferFrom(address(this), admin, _tokenIds[i]);
    }
    delete tokenIdsByContract[nft];
}
function onERC721Received(
    address,
    address,
    uint256 _tokenId,
    bytes memory
) public virtual override returns (bytes4) {
    tokenIdsByContract[msg.sender].push(_tokenId);
    return this.onERC721Received.selector;
}

function tokenIdsByNFT(address nft) external view returns(uint256[] memory){
    return tokenIdsByContract[nft];
}

}

// File: contracts/factory.sol

pragma solidity ^0.8.0;

contract Factory is IERC721Receiver{

address public admin;
address[] public minters;
uint256 salt = 0;
uint256 tokenId;

constructor(address _admin) {
    admin = _admin;
}

function getBytecode() internal view returns (bytes memory) {
    bytes memory bytecode = type(NftMinter).creationCode;
    
    return abi.encodePacked(bytecode, abi.encode(admin));
}

function deploy(uint256 amount) external {
    bytes memory bytecode = getBytecode();
    for(uint256 i = 0; i < amount; i ++) {
        address addr;
        uint256 _salt = salt;
        assembly {
            addr := create2(callvalue(), add(bytecode, 0x20), mload(bytecode), _salt)

            if iszero(extcodesize(addr)) {
                revert(0, 0)
            }
        }
        minters.push(addr);
        salt++;
    }
}

function mintBySubContract(
    address nft,
    uint256 amount,
    bytes calldata param
) external payable {
    uint256 price = msg.value / amount;
    for(uint256 i = 0; i < amount; i ++) {
        NftMinter(minters[i]).mint{value: price}(nft, param);
    }
}

function _mintBySubContract(
address nft,
uint256 amount,
bytes calldata param
) external {
for(uint256 i = 0; i < amount; i ++) {
NftMinter(minters[i])._mint(nft, param);
}
}

function transferBySubContract(
    address nft,
    uint256 amount
) external {
    for(uint256 i = 0; i < amount; i ++) {
        NftMinter(minters[i]).transfer(nft);
    }
}


function mintAndTransfer(
    address nft,
    uint256 amount,
    bytes calldata param
) external {
    for(uint256 i = 0; i < amount; i ++) {
        (bool success, ) = nft.call(param);
        require(success);
        IERC721(nft).transferFrom(address(this), admin, tokenId);
    }
}

function mint(
    address nft,
    uint256 amount,
    bytes calldata param
) external {
    for(uint256 i = 0; i < amount; i ++) {
        (bool success, ) = nft.call(param);
        require(success);
    }
}

function onERC721Received(
  address,
  address,
  uint256 _tokenId,
  bytes memory
) public virtual override returns (bytes4) {
    tokenId = _tokenId;
    return this.onERC721Received.selector;
}

}

@Vectorized
Copy link
Collaborator

I can't find anything that is subclassing ERC721A.

@sayedex
Copy link
Author

sayedex commented Jan 13, 2023

how can implement thar if i do that the function onERC721Received(
address,
address,
uint256 _tokenId,
bytes memory
) public virtual override returns (bytes4) {
///this one only working on erc721 but when i sens erc721A its not updateing my data
tokenIdsByContract[msg.sender].push(_tokenId);
return this.onERC721Received.selector;
}
will work?

@Vectorized
Copy link
Collaborator

I think you should just make a single contract inherited from ERC721A that also contains the minting function.

@sayedex
Copy link
Author

sayedex commented Jan 13, 2023

okey i will try then i will update you !

@Vectorized
Copy link
Collaborator

@sayedex
Copy link
Author

sayedex commented Jan 13, 2023

not working! same its not updaing tokenIdsByContract[msg.sender].push(_tokenId); on onERC721Received

@Vectorized
Copy link
Collaborator

Use _safeMint for the example.

@Vectorized
Copy link
Collaborator

Some general advice:

For the best results, you should just copy the code of an established project if you need it up ASAP with minimum hassle.

It seems that you are trying to implement something beyond your current Solidity level, or trying to over-engineer things, when a simple all-in-one mintable NFT contract will do the job.

You might want to consider the using the OpenZeppelin wizard instead of ERC721A.

As much as I would like, issues should not be used as a step by step tutorial. There are better resources for that.

@sayedex
Copy link
Author

sayedex commented Jan 13, 2023

thanks! actually its my client requirement only

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

No branches or pull requests

2 participants