將 erc721 代幣作為代幣所有者轉移到合約中
我正在嘗試制定一個契約,允許 erc721 令牌的所有者(來自不同的契約)將他們的 nft 發送到這個新契約。
例如:我有一個基本的 erc721 鑄幣合約:
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "hardhat/console.sol"; contract NFT is ERC721, Ownable { using Counters for Counters.Counter; Counters.Counter private _nftIds; string public URI; mapping(uint256 => address) public _getNftOwnerId; mapping(address => mapping(uint256 => uint256)) public _usersNfts; uint256[] public _allNfts; constructor() ERC721 ("Creators Never Die Moodboards", "CND") {} function mint() public returns(uint256) { uint256 newNftId = _nftIds.current(); _safeMint(msg.sender, newNftId); _getNftOwnerId[newNftId] = msg.sender; _usersNfts[msg.sender][newNftId] = newNftId; _allNfts.push(newNftId); _nftIds.increment(); console.log("nft minted with id", newNftId); return newNftId; } }
現在我有一個單獨的契約,我試圖允許
msg.sender
將他們擁有的 tokenId 發送到這個新契約。// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "hardhat/console.sol"; contract BulkTransfer { using Counters for Counters.Counter; Counters.Counter private _nftIds; constructor() {} function approveContract(address _contractAddress) external { ERC721 token = ERC721(_contractAddress); require(token.balanceOf(msg.sender) > 0, "Caller must own nft"); token.setApprovalForAll(address(this), true); } function bulkTransfer(address _contractAddress, uint256 _tokenId) external { ERC721 token = ERC721(_contractAddress); require(token.balanceOf(msg.sender) > 0, "Caller must own nft"); require(token.ownerOf(_tokenId) == msg.sender, "You must own the token"); token.transferFrom(msg.sender, address(this), _tokenId); } }
當我呼叫該
bulkTransfer
函式時,我不斷收到錯誤消息:"ERC721: transfer caller is not owner nor approved".
當我呼叫
aproveContract
函式時,我得到"ERC721: approve to caller"
我在 remix ide 中做這一切。
該行:
token.transferFrom(msg.sender, address(this), _tokenId);
要求 msg.sender 批准部署 BulkTransfer 的合約,以轉移 msg.sender 的代幣。沒有這樣的批准,因此結果為:“ERC721:轉接呼叫者不是所有者,也不是批准”。
關於“ERC721:approval to caller”看看你從OpenZeppelin呼叫 setApprovalForAl :
function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); }
用於批准的 msg.sender 是契約,並且 adress(this) 也是契約,您違反了要求聲明
require(owner != operator, "ERC721: approve to caller");
一般來說,NFT 和代幣不是這樣工作的。
當您將代幣轉移到地址(外部擁有的賬戶或契約賬戶)時,您會更新控制該代幣的智能合約中的值。
查看您的程式碼,在
bulkTransfer
函式中,您嘗試將發件人擁有的代幣 (CND) 分配給BulkTransfer
合約。如果這是你想做的,你只需要呼叫
transfer
CND 智能合約中的方法。請注意,使用 OpenZeppelin 提供的標準實現,如果您將代幣發送到由智能合約而非 EOA 控制的地址,您將永遠失去這些代幣。
相反,如果您希望使用者能夠將自己的代幣發送到多個地址,並且 CND 合約沒有實現批量傳輸功能,您可以編寫和部署智能合約來做到這一點。
使用這種聯繫人並不是很便宜,所以我仍然不明白你為什麼需要它,但這就是你需要做的。
您
bulkTransfer
必須更改為至少獲得一個接收者參數和一個tokenIds 列表,然後您必須遍歷所有選定的 tokenIds,並且您必須檢查每個 tokenIds 的容差 (getApproved
) 並將其傳輸呼叫類似token.transferFrom(msg.sender, recipient, _tokenId)
.並且在呼叫合約中的
bulkTransfer
方法之前,所有者必須向參數中指定地址的 CND 合約BulkTransfer
發送大量的批准交易( ) ,否則整個方法將失敗,即使您失敗了 100 個批准。approve(address _approved, uint256 _tokenId)``BulkTransfer``_approved
bulkTransfer