Transfer Ownership of an NFT, as well as the Price and Commission in a Single Transaction

I am developing a dapp which will be used as a market where users can buy and sell NFTs from each other. From the dapp front-end, users will be calling the setApprovalForAll ERC721 function, granting my contract authorisation to sell their NFT tokens. Upon purchasing a token, the purchaser calls the tokTransfer function in my smart contract below. Since the user wishing to sell an NFT must have granted the contract permission to sell his items, I am using “this” in the this.safeTransferFrom(from, to, tokenId); function to initiate the transfer from my contract, which is working (although I am not sure if this is the recommended way). Meanwhile, although the NFT is transferred, the entire value of the transaction is also transferred to the contract, which is not my intention. I have tried to transfer the price of the NFT sold to the seller (“from”) and the commission for the service to the contract (address(this)) using the following lines in the function below, but I am obtaining an error. How can I transfer the ownership of the NFT token from the contract (which has been granted the proper permissions with setApprovalForAll), and the price and commission as explained above in a single transaction?

 function tokTransfer(address payable from, address to, uint256 tokenId, uint256 price, uint256 commission) payable external {
    this.safeTransferFrom(from, to, tokenId);

    (bool success, ) = from.call{value: price}('');
    require(success, "Transfer failed.");
    (success, ) = address(this).call{value: commission}('');
    require(success, "Transfer failed.");   
}

Thank you. J

1 Like

Hi @JF0001,

You could look at using sendValue but you need to handle reentrancy.

1 Like

Thank you @abcoathup However, doesn’t the sendValue function just call (internally) the same recipient.call function that I am using (from.call in my code)? Also, I am not sure if it would make a difference since the entire value transferred with the call from my front-end to the tokTransfer function on the smart contract is assigned to the contract following the execution of the this.safeTransferFrom function (in which the ownership of the NFT is transferred and the entire value transferred is assigned to the contract). Perhaps I am not using the proper approach.

Thank you again. J

1 Like

After doing more reading, it appears that I need to use another (proxy) smart contract to achieve this functionality.

Hi @JF0001,

I assumed that you can just do multiple sendValue functions, though I haven’t tried this out.

I wouldn’t think that you need to use a proxy.

1 Like

Thank you @abcoathup I am first transferring all the ethers passed to the contract with “this.safeTransferFrom(from, to, tokenId)”, and then passing from the contract to the seller the price of the NFT token using “seller.transfer(1 ether)”, and this is working fine. My question is why didn’t “(bool success, ) = seller.call{value: price}(’’)” worked? I thought hat this was the new recommended way of transferring ethers.

1 Like

Hi @JF0001,

If we ignore the transfer of the token owner for now and just look at the payment, you should be able to do something like the following simple example:

// contracts/MyContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "@openzeppelin/contracts/utils/Address.sol";

contract MyContract {
    using Address for address payable;

    function doStuff(address payable a, address payable b) public payable {
        // Do other stuff; beware of reentrancy

        a.sendValue(msg.value/2);
        b.sendValue(msg.value/2);
    }
}

With our contract we can call doStuff with a payment of 1 ether that it is split between accounts[1] and accounts[2]

truffle(develop)> c = await MyContract.new()
undefined
truffle(develop)> await c.doStuff(accounts[1], accounts[2], {from: accounts[0], value: web3.utils.toWei('1')})
{ tx:
...
truffle(develop)> web3.eth.getBalance(accounts[1])
'100500000000000000000'
truffle(develop)> web3.eth.getBalance(accounts[2])
'100500000000000000000'
1 Like

Thank you very much @abcoathup That works wonderfully! One last question if I may. As explained in my initial question, users are granting authorisation to the contract to sell their NFT tokens on their behalf, by using the setApprovalForAll function. I am then calling the safeTransferFrom function from the contract using the “this” keyword (i.e this.safeTransferFrom(seller, to, tokenId)). Is it expected behaviour that while transferring the token from the “seller” to the “to”, that the amount sent during the call of the tokTransfer function on the smart contract, is transferred to the contract (in exchange of the token) instead of to the seller (which explains why I need to transfer the selling price back to the seller after the token transfer)?

1 Like

Hi @JF0001,

tokTransfer is payable, so any value when calling that function is transferred to the contract, in the same function as transferring the token, you can transfer the Ether value minus any commission to the seller. You need to take care not to create reentrancy vulnerabilities when using sendValue

1 Like

Thank you @abcoathup

1 Like