0

I'm trying to develop a dApp where I need to be able to transfer all of a user's NFTs to another wallet.

As I see it, this can be accomplished by looping through each smart contract the user owns NFTs on, and calling setApprovalForAll with the operator being an address I control. However, each call to setApprovalForAll requires a transaction to be executed, which can be very cumbersome for larger wallets.

How can I execute a single transaction which gives me access to all NFTs a user owns? Is there a way to bundle each setApprovalForAll call into a single transaction?

Many thanks.

3 Answers 3

1

There is something called MultiCall in Solidity. It packs a call to different functions of different contracts in a single function and treats it as a single transaction. I have not tried it fully, but I think this might be useful in your case.

0

One approach to this problem would be to use a contract that acts as a wrapper for the setApprovalForAll function. This contract would have a function that accepts an array of addresses for the NFT contracts, and an array of addresses for the operators (the address you control). Then, the function would loop through the arrays and call setApprovalForAll for each pair of contract and operator addresses. This way, all the setApprovalForAll calls can be executed in a single transaction.

Another approach would be to use a batch call mechanism, such as the Multisend from the contract provided by the Gnosis Safe library. This contract allows you to execute multiple calls in a single transaction, which could be used to call setApprovalForAll and send them in a single transaction.

0

If you are the one writing the NFT contract you can do this:

abstract contract Multicall is IMulticall {
    /// @inheritdoc IMulticall
    function multicall(bytes[] calldata data) public payable override returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}

And with typescript you can do something like:

const iface = new ethers.utils.Interface(NFT.abi)
let calls = []
const expender: YOUR_ADDRESS

for(const owner in owners){
 calls.push(iface.encodeFunctionData("approve", [owner, expender]))
}

tx = NFT.multicall(calls)
tx.wait()

Just a glimpse on how to do it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.