I want to transfer part of the value paid to an address whenever an NFT is traded. If the value is 0, then nothing is transferred.

My original idea was to override the transfer function in oppenzeppelin/ERC721, but its impossible to override a nonpayable function to payable.

Any way of doing this? The idea is for a DAO to make passive income every card trade.


You can make all the transfer functions private and add a fallback function which is payable. In the fallback function use msg.sig to determine which function to call. You can calculate the signatures like this.

bytes4 sigOne = bytes4(keccak256('safeTransferFrom(address,address,uint256)'))
bytes4 sigTwo = bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))

then you can implement the fallback function that calls the private transfer functions with arguments decoded. like so.

pragma solidity 0.6.6;

contract Test { 

    bytes4 sigOne = bytes4(keccak256('safeTransferFrom(address,address,uint256)'));
    bytes4 sigTwo = bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'));

    fallback () external payable {
        require(msg.value > 0);
        // transfer amount to the address

        bytes memory payload = abi.encodePacked(bytes28(0), msg.data);
        bytes4 sig = msg.sig;

        if (sig == sigOne) {
                bytes32 _,
                address from,
                address to,
                uint256 value,
            ) = abi.decode(payload, (bytes32, address, address, uint256));

            safeTransferFrom(from, to, value);
        } else if (sig == sigTwo) {
                bytes32 _,
                address from,
                address to,
                uint256 value,
                bytes memory data,
            ) = abi.decode(payload, (bytes32, address, address, uint256, bytes));

            safeTransferFrom(from, to, value, data);
        } else {
            revert("signature did not match");

Hope it helps!

  • ERC721 standard has a callable safeTransferFrom function. I could make this solution work in a custom app, but not across all apps and all sales Aug 20 '20 at 9:59
  • Update: ok I see what you mean, using a fallback function, however, I don't believe places like opensea expect eth to be sent during the call to safeTransferFrom method. So maybe this won't be possible Aug 20 '20 at 13:11
  • If you are talking about not being able to send ETH along then I believe Metamask might show the warning of failing tx because the ABI it would encode with will not be payable but ultimately it should go through even if you send the ETH. Aug 20 '20 at 17:34
  • right I appreciate this hack. Its a good work around. Gonna take a deep dive, see what I can come up with Aug 20 '20 at 19:33
  • Let me know what you come up with. I am also curious to know the solution. One other architecturally different way is to make fallback function accept ETH and record it in a mapping of address to uint256 acting as a pool and then upon transfer take out ETH from this mapping. Aug 20 '20 at 21:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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