如何将 NFT 转移到另一个智能合约?
How to transfer a NFT to another smart contract?
我正在尝试设置一个托管合约,将存款作为 NFT 存入合约。我正在努力将 NFT 存入合约。
我从一个简单的 NFT 开始,它被铸造到带有 id 的地址。
contract MyEpicNFT is ERC721URIStorage {
// Magic given to us by OpenZeppelin to help us keep track of tokenIds.
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
// We need to pass the name of our NFTs token and its symbol.
constructor() ERC721 ("SquareNFT", "SQUARE") {
console.log("This is my NFT contract. Woah!");
console.log(address(this));
}
// A function our user will hit to get their NFT.
function makeNft() public {
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, "https://jsonkeeper.com/b/1LHH");
console.log("An NFT w/ ID %s has been minted to %s", newItemId, msg.sender);
_tokenIds.increment();
}
}
在这种情况下,已将 ID 为 0 的 NFT 铸造到合约的 msg.sender 中:0xdD870fA1b7C4700F2BD7f44238821C26f7392148
我知道现在我需要批准托管合同才能“花费”此令牌。要在 MyEpicNft 合约上执行此操作,我使用 MyEpicNft 的合约地址和铸造的 NFT 的 Id 调用批准函数。
console.log:
This is my NFT contract. Woah!
0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a
在我的例子中,我用 (0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a, 0) 调用批准 - 这似乎有效。现在我需要在 NftEscrow 合约中做的就是充值 NFT
我使用的 approve 函数来自 ERC721 库
approve(address to, uint256 tokenId)
有一个 depositNFT 函数获取 NFT 地址——在我们的例子中是 0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a 和 0。但是当我这样做时,我收到错误消息:
The transaction has been reverted to the initial state.
Reason provided by the contract: "ERC721: transfer caller is not owner nor approved".
Debug the transaction to get more information.
contract NftEscrow is IERC721Receiver {
enum ProjectState {newEscrow, nftDeposited, cancelNFT, ethDeposited, canceledBeforeDelivery, deliveryInitiated, delivered}
address payable public sellerAddress;
address payable public buyerAddress;
address public nftAddress;
uint256 tokenID;
bool buyerCancel = false;
bool sellerCancel = false;
ProjectState public projectState;
receive() external payable {
}
constructor(){
sellerAddress = payable(msg.sender);
projectState = ProjectState.newEscrow;
}
function onERC721Received( address , address , uint256 , bytes calldata ) public pure override returns (bytes4) {
return this.onERC721Received.selector;
}
function depositNFT(address _NFTAddress, uint256 _TokenID) public onlySeller {
nftAddress = _NFTAddress;
tokenID = _TokenID;
ERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenID);
projectState = ProjectState.nftDeposited;
}
function depositEth() public payable {
buyerAddress = payable(msg.sender);
projectState = ProjectState.ethDeposited;
}
function confirmDelivery()public payable {
ERC721(nftAddress).safeTransferFrom(address(this), buyerAddress, tokenID);
sellerAddress.transfer(address(this).balance);
}
modifier onlySeller() {
require(msg.sender == sellerAddress);
_;
}
}
不确定我做错了什么,并为此停留了一天。为什么我不能将 NFT 存入智能合约?
如果以下 none 为真,您的托管合同将恢复为 "ERC721: transfer caller is not owner nor approved"
:
msg.sender
是合约的所有者
msg.sender
已为所有人批准
msg.sender
已被所有者批准使用该令牌
根据您的情况,我们选择第三个选项。
我们需要检查的是
- 你真的认可正确的地址吗?
- 审批功能恢复了吗?
托管合约调用NFT合约时
ERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenID);
从NFT合约的角度来看,msg.sender
就是托管合约。所以 99% 的问题出在你的审批流程上。请分享更多相关信息。
编辑:
我们正在尝试使以下条件为真,其中 spender
是托管合约的地址
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
如果 getApproved 确实是 returns 合约地址,请尝试在您的 nft 合约中添加以下功能:
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual override returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
console.log("spender %s", spender);
console.log("getApproved %s", getApproved(tokenId);
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
}
我正在尝试设置一个托管合约,将存款作为 NFT 存入合约。我正在努力将 NFT 存入合约。
我从一个简单的 NFT 开始,它被铸造到带有 id 的地址。
contract MyEpicNFT is ERC721URIStorage {
// Magic given to us by OpenZeppelin to help us keep track of tokenIds.
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
// We need to pass the name of our NFTs token and its symbol.
constructor() ERC721 ("SquareNFT", "SQUARE") {
console.log("This is my NFT contract. Woah!");
console.log(address(this));
}
// A function our user will hit to get their NFT.
function makeNft() public {
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, "https://jsonkeeper.com/b/1LHH");
console.log("An NFT w/ ID %s has been minted to %s", newItemId, msg.sender);
_tokenIds.increment();
}
}
在这种情况下,已将 ID 为 0 的 NFT 铸造到合约的 msg.sender 中:0xdD870fA1b7C4700F2BD7f44238821C26f7392148
我知道现在我需要批准托管合同才能“花费”此令牌。要在 MyEpicNft 合约上执行此操作,我使用 MyEpicNft 的合约地址和铸造的 NFT 的 Id 调用批准函数。
console.log:
This is my NFT contract. Woah!
0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a
在我的例子中,我用 (0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a, 0) 调用批准 - 这似乎有效。现在我需要在 NftEscrow 合约中做的就是充值 NFT
我使用的 approve 函数来自 ERC721 库
approve(address to, uint256 tokenId)
有一个 depositNFT 函数获取 NFT 地址——在我们的例子中是 0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a 和 0。但是当我这样做时,我收到错误消息:
The transaction has been reverted to the initial state.
Reason provided by the contract: "ERC721: transfer caller is not owner nor approved".
Debug the transaction to get more information.
contract NftEscrow is IERC721Receiver {
enum ProjectState {newEscrow, nftDeposited, cancelNFT, ethDeposited, canceledBeforeDelivery, deliveryInitiated, delivered}
address payable public sellerAddress;
address payable public buyerAddress;
address public nftAddress;
uint256 tokenID;
bool buyerCancel = false;
bool sellerCancel = false;
ProjectState public projectState;
receive() external payable {
}
constructor(){
sellerAddress = payable(msg.sender);
projectState = ProjectState.newEscrow;
}
function onERC721Received( address , address , uint256 , bytes calldata ) public pure override returns (bytes4) {
return this.onERC721Received.selector;
}
function depositNFT(address _NFTAddress, uint256 _TokenID) public onlySeller {
nftAddress = _NFTAddress;
tokenID = _TokenID;
ERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenID);
projectState = ProjectState.nftDeposited;
}
function depositEth() public payable {
buyerAddress = payable(msg.sender);
projectState = ProjectState.ethDeposited;
}
function confirmDelivery()public payable {
ERC721(nftAddress).safeTransferFrom(address(this), buyerAddress, tokenID);
sellerAddress.transfer(address(this).balance);
}
modifier onlySeller() {
require(msg.sender == sellerAddress);
_;
}
}
不确定我做错了什么,并为此停留了一天。为什么我不能将 NFT 存入智能合约?
如果以下 none 为真,您的托管合同将恢复为 "ERC721: transfer caller is not owner nor approved"
:
msg.sender
是合约的所有者msg.sender
已为所有人批准msg.sender
已被所有者批准使用该令牌
根据您的情况,我们选择第三个选项。
我们需要检查的是
- 你真的认可正确的地址吗?
- 审批功能恢复了吗?
托管合约调用NFT合约时
ERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenID);
从NFT合约的角度来看,msg.sender
就是托管合约。所以 99% 的问题出在你的审批流程上。请分享更多相关信息。
编辑:
我们正在尝试使以下条件为真,其中 spender
是托管合约的地址
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
如果 getApproved 确实是 returns 合约地址,请尝试在您的 nft 合约中添加以下功能:
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual override returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
console.log("spender %s", spender);
console.log("getApproved %s", getApproved(tokenId);
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
}