Hi,
I was following the Rarible clone youtube tutorial. I see the approve function is being called from React.js. How can I call approve function from solidity? I want buyer will again add item to the market for re-sell. Here I attached the related code
main.js
ensureMarketPlaceIsApproved = async(tokenId, tokenAddress) => {
user = await Moralis.User.current();
const userAddress = user.get("ethAddress");
const contract = new web3.eth.Contract(tokenContractAbi, tokenAddress);
const approveAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});
if (approveAddress != MARKETPLACE_CONTRACT_ADDRESS) {
// bring up metamask window to permit transfer token
//approve(address to, uint256 tokenId) : By calling this method,
//the sender authorizes the address to to transfer one of his tokens with the Id tokenId.
await contract.methods.approve(MARKETPLACE_CONTRACT_ADDRESS, tokenId).send({from: userAddress});
}
}
MorarableToken.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/ERC721.sol)
pragma solidity ^0.8.0;
import "../node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "../node_modules/@openzeppelin/contracts/utils/Counters.sol";
contract MorarableToken is ERC721 {
//we nned to access the counter struct from the counter file
//this is used as equivelent for us to say id = 0 and then increment
//in our functions saying id++
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
//we need to pass some values into our constructer
//namely the ERC721 instances for name symbol decimals etc
constructor () ERC721("MorarableToken", "MORA"){}
//we now need to initialise our item as a struct
struct Item {
uint256 id;
address creator;
string uri;
}
//now we need to make a mapping to our user account to the item struct
mapping(uint256 => Item) public Items;
//create item function
function createItem(string memory uri) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
//we can call mint from the ERC721 contract to mint our nft token
_safeMint(msg.sender, newItemId);
Items[newItemId] = Item(newItemId, msg.sender, uri);
return newItemId;
}
//we now need to override the tokenURI function form the ERC721 function to add
//a piece of extra functionality that is not provided by the base contratc function
//namely we need return the item url with the id
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return Items[tokenId].uri;
}
}
MarketPlace.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
contract MorarableMarketContract {
//we need to create a struct for the auction item
struct AuctionItem {
uint256 id;
address tokenAddress;
uint256 tokenId;
address payable seller;
uint256 askingPrice;
bool isSold;
}
//now we want to create an array of auctionItem struct instances to keep
//track of all of the auction items
AuctionItem[] public itemsForSale;
//we also want to create a mapping of active items which allows us to keep
//track of whicg items are for sale. this mapping prevents us rom looping
//through the array above
mapping(address => mapping(uint256 => bool)) activeItems;
event itemAdded(uint256 id, uint256 tokenId, address tokenAddress, uint256 askingPrice);
event itemSold (uint256 id, address buyer, uint256 askingPrice);
//we waant to create a modifier to check if the caller is the item owner
modifier onlyItemOwner (address tokenAddress, uint256 tokenId) {
IERC721 tokenContract = IERC721(tokenAddress);
require(tokenContract.ownerOf(tokenId) == msg.sender);
_;
}
//the next modifier we create checks if the marketplace has the approval of transferring
//the item on behalf of the user
modifier hasTransferApproval (address tokenAddress, uint256 tokenId) {
IERC721 tokenContract = IERC721(tokenAddress);
require(tokenContract.getApproved(tokenId) == address(this));
_;
}
//modifier which checks if the item actuall does exist
modifier itemExists(uint256 id){
require(id < itemsForSale.length && itemsForSale[id].id == id, "could not find item");
_;
}
modifier isForSale(uint256 id) {
require(itemsForSale[id].isSold == false, "item is already sold");
_;
}
//next we will create a function which adds an item for sale to the marketplace
function addItemToMarket(uint256 tokenId, address tokenAddress, uint256 askingPrice) onlyItemOwner(tokenAddress, tokenId) hasTransferApproval(tokenAddress, tokenId) external returns(uint256) {
require(activeItems[tokenAddress][tokenId] == false, "item is already up for sale");
uint256 newItemId = itemsForSale.length;
itemsForSale.push(AuctionItem(newItemId, tokenAddress, tokenId, payable(msg.sender), askingPrice, false));
activeItems[tokenAddress][tokenId] = true;
assert(itemsForSale[newItemId].id == newItemId);
emit itemAdded(newItemId, tokenId, tokenAddress, askingPrice);
return newItemId;
}
//the next function allows us to actually buy an item
function buyItem(uint256 id) payable external itemExists(id) isForSale(id) hasTransferApproval(itemsForSale[id].tokenAddress, itemsForSale[id].tokenId) {
require(msg.value >= itemsForSale[id].askingPrice, "Not enough funds for purchase");
require(msg.sender != itemsForSale[id].seller);
itemsForSale[id].isSold = true;
activeItems[itemsForSale[id].tokenAddress][itemsForSale[id].tokenId] = false;
IERC721(itemsForSale[id].tokenAddress).safeTransferFrom(itemsForSale[id].seller, msg.sender, itemsForSale[id].tokenId);
itemsForSale[id].seller.transfer(msg.value);
emit itemSold(id, msg.sender, itemsForSale[id].askingPrice);
}
}