How to interact with contract + ask for approval on metamask

Hey guys, Iā€™m implementing an NFT Staking on my website using Moralis. I canā€™t find a way to executeFunction where the user needs to approve on Metamask for the transaction. Looks like for executeFunction, approval isnā€™t needed, but for something like actually staking, i need for metamask to popup the approval screen for the user.

I also tried using return Moralis.Web3API.native.runContractFunction(options); but not asking for permission either from Metamask.

Iā€™m constantly getting an error

execution reverted: ERC721: transfer caller is not owner nor approved"

This is what Iā€™m sending:

stakeNFTSBatchByTokenIds: function (tokenIds, abiData) {
        const options = {
            chain: process.env === "production" ? "matic" : "mumbai",
            contractAddress: process.env.VUE_APP_STAKE_CONTRACT_TEST,
            functionName: "stakeBatch",
            abi: abiData,
            params: {
                tokenIds: tokenIds
            }
        };

        return Moralis.executeFunction(options);
    }

Effectively, my account is the owner of those NFTs so it shouldnā€™t be an ā€œownershipā€ thing. Metamask is never showing any approval screen so my guess is that the problem comes from that.

Does anyone know how to accomplish it? Thanks in advance.

you will need to use executeFunction twice, once for approval and one to make the transaction

1 Like

Ahhh makes sense. Contract has an ā€œapproveā€ function, but its signature is like this:

function approve(address spender, uint256 amount) external returns (bool);

spender iā€™m guessing is the ownerā€™s wallet? But what about amount?

It says it goes along with the allowance. Is there any place where i can read documentation about what these values are?

Thanks for replying too!

The amount is how much it will be allowed the spender to spend after that, usually the price of the item.

Mmmm but why would i need to set a price if iā€™m just moving NFTs from ownerā€™s wallet to stake? I was also thinking on letting the user stake in batch, so it would be easier for them to select even all their NFTs and stake them. And for approval, howā€™s that even going to work? Approve needs to be done on 1 by 1 ? :confused:

In that case you may need to allow for the contract to transfer that nft. But someone may want to buy that nft and in that case you need a price later for when someone buys an nft, in case that you use tokens and not native currency.

For nft it may be a different approve function with different parameters.

Ahhhhh, trueā€¦ even if an NFT is staking, someone can still sell it on opensea.

I was able to make it work :slight_smile: I had to setApprovalForAll from my NFTs contract, authorizing the staking contract to interact with peopleā€™s NFTs.
Quick question though, I wanted to update the UI once the tx is done (for Staking), even that Iā€™m using promises and succeeds, it happens faster than the blockchain to realize there was a transfer, so when I try to retrieve the total NFTs, i keep getting the ā€œlast valueā€, when i refresh the page after a few more seconds, it will properly update.

How do you guys manage to refresh UI? Is there any event or promise attached on Moralis returned object?

Thanks.

I donā€™t know exactly how to do it. You could also check once every second of that transaction hash made it on chain and refresh the page after you confirmed it that way

1 Like

Yea itā€™s a good idea, will check that out. Thanks!

Hey crypto, one thing. Iā€™m trying to connect to web3 through websocket, but the only server URL provided on moralis is through https. So when I attempt to subscribe using HTTPS it throws: Error: The current provider doesn't support subscriptions: HttpProvider

Is there anything for websockets?

Thanks.

You can use websockets too, in admin interface, for speedy nodes, you have a different link specific to websockets

I found another way which is by using: transaction.wait().

const transaction = await Moralis.executeFunction(options);
return transaction.wait();

It works like a charm.

Thanks for replying as usual <3

1 Like

hey could you please tell me how its possible to use

const transaction = await Moralis.executeFunction(options);
return transaction.wait();

from react? I really need to use wait()

thanks that worked perfect :slight_smile:
also i noticed that you said that " runContractFunction" is read only which is not the case. Iā€™ve been using it for approveForAll() requests aswell as isApprovedForAll()

Yes. It works for write functions too depending on your configuration and naming. I see some people use it alot.